Merge remote-tracking branch 'burnchart/master' into assembly
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
node_modules/
|
||||
*.log
|
||||
.build_cache~
|
||||
.grunt/
|
||||
build/*.map
|
||||
public/js/app.bundle.js
|
||||
public/js/app.js
|
||||
public/css/app.bundle.css
|
||||
public/css/app.css
|
89
Gruntfile.coffee
Normal file
@ -0,0 +1,89 @@
|
||||
module.exports = (grunt) ->
|
||||
grunt.initConfig
|
||||
|
||||
pkg: grunt.file.readJSON("package.json")
|
||||
|
||||
'clean': [
|
||||
'public/js'
|
||||
'public/css'
|
||||
]
|
||||
|
||||
'mkdir':
|
||||
all:
|
||||
options:
|
||||
create: [
|
||||
'public/js'
|
||||
'public/css'
|
||||
]
|
||||
|
||||
'stylus':
|
||||
app:
|
||||
src: [
|
||||
'src/styles/fonts.styl'
|
||||
'src/styles/icons.styl'
|
||||
'src/styles/chart.styl'
|
||||
'src/styles/notification.styl'
|
||||
'src/styles/app.styl'
|
||||
]
|
||||
dest: 'public/css/app.css'
|
||||
|
||||
'concat':
|
||||
css:
|
||||
src: [
|
||||
# Vendor dependencies.
|
||||
'node_modules/normalize.css/normalize.css'
|
||||
# Our style.
|
||||
'public/css/app.css'
|
||||
]
|
||||
dest: 'public/css/app.bundle.css'
|
||||
|
||||
'uglify':
|
||||
bundle:
|
||||
files:
|
||||
'public/js/app.bundle.min.js': 'public/js/app.bundle.js'
|
||||
|
||||
'cssmin':
|
||||
bundle:
|
||||
files:
|
||||
'public/css/app.min.css': 'public/css/app.css'
|
||||
'public/css/app.bundle.min.css': 'public/css/app.bundle.css'
|
||||
|
||||
'gh-pages':
|
||||
options:
|
||||
base: 'public'
|
||||
branch: 'gh-pages'
|
||||
message: 'Publish to GitHub Pages'
|
||||
push: yes
|
||||
add: yes
|
||||
src: [
|
||||
'css/**/*'
|
||||
'fonts/**/*'
|
||||
'img/**/*'
|
||||
'js/**/*'
|
||||
]
|
||||
|
||||
grunt.loadNpmTasks('grunt-mkdir')
|
||||
grunt.loadNpmTasks('grunt-contrib-clean')
|
||||
grunt.loadNpmTasks('grunt-contrib-stylus')
|
||||
grunt.loadNpmTasks('grunt-contrib-concat')
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify')
|
||||
grunt.loadNpmTasks('grunt-contrib-cssmin')
|
||||
grunt.loadNpmTasks('grunt-gh-pages');
|
||||
|
||||
# Stylus to CSS, concat all CSS.
|
||||
grunt.registerTask('css', [
|
||||
'stylus:app'
|
||||
'concat:css'
|
||||
])
|
||||
|
||||
# Cleanup public directories.
|
||||
grunt.registerTask('init', [
|
||||
'clean'
|
||||
'mkdir'
|
||||
])
|
||||
|
||||
# Minify JS, CSS and concat JS.
|
||||
grunt.registerTask('minify', [
|
||||
'uglify'
|
||||
'cssmin'
|
||||
])
|
661
LICENSE
Normal file
@ -0,0 +1,661 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
28
Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
# Install dependencies.
|
||||
install:
|
||||
npm install
|
||||
|
||||
# Watch the app sources and build with source maps.
|
||||
watch:
|
||||
./node_modules/.bin/watchify -e ./src/app.coffee -o public/js/app.bundle.js -d -v
|
||||
|
||||
# Serve locally.
|
||||
serve:
|
||||
./node_modules/.bin/static public -H '{"Cache-Control": "no-cache, must-revalidate"}'
|
||||
|
||||
# Make a minified package.
|
||||
build:
|
||||
grunt init
|
||||
./node_modules/.bin/browserify -e ./src/app.coffee -o public/js/app.bundle.js
|
||||
grunt css
|
||||
grunt minify
|
||||
|
||||
# Publish to GitHub Pages.
|
||||
publish:
|
||||
grunt gh-pages
|
||||
|
||||
# Run mocha test.
|
||||
test:
|
||||
./node_modules/.bin/mocha --compilers coffee:coffee-script/register --reporter spec --ui exports --timeout 20000 --slow 15000 --bail
|
||||
|
||||
.PHONY: test
|
54
README.md
Normal file
@ -0,0 +1,54 @@
|
||||
#burnchart
|
||||
|
||||
GitHub Burndown Chart as a service. Answers the question "are my projects on track"?
|
||||
|
||||
[![Build Status](http://img.shields.io/codeship/<ID_HERE>.svg?style=flat)](<URL_HERE>)
|
||||
[![Dependencies](http://img.shields.io/david/radekstepan/burnchart.svg?style=flat)](https://david-dm.org/radekstepan/burnchart)
|
||||
[![License](http://img.shields.io/badge/license-AGPL--3.0-red.svg?style=flat)](LICENSE)
|
||||
|
||||
##Notes
|
||||
|
||||
- *payment gateways* in Canada: [Shopify](http://www.shopify.com/payment-gateways/canada), [Chargify](http://chargify.com/payment-gateways/) list; I get free processing on first $1000 with [Stripe](https://education.github.com/pack/offers)
|
||||
- start people on a *Community* plan showing them a comparison table to upgrade to a better offering
|
||||
- community (open source, local storage), business (private repos, firebase)
|
||||
- keep discussion going via [gitter](http://gitter.im) or have people comment from the app via [helpful](https://helpful.io/)
|
||||
- [credit card form](http://designmodo.com/ux-credit-card-payment-form/) ux from Designmodo
|
||||
- workers: using a free instance of IronWorker and assuming 5s runtime each time gives us a poll every 6 minutes. Zapier would poll every 15 minutes but already integrates Stripe and FB.
|
||||
- worst case scenario I provide even Small Business plan for free and provide a better experience
|
||||
- $2.5 Node.js PaaS via Gandi with promo code `PAASLAUNCH-C50E-B077-A317`.
|
||||
- let people vote on features they want to see fast: [tally.tl](http://tally.tl/).
|
||||
- use [readme.io](https://readme.io/) for documentation
|
||||
- send handwritten thank you cards to the first customers
|
||||
- use [DigitalOcean](https://www.digitalocean.com/) as a GitHub Student (@bath.edu email) to get $100 in platform credits which translates to 20 months on the slowest (fast enough) dyno
|
||||
- payments need to be automatic, why penalize users that are loyal to us with a burden of an admin task?
|
||||
- ability to use the program needs to be frictionless; jump straight into the action, fill in data behind the scenes etc.
|
||||
- send reminders to people whose account is expiring
|
||||
- [Waffle](https://waffle.io/) from Rally software has a kanban board that will support [burnup chart](https://waffle.io/waffleio/waffle.io/cards/53e5347682b317f7d9ad6eac); it will charge $7/month
|
||||
- should we be part of https://www.zenhub.io/pricing? Pricing is per bundle of users, interesting.
|
||||
|
||||
##Plans
|
||||
|
||||
###Community Plan
|
||||
|
||||
- your repos are saved locally
|
||||
- no auto-updates to milestones, everything fetched on page load
|
||||
- no private repos
|
||||
|
||||
###Business Plan
|
||||
|
||||
- you need to pay for a license to use the app for business purposes
|
||||
- repos, milestones saved remotely
|
||||
- auto-update with new information
|
||||
- private repos
|
||||
|
||||
###Free Forever Business Plan (= Community Shareholder/Partners Plan)
|
||||
|
||||
I can't sell people on free membership, that is only a small incentive. But I can sell them on an app that does what they want. Have early access to features etc. If someone sees that my app can help them, why not tell me about it so I can make it happen?
|
||||
|
||||
I could also provide people with Assembly coins for each feedback session I've had with them, thus making them share in the profits. They are basically startup members with equity by being Product Developers.
|
||||
|
||||
To qualify, these people need to be businesses actively using the software. Thus being standin-users for other such $ paying businesses.
|
||||
|
||||
Let me call you every 3 months to ask how you are doing, how you are using the software, what can I improve, and you will get 3 months usage for free. The idea is to keep in touch with the most loyal customers, to hear them say how great/shabby the app is. If they don't want to talk they can always pay for the Business Plan.
|
||||
|
||||
If someone stops using the app, send them an email asking them for a good time to call so I can make things right. They would get 3 months usage as well.
|
237
docs/NOTES.md
Normal file
@ -0,0 +1,237 @@
|
||||
#Firebase Notes
|
||||
|
||||
##Write
|
||||
|
||||
Access a child from a root (db) reference:
|
||||
|
||||
rootRef.child('users/mchen/name');
|
||||
|
||||
Save a new user to the db:
|
||||
|
||||
var usersRef = ref.child("users");
|
||||
usersRef.set({
|
||||
alanisawesome: {
|
||||
date_of_birth: "June 23, 1912",
|
||||
full_name: "Alan Turing"
|
||||
},
|
||||
gracehop: {
|
||||
date_of_birth: "December 9, 1906",
|
||||
full_name: "Grace Hopper"
|
||||
}
|
||||
});
|
||||
|
||||
Flatten all data otherwise we are retrieving all children.
|
||||
|
||||
Check if we have a member of a group which could be used to check if we have a GitHub user stored in the db:
|
||||
|
||||
// see if Mary is in the 'alpha' group
|
||||
var ref = new Firebase("https://docs-examples.firebaseio.com/web/org/users/mchen/groups/alpha");
|
||||
ref.once('value', function(snap) {
|
||||
var result = snap.val() === null? 'is not' : 'is';
|
||||
console.log('Mary ' + result + ' a member of alpha group');
|
||||
});
|
||||
|
||||
##Read
|
||||
|
||||
The following should get triggered everytime we add a new repo to our list, updating our local (Ractive) ref. It gets called for every existing member too.
|
||||
|
||||
// Get a reference to our posts
|
||||
var postsRef = new Firebase("https://docs-examples.firebaseio.com/web/saving-data/fireblog/posts");
|
||||
|
||||
// Retrieve new posts as they are added to Firebase
|
||||
postsRef.on('child_added', function (snapshot) {
|
||||
var newPost = snapshot.val();
|
||||
console.log("Author: " + newPost.author);
|
||||
console.log("Title: " + newPost.title);
|
||||
});
|
||||
|
||||
Changes can be monitored like the following. This should work even in offline mode so we should not be changing our local state but Firebase state which calls us back with the changes.
|
||||
|
||||
// Get a reference to our posts
|
||||
var postsRef = new Firebase("https://docs-examples.firebaseio.com/web/saving-data/fireblog/posts");
|
||||
|
||||
// Get the data on a post that has changed
|
||||
postsRef.on('child_changed', function (snapshot) {
|
||||
var changedPost = snapshot.val();
|
||||
console.log('The updated post title is ' + changedPost.title);
|
||||
});
|
||||
|
||||
When we remove a repo:
|
||||
|
||||
// Get a reference to our posts
|
||||
var postsRef = new Firebase("https://docs-examples.firebaseio.com/web/saving-data/fireblog/posts");
|
||||
|
||||
// Get the data on a post that has been removed
|
||||
postsRef.on('child_removed', function (snapshot) {
|
||||
var deletedPost = snapshot.val();
|
||||
console.log('The blog post titled' + deletedPost.title + ' has been deleted');
|
||||
});
|
||||
|
||||
##Security
|
||||
|
||||
Write new users, do not update them, but allow delete.
|
||||
|
||||
// we can write as long as old data or new data does not exist
|
||||
// in other words, if this is a delete or a create, but not an update
|
||||
".write": "!data.exists() || !newData.exists()"
|
||||
|
||||
Accessing dynamic paths in the rules can be done using a `$` prefix. This serves as a wild card, and stores the value of that key for use inside the rules declarations:
|
||||
|
||||
{
|
||||
"rules": {
|
||||
"rooms": {
|
||||
// this rule applies to any child of /rooms/, the key for each room id
|
||||
// is stored inside $room_id variable for reference
|
||||
"$room_id": {
|
||||
"topic": {
|
||||
// the room's topic can be changed if the room id has "public" in it
|
||||
".write": "$room_id.contains('public')"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[User-based rules](https://www.firebase.com/docs/web/guide/user-security.html).
|
||||
|
||||
Use `uid` from Simple Login which is a string ID guaranteed to be unique across all providers.
|
||||
|
||||
Grant write access for this user.
|
||||
|
||||
{
|
||||
"rules": {
|
||||
"users": {
|
||||
"$user_id": {
|
||||
// grants write access to the owner of this user account
|
||||
// whose uid must exactly match the key ($user_id)
|
||||
".write": "$user_id === auth.uid",
|
||||
|
||||
"email": {
|
||||
// an email is only allowed in the profile if it matches
|
||||
// the auth token's email account (for Google or password auth)
|
||||
".validate": "newData.val() === auth.email"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
We want repos to have a 1 to many users mapping. This way changes in one get propagated to others. The issue is that users may be kicked from a project in which case they can't see the cached stats for a repo.
|
||||
|
||||
We can get [repositories](https://developer.github.com/v3/repos/) for a user, but we have to get orgs too and get repos there again.
|
||||
|
||||
###Getting latest repo changes
|
||||
|
||||
Only users that have a `user` timestamp on repos < 30m (our config) can receive updates from repos. Otherwise we try to fetch the latest permissions from GitHub with a x minute/second retry.
|
||||
|
||||
We get the latest data from GitHub if our data is > 30s old (user configured). Then we broadcast latest changes to all other users (including us) updating the `age` timestamp on the repo. Receiving updates resets the user-set timeout.
|
||||
|
||||
Since we do not have control over GitHub repos, we need to take care of all situations that can arise:
|
||||
|
||||
1. Repo gives us 404 (does not exist or we don't have perms): remove user from `repo`.
|
||||
1. Repo gives us success: add user to the `repo`; trigger a poll if needed to fetch latest data
|
||||
1. GitHub times out: set a system `status` message to all
|
||||
1. We run out of requests we can make: show a message to the user, similar to GitHub timeout but only to that one specific user
|
||||
|
||||
[GitHub shows 404](https://developer.github.com/v3/troubleshooting/#why-am-i-getting-a-404-error-on-a-repository-that-exists) when we don't have access OR repo does not exist.
|
||||
|
||||
Keep track of last update to a repo so we can clear old projects (later, as needed).
|
||||
|
||||
Only use repo name when we are adding the user to the repo, from there on use the repo `id` which will be preserved even if the repo is renamed. But the [milestones API](https://developer.github.com/v3/issues/milestones/) does not use the `id` :(, in which case we would show 404 and let the user delete this and add a new one. Alternatively, try to fetch the new repo name from GitHub after making a query to get the repo by its `id`:
|
||||
|
||||
GET /repositories/:id
|
||||
|
||||
When fetching the issues, we can constrain on a `milestone` and `state`.
|
||||
|
||||
**Vulnerability**: if we share repos between users, one of them can write whatever change she wants and *spoil* the chart for others. Until we fix this, let us have a 1 repo to 1 user mapping.
|
||||
|
||||
##Design
|
||||
|
||||
###Adding a new user
|
||||
|
||||
- [ ] we get a `user` object from GH
|
||||
- [ ] get a list of repos from FB by asking for our `user` root
|
||||
- [ ] *a*: user is not there so let us create this root object
|
||||
- [ ] *b*: user is there so we get back a list of repos
|
||||
|
||||
###Adding a new repo
|
||||
|
||||
- [ ] make a request to GH fetching a repo by `user/repo`
|
||||
- [ ] *a*: GH gives us 404 - show a message to the user
|
||||
- [ ] *b1*: we get back a repo object, so a write into our `user` root as a `set()` operation (overriding any existing entry if it exists)
|
||||
- [ ] *b2*: in client register our repo to receive updates from FB and since it is new - it triggers a fetch from GH immediately
|
||||
|
||||
Have the following [script](http://www.google.com/url?q=http%3A%2F%2Fjsfiddle.net%2Fkatowulf%2F5ESSp%2F&sa=D&sntz=1&usg=AFQjCNGCBxXSIqExOhOjtjSExWsrwmN8cQ) check that `private` repos are allowed:
|
||||
|
||||
"$user": {
|
||||
repos: {
|
||||
"$private": {
|
||||
".validate": "($private == false) || subscribers.$user != null"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
###Updating a repo
|
||||
|
||||
- [ ] listen for our `user`, `repo` changes from FB which actually will render new data
|
||||
- [ ] our local repo object has an `age` information, if it reaches a threshold, trigger a fetch from GH
|
||||
- [ ] *a*: GH gives us 404 - show a message to the user saying last `state` on the repo, e.g. last success 5 minutes ago, keep showing the *old* data if any
|
||||
- [ ] *b*: GH gives us data, make an `update()` on FB saying `state` is `null` (OK) updating the `age` to time now
|
||||
|
||||
###Deleting a repo
|
||||
|
||||
- [ ] remove our `repo` under the `user`, no questions asked. All subscribers are switched off and views disposed of
|
||||
|
||||
###Deleting a user
|
||||
|
||||
- [ ] execute a `remove()` in FB if our tokens match for a user, will remove all repos too
|
||||
|
||||
###Upgrading an account to private repos
|
||||
|
||||
Private repos (extra `scope` in FB login) are part of a paid plan. Need to recognize that a user has an active paid account with us, before using the extended scope.
|
||||
|
||||
GH repositories have a `private` flag.
|
||||
|
||||
Since we do not *trust* users it is I that need to be upgrading users, at the same time it needs to be automatic.
|
||||
|
||||
We should not kill a user if they are no longer paid, maybe they got behind a payment, just disable latest data from private repos.
|
||||
|
||||
Set the private scope on all auth and put the burden on me to proove who has paid for an account or not, since someone could send a request to FB saying that a repo is public when it is not.
|
||||
|
||||
I can run a script once in a while to see whose repo returns 404 when it is set as `private = false`, put the burden on me to prove.
|
||||
|
||||
Using a free instance of [IronWorker](http://dev.iron.io/worker/reference/environment/#maximum_run_time_per_worker) and assuming 5s runtime each time gives us a poll every 6 minutes.
|
||||
|
||||
[Zapier](https://zapier.com/zapbook/firebase/stripe/) would poll every 15 minutes but already integrates Stripe and FB.
|
||||
|
||||
Because security rules cannot override existing rules, we need to separate the table of subscribers from saving the info on the user herself.
|
||||
|
||||
People buy subscriptions that extends their expiry date. This expiry date is calculated and set by the worker who adds together all subscriptions to come up with an *end date*.
|
||||
|
||||
One can use `Firebase.ServerValue.TIMESTAMP` for accurate timestamping.
|
||||
|
||||
- [ ] fetch updates for a `private` repo only if our user has a `plan` flag set to `business` or whatever
|
||||
- [ ] use a JS library to allow Stripe payment processing; people submit their card details and we get a Stripe `token` back. Save this token and on FB under `payments/processing/user` collection (*dirty*).
|
||||
- [ ] have a worker process the `payments/processing/user` ever 6 minutes or faster via IronWorker, once processed, move the payment into `payments/processed/user` collection that is writable only with our admin token and is read-only for the user
|
||||
- [ ] run an extra worker to check for for repos that return 404 when user is on an `open-source` plan; this is to find cheaters
|
||||
- [ ] run an extra worker that checks for `business` plans and if we have `payments` for these or not
|
||||
- [ ] show user a list of her subscription purchases, that shows the state of the processing as workers go through these. She needs to see a due date so assume all purchases went through and do a date calculation on the client
|
||||
|
||||
The following [approach](http://stackoverflow.com/a/21220875/105707) will allow write access to certain paths by a worker:
|
||||
|
||||
|
||||
var FirebaseTokenGenerator = require("firebase-token-generator");
|
||||
var tokenGenerator = new FirebaseTokenGenerator(YOUR_FIREBASE_SECRET);
|
||||
var token = tokenGenerator.createToken({ 'isWorker': true }, { 'expires': 0 });
|
||||
|
||||
{
|
||||
"rules:
|
||||
".read": "auth.isWorker === true"
|
||||
}
|
||||
|
||||
##Components Architecture
|
||||
|
||||
1. **Views** (components) orchestrate user input, this could be coming from browser events but also 3rd party data sources like GitHub.
|
||||
1. Ractive **Models** communicate among themselves via Mediator and are observed by Views.
|
||||
1. **Persistence** layer has modules that communicate with `Firebase` and `localForage` to persist Model data in the browser or in a remote db.
|
89
docs/TODO.md
Normal file
@ -0,0 +1,89 @@
|
||||
#Tasks to do
|
||||
|
||||
- [ ] create notes about how original people can upgrade to burnchart
|
||||
- [ ] clean up docs, track them on git or using Assembly system?
|
||||
- [ ] rename repo to burnchart
|
||||
- [ ] check with austin@assembly.com if my repo looks good to be forked to Assembly
|
||||
- [ ] move domain to Assembly
|
||||
- [ ] fork it to Assembly
|
||||
- [ ] move tests from `radekstepan/github-burndown-chart`
|
||||
- [ ] landing page for the project and put message on `github-burndown-chart` repo
|
||||
- [ ] provide a documentation site (because we ref it from hero)
|
||||
- [ ] track users/make it easy for people to leave feedback
|
||||
|
||||
##Next Release
|
||||
|
||||
- [ ] http://burnchart.io#rails I would expect it to list all the projects for that owner so I can select one of them (Ryan)
|
||||
|
||||
##Backlog
|
||||
|
||||
- [ ] be able to specify milestone by name (will nicely show in title)
|
||||
- [ ] focus on form fields style (blue outline etc)
|
||||
- [ ] switch off `user-select` on buttons
|
||||
- [ ] make async pages transition so that there is no "jumping" on the page
|
||||
- [ ] index page alert tooltip (like on chart page)
|
||||
- [ ] app icon like http://thenounproject.com/term/fire/50966/
|
||||
- [ ] tell people if they have no due date
|
||||
- [ ] calculate left margin based on the total number of points text width
|
||||
- [ ] responsive layout
|
||||
- [ ] show project name on the milestone page, in the title
|
||||
- [ ] conctact the people that have starred the original burndown chart telling them about the repo; keep track of connects via a tiny crm/spreadsheet and use a custom email address like radek@burnchart.io
|
||||
- [ ] html entities (like & at the bottom of the page) are not being rendered correctly; {{{}}} ?
|
||||
- [ ] `rails/rails/24` has issues in two clusters as if merged from two milestones
|
||||
- [ ] trendline cutting into axes
|
||||
- [ ] topbar messages set position from `top`, does not work when we have scrolled on the page; show sticky to the top and move with our scroll; at the very least make them show up at the top and not be hidden
|
||||
- [ ] GitHub Pages 404 file
|
||||
- [ ] deal with Firebase timing out, are we still logged-in?
|
||||
- [ ] check that we have not run out of requests to make
|
||||
- [ ] what if milestone does not match our strategy?
|
||||
- [ ] web storage and location hash supported by 93% of browsers; good enough?
|
||||
- [ ] create a 500/400/loading system messages
|
||||
- [ ] mediator `!app/notify/edit` will edit the current notification
|
||||
- [ ] handle multiple notifications, for example success on closed milestone and then show a different chart or add a project
|
||||
- [ ] be able to logout
|
||||
- [ ] be able to delete added projects; see the cog at the bottom of tables
|
||||
- [ ] how GitHub show commit activity in weekly slots, can we have something like this in the chart? Basically show commits in that week and their users
|
||||
- [ ] add a chart straight from the hero banner
|
||||
- [ ] on chart page show a little progress bar in the title
|
||||
- [ ] use tap plugin for `Ractive`
|
||||
- [ ] the app bundle (albeit uncompressed) clocks in at 1.5MB, reduce the size (`d3` is huge (use [grunt-smash](https://github.com/cvisco/grunt-smash), [docs here](https://github.com/mbostock/smash/wiki)), `localForage` not nedded)
|
||||
- [ ] make the names consistent, reuse code, template etc.
|
||||
- [ ] implement search box that quickly takes you to a chart (and may hide "pro actions")
|
||||
- [ ] make an extensible architecture; for example I might want to enable another trendline in the chart which shows estimated end date if one keeps up the pace of last 5 days.
|
||||
- [ ] desktop app via `node-gyp`
|
||||
- [ ] when watching, only build changed files and then concat them to make builds much faster
|
||||
- [ ] smooth animation when transitioning between icons and notifications
|
||||
- [ ] show animated lines when drawing the chart
|
||||
- [ ] highlight changes from past fetch
|
||||
- [ ] In add a project form autocomplete on my username, orgs I am member of and repos I have access to
|
||||
- [ ] Make sure the padding fits throughout the interface; we have user-select on elements.
|
||||
- [ ] Have an app wide of triggering a URL and have named routes too
|
||||
- [ ] rotate between percentage progress and points left
|
||||
- [ ] be able to config options through UI that currently have to be hardcoded in config
|
||||
- [ ] choose your own theme
|
||||
- [ ] show burndown chart for all milestones
|
||||
- [ ] handle Enterprise editions of GH (signed up in gh dev program)
|
||||
- [ ] auto-update the chart (with delay when no activity) when logged-in
|
||||
- [ ] add weekly velocity across all projects and a bar chart to that effect
|
||||
- [ ] show a little lightning and a number for today's velocity
|
||||
- [ ] show burnchart only for your tasks; this would be a second category of projects & tasks in the dashboard
|
||||
- [ ] show an overall text-based status like: all projects on time etc.
|
||||
- [ ] until GH fix milestone start date then provide an option to specify it (either do that on GH server or locally); for example a text like this: `starts: 09-10-2014` in the description which we provide regex for
|
||||
- [ ] work on mobile devices
|
||||
- [ ] show velocity number for each member of the team in the corner of the layout (the point is to get better at planning how many tasks can people take on, thus how fast can we work)
|
||||
- [ ] if we have the above, we could get a suggestion as to how many points we are able to go through in the next iteration while keeping everyone at their max capacity. One could almost drag & drop tasks to people and see a live progress of how the ideal trendline will fare based on a known speed of people; or we could be somehow notified that people are maxed out
|
||||
- [ ] show velocity for all team members and how it progresses through time
|
||||
- [ ] points collector - give medals for 1st 3 spots in terms of velocity
|
||||
- [ ] show past commits or due dates like in [this calendar](https://dribbble.com/shots/1736128-Meetups-Page?list=shots&sort=popular&timeframe=now&offset=5)
|
||||
- [ ] support Jira & Gitlab
|
||||
- [ ] when fetching subsequent updates, fetch only the last page of issues since some repos are large (2.5MB & 19 pages for `mbostock/d3`); actually that is for all issues, not milestone constrained. So only an issue if we want to see a burnchart for all the issues for a repo
|
||||
- [ ] if all issue circles are close to each other, make a "master circle" that amalgamates all the issues into one large circle, makes for a prettier view
|
||||
- [ ] make better x-axis date display, otherwise we see all 1s.
|
||||
- [ ] some [fun loading messages](http://www.gamefaqs.com/pc/561176-simcity-4/faqs/22135) from Sim City.
|
||||
- [ ] show number of tasks, points, days left just like in Assembly on chart page
|
||||
- [ ] receive reminders when a due date is nearing and our project is behind schedule; receive a daily digest saying how the progress went in that day/week; these are all ways we can help people answer the question: is my project on track?
|
||||
- [ ] if we save user's tokens we could check data on their behalf, then messaging would work; API could be provided so that others could plug into the data
|
||||
- [ ] derive insights; one part is to see if we are on track, the other is to get better at estimating. If we know when an issue is worked on and when closed, with its accompanying size, we can say which issues went well, and which fared poorly. Then we can visualize a weekly/monthly/per-milestone list of loosers and winners. Perhaps the user can glean a pattern from that.
|
||||
- [ ] create fake Firebase endpoint for GitHub auth, or change the endpoint in settings (easier)
|
||||
- [ ] have an icon that shows a progress for a milestone that can be shown on GitHub README page
|
||||
- [ ] try appending '.0' to milestone titles to pass `semver` validation and compare 4.0, 5.x etc.
|
64
package.json
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "burnchart",
|
||||
"version": "0.0.0",
|
||||
"description": "GitHub Burndown Chart as a Service",
|
||||
"author": "Radek Stepan <dev@radekstepan.com> (http://radekstepan.com)",
|
||||
"license": "AGPL-3.0",
|
||||
"keywords": [
|
||||
"github",
|
||||
"issues",
|
||||
"burndown",
|
||||
"chart",
|
||||
"scrum"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/radekstepan/burnchart.git"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "make serve",
|
||||
"test": "make test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"grunt": "~0.4.5",
|
||||
"grunt-mkdir": "~0.1.2",
|
||||
"grunt-contrib-clean": "~0.6.0",
|
||||
"grunt-contrib-stylus": "~0.9.0",
|
||||
"grunt-contrib-concat": "~0.5.0",
|
||||
"grunt-contrib-uglify": "~0.6.0",
|
||||
"grunt-contrib-cssmin": "~0.10.0",
|
||||
"grunt-gh-pages": "~0.9.1",
|
||||
"coffeeify": "~0.7.0L",
|
||||
"ractivate": "~0.2.0",
|
||||
"browserify": "~6.1.0",
|
||||
"watchify": "~2.1.0",
|
||||
"node-static": "~0.7.6",
|
||||
|
||||
"mocha": "~2.0.1",
|
||||
"coffee-script": "~1.8.0",
|
||||
|
||||
"async": "~0.9.0",
|
||||
"d3": "~3.4.13",
|
||||
"d3-tip": "Caged/d3-tip",
|
||||
"proxyquire": "~1.0.1",
|
||||
"lodash": "~2.4.1",
|
||||
"director": "~1.2.3",
|
||||
"firebase": "~1.1.2",
|
||||
"lscache": "~1.0.2",
|
||||
"marked": "~0.3.2",
|
||||
"moment": "~2.8.3",
|
||||
"normalize.css": "~3.0.2",
|
||||
"ractive": "~0.6.1",
|
||||
"ractive-ractive": "~0.4.4",
|
||||
"ractive-transitions-fade": "~0.1.2",
|
||||
"sortedindex-compare": "0.0.1",
|
||||
"superagent": "~0.20.0",
|
||||
"semver": "~4.1.0"
|
||||
},
|
||||
"browserify": {
|
||||
"transform": [
|
||||
"coffeeify",
|
||||
"ractivate"
|
||||
]
|
||||
}
|
||||
}
|
1
public/css/app.bundle.min.css
vendored
Normal file
1
public/css/app.min.css
vendored
Normal file
BIN
public/fonts/fontello.eot
Normal file
25
public/fonts/fontello.svg
Normal file
@ -0,0 +1,25 @@
|
||||
<?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>Copyright (C) 2014 by original authors @ fontello.com</metadata>
|
||||
<defs>
|
||||
<font id="fontello" horiz-adv-x="1000" >
|
||||
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
|
||||
<missing-glyph horiz-adv-x="1000" />
|
||||
<glyph glyph-name="cog" unicode="" d="m0 289v124q0 7 5 13t10 7l104 16q8 25 22 51-23 32-60 77-6 7-6 14 0 5 5 12 15 20 55 60t53 40q7 0 15-5l77-60q24 13 50 21 9 76 17 104 3 15 20 15h124q7 0 13-4t7-12l15-103q28-9 50-21l80 60q5 5 13 5 7 0 14-5 72-67 92-95 4-5 4-13 0-6-4-12-9-12-29-38t-30-39q14-28 23-55l102-15q7-1 12-7t4-13v-124q0-7-4-13t-11-7l-104-16q-10-30-21-51 19-28 59-77 6-6 6-14t-5-12q-15-21-55-61t-53-39q-7 0-14 5l-77 60q-25-13-51-21-9-76-16-104-4-16-20-16h-124q-8 0-14 5t-6 12l-16 103q-27 9-50 20l-79-59q-6-5-14-5-8 0-14 6-70 63-92 94-4 5-4 12 0 7 5 13 8 12 28 37t30 40q-15 28-23 55l-102 15q-7 1-11 7t-5 13z m286 61q0-59 42-101t101-42 101 42 41 101-41 101-101 42-101-42-42-101z" horiz-adv-x="857.1" />
|
||||
<glyph glyph-name="search" unicode="" d="m0 386q0 80 31 152t84 126 125 84 153 31 152-31 126-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51 0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 83-84 126-31 153z m143 0q0-103 73-177t177-73 176 73 74 177-74 176-176 74-177-74-73-176z" horiz-adv-x="928.6" />
|
||||
<glyph glyph-name="github" unicode="" d="m0 270q0 132 76 221-15 45-15 94 0 65 28 122 61 0 106-22t106-69q82 20 172 20 83 0 156-18 59 46 105 67t105 22q29-57 29-122 0-48-15-93 76-90 76-222 0-116-34-185-22-43-59-74t-79-48-95-27-96-12-93-3q-43 0-79 2t-82 7-85 17-77 28-67 46-48 64q-35 69-35 185z m125-99q0-49 18-85t45-58 68-33 78-17 83-4h94q46 0 83 4t78 17 69 33 45 58 18 85q0 67-39 114t-104 47q-23 0-109-12-40-6-88-6t-87 6q-85 12-109 12-66 0-104-47t-39-114z m89 0q0 23 7 46t24 43 41 19 40-19 24-43 7-46-7-45-24-43-40-19-41 19-24 43-7 45z m357 0q0 23 7 46t24 43 41 19 40-19 24-43 7-46-7-45-24-43-40-19-41 19-24 43-7 45z" horiz-adv-x="928.6" />
|
||||
<glyph glyph-name="address" unicode="" d="m426 800q20 0 20-20l0-860q0-20-20-20l-46 0q-20 0-20 20l0 440-176 0q-16 0-28 6-12 2-26 12l-120 82q-10 6-10 16t10 16l120 82q14 10 26 12 8 4 28 4l176 0 0 190q0 20 20 20l46 0z m564-208q10-6 10-16t-10-16l-118-82q-22-12-26-12-14-6-28-6l-302 0-40 230 342 0q18 0 28-4t26-12z" horiz-adv-x="1000" />
|
||||
<glyph glyph-name="plus-circled" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m179-36q0-14 10-25t25-10h143v-143q0-15 11-25t25-11h71q15 0 25 11t11 25v143h143q14 0 25 10t11 25v72q0 14-11 25t-25 10h-143v143q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-143h-143q-14 0-25-10t-10-25v-72z" horiz-adv-x="857.1" />
|
||||
<glyph glyph-name="fire-station" unicode="" d="m425 775l-175-250-100 150c-33-58-150-200-150-350 0-221 204-400 425-400 221 0 425 179 425 400 0 150-117 292-150 350l-100-150z m0-400s175-134 175-250c0-50-75-100-175-100s-175 50-175 100c0 112 175 250 175 250z" horiz-adv-x="850" />
|
||||
<glyph glyph-name="sort-alphabet" unicode="" d="m516 165q12-25-2-50t-44-25q-33 0-47 29l-37 75-249 0-37-75q-9-20-30-27t-40 3q-20 9-27 29t3 41l209 417q13 27 47 27t46-27z m-326 134l143 0-72 143z m905-209l-313 0q-30 0-45 27t4 57l250 332-209 0q-21 0-37 16t-15 37 15 36 37 16l313 0q30 0 45-28t-4-56l-250-333 209 0q21 0 37-15t15-37-15-37-37-15z m-417 209l-105 0q-21 0-36 15t-15 36 15 37 36 15l105 0q22 0 37-15t15-37-15-36-37-15z" horiz-adv-x="1147" />
|
||||
<glyph glyph-name="down-open" unicode="" d="m50 425q0 14 11 25l92 92q11 11 26 11t25-11l296-296 296 296q11 11 25 11t26-11l92-92q11-11 11-25t-11-26l-414-413q-10-11-25-11t-25 11l-414 413q-11 11-11 26z" horiz-adv-x="1000" />
|
||||
<glyph glyph-name="spin6" unicode="" d="m855 9c-189-190-520-172-705 13-190 190-200 494-28 695 11 13 21 26 35 34 36 23 85 18 117-13 30-31 35-76 16-112-5-9-9-15-16-22-140-151-145-379-8-516 153-153 407-121 542 34 106 122 142 297 77 451-83 198-305 291-510 222l0 1c236 82 492-24 588-252 71-167 37-355-72-493-11-15-23-29-36-42z" horiz-adv-x="1000" />
|
||||
<glyph glyph-name="megaphone" unicode="" d="m0 413q0 66 36 111t89 45l289 0q63 0 119 45t96 125l2 0q58 111 150 111 102 0 160-131t59-307-59-306-160-131q-92 0-150 111l-2 0q-78 155-199 168-6-2-8-2l0-2q-6-2-10-7-2-2-2-4-4-6-4-12l0-221q0-8 16-26t16-36l0-32q0-25-19-43t-44-19l-125 0q-25 0-44 19t-18 43l0 282q0 25-19 44t-44 18q-53 0-89 45t-36 111z m63 0q0-40 18-67t44-27l219 0q-31 37-31 94t31 93l-219 0q-25 0-44-27t-18-66z m169-157q18-29 18-62l0-282 125 0 0 28-2 2-2 2q-27 33-27 62l0 219q0 16 6 31l-118 0z m112 157q0-40 18-67t44-27l8 0q86 0 162-63-13 74-13 157 0 80 13 156-76-63-162-63l-8 0q-25 0-44-27t-18-66z m281 0q0-47 6-94l88 0q25 0 44 27t18 67-18 66-44 27l-88 0q-6-47-6-93z m14-157q19-97 57-158t85-60q65 0 111 109t45 266-45 265-111 109q-47 0-85-60t-57-158l80 0q52 0 89-45t36-112-36-111-89-45l-80 0z" horiz-adv-x="1000" />
|
||||
<glyph glyph-name="spin4" unicode="" d="m498 850c-114 0-228-39-320-116l0 0c173 140 428 130 588-31 134-134 164-332 89-495-10-29-5-50 12-68 21-20 61-23 84 0 3 3 12 15 15 24 71 180 33 393-112 539-99 98-228 147-356 147z m-409-274c-14 0-29-5-39-16-3-3-13-15-15-24-71-180-34-393 112-539 185-185 479-195 676-31l0 0c-173-140-428-130-589 31-134 134-163 333-89 495 11 29 6 50-12 68-11 11-27 17-44 16z" horiz-adv-x="1001" />
|
||||
<glyph glyph-name="spinner1" unicode="" d="m469 614v204q129 0 237-61t169-170 62-237h-204q0 72-36 133t-95 96-133 35z" horiz-adv-x="937.5" />
|
||||
<glyph glyph-name="attention" unicode="" d="m957-24q10-16 0-34-10-16-30-16l-892 0q-18 0-28 16-13 18-2 34l446 782q8 18 30 18t30-18z m-420 50l0 100-110 0 0-100 110 0z m0 174l0 300-110 0 0-300 110 0z" horiz-adv-x="962" />
|
||||
<glyph glyph-name="download-cloud" unicode="" d="m0 243q0 72 39 134t105 92q-1 17-1 24 0 118 84 202t202 84q87 0 159-49t105-129q40 35 93 35 59 0 101-42t42-101q0-43-23-77 72-17 119-76t46-133q0-89-62-151t-152-63h-607q-103 0-177 73t-73 177z m286 89q0-8 5-13l196-196q5-5 13-5t13 5l196 196q5 6 5 13 0 8-5 13t-13 5h-125v196q0 8-5 13t-12 5h-108q-7 0-12-5t-5-13v-196h-125q-8 0-13-5t-5-13z" horiz-adv-x="1071.4" />
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
BIN
public/fonts/fontello.ttf
Normal file
BIN
public/fonts/fontello.woff
Normal file
BIN
public/fonts/museo-sans-500.eot
Normal file
BIN
public/fonts/museo-sans-500.otf
Normal file
225
public/fonts/museo-sans-500.svg
Normal file
@ -0,0 +1,225 @@
|
||||
<?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="MuseoSans500Regular" horiz-adv-x="1681" >
|
||||
<font-face units-per-em="2048" ascent="1536" descent="-512" />
|
||||
<missing-glyph horiz-adv-x="526" />
|
||||
<glyph unicode="fi" horiz-adv-x="1198" d="M82 877v159h129v35q0 97 28.5 170.5t70 113t98 64t101 31t91.5 6.5q20 0 39 -1.5t28 -2.5l9 -2v-170q-20 4 -51 4q-27 0 -52 -4t-56.5 -17.5t-54.5 -35.5t-38.5 -63.5t-15.5 -96.5v-31h634v-1036h-198v877h-436v-877h-197v877h-129zM842 1243v203h200v-203h-200z" />
|
||||
<glyph unicode="fl" horiz-adv-x="1230" d="M82 862v160h129v49q0 97 28.5 170.5t70 113t98 64t101 31t91.5 6.5q20 0 39 -1.5t28 -2.5l9 -2v-170q-20 4 -51 4q-27 0 -52 -4t-56.5 -17.5t-54.5 -35.5t-38.5 -63.5t-15.5 -96.5v-45h245v-160h-245v-862h-197v862h-129zM831 283v1163h199v-1129q0 -86 29 -116.5 t82 -30.5l35 2v-176q-31 -4 -66 -4q-40 0 -73 5t-73 23t-67.5 48t-46.5 85t-19 130z" />
|
||||
<glyph unicode="ffi" horiz-adv-x="1886" d="M82 877v159h129v35q0 97 28.5 170.5t70 113t98 64t101 31t91.5 6.5q20 0 39 -1.5t28 -2.5l9 -2v-170q-20 4 -51 4q-27 0 -52 -4t-56.5 -17.5t-54.5 -35.5t-38.5 -63.5t-15.5 -96.5v-31h491v35q0 97 28.5 170.5t70 113t98 64t101 31t91.5 6.5q20 0 39 -1.5t28 -2.5l9 -2 v-170q-20 4 -51 4q-27 0 -52 -4t-56.5 -17.5t-54.5 -35.5t-38.5 -63.5t-15.5 -96.5v-31h635v-1036h-199v877h-436v-877h-197v877h-491v-877h-197v877h-129zM1530 1243v203h201v-203h-201z" />
|
||||
<glyph unicode="ffl" horiz-adv-x="1918" d="M82 877v159h129v35q0 97 28.5 170.5t70 113t98 64t101 31t91.5 6.5q20 0 39 -1.5t28 -2.5l9 -2v-170q-20 4 -51 4q-27 0 -52 -4t-56.5 -17.5t-54.5 -35.5t-38.5 -63.5t-15.5 -96.5v-31h491v35q0 97 28.5 170.5t70 113t98 64t101 31t91.5 6.5q20 0 39 -1.5t28 -2.5l9 -2 v-170q-20 4 -51 4q-27 0 -52 -4t-56.5 -17.5t-54.5 -35.5t-38.5 -63.5t-15.5 -96.5v-31h245v-159h-245v-877h-197v877h-491v-877h-197v877h-129zM1520 283v1163h198v-1129q0 -86 29 -116.5t82 -30.5l35 2v-176q-31 -4 -66 -4q-40 0 -73 5t-73 23t-67.5 48t-46 85t-18.5 130z " />
|
||||
<glyph horiz-adv-x="0" />
|
||||
<glyph horiz-adv-x="2048" />
|
||||
<glyph unicode=" " horiz-adv-x="526" />
|
||||
<glyph unicode="	" horiz-adv-x="526" />
|
||||
<glyph unicode=" " horiz-adv-x="526" />
|
||||
<glyph unicode="!" horiz-adv-x="651" d="M223 1446h205l-12 -1049h-178zM225 0v199h203v-199h-203z" />
|
||||
<glyph unicode=""" horiz-adv-x="700" d="M129 1085v385h156v-385h-156zM416 1085v385h155v-385h-155z" />
|
||||
<glyph unicode="#" horiz-adv-x="1470" d="M90 391l25 152h268l59 344h-264l25 149h266l72 410h166l-72 -410h317l72 410h166l-72 -410h268l-26 -149h-266l-62 -344h266l-26 -152h-264l-70 -391h-166l68 391h-318l-67 -391h-166l67 391h-266zM549 543h317l62 344h-318z" />
|
||||
<glyph unicode="$" horiz-adv-x="1159" d="M111 166l114 153q6 -6 18 -16.5t50 -37.5t78.5 -47t101.5 -37t121 -17q106 0 178 57t72 156q0 48 -24.5 88t-65.5 69.5t-94 56.5t-112 53t-117.5 53.5t-111.5 63t-94 77t-65.5 100.5t-24.5 129q0 150 106 261t275 136v193h146v-191q64 -4 123.5 -20.5t99 -36.5t69.5 -39 t44 -32l14 -13l-92 -168q-5 5 -15.5 13.5t-43.5 30t-68 38t-87 30t-104 13.5q-115 0 -188.5 -61.5t-73.5 -149.5q0 -46 24.5 -84t65.5 -66t94 -53.5t111.5 -50t117.5 -52t112 -63.5t94 -79t65.5 -104.5t24.5 -135.5q0 -157 -104.5 -269.5t-282.5 -133.5v-189h-146v189 q-73 8 -142 29.5t-114.5 47.5t-80.5 51t-51 42z" />
|
||||
<glyph unicode="%" horiz-adv-x="1558" d="M98 1167q0 125 90.5 214t219.5 89t220 -89t91 -214q0 -126 -91 -214.5t-220 -88.5t-219.5 88.5t-90.5 214.5zM129 0l1106 1446h192l-1105 -1446h-193zM256 1167q0 -64 43.5 -107.5t108.5 -43.5q64 0 107.5 43t43.5 108q0 64 -43.5 109t-107.5 45t-108 -45t-44 -109z M840 279q0 125 90.5 214t220.5 89q128 0 219.5 -89.5t91.5 -213.5q0 -126 -91.5 -215t-219.5 -89q-130 0 -220.5 89t-90.5 215zM999 279q0 -65 43.5 -108.5t108.5 -43.5q63 0 107.5 44t44.5 108q0 63 -44.5 108t-107.5 45q-64 0 -108 -45t-44 -108z" />
|
||||
<glyph unicode="&" horiz-adv-x="1400" d="M111 406q0 124 68.5 227.5t185.5 142.5v4q-4 1 -11 4t-26.5 15t-38 27t-40.5 41.5t-37.5 57.5t-26.5 76.5t-11 96.5q0 176 123 274t321 98q36 0 80 -5.5t70 -10.5l27 -6l-52 -162q-59 12 -108 12q-111 0 -183.5 -59t-72.5 -162q0 -30 6 -58.5t24 -60t46 -54.5t77 -38.5 t113 -15.5h268v197h199v-197h193v-176h-193v-193q0 -240 -133.5 -373t-366.5 -133q-223 0 -362 122.5t-139 308.5zM317 416q0 -107 81.5 -180.5t213.5 -73.5q143 0 222 81t79 246v185h-276q-153 0 -236.5 -68t-83.5 -190z" />
|
||||
<glyph unicode="'" horiz-adv-x="415" d="M129 1085v385h158v-385h-158z" />
|
||||
<glyph unicode="(" horiz-adv-x="618" d="M150 696q0 432 237 809h174q-231 -385 -231 -811q0 -470 231 -889h-174q-112 188 -174.5 418t-62.5 473z" />
|
||||
<glyph unicode=")" horiz-adv-x="618" d="M57 -195q232 420 232 889q0 424 -232 811h174q238 -379 238 -809q0 -243 -62.5 -473t-175.5 -418h-174z" />
|
||||
<glyph unicode="*" horiz-adv-x="956" d="M74 1085l53 172l272 -102l-14 291h186l-16 -291l274 102l56 -172l-281 -75v-4l180 -226l-145 -106l-158 241h-4l-160 -241l-147 106l182 226v4z" />
|
||||
<glyph unicode="+" horiz-adv-x="1398" d="M158 504v160h458v503h168v-503h457v-160h-457v-504h-168v504h-458z" />
|
||||
<glyph unicode="," horiz-adv-x="522" d="M55 -207l127 422h203l-172 -422h-158z" />
|
||||
<glyph unicode="-" horiz-adv-x="966" d="M184 496v176h598v-176h-598z" />
|
||||
<glyph unicode="." horiz-adv-x="520" d="M156 0v211h209v-211h-209z" />
|
||||
<glyph unicode="/" horiz-adv-x="827" d="M74 -86l520 1610h176l-520 -1610h-176z" />
|
||||
<glyph unicode="0" horiz-adv-x="1280" d="M129 725q0 129 16 237.5t53 204t94.5 161.5t145.5 104t201 38t201.5 -38t146.5 -104t95 -161.5t53 -204t16 -237.5q0 -130 -16 -239t-53 -205t-95 -162.5t-146.5 -105t-201.5 -38.5t-201 38.5t-145.5 105t-94.5 162.5t-53 205t-16 239zM336 725q0 -125 14.5 -222 t48 -176.5t94 -122t146.5 -42.5q70 0 123 29t87 78t56 122t30.5 154t8.5 180q0 98 -8.5 178.5t-30.5 153t-56 121.5t-87 77.5t-123 28.5q-69 0 -122 -28.5t-87 -77.5t-55.5 -121.5t-30 -153t-8.5 -178.5z" />
|
||||
<glyph unicode="1" horiz-adv-x="1001" d="M104 1110l347 336h180v-1270h315v-176h-831v176h319v934l2 90h-4q-17 -33 -70 -84l-135 -133z" />
|
||||
<glyph unicode="2" horiz-adv-x="1171" d="M113 111q0 83 24 156.5t65 130t94.5 107.5t112 94t117 83.5t112 80.5t94.5 81.5t65 91.5t24 104q0 107 -72.5 173.5t-187.5 66.5q-53 0 -103 -19t-83 -46t-58.5 -54t-36.5 -46l-12 -19l-149 100q3 6 8 15.5t25 38t43.5 54.5t63 57.5t83.5 54.5t105 38.5t128 15.5 q201 0 329 -114.5t128 -300.5q0 -96 -38 -180t-99 -145t-134.5 -116t-147.5 -104t-135.5 -98t-100 -109t-39.5 -127h717v-176h-932q-10 65 -10 111z" />
|
||||
<glyph unicode="3" horiz-adv-x="1161" d="M82 172l111 154q6 -6 16.5 -17t46 -38t74 -48t96.5 -38t117 -17q124 0 209.5 74.5t85.5 189.5q0 127 -97 196.5t-239 69.5h-101l-47 109l316 371q21 24 43.5 47.5t34.5 34.5l12 12v4q-43 -6 -123 -6h-490v176h865v-129l-394 -453q60 -6 117.5 -24.5t113.5 -53t98.5 -81.5 t68.5 -115.5t26 -149.5q0 -93 -35.5 -177.5t-98 -148t-156 -101.5t-201.5 -38q-60 0 -118.5 11t-103.5 28t-86 38t-69.5 42.5t-50 38.5t-31.5 28z" />
|
||||
<glyph unicode="4" horiz-adv-x="1241" d="M63 387v127l668 932h232v-887h196v-172h-196v-387h-199v387h-701zM287 559h477v526q0 30 2 66t4 57l2 21h-4q-33 -68 -72 -119l-409 -547v-4z" />
|
||||
<glyph unicode="5" horiz-adv-x="1153" d="M98 176l113 148q5 -6 13.5 -16.5t39 -37.5t64.5 -47.5t88.5 -37.5t111.5 -17q131 0 224.5 82t93.5 211t-94.5 213t-235.5 84q-63 0 -124 -18t-90 -36l-30 -18l-116 43l71 717h729v-176h-553l-34 -305q-1 -19 -3.5 -38t-5.5 -29l-2 -9h4q9 5 25.5 12.5t65.5 20t96 12.5 q224 0 364 -136t140 -335q0 -209 -146 -348.5t-366 -139.5q-83 0 -159.5 20.5t-125.5 50t-86.5 59.5t-54.5 51z" />
|
||||
<glyph unicode="6" horiz-adv-x="1226" d="M121 657q0 114 24 227t76.5 219.5t127 187.5t184 130t239.5 49q76 0 146 -15t102 -29l33 -15l-66 -174q-10 5 -28.5 13t-73 21t-105.5 13q-96 0 -175 -41.5t-131 -111.5t-84 -154t-44 -178h4q45 61 134.5 99t185.5 38q202 0 329 -136.5t127 -340.5q0 -213 -130.5 -348.5 t-333.5 -135.5q-235 0 -388 188.5t-153 493.5zM334 561q0 -94 42 -186t118.5 -152.5t164.5 -60.5q122 0 194.5 84t72.5 213q0 134 -80.5 219.5t-216.5 85.5q-121 0 -208 -61.5t-87 -141.5z" />
|
||||
<glyph unicode="7" horiz-adv-x="1083" d="M72 1270v176h966v-139l-653 -1307h-209l563 1139q18 36 39 69.5t33 48.5l12 15v4q-32 -6 -106 -6h-645z" />
|
||||
<glyph unicode="8" horiz-adv-x="1243" d="M117 418q0 62 21 122.5t48 100.5t65 78.5t57.5 54t39.5 29.5q-162 117 -162 289q0 59 17.5 113.5t54 103t88.5 84t127 56.5t164 21q203 0 329 -105t126 -282q0 -185 -172 -376q93 -57 144.5 -130t51.5 -178q0 -113 -60 -209t-174.5 -155.5t-260.5 -59.5q-218 0 -361 124 t-143 319zM324 430q0 -120 88.5 -196t208.5 -76q118 0 202 69.5t84 178.5q0 38 -18 71.5t-43 57t-71.5 50.5t-82 43.5t-97.5 44t-97 44.5q-174 -122 -174 -287zM387 1087q0 -26 6 -49.5t21 -44t29.5 -37.5t41 -34.5t46 -29.5t55 -28.5t57 -25.5t62.5 -26t61 -26 q15 15 30.5 34.5t40.5 57.5t40.5 89t15.5 104q0 99 -71.5 158t-186.5 59q-116 0 -182 -57t-66 -144z" />
|
||||
<glyph unicode="9" horiz-adv-x="1226" d="M100 987q0 213 131 348t334 135q114 0 213.5 -49t172 -136.5t114 -216t41.5 -280.5q0 -114 -24 -227t-76.5 -219.5t-127 -187.5t-184 -130t-239.5 -49q-76 0 -146.5 15t-102.5 30l-32 15l66 176q10 -5 28.5 -13.5t72.5 -22t105 -13.5q96 0 175 41.5t131 111.5t84.5 154 t44.5 178h-4q-44 -61 -133.5 -98t-186.5 -37q-203 0 -330 135.5t-127 339.5zM301 987q0 -135 80 -220t217 -85q120 0 207.5 62.5t87.5 140.5q0 94 -42.5 186t-119 152.5t-164.5 60.5q-123 0 -194.5 -83.5t-71.5 -213.5z" />
|
||||
<glyph unicode=":" horiz-adv-x="598" d="M195 0v211h208v-211h-208zM195 825v211h208v-211h-208z" />
|
||||
<glyph unicode=";" horiz-adv-x="600" d="M96 -207l109 422h205l-154 -422h-160zM207 825v211h209v-211h-209z" />
|
||||
<glyph unicode="<" horiz-adv-x="1142" d="M68 516v135l954 426v-182l-733 -309v-4l733 -310v-182z" />
|
||||
<glyph unicode="=" horiz-adv-x="1370" d="M197 309v160h977v-160h-977zM197 696v160h977v-160h-977z" />
|
||||
<glyph unicode=">" horiz-adv-x="1142" d="M121 90v182l731 310v4l-731 309v182l954 -426v-135z" />
|
||||
<glyph unicode="?" horiz-adv-x="1001" d="M66 1343q6 5 16 14t45.5 32t74 40t99.5 31.5t123 14.5q178 0 303 -104.5t125 -270.5q0 -69 -20 -127.5t-52 -100.5t-70.5 -79.5t-77.5 -71.5t-71 -68.5t-52 -78t-20 -93.5v-84h-194v97q0 63 19 118t50 94.5t68 76t74 69.5t68 66.5t50 76t19 90.5q0 87 -66 145t-167 58 q-57 0 -115.5 -21.5t-88.5 -42.5l-30 -22zM291 0v199h203v-199h-203z" />
|
||||
<glyph unicode="@" d="M121 494q0 156 58.5 296t158 241t238 160.5t292.5 59.5q115 0 206.5 -22.5t152 -61t100.5 -92t57 -113t17 -126.5v-580h147v-150h-559q-187 0 -305.5 114t-118.5 274q0 102 51.5 189t149.5 140.5t223 53.5h221q-3 91 -90.5 150.5t-240.5 59.5q-155 0 -284.5 -81.5 t-202.5 -217.5t-73 -294q0 -162 72 -295.5t206 -213t304 -79.5v-162q-169 0 -315 58.5t-247.5 159.5t-159.5 239t-58 293zM766 496q0 -101 67.5 -170.5t170.5 -69.5h206v483h-202q-105 0 -173.5 -70.5t-68.5 -172.5z" />
|
||||
<glyph unicode="A" horiz-adv-x="1286" d="M16 0l521 1446h213l520 -1446h-211l-146 416h-544l-144 -416h-209zM422 584h438l-160 458q-11 33 -25 84t-22 86l-8 35h-4q-32 -131 -57 -205z" />
|
||||
<glyph unicode="B" horiz-adv-x="1298" d="M197 0v1446h505q187 0 303.5 -99t116.5 -270q0 -105 -48 -186.5t-132 -124.5v-4q112 -33 175 -129t63 -221q0 -99 -37 -178.5t-100.5 -130t-147.5 -77t-180 -26.5h-518zM399 176h326q116 0 182 67t66 179q0 111 -68.5 179.5t-181.5 68.5h-324v-494zM399 838h303 q97 0 155 61t58 158t-57 155t-160 58h-299v-432z" />
|
||||
<glyph unicode="C" horiz-adv-x="1478" d="M98 731q0 155 56.5 292t153.5 235t234 155t292 57q97 0 187 -19.5t149 -47.5t104 -56t66 -47l20 -20l-100 -152q-7 6 -19.5 17t-55 38t-88.5 48t-115.5 38t-139.5 17q-158 0 -281 -74.5t-188.5 -200t-65.5 -278.5q0 -155 66 -284.5t190 -208t281 -78.5q76 0 150 19.5 t125 47t91.5 55t59.5 46.5l20 20l109 -145q-8 -9 -23.5 -24.5t-69.5 -55.5t-114 -70t-156.5 -55t-197.5 -25q-213 0 -383 100.5t-263.5 273t-93.5 382.5z" />
|
||||
<glyph unicode="D" horiz-adv-x="1515" d="M197 0v1446h479q221 0 386 -84t256 -248t91 -389q0 -340 -198.5 -532.5t-534.5 -192.5h-479zM399 176h263q249 0 393.5 143t144.5 406q0 261 -145 403t-393 142h-263v-1094z" />
|
||||
<glyph unicode="E" horiz-adv-x="1173" d="M197 0v1446h839v-176h-637v-453h519v-176h-519v-465h672v-176h-874z" />
|
||||
<glyph unicode="F" horiz-adv-x="1067" d="M197 0v1446h796v-176h-594v-475h506v-177h-506v-618h-202z" />
|
||||
<glyph unicode="G" horiz-adv-x="1556" d="M100 725q0 155 56.5 292.5t154 237t235 157.5t292.5 58q97 0 187 -18t148.5 -43.5t104 -51t66.5 -43.5l20 -18l-102 -151q-7 6 -19 15.5t-53.5 33.5t-86 43t-112.5 34t-137 15q-165 0 -290.5 -75t-190 -201t-64.5 -281q0 -165 70 -295t191.5 -201t271.5 -71 q70 0 138 18.5t115 45t83.5 53t54.5 45.5l18 18v209h-235v176h420v-727h-179v90l3 62h-5q-6 -7 -18.5 -19t-55 -42.5t-90 -54t-124 -42.5t-156.5 -19q-145 0 -275 55.5t-226.5 153t-153 238.5t-56.5 303z" />
|
||||
<glyph unicode="H" horiz-adv-x="1548" d="M197 0v1446h202v-635h750v635h203v-1446h-203v635h-750v-635h-202z" />
|
||||
<glyph unicode="I" horiz-adv-x="595" d="M197 0v1446h202v-1446h-202z" />
|
||||
<glyph unicode="J" horiz-adv-x="1099" d="M61 416v71h201v-61q0 -71 19.5 -124t53 -82.5t73 -43.5t84.5 -14q95 0 160 62t65 194v852h-365v176h568v-1030q0 -91 -24.5 -166t-66 -125t-97.5 -84.5t-117 -50t-126 -15.5t-125.5 15.5t-116 50.5t-96.5 85t-65.5 125t-24.5 165z" />
|
||||
<glyph unicode="K" horiz-adv-x="1275" d="M197 0v1446h202v-608h215l365 608h223l-420 -686v-4l447 -756h-230l-385 664h-215v-664h-202z" />
|
||||
<glyph unicode="L" horiz-adv-x="1083" d="M197 0v1446h202v-1270h648v-176h-850z" />
|
||||
<glyph unicode="M" horiz-adv-x="1773" d="M152 0l116 1446h213l332 -782q15 -36 33 -84.5t28 -79.5l11 -31h4q39 115 72 195l331 782h213l117 -1446h-201l-71 911q-4 39 -4 93v33q0 31 1 53l1 34h-5q-42 -133 -77 -213l-289 -651h-180l-287 651q-15 35 -34.5 89t-31.5 91l-12 37h-4v-62q0 -89 -4 -155l-70 -911 h-202z" />
|
||||
<glyph unicode="N" horiz-adv-x="1550" d="M197 0v1446h200l643 -940q24 -35 54 -87t48 -87l19 -35h4q-14 129 -14 209v940h203v-1446h-199l-645 938q-24 36 -54 88.5t-48 87.5l-19 35h-4q14 -129 14 -211v-938h-202z" />
|
||||
<glyph unicode="O" d="M98 733q0 153 58 290t157 235t237 155t292 57q206 0 376 -97t267.5 -266t97.5 -374q0 -210 -97.5 -384t-267.5 -274t-376 -100q-154 0 -292 59t-237 160t-157 241.5t-58 297.5zM307 733q0 -160 72 -291.5t194.5 -205.5t268.5 -74q109 0 207.5 44t169.5 119t113 181.5 t42 226.5q0 155 -71 282t-193 199t-268 72t-268.5 -72t-194.5 -199.5t-72 -281.5z" />
|
||||
<glyph unicode="P" horiz-adv-x="1243" d="M197 0v1446h528q200 0 327.5 -124.5t127.5 -328.5t-128 -331t-327 -127h-326v-535h-202zM399 711h293q130 0 205.5 75.5t75.5 206.5q0 130 -74.5 203.5t-204.5 73.5h-295v-559z" />
|
||||
<glyph unicode="Q" horiz-adv-x="1705" d="M100 731q0 154 57.5 291.5t156.5 235.5t236.5 155t291.5 57q207 0 377.5 -97t268 -266.5t97.5 -375.5q0 -133 -45 -256t-125 -221l172 -164l-119 -127l-168 168q-195 -156 -458 -156q-123 0 -237 38t-205 107t-159 162t-104.5 208.5t-36.5 240.5zM309 731 q0 -159 70.5 -290t192.5 -205t270 -74q83 0 167 28t146 78l-170 166l119 127l166 -168q106 145 106 338q0 157 -70.5 284.5t-192.5 199t-271 71.5q-111 0 -209.5 -42t-169.5 -115.5t-112.5 -177t-41.5 -220.5z" />
|
||||
<glyph unicode="R" horiz-adv-x="1312" d="M197 0v1446h442q179 0 270 -33q112 -42 178 -146t66 -245q0 -138 -71 -245.5t-189 -145.5v-4q16 -19 43 -66l307 -561h-229l-305 575h-310v-575h-202zM399 752h291q119 0 187.5 70.5t68.5 191.5q0 159 -115 223q-64 33 -198 33h-234v-518z" />
|
||||
<glyph unicode="S" horiz-adv-x="1118" d="M86 166l115 153q6 -6 17.5 -16.5t49.5 -37.5t78.5 -47t101.5 -37t121 -17q106 0 178 57t72 156q0 50 -24 91t-64.5 71t-93 57t-110.5 52t-116 51.5t-110.5 61t-93 76t-64.5 100.5t-24 130q0 170 132.5 286.5t334.5 116.5q75 0 145 -15t115.5 -36t81 -42.5t51.5 -36.5 l16 -15l-92 -168q-5 5 -15.5 13.5t-43 30t-67.5 38t-87 30t-104 13.5q-114 0 -188 -61.5t-74 -149.5q0 -48 24 -87t64.5 -67t93 -53t110.5 -49t116 -50.5t110.5 -61.5t93 -78t64.5 -105t24 -137q0 -173 -125 -290.5t-334 -117.5q-86 0 -167 19.5t-135 48t-96 56.5t-61 47z " />
|
||||
<glyph unicode="T" horiz-adv-x="1214" d="M10 1270v176h1194v-176h-495v-1270h-203v1270h-496z" />
|
||||
<glyph unicode="U" horiz-adv-x="1490" d="M176 512v934h203v-934q0 -164 98.5 -257t265.5 -93q169 0 269 93.5t100 260.5v930h203v-934q0 -241 -158 -389t-412 -148t-411.5 148t-157.5 389z" />
|
||||
<glyph unicode="V" horiz-adv-x="1294" d="M12 1446h219l359 -1022q12 -35 26 -84.5t22 -81.5l7 -33h4q29 121 56 199l362 1022h215l-532 -1446h-203z" />
|
||||
<glyph unicode="W" horiz-adv-x="1941" d="M68 1446h208l256 -1061q8 -35 15 -73.5t9 -59.5l3 -21h4q11 74 31 154l283 1061h180l282 -1061q9 -36 16.5 -74.5t10.5 -58.5l4 -21h4q7 76 27 154l266 1061h209l-379 -1446h-235l-250 938q-11 41 -22 92t-16 82l-5 31h-4q-18 -113 -43 -205l-250 -938h-236z" />
|
||||
<glyph unicode="X" horiz-adv-x="1253" d="M45 0l457 745l-428 701h233l228 -391l92 -172h4q41 92 88 172l227 391h234l-428 -701l456 -745h-229l-262 444l-92 166h-4q-39 -86 -86 -166l-263 -444h-227z" />
|
||||
<glyph unicode="Y" horiz-adv-x="1204" d="M16 1446h230l268 -475q20 -36 42 -81.5t34 -73.5l12 -28h4q43 101 88 183l264 475h230l-483 -834v-612h-203v612z" />
|
||||
<glyph unicode="Z" horiz-adv-x="1243" d="M84 0v135l696 1004q24 36 50.5 69.5t40.5 48.5l14 15v4q-39 -6 -109 -6h-655v176h1016v-133l-697 -1006q-24 -36 -50 -68.5t-40 -47.5l-14 -15v-4q38 4 108 4h701v-176h-1061z" />
|
||||
<glyph unicode="[" horiz-adv-x="616" d="M207 -195v1700h338v-149h-164v-1399h164v-152h-338z" />
|
||||
<glyph unicode="\" horiz-adv-x="827" d="M57 1524h176l521 -1610h-176z" />
|
||||
<glyph unicode="]" horiz-adv-x="618" d="M72 -43h166v1399h-166v149h340v-1700h-340v152z" />
|
||||
<glyph unicode="^" horiz-adv-x="1255" d="M141 506l410 940h129l407 -940h-178l-295 721l-292 -721h-181z" />
|
||||
<glyph unicode="_" horiz-adv-x="1216" d="M57 0h1102v-160h-1102v160z" />
|
||||
<glyph unicode="`" horiz-adv-x="1021" d="M330 1806h213l149 -260h-168z" />
|
||||
<glyph unicode="a" horiz-adv-x="1081" d="M72 291q0 70 26.5 127t66 93.5t99 63t113 40t120.5 21.5t108.5 9.5t90.5 1.5h45v19q0 227 -227 227q-45 0 -91 -10.5t-80 -25t-62 -29t-42 -24.5l-14 -11l-82 145q6 5 17.5 13.5t50 29.5t80.5 37t107 29.5t132 13.5q197 0 303.5 -105t106.5 -301v-655h-184v98l4 82h-4 q-2 -4 -5.5 -11.5t-17 -29t-30 -40.5t-45 -43t-60.5 -41t-77.5 -28.5t-96.5 -11.5q-143 0 -247.5 84.5t-104.5 231.5zM272 301q0 -68 51.5 -117t143.5 -49q80 0 145 51t98 125.5t33 153.5v33h-51q-39 0 -71 -1t-77.5 -5.5t-80.5 -12.5t-72.5 -22.5t-62 -35t-40.5 -51.5 t-16 -69z" />
|
||||
<glyph unicode="b" horiz-adv-x="1228" d="M156 0v1446h198v-473l-4 -88h4q4 7 11 19t35.5 42.5t63 53.5t94.5 42t128 19q208 0 331.5 -150t123.5 -393q0 -245 -132 -394t-339 -149q-65 0 -122 18.5t-93 44.5t-62.5 52.5t-37.5 45.5l-11 18h-4q4 -33 4 -78v-76h-188zM348 514q0 -96 31 -177.5t99.5 -136.5 t162.5 -55q128 0 213.5 100t85.5 271q0 167 -81.5 269t-211.5 102q-128 0 -213.5 -93.5t-85.5 -279.5z" />
|
||||
<glyph unicode="c" horiz-adv-x="1120" d="M82 518q0 232 156.5 387.5t398.5 155.5q73 0 139.5 -15.5t110 -38t76.5 -45t48 -38.5l15 -15l-94 -139q-5 5 -13.5 13t-37 28.5t-59.5 36t-79.5 28.5t-97.5 13q-157 0 -258.5 -104.5t-101.5 -264.5t103 -266.5t263 -106.5q54 0 107 14.5t89.5 35t66 41t43.5 34.5l14 15 l80 -146q-6 -7 -17 -18t-50.5 -39.5t-84 -50.5t-115.5 -40t-147 -18q-243 0 -399 154t-156 389z" />
|
||||
<glyph unicode="d" horiz-adv-x="1230" d="M88 518q0 245 131 394t338 149q67 0 125 -17t92 -41t59 -48t35 -41l9 -17h4q-4 31 -4 70v479h198v-1446h-188v98l2 70h-4q-3 -8 -10.5 -21t-35.5 -46t-63.5 -58.5t-97 -46.5t-133.5 -21q-209 0 -333 149.5t-124 393.5zM291 518q0 -167 81.5 -269t211.5 -102 q60 0 112 21.5t95 65t67.5 117.5t24.5 169q0 96 -31 177.5t-99.5 136.5t-162.5 55q-128 0 -213.5 -100t-85.5 -271z" />
|
||||
<glyph unicode="e" horiz-adv-x="1136" d="M84 518q0 244 146.5 393.5t371.5 149.5q142 0 245.5 -66.5t153.5 -175t50 -244.5l-7 -86h-755q7 -163 108.5 -252.5t247.5 -89.5q50 0 100 12.5t85.5 30.5t64 35.5t43.5 30.5l14 12l82 -145q-6 -6 -18 -16t-51.5 -35.5t-83 -45t-111.5 -35.5t-137 -16q-160 0 -286 71.5 t-194.5 195t-68.5 276.5zM295 639h553q-4 128 -74.5 196t-175.5 68q-117 0 -199.5 -69.5t-103.5 -194.5z" />
|
||||
<glyph unicode="f" horiz-adv-x="688" d="M82 862v160h129v49q0 97 28.5 170.5t70 113t98 64t101 31t91.5 6.5q20 0 39 -1.5t28 -2.5l9 -2v-170q-20 4 -51 4q-27 0 -52 -4t-56.5 -17.5t-54.5 -35.5t-38.5 -63.5t-15.5 -96.5v-45h245v-160h-245v-862h-197v862h-129z" />
|
||||
<glyph unicode="g" horiz-adv-x="1214" d="M88 543q0 228 121.5 373t331.5 145q70 0 129 -16t93.5 -38.5t59.5 -45t34 -38.5l9 -16h4q-2 15 -2 33v96h191v-993q0 -123 -44 -217t-119.5 -148.5t-166 -81t-192.5 -26.5q-186 0 -355 86l66 156q14 -8 39.5 -19.5t100.5 -31t144 -19.5q146 0 237 71t91 220v76l2 65h-4 q-97 -162 -307 -162q-141 0 -247.5 70.5t-161 190.5t-54.5 270zM289 547q0 -163 81.5 -263t219.5 -100q120 0 197 84.5t77 272.5q0 348 -293 348q-134 0 -208 -91t-74 -251z" />
|
||||
<glyph unicode="h" horiz-adv-x="1234" d="M156 0v1446h198v-531l-4 -86h4q40 89 141 160.5t242 71.5q182 0 269.5 -99t87.5 -298v-664h-199v618q0 60 -8 103t-28 81t-60.5 57.5t-100.5 19.5q-116 0 -205 -71t-122 -185q-17 -58 -17 -138v-485h-198z" />
|
||||
<glyph unicode="i" horiz-adv-x="509" d="M154 1243v203h200v-203h-200zM156 0v1036h198v-1036h-198z" />
|
||||
<glyph unicode="j" horiz-adv-x="507" d="M-113 -248q18 -2 45 -2t52.5 4t58.5 18t56.5 37t40 66.5t16.5 101.5v1059h196v-1071q0 -71 -15.5 -130t-40 -98.5t-59.5 -69t-70 -46t-75.5 -27t-71.5 -13.5t-63 -3l-70 4v170zM154 1243v203h200v-203h-200z" />
|
||||
<glyph unicode="k" horiz-adv-x="1077" d="M156 0v1446h198v-791h146l282 381h226l-344 -456v-5l383 -575h-232l-311 487h-150v-487h-198z" />
|
||||
<glyph unicode="l" horiz-adv-x="542" d="M143 283v1163h199v-1129q0 -86 29 -116.5t82 -30.5l34 2v-176q-30 -4 -65 -4q-40 0 -73 5t-73 23t-67.5 48t-46.5 85t-19 130z" />
|
||||
<glyph unicode="m" horiz-adv-x="1871" d="M156 0v1036h192v-137l-4 -76h4q39 96 139.5 167t217.5 71q258 0 311 -236h4q45 99 146.5 167.5t222.5 68.5q174 0 258 -99t84 -298v-664h-199v621q0 60 -7 103t-26 80.5t-57 57t-94 19.5q-104 0 -183 -76.5t-108 -188.5q-15 -65 -15 -143v-473h-198v621q0 46 -3 79.5 t-14 69.5t-30 59t-53 37.5t-80 14.5q-109 0 -187.5 -78t-109.5 -195q-13 -53 -13 -135v-473h-198z" />
|
||||
<glyph unicode="n" horiz-adv-x="1234" d="M156 0v1036h192v-137l-4 -76h4q17 38 47.5 76t77 76t115.5 62t149 24q182 0 269.5 -99t87.5 -298v-664h-199v618q0 60 -8 103t-28 81t-60.5 57.5t-100.5 19.5q-117 0 -205.5 -70t-121.5 -184q-17 -58 -17 -140v-485h-198z" />
|
||||
<glyph unicode="o" horiz-adv-x="1277" d="M80 520q0 115 44 216t119.5 172t178 112t217.5 41t217.5 -41t178 -112t119.5 -172t44 -216q0 -154 -75 -279.5t-203 -195.5t-281 -70t-281 70t-203 195.5t-75 279.5zM283 520q0 -161 104 -267t252 -106q150 0 253 106t103 267q0 159 -103 264t-253 105q-148 0 -252 -105 t-104 -264z" />
|
||||
<glyph unicode="p" horiz-adv-x="1228" d="M156 -410v1446h182v-88l-4 -76h4q4 8 11.5 20.5t36.5 45t65 57.5t99 45.5t136 20.5q208 0 331.5 -150t123.5 -393q0 -244 -132 -393.5t-337 -149.5q-64 0 -120 17.5t-90.5 42.5t-60.5 50t-37 43l-10 17h-4q4 -37 4 -90v-465h-198zM348 514q0 -95 32.5 -177.5t101 -137 t159.5 -54.5q128 0 213.5 100t85.5 271q0 167 -81.5 269t-211.5 102q-128 0 -213.5 -93.5t-85.5 -279.5z" />
|
||||
<glyph unicode="q" horiz-adv-x="1230" d="M88 518q0 245 131 394t338 149q67 0 125.5 -18t94 -43.5t61.5 -51t36 -43.5l11 -18h4q-2 30 -2 71v78h188v-1446h-198v473l4 91h-4q-4 -7 -11 -19t-35 -43t-62.5 -54.5t-94.5 -43t-129 -19.5q-209 0 -333 149.5t-124 393.5zM291 518q0 -167 81.5 -269t211.5 -102 q60 0 112 21.5t95 65t67.5 117.5t24.5 169q0 96 -31 177.5t-99.5 136.5t-162.5 55q-128 0 -213.5 -100t-85.5 -271z" />
|
||||
<glyph unicode="r" horiz-adv-x="768" d="M156 0v1036h192v-180l-4 -78h4q37 119 124.5 195t203.5 76l51 -5v-196q-26 6 -57 6q-97 0 -176.5 -65t-114.5 -179q-25 -82 -25 -186v-424h-198z" />
|
||||
<glyph unicode="s" horiz-adv-x="917" d="M72 127l96 141q5 -5 14 -13t38.5 -29t62 -37t82.5 -29t100 -13q69 0 120.5 34.5t51.5 94.5q0 38 -29.5 68.5t-76.5 53t-104 44.5t-113.5 49.5t-103.5 62t-76.5 89t-29.5 123.5q0 137 107 216t268 79q64 0 121.5 -12t94.5 -28.5t65 -33.5t40 -29l13 -12l-80 -149 q-4 4 -11 10t-32 22t-52.5 28t-71 22t-89.5 10q-71 0 -120.5 -32t-49.5 -95q0 -37 29.5 -67t76.5 -51.5t103.5 -43t113.5 -49.5t104 -62.5t76.5 -89t29.5 -123.5q0 -131 -103.5 -216t-271.5 -85q-71 0 -137.5 15.5t-111 38t-78.5 45t-50 38.5z" />
|
||||
<glyph unicode="t" horiz-adv-x="733" d="M63 862v160h142v299h192v-299h250v-160h-250v-461q0 -59 16 -103.5t39.5 -68.5t55.5 -38.5t57.5 -18.5t52.5 -4l48 4v-176q-29 -4 -70 -4q-48 0 -93 6.5t-103 30.5t-100 63.5t-71.5 113.5t-29.5 173v483h-136z" />
|
||||
<glyph unicode="u" horiz-adv-x="1224" d="M141 373v663h199v-618q0 -59 7.5 -101.5t27.5 -80t60 -57t100 -19.5q152 0 243.5 115t91.5 276v485h199v-1036h-192v137l4 76h-4q-38 -90 -140 -164t-241 -74q-177 0 -266 97.5t-89 300.5z" />
|
||||
<glyph unicode="v" horiz-adv-x="1028" d="M14 1036h211l252 -700q9 -25 17 -60.5t12.5 -58t5.5 -22.5h4q1 0 6 22.5t13.5 58t17.5 60.5l252 700h209l-383 -1036h-230z" />
|
||||
<glyph unicode="w" horiz-adv-x="1667" d="M35 1036h211l215 -727q7 -23 13 -51t9 -43.5t4 -15.5h5q10 57 26 110l225 725h183l223 -725l29 -110h4q8 57 24 110l217 727h209l-334 -1036h-219l-215 666l-28 112h-5q-12 -59 -28 -112l-213 -666h-221z" />
|
||||
<glyph unicode="x" horiz-adv-x="1040" d="M45 0l352 532l-334 504h228l192 -315l35 -62h4q19 35 35 62l193 315h227l-334 -504l352 -532h-225l-217 346l-31 57h-4q-17 -32 -31 -57l-217 -346h-225z" />
|
||||
<glyph unicode="y" horiz-adv-x="1044" d="M4 1036h223l260 -678q9 -24 18.5 -55t14.5 -51l6 -19h4q17 70 35 123l252 680h215l-485 -1222q-46 -118 -135.5 -181t-200.5 -63q-52 0 -102 16t-75 32l-24 15l70 152q58 -43 121 -43q59 0 107.5 40.5t78.5 111.5l51 118z" />
|
||||
<glyph unicode="z" horiz-adv-x="1058" d="M80 0v115l522 655q20 24 41.5 48t32.5 36l12 12v4q-32 -4 -100 -4h-486v170h854v-114l-522 -658q-19 -24 -41 -47.5t-35 -34.5l-12 -12v-4q35 4 103 4h526v-170h-895z" />
|
||||
<glyph unicode="{" horiz-adv-x="716" d="M100 578v176q7 1 19 3t42 16t52.5 36t41.5 67t19 105v172q0 92 26 161t62 105t85.5 57.5t85.5 27t73 5.5l47 -2v-151h-28q-20 0 -38.5 -3t-45 -16t-45.5 -35t-33 -63.5t-14 -97.5v-211q0 -57 -17 -104.5t-41.5 -75t-49 -47t-41.5 -26.5l-17 -7v-4q7 -2 18 -6.5 t39.5 -24.5t50.5 -46t40 -75t18 -108v-236q0 -56 14 -97.5t33 -63.5t45.5 -35t45 -16t38.5 -3h28v-152q-18 -4 -47 -4q-37 0 -73 5.5t-85.5 27.5t-85.5 58.5t-62 105.5t-26 162v196q0 59 -18 103.5t-43.5 66t-51 35t-43.5 16.5z" />
|
||||
<glyph unicode="|" horiz-adv-x="579" d="M203 -326v1948h174v-1948h-174z" />
|
||||
<glyph unicode="}" horiz-adv-x="716" d="M63 -45h29q20 0 38.5 3t45 16t45.5 35t33 63.5t14 97.5v236q0 59 17 107.5t41.5 75.5t49 45.5t41.5 25.5l17 6v4q-7 2 -18 7t-39.5 26t-50.5 47.5t-40 74.5t-18 105v211q0 56 -14 97.5t-33 63.5t-45.5 35t-45 16t-38.5 3h-29v151q19 2 48 2q25 0 49.5 -2.5t58.5 -11.5 t63.5 -24t60 -42t51.5 -63.5t34.5 -91t13.5 -121.5v-172q0 -60 18 -105t43.5 -67t51 -36t43.5 -17l18 -2v-176q-7 -1 -19 -3t-42 -16t-52.5 -35.5t-41.5 -66t-19 -103.5v-196q0 -93 -26 -162t-62 -105.5t-85 -58.5t-85 -27.5t-73 -5.5l-48 4v152z" />
|
||||
<glyph unicode="~" horiz-adv-x="1245" d="M137 418q0 174 75 260t212 86q59 0 107 -20.5t80 -50t61 -59.5t65 -50.5t78 -20.5q39 0 67 17.5t42.5 47t21 61.5t6.5 67h162q0 -175 -74.5 -260.5t-210.5 -85.5q-59 0 -107.5 20.5t-80 49.5t-60.5 58t-65.5 49.5t-79.5 20.5q-38 0 -66 -17.5t-42.5 -46.5t-21.5 -60.5 t-7 -65.5h-162z" />
|
||||
<glyph unicode="¡" horiz-adv-x="591" d="M193 -410l14 1049h178l12 -1049h-204zM193 838v198h202v-198h-202z" />
|
||||
<glyph unicode="¢" horiz-adv-x="1179" d="M109 723q0 149 51 272t150 204t231 99v172h145v-172q133 -20 232 -103.5t153 -213.5l-180 -70q-90 203 -273 203q-144 0 -225.5 -110t-81.5 -281q0 -176 79.5 -282.5t227.5 -106.5q95 0 163.5 55t109.5 148l180 -72q-55 -126 -152.5 -213.5t-232.5 -101.5v-177h-145v177 q-132 18 -231 98.5t-150 203.5t-51 271z" />
|
||||
<glyph unicode="£" horiz-adv-x="1210" d="M115 0v176h125v477h-90v144h90v278q0 171 125.5 283t318.5 112q58 0 114.5 -13.5t96 -33t70.5 -38.5t46 -33l15 -13l-117 -141q-11 10 -30.5 24.5t-78 39t-114.5 24.5q-111 0 -176.5 -62.5t-65.5 -156.5v-270h377v-144h-377v-477h666v-176h-995z" />
|
||||
<glyph unicode="¥" horiz-adv-x="1243" d="M57 1446h232l241 -451q20 -43 42 -95t34 -83l12 -31h5q43 113 88 209l243 451h232l-340 -606h209v-129h-277l-55 -99v-75h332v-129h-332v-408h-205v408h-334v129h334v75l-55 99h-279v129h211z" />
|
||||
<glyph unicode="§" horiz-adv-x="905" d="M98 -23l90 138q3 -3 9.5 -8t27.5 -18.5t42.5 -23.5t54.5 -18t65 -8q95 0 156 56t61 159q0 40 -12 92l-135 770h161l144 -799q10 -55 10 -92q0 -155 -104 -253.5t-281 -98.5q-50 0 -98 10.5t-81 26t-59 31t-39 25.5zM129 1120q0 153 104.5 251.5t282.5 98.5q49 0 97 -10.5 t81 -26t59.5 -31t38.5 -26.5l13 -10l-94 -131q-9 8 -26 19.5t-68 31t-101 19.5q-97 0 -158 -53.5t-61 -153.5q0 -36 12 -82l140 -789h-164l-144 799q-12 46 -12 94z" />
|
||||
<glyph unicode="¨" horiz-adv-x="1021" d="M258 1599v207h164v-207h-164zM600 1599v207h164v-207h-164z" />
|
||||
<glyph unicode="©" d="M111 723q0 153 57.5 291.5t154.5 238.5t231.5 158.5t283.5 58.5q201 0 369.5 -99.5t266 -271t97.5 -376.5q0 -153 -57.5 -292t-155.5 -238.5t-234 -158.5t-286 -59q-149 0 -283.5 59t-231.5 158.5t-154.5 238.5t-57.5 292zM260 723q0 -126 45 -239t121.5 -194t184 -128 t227.5 -47q162 0 296 80t210.5 219.5t76.5 308.5t-76.5 308.5t-210.5 219.5t-296 80q-120 0 -227.5 -47t-184 -128t-121.5 -194t-45 -239zM449 721q0 81 28.5 155t79.5 130.5t128 90t167 33.5q66 0 125 -21t95.5 -50.5t63.5 -59t38 -50.5l12 -21l-125 -68q-3 5 -8.5 14 t-24.5 31t-41 39t-57 31t-72 14q-117 0 -185.5 -78.5t-68.5 -189.5q0 -114 67 -191t187 -77q38 0 72.5 13.5t57.5 32.5t40 37.5t25 31.5l8 14l125 -68q-4 -8 -12 -22t-37.5 -49t-64.5 -61.5t-94.5 -48.5t-125.5 -22q-180 0 -291.5 120.5t-111.5 289.5z" />
|
||||
<glyph unicode="ª" horiz-adv-x="864" d="M150 543v116h563v-116h-563zM152 981q0 225 385 225h20v13q0 129 -131 129q-39 0 -81.5 -14.5t-65.5 -29.5l-23 -14l-59 101q4 3 11 8t31 18t50.5 23t68.5 18t86 8q127 0 194 -66.5t67 -191.5v-411h-140v94h-4q-2 -4 -6.5 -11.5t-21.5 -26.5t-36.5 -33t-53 -26t-70.5 -12 q-88 0 -154.5 53.5t-66.5 145.5zM299 991q0 -37 27.5 -62.5t76.5 -25.5q67 0 110.5 56.5t43.5 125.5v17h-25q-233 0 -233 -111z" />
|
||||
<glyph unicode="«" horiz-adv-x="1138" d="M90 578l336 421h199l-336 -421l336 -420h-199zM502 578l336 421h198l-336 -421l336 -420h-198z" />
|
||||
<glyph unicode="¬" horiz-adv-x="1257" d="M123 696v160h977v-547h-166v387h-811z" />
|
||||
<glyph unicode="­" horiz-adv-x="882" d="M143 496v176h598v-176h-598z" />
|
||||
<glyph unicode="®" d="M111 723q0 153 57.5 291.5t154.5 238.5t231.5 158.5t283.5 58.5q201 0 369.5 -99.5t266 -271t97.5 -376.5q0 -153 -57.5 -292t-155.5 -238.5t-234 -158.5t-286 -59q-149 0 -283.5 59t-231.5 158.5t-154.5 238.5t-57.5 292zM260 723q0 -126 45 -239t121.5 -194t184 -128 t227.5 -47q162 0 296 80t210.5 219.5t76.5 308.5t-76.5 308.5t-210.5 219.5t-296 80q-120 0 -227.5 -47t-184 -128t-121.5 -194t-45 -239zM588 340v772h297q109 0 176 -64t67 -171q0 -82 -43.5 -136.5t-97.5 -68.5v-4q9 -8 27 -43l147 -285h-160l-143 299h-125v-299h-145z M733 745h123q57 0 91 35.5t34 96.5q0 59 -33.5 91.5t-91.5 32.5h-123v-256z" />
|
||||
<glyph unicode="¯" horiz-adv-x="1021" d="M250 1606v143h522v-143h-522z" />
|
||||
<glyph unicode="°" horiz-adv-x="796" d="M88 1167q0 125 90 214t219 89t220.5 -89t91.5 -214q0 -126 -91.5 -214.5t-220.5 -88.5t-219 88.5t-90 214.5zM246 1167q0 -63 43.5 -107t107.5 -44t108 44t44 107q0 64 -44 109t-108 45t-107.5 -45t-43.5 -109z" />
|
||||
<glyph unicode="±" horiz-adv-x="1394" d="M156 504v160h458v503h168v-503h457v-160h-457v-504h-168v504h-458zM188 -195h1018v-159h-1018v159z" />
|
||||
<glyph unicode="²" horiz-adv-x="796" d="M96 940q0 70 24 129t62 99.5t84.5 75t93 63.5t84.5 58t62 65t24 77q0 57 -41.5 95t-105.5 38q-44 0 -87 -24.5t-64 -49.5l-21 -24l-100 92q4 6 11 16t33 35.5t56 45t78.5 35.5t101.5 16q128 0 211.5 -74.5t83.5 -194.5q0 -61 -22.5 -112t-59 -87t-80.5 -67t-89 -58 t-82 -54t-62 -61t-27 -73h436v-135h-598q-1 8 -2.5 23.5t-2.5 28t-1 22.5z" />
|
||||
<glyph unicode="³" horiz-adv-x="796" d="M82 981l86 109q3 -4 9 -11t26 -25t42.5 -31.5t58 -24.5t73.5 -11q67 0 118.5 45t51.5 111q0 67 -54 106t-128 39h-70l-33 78l182 211q8 10 20.5 22.5t21.5 19.5l8 7v4q-39 -6 -74 -6h-289v137h555v-98l-223 -258q102 -15 170.5 -81t68.5 -181q0 -122 -90.5 -209.5 t-228.5 -87.5q-58 0 -110.5 14t-85.5 34t-58 39.5t-36 33.5z" />
|
||||
<glyph unicode="´" horiz-adv-x="1021" d="M330 1546l149 260h213l-196 -260h-166z" />
|
||||
<glyph unicode="¶" horiz-adv-x="1208" d="M88 971q0 131 65.5 241t176.5 172t241 62h557v-176h-401v-1372h-154v596q-130 0 -241.5 62.5t-177.5 173t-66 241.5zM854 -102v1255h152v-1255h-152z" />
|
||||
<glyph unicode="·" horiz-adv-x="563" d="M180 489v211h203v-211h-203z" />
|
||||
<glyph unicode="¸" horiz-adv-x="1021" d="M350 -291q41 -14 86 -14q43 0 71 15t28 48q0 31 -30 47.5t-79 16.5l-37 -2l60 227l100 -20v-17l-25 -112q66 -8 107 -47t41 -103q0 -88 -60.5 -130t-148.5 -42q-29 0 -57.5 3.5t-41.5 6.5l-14 4v119z" />
|
||||
<glyph unicode="¹" horiz-adv-x="796" d="M133 1550l217 211h139v-760h187v-135h-531v135h191v510l4 54h-4q-8 -18 -37 -45l-72 -70z" />
|
||||
<glyph unicode="º" horiz-adv-x="956" d="M127 1130q0 145 101 241.5t247 96.5q148 0 250 -96.5t102 -241.5q0 -149 -101.5 -246.5t-248.5 -97.5q-148 0 -249 97.5t-101 246.5zM160 543v116h639v-116h-639zM274 1130q0 -93 58.5 -152.5t144.5 -59.5q85 0 143 60t58 152q0 90 -58.5 148.5t-142.5 58.5 q-86 0 -144.5 -58.5t-58.5 -148.5z" />
|
||||
<glyph unicode="»" horiz-adv-x="1140" d="M102 158l336 420l-336 421h199l336 -421l-336 -420h-199zM516 158l336 420l-336 421h199l336 -421l-336 -420h-199z" />
|
||||
<glyph unicode="¼" horiz-adv-x="1980" d="M109 1235l217 211h139v-760h186v-135h-530v135h190v510l4 53h-4q-8 -18 -37 -45l-71 -69zM535 0l688 1446h153l-688 -1446h-153zM1167 219v103l412 573h166v-541h125v-135h-125v-219h-152v219h-426zM1335 354h258v252l6 119h-4q-28 -55 -59 -98l-201 -269v-4z" />
|
||||
<glyph unicode="½" horiz-adv-x="1968" d="M109 1235l217 211h139v-760h186v-135h-530v135h190v510l4 53h-4q-8 -18 -37 -45l-71 -69zM539 0l688 1446h153l-688 -1446h-153zM1229 74q0 70 24 129t62 99.5t84.5 75t93 63.5t84.5 58t62 65t24 77q0 57 -41.5 95t-105.5 38q-28 0 -56 -10t-48 -24.5t-36.5 -29 t-24.5 -24.5l-8 -10l-100 92q4 6 11.5 16t33.5 35t56 44.5t78.5 35.5t101.5 16q128 0 211.5 -74t83.5 -194q0 -61 -22.5 -112t-59 -87t-80.5 -67t-89 -58t-82 -54t-62 -61t-27 -73h436v-135h-598q-1 8 -2.5 23.5t-2.5 28t-1 22.5z" />
|
||||
<glyph unicode="¾" horiz-adv-x="2004" d="M82 666l86 108q3 -4 9 -11t26 -24.5t42.5 -31t58 -24.5t73.5 -11q67 0 118.5 44.5t51.5 110.5q0 67 -54 106.5t-128 39.5h-70l-33 78l182 211q8 10 20.5 22.5t21.5 19.5l8 7v4q-39 -6 -74 -6h-289v137h555v-98l-223 -258q102 -15 170.5 -81.5t68.5 -181.5 q0 -122 -90.5 -209.5t-228.5 -87.5q-58 0 -110.5 14t-85.5 34t-58 40t-36 34zM559 0l688 1446h154l-688 -1446h-154zM1192 219v103l412 573h165v-541h125v-135h-125v-219h-151v219h-426zM1360 354h258v252l6 119h-4q-28 -55 -59 -98l-201 -269v-4z" />
|
||||
<glyph unicode="¿" horiz-adv-x="921" d="M80 -57q0 69 20 127.5t52 100.5t70.5 79.5t77 71.5t70.5 68.5t52 78.5t20 94v76h193v-88q0 -63 -19 -118t-49.5 -95t-67.5 -76.5t-74 -70t-67.5 -67t-49.5 -76t-19 -89.5q0 -87 66 -146t167 -59q57 0 115.5 22t88.5 44l30 22l108 -141q-5 -5 -15.5 -14t-45.5 -31.5 t-73.5 -40t-99 -31.5t-122.5 -14q-116 0 -213 45t-156 131.5t-59 196.5zM438 838v198h203v-198h-203z" />
|
||||
<glyph unicode="À" horiz-adv-x="1286" d="M16 0l521 1446h213l520 -1446h-211l-146 416h-544l-144 -416h-209zM369 1806h213l149 -260h-168zM422 584h438l-160 458q-11 33 -25 84t-22 86l-8 35h-4q-32 -131 -57 -205z" />
|
||||
<glyph unicode="Á" horiz-adv-x="1286" d="M16 0l521 1446h213l520 -1446h-211l-146 416h-544l-144 -416h-209zM422 584h438l-160 458q-11 33 -25 84t-22 86l-8 35h-4q-32 -131 -57 -205zM553 1546l149 260h213l-196 -260h-166z" />
|
||||
<glyph unicode="Â" horiz-adv-x="1286" d="M16 0l521 1446h213l520 -1446h-211l-146 416h-544l-144 -416h-209zM358 1546l181 260h206l181 -260h-174l-109 164h-4l-107 -164h-174zM422 584h438l-160 458q-11 33 -25 84t-22 86l-8 35h-4q-32 -131 -57 -205z" />
|
||||
<glyph unicode="Ã" horiz-adv-x="1286" d="M16 0l521 1446h213l520 -1446h-211l-146 416h-544l-144 -416h-209zM299 1548q0 260 209 260q38 0 70.5 -14.5t55 -35t42.5 -40.5t43 -34.5t47 -14.5q42 0 61 40t19 93h143q0 -260 -209 -260q-38 0 -70.5 14.5t-55 35t-42.5 40.5t-43 34.5t-47 14.5q-42 0 -61 -39.5 t-19 -93.5h-143zM422 584h438l-160 458q-11 33 -25 84t-22 86l-8 35h-4q-32 -131 -57 -205z" />
|
||||
<glyph unicode="Ä" horiz-adv-x="1286" d="M16 0l521 1446h213l520 -1446h-211l-146 416h-544l-144 -416h-209zM391 1599v207h164v-207h-164zM422 584h438l-160 458q-11 33 -25 84t-22 86l-8 35h-4q-32 -131 -57 -205zM733 1599v207h164v-207h-164z" />
|
||||
<glyph unicode="Å" horiz-adv-x="1286" d="M16 0l521 1446h213l520 -1446h-211l-146 416h-544l-144 -416h-209zM422 584h438l-160 458q-11 33 -25 84t-22 86l-8 35h-4q-32 -131 -57 -205zM469 1673q0 70 51 112t123 42q71 0 122.5 -42.5t51.5 -111.5q0 -68 -51.5 -109.5t-122.5 -41.5q-72 0 -123 41.5t-51 109.5z M575 1673q0 -29 18.5 -48t49.5 -19q29 0 48.5 19t19.5 48q0 32 -19 52t-49 20q-31 0 -49.5 -20t-18.5 -52z" />
|
||||
<glyph unicode="Æ" horiz-adv-x="1798" d="M8 0l598 1446h1057v-176h-639v-453h520v-176h-520v-465h674v-176h-875v643h-346l-258 -643h-211zM545 811h278v459h-94z" />
|
||||
<glyph unicode="Ç" horiz-adv-x="1482" d="M102 731q0 155 56.5 292t153.5 235t234 155t292 57q97 0 187 -19.5t149 -47.5t104 -56t66 -47l20 -20l-100 -152q-7 6 -19.5 17t-55 38t-88.5 48t-115.5 38t-139.5 17q-158 0 -281 -74.5t-188.5 -200t-65.5 -278.5q0 -155 66 -284.5t190 -208t281 -78.5q76 0 150 19.5 t125 47t91.5 55t59.5 46.5l20 20l109 -145q-8 -9 -22.5 -23.5t-65.5 -52.5t-108 -68t-148 -56t-187 -30l-16 -77q66 -8 107 -47t41 -103q0 -88 -60.5 -130t-148.5 -42q-29 0 -57.5 3.5t-41.5 6.5l-14 4v119q41 -14 86 -14q98 0 98 63q0 31 -29.5 47.5t-78.5 16.5l-37 -2 l41 160q-291 28 -475.5 239.5t-184.5 511.5z" />
|
||||
<glyph unicode="È" horiz-adv-x="1173" d="M197 0v1446h839v-176h-637v-453h519v-176h-519v-465h672v-176h-874zM365 1806h213l149 -260h-168z" />
|
||||
<glyph unicode="É" horiz-adv-x="1173" d="M197 0v1446h839v-176h-637v-453h519v-176h-519v-465h672v-176h-874zM551 1546l149 260h213l-196 -260h-166z" />
|
||||
<glyph unicode="Ê" horiz-adv-x="1173" d="M197 0v1446h839v-176h-637v-453h519v-176h-519v-465h672v-176h-874zM356 1546l181 260h206l181 -260h-174l-109 164h-4l-107 -164h-174z" />
|
||||
<glyph unicode="Ë" horiz-adv-x="1173" d="M197 0v1446h839v-176h-637v-453h519v-176h-519v-465h672v-176h-874zM387 1599v207h164v-207h-164zM729 1599v207h164v-207h-164z" />
|
||||
<glyph unicode="Ì" horiz-adv-x="595" d="M25 1806h213l149 -260h-168zM197 0v1446h202v-1446h-202z" />
|
||||
<glyph unicode="Í" horiz-adv-x="595" d="M197 0v1446h202v-1446h-202zM211 1546l149 260h213l-196 -260h-166z" />
|
||||
<glyph unicode="Î" horiz-adv-x="595" d="M14 1546l181 260h206l181 -260h-174l-109 164h-4l-107 -164h-174zM197 0v1446h202v-1446h-202z" />
|
||||
<glyph unicode="Ï" horiz-adv-x="595" d="M47 1599v207h164v-207h-164zM197 0v1446h202v-1446h-202zM389 1599v207h164v-207h-164z" />
|
||||
<glyph unicode="Ð" horiz-adv-x="1554" d="M115 639v168h121v639h479q221 0 386 -84t256 -248t91 -389q0 -340 -198.5 -532.5t-534.5 -192.5h-479v639h-121zM438 176h262q249 0 394 143t145 406q0 261 -145.5 403t-393.5 142h-262v-463h305v-168h-305v-463z" />
|
||||
<glyph unicode="Ñ" horiz-adv-x="1550" d="M197 0v1446h200l643 -940q24 -35 54 -87t48 -87l19 -35h4q-14 129 -14 209v940h203v-1446h-199l-645 938q-24 36 -54 88.5t-48 87.5l-19 35h-4q14 -129 14 -211v-938h-202zM430 1548q0 260 209 260q38 0 70.5 -14.5t55 -35t42.5 -40.5t43 -34.5t47 -14.5q42 0 61 40 t19 93h143q0 -260 -209 -260q-38 0 -70.5 14.5t-55 35t-42.5 40.5t-43 34.5t-47 14.5q-42 0 -61 -39.5t-19 -93.5h-143z" />
|
||||
<glyph unicode="Ò" d="M98 733q0 153 58 290t157 235t237 155t292 57q206 0 376 -97t267.5 -266t97.5 -374q0 -210 -97.5 -384t-267.5 -274t-376 -100q-154 0 -292 59t-237 160t-157 241.5t-58 297.5zM307 733q0 -160 72 -291.5t194.5 -205.5t268.5 -74q109 0 207.5 44t169.5 119t113 181.5 t42 226.5q0 155 -71 282t-193 199t-268 72t-268.5 -72t-194.5 -199.5t-72 -281.5zM567 1806h213l150 -260h-168z" />
|
||||
<glyph unicode="Ó" d="M98 733q0 153 58 290t157 235t237 155t292 57q206 0 376 -97t267.5 -266t97.5 -374q0 -210 -97.5 -384t-267.5 -274t-376 -100q-154 0 -292 59t-237 160t-157 241.5t-58 297.5zM307 733q0 -160 72 -291.5t194.5 -205.5t268.5 -74q109 0 207.5 44t169.5 119t113 181.5 t42 226.5q0 155 -71 282t-193 199t-268 72t-268.5 -72t-194.5 -199.5t-72 -281.5zM754 1546l149 260h213l-196 -260h-166z" />
|
||||
<glyph unicode="Ô" d="M98 733q0 153 58 290t157 235t237 155t292 57q206 0 376 -97t267.5 -266t97.5 -374q0 -210 -97.5 -384t-267.5 -274t-376 -100q-154 0 -292 59t-237 160t-157 241.5t-58 297.5zM307 733q0 -160 72 -291.5t194.5 -205.5t268.5 -74q109 0 207.5 44t169.5 119t113 181.5 t42 226.5q0 155 -71 282t-193 199t-268 72t-268.5 -72t-194.5 -199.5t-72 -281.5zM557 1546l180 260h207l180 -260h-174l-108 164h-4l-107 -164h-174z" />
|
||||
<glyph unicode="Õ" d="M98 733q0 153 58 290t157 235t237 155t292 57q206 0 376 -97t267.5 -266t97.5 -374q0 -210 -97.5 -384t-267.5 -274t-376 -100q-154 0 -292 59t-237 160t-157 241.5t-58 297.5zM307 733q0 -160 72 -291.5t194.5 -205.5t268.5 -74q109 0 207.5 44t169.5 119t113 181.5 t42 226.5q0 155 -71 282t-193 199t-268 72t-268.5 -72t-194.5 -199.5t-72 -281.5zM498 1548q0 260 209 260q38 0 70.5 -14.5t55 -35t42.5 -40.5t43 -34.5t47 -14.5q42 0 60.5 40t18.5 93h144q0 -260 -209 -260q-38 0 -70.5 14.5t-55 35t-42.5 40.5t-43 34.5t-47 14.5 q-42 0 -61 -39.5t-19 -93.5h-143z" />
|
||||
<glyph unicode="Ö" d="M98 733q0 153 58 290t157 235t237 155t292 57q206 0 376 -97t267.5 -266t97.5 -374q0 -210 -97.5 -384t-267.5 -274t-376 -100q-154 0 -292 59t-237 160t-157 241.5t-58 297.5zM307 733q0 -160 72 -291.5t194.5 -205.5t268.5 -74q109 0 207.5 44t169.5 119t113 181.5 t42 226.5q0 155 -71 282t-193 199t-268 72t-268.5 -72t-194.5 -199.5t-72 -281.5zM590 1599v207h164v-207h-164zM932 1599v207h164v-207h-164z" />
|
||||
<glyph unicode="×" horiz-adv-x="1320" d="M129 113l422 471l-422 471l113 112l417 -467l420 467l113 -112l-424 -471l424 -471l-113 -113l-420 465l-417 -465z" />
|
||||
<glyph unicode="Ø" horiz-adv-x="1687" d="M102 733q0 153 58 290t157 235t237 155t292 57q203 0 379 -100l94 129l100 -69l-94 -132q124 -101 193 -247.5t69 -317.5q0 -210 -97.5 -384t-267.5 -274t-376 -100q-217 0 -393 109l-97 -135l-102 69l100 142q-119 105 -185.5 253t-66.5 320zM311 733q0 -244 160 -411 l641 890q-123 74 -266 74q-146 0 -268.5 -72t-194.5 -199.5t-72 -281.5zM567 242q125 -80 279 -80q109 0 207.5 44t169.5 119t113 181.5t42 226.5q0 121 -44.5 226t-123.5 180z" />
|
||||
<glyph unicode="Ù" horiz-adv-x="1490" d="M176 512v934h203v-934q0 -164 98.5 -257t265.5 -93q169 0 269 93.5t100 260.5v930h203v-934q0 -241 -158 -389t-412 -148t-411.5 148t-157.5 389zM471 1806h213l150 -260h-168z" />
|
||||
<glyph unicode="Ú" horiz-adv-x="1490" d="M176 512v934h203v-934q0 -164 98.5 -257t265.5 -93q169 0 269 93.5t100 260.5v930h203v-934q0 -241 -158 -389t-412 -148t-411.5 148t-157.5 389zM655 1546l150 260h213l-197 -260h-166z" />
|
||||
<glyph unicode="Û" horiz-adv-x="1490" d="M176 512v934h203v-934q0 -164 98.5 -257t265.5 -93q169 0 269 93.5t100 260.5v930h203v-934q0 -241 -158 -389t-412 -148t-411.5 148t-157.5 389zM461 1546l180 260h207l180 -260h-174l-109 164h-4l-106 -164h-174z" />
|
||||
<glyph unicode="Ü" horiz-adv-x="1490" d="M176 512v934h203v-934q0 -164 98.5 -257t265.5 -93q169 0 269 93.5t100 260.5v930h203v-934q0 -241 -158 -389t-412 -148t-411.5 148t-157.5 389zM494 1599v207h163v-207h-163zM836 1599v207h163v-207h-163z" />
|
||||
<glyph unicode="Ý" horiz-adv-x="1204" d="M16 1446h230l268 -475q20 -36 42 -81.5t34 -73.5l12 -28h4q43 101 88 183l264 475h230l-483 -834v-612h-203v612zM514 1546l150 260h213l-197 -260h-166z" />
|
||||
<glyph unicode="Þ" horiz-adv-x="1243" d="M197 0v1446h200v-246h328q200 0 326.5 -124t126.5 -328t-127 -331.5t-328 -127.5h-326v-289h-200zM397 465h295q130 0 205.5 76t75.5 207q0 130 -74.5 203t-204.5 73h-297v-559z" />
|
||||
<glyph unicode="ß" horiz-adv-x="1204" d="M156 0v1085q0 121 65 210.5t163.5 132t213.5 42.5q168 0 278.5 -95.5t110.5 -233.5q0 -47 -15 -89t-38 -71t-49.5 -59t-49.5 -53t-38 -52t-15 -57q0 -30 27 -61.5t68 -58t88.5 -63t88.5 -73.5t68 -91.5t27 -115.5q0 -148 -102.5 -229.5t-247.5 -81.5q-84 0 -157 15 t-104 29l-30 15v176q13 -7 36 -17.5t92.5 -28t137.5 -17.5q74 0 123 37t49 110q0 39 -27 76t-68 65.5t-88 63t-88 67.5t-68 79.5t-27 97.5q0 47 21 90t51.5 76.5t61 66t51.5 72t21 80.5q0 65 -51 112t-143 47q-98 0 -168 -59t-70 -168v-1071h-198z" />
|
||||
<glyph unicode="à" horiz-adv-x="1081" d="M72 291q0 70 26.5 127t66 93.5t99 63t113 40t120.5 21.5t108.5 9.5t90.5 1.5h45v19q0 227 -227 227q-45 0 -91 -10.5t-80 -25t-62 -29t-42 -24.5l-14 -11l-82 145q6 5 17.5 13.5t50 29.5t80.5 37t107 29.5t132 13.5q197 0 303.5 -105t106.5 -301v-655h-184v98l4 82h-4 q-2 -4 -5.5 -11.5t-17 -29t-30 -40.5t-45 -43t-60.5 -41t-77.5 -28.5t-96.5 -11.5q-143 0 -247.5 84.5t-104.5 231.5zM264 1446h213l150 -260h-168zM272 301q0 -68 51.5 -117t143.5 -49q80 0 145 51t98 125.5t33 153.5v33h-51q-39 0 -71 -1t-77.5 -5.5t-80.5 -12.5 t-72.5 -22.5t-62 -35t-40.5 -51.5t-16 -69z" />
|
||||
<glyph unicode="á" horiz-adv-x="1081" d="M72 291q0 70 26.5 127t66 93.5t99 63t113 40t120.5 21.5t108.5 9.5t90.5 1.5h45v19q0 227 -227 227q-45 0 -91 -10.5t-80 -25t-62 -29t-42 -24.5l-14 -11l-82 145q6 5 17.5 13.5t50 29.5t80.5 37t107 29.5t132 13.5q197 0 303.5 -105t106.5 -301v-655h-184v98l4 82h-4 q-2 -4 -5.5 -11.5t-17 -29t-30 -40.5t-45 -43t-60.5 -41t-77.5 -28.5t-96.5 -11.5q-143 0 -247.5 84.5t-104.5 231.5zM272 301q0 -68 51.5 -117t143.5 -49q80 0 145 51t98 125.5t33 153.5v33h-51q-39 0 -71 -1t-77.5 -5.5t-80.5 -12.5t-72.5 -22.5t-62 -35t-40.5 -51.5 t-16 -69zM446 1186l150 260h213l-197 -260h-166z" />
|
||||
<glyph unicode="â" horiz-adv-x="1081" d="M72 291q0 70 26.5 127t66 93.5t99 63t113 40t120.5 21.5t108.5 9.5t90.5 1.5h45v19q0 227 -227 227q-45 0 -91 -10.5t-80 -25t-62 -29t-42 -24.5l-14 -11l-82 145q6 5 17.5 13.5t50 29.5t80.5 37t107 29.5t132 13.5q197 0 303.5 -105t106.5 -301v-655h-184v98l4 82h-4 q-2 -4 -5.5 -11.5t-17 -29t-30 -40.5t-45 -43t-60.5 -41t-77.5 -28.5t-96.5 -11.5q-143 0 -247.5 84.5t-104.5 231.5zM252 1186l180 260h207l180 -260h-174l-108 164h-5l-106 -164h-174zM272 301q0 -68 51.5 -117t143.5 -49q80 0 145 51t98 125.5t33 153.5v33h-51 q-39 0 -71 -1t-77.5 -5.5t-80.5 -12.5t-72.5 -22.5t-62 -35t-40.5 -51.5t-16 -69z" />
|
||||
<glyph unicode="ã" horiz-adv-x="1081" d="M72 291q0 70 26.5 127t66 93.5t99 63t113 40t120.5 21.5t108.5 9.5t90.5 1.5h45v19q0 227 -227 227q-45 0 -91 -10.5t-80 -25t-62 -29t-42 -24.5l-14 -11l-82 145q6 5 17.5 13.5t50 29.5t80.5 37t107 29.5t132 13.5q197 0 303.5 -105t106.5 -301v-655h-184v98l4 82h-4 q-2 -4 -5.5 -11.5t-17 -29t-30 -40.5t-45 -43t-60.5 -41t-77.5 -28.5t-96.5 -11.5q-143 0 -247.5 84.5t-104.5 231.5zM193 1188q0 260 208 260q38 0 70.5 -14.5t55 -35t42.5 -40.5t43 -34.5t47 -14.5q42 0 61 40t19 93h144q0 -260 -209 -260q-38 0 -70.5 14.5t-55 35 t-42.5 40.5t-43 34.5t-47 14.5q-42 0 -61 -39.5t-19 -93.5h-143zM272 301q0 -68 51.5 -117t143.5 -49q80 0 145 51t98 125.5t33 153.5v33h-51q-39 0 -71 -1t-77.5 -5.5t-80.5 -12.5t-72.5 -22.5t-62 -35t-40.5 -51.5t-16 -69z" />
|
||||
<glyph unicode="ä" horiz-adv-x="1081" d="M72 291q0 70 26.5 127t66 93.5t99 63t113 40t120.5 21.5t108.5 9.5t90.5 1.5h45v19q0 227 -227 227q-45 0 -91 -10.5t-80 -25t-62 -29t-42 -24.5l-14 -11l-82 145q6 5 17.5 13.5t50 29.5t80.5 37t107 29.5t132 13.5q197 0 303.5 -105t106.5 -301v-655h-184v98l4 82h-4 q-2 -4 -5.5 -11.5t-17 -29t-30 -40.5t-45 -43t-60.5 -41t-77.5 -28.5t-96.5 -11.5q-143 0 -247.5 84.5t-104.5 231.5zM272 301q0 -68 51.5 -117t143.5 -49q80 0 145 51t98 125.5t33 153.5v33h-51q-39 0 -71 -1t-77.5 -5.5t-80.5 -12.5t-72.5 -22.5t-62 -35t-40.5 -51.5 t-16 -69zM285 1239v207h164v-207h-164zM627 1239v207h164v-207h-164z" />
|
||||
<glyph unicode="å" horiz-adv-x="1081" d="M72 291q0 70 26.5 127t66 93.5t99 63t113 40t120.5 21.5t108.5 9.5t90.5 1.5h45v19q0 227 -227 227q-45 0 -91 -10.5t-80 -25t-62 -29t-42 -24.5l-14 -11l-82 145q6 5 17.5 13.5t50 29.5t80.5 37t107 29.5t132 13.5q197 0 303.5 -105t106.5 -301v-655h-184v98l4 82h-4 q-2 -4 -5.5 -11.5t-17 -29t-30 -40.5t-45 -43t-60.5 -41t-77.5 -28.5t-96.5 -11.5q-143 0 -247.5 84.5t-104.5 231.5zM272 301q0 -68 51.5 -117t143.5 -49q80 0 145 51t98 125.5t33 153.5v33h-51q-39 0 -71 -1t-77.5 -5.5t-80.5 -12.5t-72.5 -22.5t-62 -35t-40.5 -51.5 t-16 -69zM362 1313q0 69 51.5 111t123.5 42q71 0 122.5 -42t51.5 -111q0 -68 -51.5 -110t-122.5 -42q-72 0 -123.5 42t-51.5 110zM469 1313q0 -30 19 -49t49 -19q29 0 48 19.5t19 48.5q0 32 -18.5 51.5t-48.5 19.5q-31 0 -49.5 -19.5t-18.5 -51.5z" />
|
||||
<glyph unicode="æ" horiz-adv-x="1769" d="M74 291q0 67 23.5 121.5t61 91t92 63.5t108 42t118.5 24t113.5 11.5t101.5 2.5h51v19q0 227 -233 227q-69 0 -140.5 -25t-107.5 -50l-37 -25l-80 145q6 5 17 13.5t48.5 29.5t78.5 37t105 29.5t130 13.5q260 0 344 -182h4q123 182 379 182q136 0 235 -67.5t148 -180.5 t49 -256l-4 -59h-743q7 -169 102.5 -260t241.5 -91q50 0 100 12.5t85.5 29.5t64 34.5t42.5 30.5l15 12l82 -143q-6 -6 -18 -16t-51.5 -35.5t-83 -45t-110.5 -35.5t-136 -16q-154 0 -269 68.5t-178 192.5h-4q-7 -21 -21.5 -48t-47 -66.5t-74 -70.5t-107 -53.5t-141.5 -22.5 q-149 0 -251.5 85.5t-102.5 230.5zM276 301q0 -69 51 -117.5t144 -48.5q81 0 145.5 51.5t96.5 126.5t32 154v31h-96q-43 0 -82 -3t-83.5 -10.5t-80 -22t-65 -35.5t-46 -53t-16.5 -73zM944 647h539q-4 125 -74 190.5t-172 65.5q-117 0 -194.5 -64.5t-98.5 -191.5z" />
|
||||
<glyph unicode="ç" horiz-adv-x="1122" d="M84 518q0 232 156.5 387.5t398.5 155.5q73 0 139.5 -15.5t110 -38t76.5 -45t48 -38.5l15 -15l-94 -139q-5 5 -13.5 13t-37 28.5t-59.5 36t-79.5 28.5t-97.5 13q-157 0 -258.5 -104.5t-101.5 -264.5t103 -266.5t263 -106.5q54 0 107 14.5t89.5 35t66 41t43.5 34.5l14 15 l80 -146q-6 -6 -16.5 -17t-47.5 -38t-78.5 -48.5t-108.5 -40.5t-138 -22l-17 -77q66 -8 107 -47t41 -103q0 -88 -60.5 -130t-148.5 -42q-29 0 -57.5 3.5t-42.5 6.5l-13 4v119q41 -14 86 -14q98 0 98 63q0 31 -29.5 47.5t-78.5 16.5l-37 -2l41 162q-210 28 -339.5 175.5 t-129.5 360.5z" />
|
||||
<glyph unicode="è" horiz-adv-x="1136" d="M84 518q0 244 146.5 393.5t371.5 149.5q142 0 245.5 -66.5t153.5 -175t50 -244.5l-7 -86h-755q7 -163 108.5 -252.5t247.5 -89.5q50 0 100 12.5t85.5 30.5t64 35.5t43.5 30.5l14 12l82 -145q-6 -6 -18 -16t-51.5 -35.5t-83 -45t-111.5 -35.5t-137 -16q-160 0 -286 71.5 t-194.5 195t-68.5 276.5zM295 639h553q-4 128 -74.5 196t-175.5 68q-117 0 -199.5 -69.5t-103.5 -194.5zM330 1446h213l149 -260h-168z" />
|
||||
<glyph unicode="é" horiz-adv-x="1136" d="M84 518q0 244 146.5 393.5t371.5 149.5q142 0 245.5 -66.5t153.5 -175t50 -244.5l-7 -86h-755q7 -163 108.5 -252.5t247.5 -89.5q50 0 100 12.5t85.5 30.5t64 35.5t43.5 30.5l14 12l82 -145q-6 -6 -18 -16t-51.5 -35.5t-83 -45t-111.5 -35.5t-137 -16q-160 0 -286 71.5 t-194.5 195t-68.5 276.5zM295 639h553q-4 128 -74.5 196t-175.5 68q-117 0 -199.5 -69.5t-103.5 -194.5zM514 1186l150 260h213l-197 -260h-166z" />
|
||||
<glyph unicode="ê" horiz-adv-x="1136" d="M84 518q0 244 146.5 393.5t371.5 149.5q142 0 245.5 -66.5t153.5 -175t50 -244.5l-7 -86h-755q7 -163 108.5 -252.5t247.5 -89.5q50 0 100 12.5t85.5 30.5t64 35.5t43.5 30.5l14 12l82 -145q-6 -6 -18 -16t-51.5 -35.5t-83 -45t-111.5 -35.5t-137 -16q-160 0 -286 71.5 t-194.5 195t-68.5 276.5zM295 639h553q-4 128 -74.5 196t-175.5 68q-117 0 -199.5 -69.5t-103.5 -194.5zM317 1186l181 260h207l180 -260h-174l-109 164h-4l-106 -164h-175z" />
|
||||
<glyph unicode="ë" horiz-adv-x="1136" d="M84 518q0 244 146.5 393.5t371.5 149.5q142 0 245.5 -66.5t153.5 -175t50 -244.5l-7 -86h-755q7 -163 108.5 -252.5t247.5 -89.5q50 0 100 12.5t85.5 30.5t64 35.5t43.5 30.5l14 12l82 -145q-6 -6 -18 -16t-51.5 -35.5t-83 -45t-111.5 -35.5t-137 -16q-160 0 -286 71.5 t-194.5 195t-68.5 276.5zM295 639h553q-4 128 -74.5 196t-175.5 68q-117 0 -199.5 -69.5t-103.5 -194.5zM350 1239v207h164v-207h-164zM692 1239v207h164v-207h-164z" />
|
||||
<glyph unicode="ì" horiz-adv-x="509" d="M-18 1446h213l149 -260h-168zM156 0v1036h198v-1036h-198z" />
|
||||
<glyph unicode="í" horiz-adv-x="509" d="M156 0v1036h198v-1036h-198zM168 1186l149 260h213l-196 -260h-166z" />
|
||||
<glyph unicode="î" horiz-adv-x="509" d="M-27 1186l181 260h206l181 -260h-174l-109 164h-4l-107 -164h-174zM156 0v1036h198v-1036h-198z" />
|
||||
<glyph unicode="ï" horiz-adv-x="509" d="M4 1239v207h164v-207h-164zM156 0v1036h198v-1036h-198zM346 1239v207h164v-207h-164z" />
|
||||
<glyph unicode="ð" horiz-adv-x="1206" d="M88 481q0 92 32 176t91.5 151t153.5 106.5t208 39.5q46 0 89 -9t71 -21.5t50 -25t32 -21.5l10 -9h4q-61 163 -223 273l-370 -164l-21 127l254 113q-127 64 -264 94l55 162q240 -55 424 -164l285 125l18 -125l-188 -86q137 -114 216 -280t79 -380q0 -86 -18 -167.5 t-58.5 -158.5t-99.5 -134.5t-148 -92.5t-197 -35q-113 0 -206.5 43t-153.5 114.5t-92.5 161.5t-32.5 187zM289 477q0 -135 77 -232.5t212 -97.5q80 0 142.5 34.5t98.5 90.5t54 121.5t18 134.5q0 117 -79.5 192t-209.5 75q-150 0 -231.5 -93.5t-81.5 -224.5z" />
|
||||
<glyph unicode="ñ" horiz-adv-x="1234" d="M156 0v1036h192v-137l-4 -76h4q17 38 47.5 76t77 76t115.5 62t149 24q182 0 269.5 -99t87.5 -298v-664h-199v618q0 60 -8 103t-28 81t-60.5 57.5t-100.5 19.5q-117 0 -205.5 -70t-121.5 -184q-17 -58 -17 -140v-485h-198zM297 1188q0 260 209 260q38 0 70.5 -14.5t55 -35 t42.5 -40.5t43 -34.5t47 -14.5q42 0 61 40t19 93h143q0 -260 -209 -260q-38 0 -70.5 14.5t-55 35t-42.5 40.5t-43 34.5t-47 14.5q-42 0 -61 -39.5t-19 -93.5h-143z" />
|
||||
<glyph unicode="ò" horiz-adv-x="1277" d="M80 520q0 115 44 216t119.5 172t178 112t217.5 41t217.5 -41t178 -112t119.5 -172t44 -216q0 -154 -75 -279.5t-203 -195.5t-281 -70t-281 70t-203 195.5t-75 279.5zM283 520q0 -161 104 -267t252 -106q150 0 253 106t103 267q0 159 -103 264t-253 105q-148 0 -252 -105 t-104 -264zM365 1446h213l149 -260h-168z" />
|
||||
<glyph unicode="ó" horiz-adv-x="1277" d="M80 520q0 115 44 216t119.5 172t178 112t217.5 41t217.5 -41t178 -112t119.5 -172t44 -216q0 -154 -75 -279.5t-203 -195.5t-281 -70t-281 70t-203 195.5t-75 279.5zM283 520q0 -161 104 -267t252 -106q150 0 253 106t103 267q0 159 -103 264t-253 105q-148 0 -252 -105 t-104 -264zM551 1186l149 260h213l-196 -260h-166z" />
|
||||
<glyph unicode="ô" horiz-adv-x="1277" d="M80 520q0 115 44 216t119.5 172t178 112t217.5 41t217.5 -41t178 -112t119.5 -172t44 -216q0 -154 -75 -279.5t-203 -195.5t-281 -70t-281 70t-203 195.5t-75 279.5zM283 520q0 -161 104 -267t252 -106q150 0 253 106t103 267q0 159 -103 264t-253 105q-148 0 -252 -105 t-104 -264zM356 1186l181 260h206l181 -260h-174l-109 164h-4l-107 -164h-174z" />
|
||||
<glyph unicode="õ" horiz-adv-x="1277" d="M80 520q0 115 44 216t119.5 172t178 112t217.5 41t217.5 -41t178 -112t119.5 -172t44 -216q0 -154 -75 -279.5t-203 -195.5t-281 -70t-281 70t-203 195.5t-75 279.5zM283 520q0 -161 104 -267t252 -106q150 0 253 106t103 267q0 159 -103 264t-253 105q-148 0 -252 -105 t-104 -264zM295 1188q0 260 209 260q38 0 70.5 -14.5t55 -35t42.5 -40.5t43 -34.5t47 -14.5q42 0 61 40t19 93h143q0 -260 -209 -260q-38 0 -70.5 14.5t-55 35t-42.5 40.5t-43 34.5t-47 14.5q-42 0 -61 -39.5t-19 -93.5h-143z" />
|
||||
<glyph unicode="ö" horiz-adv-x="1277" d="M80 520q0 115 44 216t119.5 172t178 112t217.5 41t217.5 -41t178 -112t119.5 -172t44 -216q0 -154 -75 -279.5t-203 -195.5t-281 -70t-281 70t-203 195.5t-75 279.5zM283 520q0 -161 104 -267t252 -106q150 0 253 106t103 267q0 159 -103 264t-253 105q-148 0 -252 -105 t-104 -264zM387 1239v207h164v-207h-164zM729 1239v207h164v-207h-164z" />
|
||||
<glyph unicode="÷" horiz-adv-x="1300" d="M133 504v160h1034v-160h-1034zM553 90v186h192v-186h-192zM553 891v186h192v-186h-192z" />
|
||||
<glyph unicode="ø" horiz-adv-x="1277" d="M80 520q0 115 44 216t119.5 172t178 112t217.5 41q146 0 276 -68l82 113l97 -70l-80 -110q86 -73 135 -178.5t49 -227.5q0 -154 -75 -279.5t-203 -195.5t-281 -70q-136 0 -262 60l-80 -113l-98 72l75 106q-91 73 -142.5 182.5t-51.5 237.5zM283 520q0 -159 102 -266 l426 592q-81 43 -172 43q-148 0 -252 -105t-104 -264zM483 182q72 -35 156 -35q150 0 253 106t103 267q0 148 -92 250z" />
|
||||
<glyph unicode="ù" horiz-adv-x="1224" d="M141 373v663h199v-618q0 -59 7.5 -101.5t27.5 -80t60 -57t100 -19.5q152 0 243.5 115t91.5 276v485h199v-1036h-192v137l4 76h-4q-38 -90 -140 -164t-241 -74q-177 0 -266 97.5t-89 300.5zM332 1446h213l149 -260h-168z" />
|
||||
<glyph unicode="ú" horiz-adv-x="1224" d="M141 373v663h199v-618q0 -59 7.5 -101.5t27.5 -80t60 -57t100 -19.5q152 0 243.5 115t91.5 276v485h199v-1036h-192v137l4 76h-4q-38 -90 -140 -164t-241 -74q-177 0 -266 97.5t-89 300.5zM516 1186l150 260h213l-197 -260h-166z" />
|
||||
<glyph unicode="û" horiz-adv-x="1224" d="M141 373v663h199v-618q0 -59 7.5 -101.5t27.5 -80t60 -57t100 -19.5q152 0 243.5 115t91.5 276v485h199v-1036h-192v137l4 76h-4q-38 -90 -140 -164t-241 -74q-177 0 -266 97.5t-89 300.5zM322 1186l180 260h207l180 -260h-174l-109 164h-4l-106 -164h-174z" />
|
||||
<glyph unicode="ü" horiz-adv-x="1224" d="M141 373v663h199v-618q0 -59 7.5 -101.5t27.5 -80t60 -57t100 -19.5q152 0 243.5 115t91.5 276v485h199v-1036h-192v137l4 76h-4q-38 -90 -140 -164t-241 -74q-177 0 -266 97.5t-89 300.5zM354 1239v207h164v-207h-164zM696 1239v207h164v-207h-164z" />
|
||||
<glyph unicode="ý" horiz-adv-x="1044" d="M4 1036h223l260 -678q9 -24 18.5 -55t14.5 -51l6 -19h4q17 70 35 123l252 680h215l-485 -1222q-46 -118 -135.5 -181t-200.5 -63q-52 0 -102 16t-75 32l-24 15l70 152q58 -43 121 -43q59 0 107.5 40.5t78.5 111.5l51 118zM440 1186l150 260h213l-197 -260h-166z" />
|
||||
<glyph unicode="þ" horiz-adv-x="1228" d="M156 -410v1856h198v-471l-2 -86h4q2 2 18 22t30.5 36t43.5 38.5t59.5 38t76.5 26.5t98 11q139 0 244.5 -70t161 -193t55.5 -280q0 -239 -130.5 -391t-336.5 -152q-67 0 -124.5 17.5t-92 42.5t-60 50t-35.5 43l-10 17h-4q4 -37 4 -90v-465h-198zM348 516q0 -162 81 -265.5 t216 -103.5q128 0 211.5 103t83.5 268t-80.5 268t-210.5 103q-61 0 -114 -21t-95.5 -64.5t-67 -117t-24.5 -170.5z" />
|
||||
<glyph unicode="ÿ" horiz-adv-x="1044" d="M4 1036h223l260 -678q9 -24 18.5 -55t14.5 -51l6 -19h4q17 70 35 123l252 680h215l-485 -1222q-46 -118 -135.5 -181t-200.5 -63q-52 0 -102 16t-75 32l-24 15l70 152q58 -43 121 -43q59 0 107.5 40.5t78.5 111.5l51 118zM276 1239v207h164v-207h-164zM618 1239v207h164 v-207h-164z" />
|
||||
<glyph unicode="Œ" horiz-adv-x="1966" d="M98 725q0 205 97.5 374.5t269 267t381.5 97.5q54 0 137 -9t115 -9h733v-176h-639v-453h520v-176h-520v-465h676v-176h-768q-32 0 -116 -9t-138 -9q-210 0 -381.5 98t-269 268.5t-97.5 376.5zM307 725q0 -158 68 -287.5t192 -204.5t279 -75q36 0 72.5 3.5t54.5 6.5l18 4 v1102q-63 16 -145 16q-155 0 -279 -75.5t-192 -204t-68 -285.5z" />
|
||||
<glyph unicode="œ" horiz-adv-x="2048" d="M82 516q0 160 75.5 285.5t201 192.5t276.5 67q150 0 264 -65t184 -181h4q63 118 171 182t255 64q142 0 245.5 -66.5t153.5 -175t50 -244.5l-6 -86h-756q6 -83 37 -149.5t80 -108t109.5 -63t129.5 -21.5q79 0 156 30.5t114 60.5l38 30l82 -145q-6 -6 -18 -16t-52 -35.5 t-83.5 -45t-111.5 -35.5t-137 -16q-157 0 -272 67t-180 185h-5q-68 -119 -183.5 -185.5t-268.5 -66.5q-151 0 -276.5 66t-201 190.5t-75.5 284.5zM285 516q0 -165 102.5 -267t251.5 -102t252.5 103.5t103.5 271.5q0 163 -104.5 265t-251.5 102q-148 0 -251 -104t-103 -269z M1206 639h553q-4 127 -73.5 195.5t-174.5 68.5q-118 0 -201 -69.5t-104 -194.5z" />
|
||||
<glyph unicode="Ÿ" horiz-adv-x="1204" d="M16 1446h230l268 -475q20 -36 42 -81.5t34 -73.5l12 -28h4q43 101 88 183l264 475h230l-483 -834v-612h-203v612zM344 1599v207h164v-207h-164zM686 1599v207h164v-207h-164z" />
|
||||
<glyph unicode="ˆ" horiz-adv-x="1021" d="M227 1546l181 260h206l181 -260h-174l-109 164h-4l-107 -164h-174z" />
|
||||
<glyph unicode="˜" horiz-adv-x="1021" d="M166 1548q0 260 209 260q38 0 70.5 -14.5t55 -35t42.5 -40.5t43 -34.5t47 -14.5q42 0 61 40t19 93h143q0 -260 -209 -260q-38 0 -70.5 14.5t-55 35t-42.5 40.5t-43 34.5t-47 14.5q-42 0 -61 -39.5t-19 -93.5h-143z" />
|
||||
<glyph unicode="–" horiz-adv-x="1445" d="M184 504v160h1078v-160h-1078z" />
|
||||
<glyph unicode="—" horiz-adv-x="1855" d="M184 504v160h1487v-160h-1487z" />
|
||||
<glyph unicode="‘" horiz-adv-x="464" d="M100 1069l136 399h145l-88 -399h-193z" />
|
||||
<glyph unicode="’" horiz-adv-x="448" d="M104 1071l89 399h192l-133 -399h-148z" />
|
||||
<glyph unicode="‚" horiz-adv-x="499" d="M86 -184l88 399h186l-133 -399h-141z" />
|
||||
<glyph unicode="“" horiz-adv-x="755" d="M100 1069l136 399h147l-88 -399h-195zM389 1069l135 399h148l-88 -399h-195z" />
|
||||
<glyph unicode="”" horiz-adv-x="737" d="M104 1071l89 399h194l-135 -399h-148zM393 1071l88 399h195l-133 -399h-150z" />
|
||||
<glyph unicode="„" horiz-adv-x="784" d="M86 -184l88 399h186l-133 -399h-141zM369 -184l88 399h188l-133 -399h-143z" />
|
||||
<glyph unicode="•" horiz-adv-x="841" d="M104 596q0 132 93 224.5t225 92.5q131 0 223 -92.5t92 -224.5t-92 -224.5t-223 -92.5q-132 0 -225 92.5t-93 224.5z" />
|
||||
<glyph unicode="…" horiz-adv-x="1576" d="M156 0v211h202v-211h-202zM686 0v211h205v-211h-205zM1219 0v211h202v-211h-202z" />
|
||||
<glyph unicode="‹" horiz-adv-x="727" d="M90 578l336 421h199l-336 -421l336 -420h-199z" />
|
||||
<glyph unicode="›" horiz-adv-x="727" d="M102 158l336 420l-336 421h199l336 -421l-336 -420h-199z" />
|
||||
<glyph unicode="€" horiz-adv-x="1210" d="M78 528v129h112q-9 82 0 148h-112v131h137q62 236 251.5 385t440.5 149q51 0 103 -6t78 -12l26 -6l-49 -186q-76 22 -162 22q-170 0 -295.5 -93.5t-177.5 -252.5h576l-27 -131h-578q-12 -68 -2 -148h553l-26 -129h-492q48 -162 177.5 -261t299.5 -99q45 0 92 7t71 13 l24 7l39 -185q-99 -35 -230 -35q-258 0 -447 153t-247 400h-135z" />
|
||||
<glyph unicode="™" horiz-adv-x="1925" d="M47 1309v137h778v-137h-311v-764h-156v764h-311zM891 545l72 901h141l213 -471q7 -16 14.5 -37.5t10.5 -35.5l4 -13h4q12 49 26 86l213 471h144l69 -901h-153l-43 538l2 62h-4l-195 -434h-125l-194 434h-5l2 -62l-43 -538h-153z" />
|
||||
<glyph unicode="" horiz-adv-x="1034" d="M0 0v1034h1034v-1034h-1034z" />
|
||||
</font>
|
||||
</defs></svg>
|
After Width: | Height: | Size: 58 KiB |
BIN
public/fonts/museo-sans-500.ttf
Normal file
BIN
public/fonts/museo-sans-500.woff
Normal file
BIN
public/fonts/museo-slab-500.eot
Normal file
BIN
public/fonts/museo-slab-500.otf
Normal file
225
public/fonts/museo-slab-500.svg
Normal file
@ -0,0 +1,225 @@
|
||||
<?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="MuseoSlab500Regular" horiz-adv-x="1136" >
|
||||
<font-face units-per-em="2048" ascent="1536" descent="-512" />
|
||||
<missing-glyph horiz-adv-x="512" />
|
||||
<glyph unicode="fi" horiz-adv-x="1388" d="M88 883v153h172v51q0 95 27.5 166t67.5 109t94.5 61.5t97 30t86.5 6.5q24 0 47.5 -1.5t35.5 -2.5l11 -2v-164q-27 6 -74 6q-24 0 -46 -3t-50.5 -15.5t-48.5 -33t-34.5 -60t-14.5 -92.5v-56h704v-882h162v-154h-524v154h164v729h-506v-729h190v-154h-551v154h162v729h-172 zM958 1243v203h209v-203h-209z" />
|
||||
<glyph unicode="fl" horiz-adv-x="1351" d="M88 883v153h172v31q0 93 28 166t74 118.5t110 75t130 41t139 11.5q96 0 192 -13t143 -26l48 -13v-1120q0 -74 23.5 -110.5t93.5 -36.5l47 2v-164q-41 -4 -88 -4q-60 0 -106.5 13.5t-86 45.5t-60.5 93t-21 149v1005q-66 21 -191 21q-56 0 -103 -13t-87 -40.5t-63 -77 t-23 -117.5v-37h250v-153h-250v-729h190v-154h-551v154h162v729h-172z" />
|
||||
<glyph unicode="ffi" horiz-adv-x="2091" d="M88 883v153h172v51q0 95 27.5 166t67.5 109t94.5 61.5t97 30t86.5 6.5q24 0 47.5 -1.5t35.5 -2.5l11 -2v-164q-27 6 -74 6q-24 0 -46 -3t-50.5 -15.5t-48.5 -33t-34.5 -60t-14.5 -92.5v-56h506v51q0 95 27.5 166t66.5 109t93 61.5t96.5 30t86.5 6.5q25 0 49.5 -1.5 t35.5 -2.5l12 -2v-164q-27 6 -76 6q-23 0 -44.5 -3t-50 -15.5t-49 -33t-35 -60t-14.5 -92.5v-56h703v-882h164v-154h-525v154h164v729h-506v-729h191v-154h-553v154h164v729h-506v-729h190v-154h-551v154h162v729h-172zM1663 1243v203h209v-203h-209z" />
|
||||
<glyph unicode="ffl" horiz-adv-x="2054" d="M88 883v153h172v51q0 80 18.5 143t51 102t70 66t82.5 39.5t80.5 17.5t72.5 5q24 0 47 -1.5t34 -2.5l11 -2v-164q-27 6 -72 6q-196 0 -196 -204v-56h506v31q0 93 28 166t74 118.5t109.5 75t129.5 41t140 11.5q96 0 191.5 -13t142.5 -26l47 -13v-1120q0 -74 24.5 -110.5 t94.5 -36.5l47 2l-2 -164q-39 -4 -86 -4q-60 0 -107 13.5t-87 45.5t-61.5 93t-21.5 149v1005q-63 21 -188 21q-57 0 -104.5 -13t-87.5 -40.5t-62.5 -77t-22.5 -117.5v-37h250v-153h-250v-729h191v-154h-553v154h164v729h-506v-729h190v-154h-551v154h162v729h-172z" />
|
||||
<glyph horiz-adv-x="0" />
|
||||
<glyph horiz-adv-x="2048" />
|
||||
<glyph unicode=" " horiz-adv-x="512" />
|
||||
<glyph unicode="	" horiz-adv-x="512" />
|
||||
<glyph unicode=" " horiz-adv-x="512" />
|
||||
<glyph unicode="!" horiz-adv-x="505" d="M150 1446h204l-12 -1049h-178zM152 0v201h204v-201h-204z" />
|
||||
<glyph unicode=""" horiz-adv-x="704" d="M131 1036v434h156v-434h-156zM418 1036v434h155v-434h-155z" />
|
||||
<glyph unicode="#" horiz-adv-x="1468" d="M86 391l25 152h268l61 344h-266l25 149h266l72 410h165l-71 -410h317l72 410h168l-72 -410h266l-24 -149h-268l-62 -344h266l-24 -152h-266l-68 -391h-168l70 391h-318l-69 -391h-166l69 391h-268zM545 543h317l62 344h-318z" />
|
||||
<glyph unicode="$" horiz-adv-x="1112" d="M86 197l111 145q6 -6 18 -16.5t51 -37.5t79.5 -47.5t100.5 -37.5t119 -17q108 0 181 58t73 155q0 51 -30.5 92t-80 68t-113.5 55.5t-130 53t-130 60.5t-113.5 78t-80 106.5t-30.5 144.5q0 143 105.5 247.5t275.5 129.5v223h145v-221q64 -4 123.5 -20.5t99 -36.5 t69.5 -39.5t44 -32.5l14 -13l-88 -157q-6 5 -16.5 13.5t-44 30t-68.5 38t-86.5 30t-101.5 13.5q-120 0 -193.5 -57t-73.5 -144q0 -48 24.5 -87.5t65.5 -67t94 -51.5t112 -46.5t117.5 -46.5t111.5 -56.5t94 -71.5t65.5 -96t24.5 -126q0 -155 -105 -268.5t-282 -133.5v-219 h-145v219q-73 8 -142 30t-115 48t-81 51t-52 41z" />
|
||||
<glyph unicode="%" horiz-adv-x="1536" d="M88 1167q0 125 90 214t219 89t220.5 -89t91.5 -214q0 -126 -91.5 -214.5t-220.5 -88.5t-219 88.5t-90 214.5zM119 0l1106 1446h192l-1106 -1446h-192zM246 1167q0 -65 43 -108t108 -43t108.5 43.5t43.5 107.5t-44 109t-108 45t-107.5 -45t-43.5 -109zM829 279 q0 125 91 214t221 89q127 0 218 -89t91 -214q0 -126 -90.5 -215t-218.5 -89q-130 0 -221 89t-91 215zM989 279q0 -65 43.5 -108.5t108.5 -43.5q63 0 107 44t44 108q0 63 -44 108t-107 45q-64 0 -108 -45t-44 -108z" />
|
||||
<glyph unicode="&" horiz-adv-x="1382" d="M100 403q0 127 70.5 230.5t191.5 142.5v4q-8 3 -21.5 9t-48 31t-61 57t-48 91t-21.5 130q0 175 129.5 273.5t333.5 98.5q38 0 83 -5.5t71 -10.5l26 -6l-51 -162q-60 12 -109 12q-121 0 -198.5 -59t-77.5 -162q0 -40 11 -76.5t38 -73.5t83 -59t136 -22h307v201h199v-201 h190v-168h-190v-197q0 -239 -139 -372.5t-379 -133.5q-233 0 -379 122t-146 306zM307 420q0 -115 86 -188.5t232 -73.5q150 0 234.5 82t84.5 249v189h-317q-154 0 -237 -68.5t-83 -189.5z" />
|
||||
<glyph unicode="'" horiz-adv-x="419" d="M131 1036v434h158v-434h-158z" />
|
||||
<glyph unicode="(" horiz-adv-x="643" d="M141 696q0 430 238 809h174q-231 -385 -231 -811q0 -476 231 -889h-174q-113 188 -175.5 418t-62.5 473z" />
|
||||
<glyph unicode=")" horiz-adv-x="643" d="M90 -195q232 420 232 889q0 424 -232 811h174q238 -379 238 -809q0 -243 -62.5 -473t-175.5 -418h-174z" />
|
||||
<glyph unicode="*" horiz-adv-x="980" d="M84 1085l55 172l273 -102l-17 291h187l-17 -291l275 102l57 -172l-283 -75v-4l183 -226l-148 -106l-157 241h-5l-157 -241l-148 106l183 226v4z" />
|
||||
<glyph unicode="+" horiz-adv-x="1255" d="M86 504v160h459v503h168v-503h456v-160h-456v-504h-168v504h-459z" />
|
||||
<glyph unicode="," horiz-adv-x="534" d="M41 -254l143 469h209l-194 -469h-158z" />
|
||||
<glyph unicode="-" horiz-adv-x="974" d="M188 496v176h598v-176h-598z" />
|
||||
<glyph unicode="." horiz-adv-x="524" d="M156 0v215h213v-215h-213z" />
|
||||
<glyph unicode="/" horiz-adv-x="868" d="M84 -86l522 1610h176l-522 -1610h-176z" />
|
||||
<glyph unicode="0" horiz-adv-x="1269" d="M123 725q0 129 16 237.5t53 204t95 161.5t146.5 104t201.5 38t201 -38t146 -104t95.5 -161.5t53.5 -204t16 -237.5q0 -130 -16 -239t-53.5 -205t-95.5 -162.5t-146 -105t-201 -38.5t-201.5 38.5t-146.5 105t-95 162.5t-53 205t-16 239zM332 725q0 -127 14.5 -224.5 t47.5 -177.5t94 -122.5t147 -42.5t146.5 42.5t94 122.5t48 178t14.5 224q0 125 -14.5 222.5t-48 177t-94 122.5t-146.5 43t-147 -43t-94 -123t-47.5 -177t-14.5 -222z" />
|
||||
<glyph unicode="1" horiz-adv-x="980" d="M94 1110l346 336h181v-1278h315v-168h-832v168h320v942l2 88h-4q-17 -31 -70 -82l-135 -133z" />
|
||||
<glyph unicode="2" horiz-adv-x="1200" d="M100 111q0 83 24.5 156t66 129.5t95.5 107t114 93t119.5 83t113.5 81.5t95.5 83.5t66 94t24.5 108.5q0 111 -71.5 177t-188.5 66q-53 0 -103.5 -20t-84.5 -48t-60 -56t-39 -48l-12 -20l-143 98q3 6 8 15.5t25 38t43.5 54.5t63.5 57.5t84 54.5t105.5 38.5t128.5 15.5 q200 0 328.5 -114.5t128.5 -300.5q0 -94 -39 -176.5t-101.5 -143t-137.5 -115.5t-151 -105t-138.5 -100.5t-102 -113.5t-40.5 -133h589v192h179v-360h-979q-11 72 -11 111z" />
|
||||
<glyph unicode="3" horiz-adv-x="1167" d="M86 172l107 145l17 -17t47 -38.5t74.5 -48.5t97 -38t116.5 -17q124 0 210.5 78t86.5 196q0 125 -91.5 196.5t-228.5 71.5q-66 0 -86 -4l-47 107l352 424q10 13 24 26t23 20l9 7v4q-45 -6 -74 -6h-404v-184h-178v352h883v-141l-383 -451q57 -6 112 -23t110 -50.5t96 -79 t66.5 -113.5t25.5 -148q0 -93 -35.5 -177.5t-99 -148t-157.5 -101.5t-204 -38q-83 0 -162 20.5t-132 49.5t-94.5 57.5t-60.5 49.5z" />
|
||||
<glyph unicode="4" horiz-adv-x="1226" d="M53 387v127l670 932h229v-895h197v-164h-197v-387h-198v387h-701zM274 551h480v567q0 22 2.5 49.5t5.5 44.5l2 17h-6q-22 -51 -53 -96l-431 -578v-4z" />
|
||||
<glyph unicode="5" horiz-adv-x="1155" d="M86 162l107 143q5 -6 14.5 -16t41.5 -35t67 -44.5t91 -35.5t115 -16q136 0 231 86t95 209q0 134 -89.5 216.5t-238.5 82.5q-68 0 -131.5 -18.5t-92.5 -37.5l-30 -18l-119 43l72 725h748v-352h-179v184h-393l-37 -346l-10 -58h4q9 5 25.5 12.5t70 20.5t109.5 13 q221 0 360.5 -131.5t139.5 -327.5q0 -134 -68 -245.5t-188.5 -176t-268.5 -64.5q-82 0 -158 19.5t-126 46.5t-88.5 54.5t-55.5 46.5z" />
|
||||
<glyph unicode="6" horiz-adv-x="1222" d="M115 651q0 118 24 232.5t76.5 221t128 187.5t186 129.5t242.5 48.5q74 0 143 -15t101 -29l33 -15l-64 -170q-10 5 -28.5 13.5t-73.5 22t-107 13.5q-96 0 -175.5 -42t-131.5 -113t-84.5 -156t-44.5 -180h4q47 62 137 99.5t191 37.5q201 0 329.5 -136t128.5 -337 q0 -214 -135 -351t-340 -137q-238 0 -389 187t-151 489zM328 545q0 -86 40 -174t116.5 -150.5t168.5 -62.5q124 0 197.5 84.5t73.5 220.5q0 134 -82 218.5t-228 84.5q-120 0 -203 -66t-83 -155z" />
|
||||
<glyph unicode="7" horiz-adv-x="1112" d="M82 1094v352h991v-139l-653 -1307h-209l598 1208q10 21 21.5 39t17.5 25l6 8v4q-37 -6 -84 -6h-510v-184h-178z" />
|
||||
<glyph unicode="8" horiz-adv-x="1228" d="M111 408q0 228 233 393q-176 117 -176 291q0 74 28.5 141t82.5 120.5t141.5 85t197.5 31.5q204 0 331.5 -104.5t127.5 -275.5q0 -69 -21.5 -137t-55.5 -119.5t-55 -77.5t-40 -45q207 -122 207 -314q0 -83 -35.5 -159.5t-99 -134.5t-157.5 -93t-204 -35q-217 0 -361 123.5 t-144 309.5zM315 428q0 -121 88 -197.5t211 -76.5q117 0 204 70t87 173q0 35 -10.5 64.5t-34 54.5t-48 44t-67.5 40.5t-75.5 36t-89.5 38.5t-93 40q-29 -22 -46.5 -37.5t-52.5 -54.5t-54 -89t-19 -106zM369 1090q0 -30 9.5 -57.5t22.5 -48t39.5 -42t47.5 -35.5t60 -33 t63.5 -29.5t71.5 -30t71 -30.5q125 147 125 283q0 106 -71 166.5t-190 60.5q-117 0 -183 -58t-66 -146z" />
|
||||
<glyph unicode="9" horiz-adv-x="1222" d="M92 985q0 213 135.5 349t341.5 136q237 0 388 -186.5t151 -488.5q0 -117 -24 -231t-76.5 -221t-127.5 -188.5t-186 -130.5t-243 -49q-74 0 -143.5 15t-102.5 30l-33 15l64 172q10 -5 28.5 -13.5t73.5 -22t108 -13.5q97 0 177 42t132.5 113t85 156t44.5 180h-4 q-47 -59 -138 -95t-192 -36q-201 0 -330 134.5t-129 332.5zM301 985q0 -132 80.5 -214.5t222.5 -82.5q119 0 205 65.5t86 153.5q0 64 -25 132t-67.5 124t-104.5 91.5t-129 35.5q-122 0 -195 -86t-73 -219z" />
|
||||
<glyph unicode=":" horiz-adv-x="610" d="M199 0v215h213v-215h-213zM199 821v215h213v-215h-213z" />
|
||||
<glyph unicode=";" horiz-adv-x="612" d="M88 -254l125 469h209l-174 -469h-160zM209 821v215h209v-215h-209z" />
|
||||
<glyph unicode="<" horiz-adv-x="1255" d="M119 516v135l954 426v-182l-731 -309v-4l731 -310v-182z" />
|
||||
<glyph unicode="=" horiz-adv-x="1255" d="M139 309v160h977v-160h-977zM139 696v160h977v-160h-977z" />
|
||||
<glyph unicode=">" horiz-adv-x="1255" d="M180 90v182l733 310v4l-733 309v182l957 -426v-135z" />
|
||||
<glyph unicode="?" horiz-adv-x="960" d="M74 1343q6 5 16 14t45.5 32t74 40t99.5 31.5t123 14.5q178 0 303 -104.5t125 -270.5q0 -69 -20 -127.5t-52 -100.5t-70.5 -79.5t-77 -71.5t-70.5 -68.5t-52 -78t-20 -93.5v-84h-195v97q0 63 19 118t50 94.5t68 76t74 69.5t68 66.5t50 76t19 90.5q0 87 -66 145t-167 58 q-57 0 -115.5 -21.5t-88.5 -42.5l-30 -22zM297 0v201h207v-201h-207z" />
|
||||
<glyph unicode="@" horiz-adv-x="1611" d="M88 496q0 156 57 295t158 240.5t246 160.5t313 59q128 0 227.5 -34t159 -92.5t89.5 -131.5t30 -157v-580h148v-150h-560q-187 0 -305.5 114t-118.5 274q0 102 51.5 189t149.5 140.5t223 53.5h222q-2 89 -90 149.5t-232 60.5q-162 0 -293.5 -81.5t-203.5 -217.5t-72 -296 q0 -159 72 -292.5t206 -213.5t303 -80v-162q-168 0 -314 58.5t-248 159t-160 239t-58 295.5zM733 494q0 -98 68.5 -168t171.5 -70h205v483h-201q-106 0 -175 -71t-69 -174z" />
|
||||
<glyph unicode="A" horiz-adv-x="1476" d="M23 0v160h139l461 1286h231l461 -1286h139v-160h-502v160h154l-113 321h-512l-112 -321h155v-160h-501zM532 645h410l-176 502q-9 26 -15 53.5t-8 41.5l-2 15h-6q-6 -51 -24 -110z" />
|
||||
<glyph unicode="B" horiz-adv-x="1392" d="M109 0v160h180v1128h-180v158h657q160 0 254 -43q89 -40 144 -126t55 -200q0 -105 -48.5 -186.5t-134.5 -124.5v-4q114 -33 177 -128.5t63 -221.5q0 -138 -75 -241.5t-191 -143.5q-82 -27 -217 -27h-684zM494 168h307q80 0 129 20q63 26 100 89t37 145q0 113 -68 180.5 t-182 67.5h-323v-502zM494 838h303q97 0 155 61t58 160q0 64 -25 114t-70 76q-59 29 -149 29h-272v-440z" />
|
||||
<glyph unicode="C" horiz-adv-x="1523" d="M100 731q0 209 97.5 378.5t267 265t375.5 95.5q58 0 124.5 -8t144 -29t139 -52t102.5 -82t41 -115v-176h-191v112q0 45 -35.5 80.5t-91 54.5t-113.5 29t-112 10q-233 0 -385 -155.5t-152 -399.5q0 -255 156 -420t393 -165q45 0 100.5 8.5t117 26t102.5 53t41 82.5v112 h190v-176q0 -61 -39.5 -111t-100.5 -81.5t-138.5 -53t-148.5 -30.5t-136 -9q-160 0 -299.5 59t-237.5 160.5t-154.5 241t-56.5 295.5z" />
|
||||
<glyph unicode="D" horiz-adv-x="1595" d="M109 0v160h180v1128h-180v158h616q191 0 307 -35q210 -66 333.5 -247t123.5 -441t-121 -438t-336 -246q-118 -39 -305 -39h-618zM494 168h221q152 0 246 37q148 52 231.5 187t83.5 331q0 197 -83 333t-230 189q-91 33 -248 33h-221v-1110z" />
|
||||
<glyph unicode="E" horiz-adv-x="1294" d="M109 0v160h180v1128h-180v158h1046v-336h-178v168h-483v-465h512v-168h-512v-477h518v174h178v-342h-1081z" />
|
||||
<glyph unicode="F" horiz-adv-x="1181" d="M109 0v160h180v1128h-180v158h1001v-342h-178v166h-438v-479h499v-168h-499v-463h196v-160h-581z" />
|
||||
<glyph unicode="G" horiz-adv-x="1568" d="M100 727q0 159 55.5 296.5t154 236t240.5 154.5t308 56q97 0 194 -19t178.5 -54t132 -90.5t50.5 -120.5v-178h-188v106q0 57 -56 99.5t-136 61.5t-169 19q-251 0 -401 -155t-150 -406q0 -167 67.5 -298t195 -206t294.5 -75q55 0 116 9t125 28t105 56t41 87v190h-282v160 h471v-405q0 -64 -41 -117t-104 -86.5t-143.5 -57t-156.5 -33.5t-145 -10q-218 0 -391.5 98.5t-269 270t-95.5 383.5z" />
|
||||
<glyph unicode="H" horiz-adv-x="1736" d="M109 0v160h180v1128h-180v158h567v-158h-182v-481h749v481h-182v158h567v-158h-180v-1128h180v-160h-567v160h182v479h-749v-479h182v-160h-567z" />
|
||||
<glyph unicode="I" horiz-adv-x="782" d="M109 0v160h180v1128h-180v158h567v-158h-182v-1128h182v-160h-567z" />
|
||||
<glyph unicode="J" d="M49 403v84h199v-63q0 -115 55 -190.5t168 -75.5q96 0 157.5 64t61.5 202v864h-209v158h576v-158h-162v-876q0 -111 -36.5 -197.5t-98.5 -137.5t-136 -76.5t-155 -25.5q-64 0 -123.5 14.5t-114 47.5t-94.5 81.5t-64 121.5t-24 163z" />
|
||||
<glyph unicode="K" horiz-adv-x="1417" d="M109 0v160h180v1128h-180v158h542v-158h-157v-454h186l315 454h-133v158h490v-158h-140l-374 -522v-4q5 -2 12.5 -7t29.5 -29.5t40 -59.5l260 -453q17 -29 40.5 -41t61.5 -12h68v-160h-146q-60 0 -96.5 11.5t-58 33t-45.5 64.5l-279 499q-19 31 -44.5 44.5t-68.5 13.5 h-118v-506h178v-160h-563z" />
|
||||
<glyph unicode="L" horiz-adv-x="1236" d="M111 0v160h180v1118h-180v168h567v-168h-182v-1110h503v233h181v-401h-1069z" />
|
||||
<glyph unicode="M" horiz-adv-x="1961" d="M78 0v160h180l92 1128h-184v158h409l371 -881q10 -26 18.5 -52t11.5 -39l3 -13h4q10 45 33 104l370 881h410v-158h-184l92 -1128h180v-160h-557v160h174l-65 864q-1 20 0.5 50t3.5 50l2 19h-6q-17 -70 -33 -111l-332 -760h-180l-332 760q-7 18 -15.5 46t-13.5 46l-4 19 h-6q1 -8 2 -21.5t3 -45.5t1 -52l-65 -864h174v-160h-557z" />
|
||||
<glyph unicode="N" horiz-adv-x="1716" d="M109 0v160h180v1128h-180v158h383l710 -1036q11 -18 23.5 -44.5t18.5 -43.5l7 -17h6q-10 72 -10 117v866h-184v158h571v-158h-182v-1288h-201l-710 1036q-12 18 -24 44.5t-19 43.5l-6 17h-7q1 -8 3 -21t4.5 -44.5t1.5 -51.5v-864h186v-160h-571z" />
|
||||
<glyph unicode="O" horiz-adv-x="1683" d="M98 733q0 153 57.5 290t156.5 235t237 155t293 57q206 0 376.5 -97t268.5 -266t98 -374q0 -210 -98 -384t-268.5 -274t-376.5 -100q-155 0 -293 59t-237 160t-156.5 241.5t-57.5 297.5zM309 733q0 -160 71.5 -292.5t193.5 -207.5t268 -75q108 0 206 44.5t169 120.5 t113 183t42 227q0 155 -71 283t-192.5 201t-266.5 73q-146 0 -268 -73t-193.5 -201t-71.5 -283z" />
|
||||
<glyph unicode="P" horiz-adv-x="1337" d="M109 0v160h180v1128h-180v158h673q163 0 248 -39q113 -48 179.5 -157t66.5 -253q0 -152 -73.5 -266.5t-198.5 -157.5q-82 -30 -218 -30h-292v-383h182v-160h-567zM494 711h268q92 0 162 28q69 31 107 98t38 160q0 178 -129 246q-63 35 -176 35h-270v-567z" />
|
||||
<glyph unicode="Q" horiz-adv-x="1689" d="M100 731q0 206 97 375.5t267.5 266.5t379.5 97q208 0 378.5 -94t268.5 -261.5t98 -373.5q0 -282 -174 -487l172 -164l-117 -127l-170 170q-194 -158 -458 -158q-206 0 -377 100.5t-268 274t-97 381.5zM311 731q0 -159 70.5 -291t193 -207t269.5 -75q83 0 168.5 28 t146.5 80l-213 211l117 125l211 -213q108 154 108 344q0 236 -155.5 396.5t-382.5 160.5q-225 0 -379 -160.5t-154 -398.5z" />
|
||||
<glyph unicode="R" horiz-adv-x="1437" d="M109 0v160h180v1128h-180v158h626q174 0 266 -31q118 -39 185 -135t67 -240q0 -156 -80 -262.5t-219 -142.5v-4q37 -21 62 -68l205 -356q17 -28 38.5 -37.5t61.5 -9.5h43v-160h-123q-89 0 -126 21t-75 88l-223 395q-29 47 -58 63.5t-93 16.5h-172v-424h178v-160h-563z M494 752h290q120 0 191.5 73t71.5 199q0 171 -136 227q-70 27 -178 27h-239v-526z" />
|
||||
<glyph unicode="S" horiz-adv-x="1183" d="M109 283v151h188v-106q0 -77 85 -123.5t204 -46.5q128 0 207 58t79 163q0 56 -22.5 99t-76.5 77.5t-93 53t-123 50.5q-22 9 -33 13q-44 17 -72 28t-68 29.5t-66 36t-57 41.5t-50.5 51.5t-37.5 60.5t-26 74t-8 88q0 99 37.5 175t103 122t147 69t175.5 23q83 0 160.5 -15.5 t140 -44.5t100 -75.5t37.5 -103.5v-170h-190v100q0 59 -75.5 94t-172.5 35q-111 0 -182.5 -51t-71.5 -147q0 -23 3.5 -43t13.5 -38t18 -32.5t27 -29.5t30 -25t37.5 -23.5t39 -20t45 -19.5t45 -17.5t48.5 -18.5q59 -22 91.5 -35t84.5 -38t81.5 -46t65.5 -54t55 -68.5 t32.5 -84t13.5 -104.5q0 -133 -68 -230t-178 -143.5t-247 -46.5q-87 0 -170 19.5t-152.5 56.5t-112 97.5t-42.5 134.5z" />
|
||||
<glyph unicode="T" horiz-adv-x="1359" d="M59 1053v393h1241v-393h-178v225h-340v-1118h183v-160h-570v160h183v1118h-340v-225h-179z" />
|
||||
<glyph unicode="U" horiz-adv-x="1632" d="M63 1288v158h570v-158h-182v-747q0 -148 55 -236q44 -70 125.5 -108.5t185.5 -38.5t185.5 39t125.5 112q56 94 56 234v745h-183v158h568v-158h-180v-749q0 -209 -101 -353q-72 -102 -196 -156.5t-275 -54.5q-153 0 -277 55.5t-198 155.5q-96 130 -96 353v749h-183z" />
|
||||
<glyph unicode="V" horiz-adv-x="1462" d="M25 1288v158h516v-158h-160l324 -952q7 -23 13 -51t8 -45l3 -17h6q9 62 25 113l323 952h-159v158h516v-158h-144l-456 -1288h-217l-457 1288h-141z" />
|
||||
<glyph unicode="W" horiz-adv-x="2066" d="M33 1288v158h514v-158h-172l225 -948l16 -109h7q8 58 20 109l303 1106h174l301 -1106q6 -23 11.5 -50t7.5 -43l2 -16h8q4 58 14 109l226 948h-172v158h516v-158h-140l-323 -1288h-234l-282 1026q-6 23 -11 51.5t-6 46.5l-2 17h-8q-4 -64 -18 -115l-283 -1026h-233 l-322 1288h-139z" />
|
||||
<glyph unicode="X" horiz-adv-x="1370" d="M61 0v160h136l372 571l-366 557h-133v158h503v-158h-153l239 -379l37 -57h4q12 26 35 57l232 379h-150v158h490v-158h-136l-374 -575l368 -553h138v-160h-504v160h151l-241 377l-37 59h-4q-1 0 -4.5 -7t-12 -22.5t-16.5 -29.5l-234 -377h152v-160h-492z" />
|
||||
<glyph unicode="Y" horiz-adv-x="1331" d="M20 1288v158h498v-158h-151l268 -454l29 -62h4q12 31 30 62l269 454h-150v158h494v-158h-137l-406 -676v-452h182v-160h-569v160h182v452l-405 676h-138z" />
|
||||
<glyph unicode="Z" horiz-adv-x="1294" d="M111 0v135l745 1075q13 18 27.5 35.5t22.5 26.5l9 8v4q-40 -6 -81 -6h-535v-225h-178v393h1042v-133l-745 -1077q-13 -18 -28 -35.5t-24 -26.5l-8 -8v-4q41 6 82 6h566v233h178v-401h-1073z" />
|
||||
<glyph unicode="[" horiz-adv-x="636" d="M199 -195v1700h338v-149h-164v-1399h164v-152h-338z" />
|
||||
<glyph unicode="\" horiz-adv-x="866" d="M86 1524h176l520 -1610h-174z" />
|
||||
<glyph unicode="]" horiz-adv-x="638" d="M100 -43h166v1399h-166v149h340v-1700h-340v152z" />
|
||||
<glyph unicode="^" horiz-adv-x="1255" d="M141 506l410 940h129l410 -940h-181l-295 721l-292 -721h-181z" />
|
||||
<glyph unicode="_" horiz-adv-x="1140" d="M20 0h1100v-160h-1100v160z" />
|
||||
<glyph unicode="`" horiz-adv-x="1021" d="M285 1806h229l211 -260h-186z" />
|
||||
<glyph unicode="a" d="M68 289q0 67 25 121.5t64 90t95.5 62t109 40.5t116 22t106 10t88.5 2h65v39q0 221 -221 221q-73 0 -147 -25t-112 -50l-38 -25l-80 141q6 5 17.5 13.5t51 29.5t82 37t108.5 29.5t134 13.5q198 0 301 -101.5t103 -297.5v-463q0 -45 45 -45h104v-154h-206q-129 0 -129 113 v14q0 18 2 35t4 25l2 8h-4q-4 -9 -11.5 -24t-36.5 -52.5t-64.5 -66.5t-97 -53t-132.5 -24q-90 0 -166 33t-127 106t-51 175zM268 305q0 -73 50.5 -124.5t136.5 -51.5q84 0 150.5 52t100 128t33.5 156v43h-51q-29 0 -53.5 -0.5t-70 -5t-81.5 -11.5t-78.5 -22.5t-70.5 -36 t-47 -53.5t-19 -74z" />
|
||||
<glyph unicode="b" horiz-adv-x="1247" d="M0 1292v154h373v-479q0 -22 -1.5 -43.5t-3.5 -31.5l-1 -11h4q4 7 11.5 19.5t36.5 43.5t64 54.5t94.5 43t127.5 19.5q209 0 332.5 -149.5t123.5 -393.5q0 -245 -132.5 -394t-340.5 -149q-49 0 -93.5 10.5t-76.5 27t-59.5 36.5t-45 40.5t-30 37t-17.5 27.5l-6 10h-4 q6 -37 6 -82v-82h-188v1292h-174zM367 514q0 -96 31 -177t100 -135.5t164 -54.5q127 0 211.5 99t84.5 270q0 168 -81 269.5t-211 101.5q-60 0 -112 -21.5t-95 -65t-67.5 -117.5t-24.5 -169z" />
|
||||
<glyph unicode="c" horiz-adv-x="1132" d="M82 516q0 156 72.5 281t198 194.5t278.5 69.5q49 0 101.5 -7t107.5 -25t98 -44t70.5 -67.5t27.5 -92.5v-127h-176v72q0 55 -71.5 87t-151.5 32q-157 0 -254.5 -102t-97.5 -267q0 -171 104.5 -272t259.5 -101q165 0 324 128q3 2 4.5 3.5t3.5 2.5l76 -146q-24 -22 -56 -44 t-85.5 -51t-125.5 -47t-149 -18q-151 0 -277 64.5t-204 189.5t-78 287z" />
|
||||
<glyph unicode="d" horiz-adv-x="1288" d="M86 518q0 246 130 394.5t341 148.5q66 0 123.5 -18t92 -43.5t59.5 -51t35 -43.5l10 -18h4q-7 33 -7 78v327h-172v154h371v-1247q0 -45 45 -45h105v-154h-207q-129 0 -129 113v14q0 16 1.5 29.5t3.5 19.5l1 6h-4q-3 -8 -10.5 -22t-36.5 -50t-65 -63t-100 -49.5t-138 -22.5 q-207 0 -330 149.5t-123 393.5zM289 518q0 -167 81.5 -269t211.5 -102q126 0 212.5 93.5t86.5 275.5q0 98 -31 180.5t-99.5 136.5t-162.5 54q-129 0 -214 -98.5t-85 -270.5z" />
|
||||
<glyph unicode="e" d="M84 518q0 244 146.5 393.5t371.5 149.5q143 0 246.5 -66.5t153 -174.5t49.5 -245l-7 -75h-757q9 -165 111 -259t247 -94q50 0 100.5 12t86.5 29t64.5 34.5t43.5 29.5l14 12l82 -145q-6 -6 -18 -15.5t-52 -34.5t-84 -44t-112 -34.5t-137 -15.5q-160 0 -286 71.5 t-194.5 195t-68.5 276.5zM295 627h551q-4 131 -74.5 203.5t-173.5 72.5q-116 0 -199 -73.5t-104 -202.5z" />
|
||||
<glyph unicode="f" horiz-adv-x="768" d="M88 883v153h172v51q0 95 27.5 166t67.5 109t94.5 61.5t97 30t86.5 6.5q24 0 47.5 -1.5t35.5 -2.5l11 -2v-164q-27 6 -74 6q-24 0 -46 -3t-50.5 -15.5t-48.5 -33t-34.5 -60t-14.5 -92.5v-56h250v-153h-250v-729h190v-154h-551v154h162v729h-172z" />
|
||||
<glyph unicode="g" horiz-adv-x="1282" d="M88 543q0 149 52.5 265.5t157 184.5t245.5 68q110 0 203 -43t133 -127h4q-4 14 -4 41q0 51 28 77.5t90 26.5h222v-153h-115q-45 0 -45 -41v-799q0 -123 -44 -217t-119.5 -148.5t-166 -81t-192.5 -26.5q-183 0 -355 86l66 151q14 -8 39.5 -19.5t100.5 -30.5t144 -19 q146 0 237 72t91 223v82l6 65h-4q-100 -168 -311 -168q-140 0 -246.5 70.5t-161.5 190.5t-55 270zM291 547q0 -163 80.5 -263t218.5 -100q120 0 197 84.5t77 272.5q0 348 -293 348q-133 0 -206.5 -91.5t-73.5 -250.5z" />
|
||||
<glyph unicode="h" horiz-adv-x="1380" d="M55 1292v154h371v-537q0 -22 -1.5 -43.5t-2.5 -31.5l-2 -11h4q18 40 51 79.5t80.5 76.5t114.5 59.5t141 22.5q182 0 269 -98.5t87 -298.5v-510h162v-154h-360v618q0 60 -8 103t-28 81t-60.5 57.5t-100.5 19.5q-151 0 -248.5 -113t-97.5 -281v-331h164v-154h-524v154h163 v1138h-174z" />
|
||||
<glyph unicode="i" horiz-adv-x="688" d="M88 883v153h371v-882h164v-154h-525v154h162v729h-172zM256 1243v203h209v-203h-209z" />
|
||||
<glyph unicode="j" horiz-adv-x="606" d="M-33 -256q18 -2 45 -2t52.5 4t57.5 18.5t55.5 38.5t39.5 68.5t16 103.5v908h-174v153h373v-1067q0 -71 -15.5 -130t-40.5 -99t-60 -70t-70.5 -47t-76 -27.5t-71.5 -14t-63 -3.5l-68 4v162zM229 1243v203h209v-203h-209z" />
|
||||
<glyph unicode="k" horiz-adv-x="1202" d="M55 1292v154h371v-807h152l206 244h-135v153h471v-153h-137l-256 -299v-4q3 0 11.5 -5.5t27.5 -26.5t37 -52l176 -301q15 -25 32.5 -33t57.5 -8h66v-154h-156q-71 0 -104 18t-66 78l-205 350q-16 26 -37 33.5t-59 7.5h-82v-333h139v-154h-499v154h163v1138h-174z" />
|
||||
<glyph unicode="l" horiz-adv-x="600" d="M2 1292v154h371v-1139q0 -73 23.5 -110t86.5 -37l56 2l-2 -164q-41 -4 -88 -4q-59 0 -105.5 13.5t-86.5 45.5t-61.5 93.5t-21.5 148.5v997h-172z" />
|
||||
<glyph unicode="m" horiz-adv-x="2048" d="M88 883v153h234q131 0 131 -114v-54q0 -15 -1.5 -29.5t-3.5 -22.5l-2 -7h5q41 99 145 175.5t223 76.5q252 0 303 -244h4q45 102 147 173t224 71q338 0 338 -397v-510h164v-154h-363v621q0 60 -7 102.5t-25.5 80.5t-56 57.5t-93.5 19.5q-94 0 -165 -59t-105.5 -149.5 t-34.5 -195.5v-323h162v-154h-361v621q0 46 -3 79.5t-14 69.5t-30 59t-53 37.5t-80 14.5q-94 0 -167 -61.5t-108.5 -154t-35.5 -196.5v-315h164v-154h-525v154h162v686q0 43 -45 43h-127z" />
|
||||
<glyph unicode="n" horiz-adv-x="1411" d="M88 883v153h234q131 0 131 -114v-54q0 -15 -1.5 -29.5t-3.5 -22.5l-2 -7h5q7 20 24 47.5t51.5 64.5t78 67.5t109.5 51.5t140 21q177 0 260.5 -98.5t83.5 -298.5v-510h164v-154h-363v618q0 60 -7.5 103t-27 81t-59.5 57.5t-100 19.5q-101 0 -181.5 -56.5t-122.5 -147 t-42 -194.5v-327h164v-154h-525v154h162v684q0 45 -45 45h-127z" />
|
||||
<glyph unicode="o" horiz-adv-x="1282" d="M82 520q0 115 44 216t119.5 172t178 112t217.5 41t217.5 -41t178 -112t119.5 -172t44 -216q0 -154 -75 -279.5t-203 -195.5t-281 -70t-281 70t-203 195.5t-75 279.5zM285 520q0 -161 103 -267t253 -106q148 0 252 106t104 267q0 159 -104 264t-252 105q-150 0 -253 -105 t-103 -264z" />
|
||||
<glyph unicode="p" horiz-adv-x="1304" d="M59 883v153h230q127 0 127 -102v-8l-4 -60h4q4 8 11 21t36 46.5t65 59.5t99.5 47t136.5 21q208 0 331.5 -150t123.5 -393q0 -244 -132 -393.5t-337 -149.5q-64 0 -120.5 18t-91.5 44t-61.5 52.5t-37.5 44.5l-11 18h-4q6 -38 6 -91v-317h164v-154h-524v154h161v1094 q0 45 -45 45h-127zM426 514q0 -95 32 -177t100.5 -136t160.5 -54q128 0 213.5 99t85.5 270q0 168 -82 269.5t-213 101.5q-126 0 -211.5 -93.5t-85.5 -279.5z" />
|
||||
<glyph unicode="q" horiz-adv-x="1247" d="M86 518q0 245 131 394t338 149q191 0 325 -174q4 -4 5 -6h4q-4 28 -4 71v84h188v-1292h162v-154h-522v154h161v326q0 24 2 46.5t4 33.5l1 10h-4q-4 -8 -11.5 -20t-36 -44t-63.5 -56.5t-95 -44.5t-128 -20q-209 0 -333 149.5t-124 393.5zM289 518q0 -167 81.5 -269 t211.5 -102q60 0 112 21.5t95 65t67.5 117.5t24.5 169q0 96 -31 177.5t-100 136.5t-164 55q-126 0 -211.5 -100t-85.5 -271z" />
|
||||
<glyph unicode="r" horiz-adv-x="866" d="M84 883v153h233q68 0 101 -29.5t33 -91.5v-65l-5 -72h5q37 119 124 195t203 76l51 -5v-196q-24 6 -57 6q-79 0 -141.5 -37.5t-99.5 -100t-55.5 -136t-18.5 -152.5v-274h153v-154h-508v154h156v684q0 45 -45 45h-129z" />
|
||||
<glyph unicode="s" horiz-adv-x="985" d="M82 223v111h174v-68q0 -62 71.5 -95.5t166.5 -33.5q91 0 149.5 35t58.5 98q0 28 -12 51.5t-31.5 40.5t-51.5 33t-62.5 27.5t-74.5 27.5q-17 6 -26 9q-58 21 -94.5 36.5t-84.5 44.5t-76 59t-48 75.5t-20 99.5q0 74 34 131t90.5 90t122 49.5t136.5 16.5q58 0 117.5 -12 t115 -35t90.5 -65.5t35 -96.5v-125h-174v68q0 46 -53 76t-129 30q-78 0 -131 -32.5t-53 -92.5q0 -28 14 -52.5t33 -41t55.5 -34.5t62.5 -28t74 -26q42 -14 70 -24t67.5 -27.5t65 -33.5t54.5 -40.5t46 -50.5t28 -61.5t11 -75.5q0 -144 -116.5 -225t-299.5 -81 q-98 0 -188.5 27t-153.5 85t-63 136z" />
|
||||
<glyph unicode="t" horiz-adv-x="737" d="M37 883v153h178v285h195v-285h247v-153h-247v-486q0 -60 16 -105.5t39 -69.5t55 -39t57.5 -19t53.5 -4l47 2v-166q-29 -4 -72 -4q-32 0 -63.5 3t-72 13.5t-75.5 27t-69.5 46t-59 69t-40 98.5t-15.5 130v504h-174z" />
|
||||
<glyph unicode="u" horiz-adv-x="1361" d="M41 883v153h373v-622q0 -47 4 -82.5t16.5 -70t33.5 -56.5t56.5 -35.5t83.5 -13.5q100 0 178 58.5t118 149.5t40 195v324h-174v153h373v-839q0 -45 45 -45h108v-152h-215q-131 0 -131 115v45l4 61h-4q-7 -20 -23.5 -47t-50.5 -63t-76 -65.5t-107 -50t-138 -20.5 q-169 0 -254.5 97.5t-85.5 300.5v510h-174z" />
|
||||
<glyph unicode="v" horiz-adv-x="1189" d="M18 883v153h465v-153h-133l219 -604q7 -20 13 -44.5t8 -38.5l2 -14h6q7 52 23 97l221 604h-133v153h462v-153h-129l-335 -883h-224l-333 883h-132z" />
|
||||
<glyph unicode="w" horiz-adv-x="1753" d="M20 883v153h463v-153h-139l176 -602q5 -19 9.5 -43.5t6.5 -39.5l1 -14h6q4 54 16 97l227 753h181l227 -753q5 -19 9 -43.5t5 -39.5l2 -14h7q4 54 16 97l178 602h-141v153h463v-153h-129l-267 -883h-221l-219 692q-5 21 -9.5 45.5t-6.5 38.5l-2 15h-5q-6 -52 -18 -99 l-219 -692h-221l-266 883h-130z" />
|
||||
<glyph unicode="x" horiz-adv-x="1171" d="M76 0v154h155l248 381l-229 348h-168v153h291l184 -301l35 -67h4q17 34 37 67l188 301h275v-153h-158l-231 -346l256 -383h139v-154h-264l-209 336l-37 65h-4q-14 -32 -37 -67l-205 -334h-270z" />
|
||||
<glyph unicode="y" horiz-adv-x="1208" d="M18 883v153h474v-153h-138l232 -617q6 -20 10.5 -42.5t5.5 -35.5l2 -12h6q9 45 25 90l229 617h-133v153h459v-153h-129l-410 -1047q-52 -130 -147 -198t-217 -68q-59 0 -115 16t-82 32l-27 17l68 150q7 -5 19.5 -13.5t51 -22t77.5 -13.5q64 0 113 39.5t77 103.5l43 103 l-362 901h-132z" />
|
||||
<glyph unicode="z" horiz-adv-x="1079" d="M98 0v131l572 692q14 16 28 31t22 22l7 7v4q-43 -4 -84 -4h-360v-166h-174v319h858v-131l-568 -692q-14 -16 -28 -30.5t-21 -20.5l-8 -6v-4q41 2 82 2h383v165h174v-319h-883z" />
|
||||
<glyph unicode="{" horiz-adv-x="690" d="M68 578v176q7 1 19 3t42 16t52.5 36t41.5 67t19 105v172q0 67 13.5 121.5t34.5 91t51.5 63.5t60 42t63.5 24t58.5 11.5t49.5 2.5l50 -2v-151h-29q-20 0 -39 -3t-46 -16t-46 -35t-33 -63.5t-14 -97.5v-211q0 -57 -17 -104.5t-41.5 -75t-49 -47t-41.5 -26.5l-17 -7v-4 q7 -2 18 -6.5t39.5 -24.5t50.5 -46t40 -75t18 -108v-236q0 -56 14 -97.5t33 -63.5t46 -35t46 -16t39 -3h29v-152q-21 -4 -50 -4q-37 0 -73 5.5t-85 27.5t-85 58.5t-62 105.5t-26 162v196q0 59 -18 103.5t-43.5 66t-51 35t-43.5 16.5z" />
|
||||
<glyph unicode="|" horiz-adv-x="563" d="M195 -326v1948h174v-1948h-174z" />
|
||||
<glyph unicode="}" horiz-adv-x="690" d="M70 -45h28q20 0 38.5 3t45 16t45.5 35t33 63.5t14 97.5v236q0 59 17 107.5t41.5 75.5t49 45.5t41.5 25.5l17 6v4q-7 2 -18 7t-39.5 26t-50.5 47.5t-40 74.5t-18 105v211q0 56 -14 97.5t-33 63.5t-45.5 35t-45 16t-38.5 3h-28v151q18 2 47 2q37 0 73 -5.5t85.5 -27 t85.5 -57.5t62 -105t26 -161v-172q0 -60 18 -105t43.5 -67t51 -36t43.5 -17l18 -2v-176q-7 -1 -19 -3t-42 -16t-52.5 -35.5t-41.5 -66t-19 -103.5v-196q0 -93 -26 -162t-62 -105.5t-85.5 -58.5t-85.5 -27.5t-73 -5.5l-47 4v152z" />
|
||||
<glyph unicode="~" horiz-adv-x="1247" d="M137 418q0 174 74.5 260t210.5 86q60 0 108 -20.5t80 -50t61 -59.5t65 -50.5t79 -20.5q72 0 104.5 58t32.5 135h162q0 -175 -75.5 -260.5t-211.5 -85.5q-59 0 -107.5 20.5t-80 49.5t-60.5 58t-65.5 49.5t-79.5 20.5q-38 0 -65.5 -17.5t-42 -46.5t-21 -60.5t-6.5 -65.5 h-162z" />
|
||||
<glyph unicode="¡" horiz-adv-x="491" d="M141 836v200h207v-200h-207zM143 -410l13 1049h178l14 -1049h-205z" />
|
||||
<glyph unicode="¢" horiz-adv-x="1134" d="M84 723q0 149 51.5 272.5t150.5 204t230 98.5v172h146v-172q133 -20 232 -103.5t153 -213.5l-181 -70q-90 203 -270 203q-145 0 -227 -110t-82 -281q0 -176 80 -282.5t229 -106.5q94 0 161.5 54.5t108.5 148.5l181 -72q-55 -126 -152.5 -213.5t-232.5 -101.5v-177h-146 v177q-131 18 -230 98.5t-150.5 203.5t-51.5 271z" />
|
||||
<glyph unicode="£" horiz-adv-x="1257" d="M88 0v164h176v489h-139v144h139v278q0 171 126 283t319 112q58 0 114.5 -13t96 -32t70.5 -37.5t46 -31.5l15 -13l-113 -139q-11 9 -31.5 23t-80 37.5t-115.5 23.5q-111 0 -176.5 -63t-65.5 -158v-270h369v-144h-369v-485h522v233h178v-401h-1081z" />
|
||||
<glyph unicode="¥" horiz-adv-x="1298" d="M86 1446h231l242 -451q20 -43 42 -95t34 -83l12 -31h4q43 113 88 209l244 451h231l-340 -606h209v-129h-276l-55 -99v-75h331v-129h-331v-408h-205v408h-334v129h334v75l-55 99h-279v129h211z" />
|
||||
<glyph unicode="§" horiz-adv-x="890" d="M92 -23l90 138q4 -3 10 -8t27 -18.5t43 -23.5t54.5 -18t64.5 -8q95 0 156 56t61 159q0 50 -12 92l-135 770h161l144 -799q10 -41 10 -92q0 -155 -104 -253.5t-281 -98.5q-50 0 -98 10.5t-81 26t-59 31t-39 25.5zM125 1120q0 153 104 251.5t281 98.5q50 0 98 -10.5t81 -26 t59 -31t38 -26.5l13 -10l-94 -131q-9 8 -26 19.5t-68 31t-101 19.5q-95 0 -156 -53.5t-61 -153.5q0 -30 10 -82l139 -789h-161l-146 799q-10 39 -10 94z" />
|
||||
<glyph unicode="¨" horiz-adv-x="1021" d="M217 1599v207h176v-207h-176zM627 1599v207h176v-207h-176z" />
|
||||
<glyph unicode="©" horiz-adv-x="1642" d="M92 723q0 153 57.5 291.5t154.5 238.5t231.5 158.5t283.5 58.5q201 0 369.5 -99.5t266 -271t97.5 -376.5q0 -153 -57.5 -292t-155.5 -238.5t-234 -158.5t-286 -59q-149 0 -283.5 59t-231.5 158.5t-154.5 238.5t-57.5 292zM242 723q0 -126 44.5 -239t121.5 -194t184 -128 t227 -47q97 0 187 30t161.5 85.5t124.5 130.5t82 168t29 194t-29 194t-82 168t-124.5 130.5t-161.5 85.5t-187 30q-120 0 -227 -47t-184 -128t-121.5 -194t-44.5 -239zM430 721q0 108 48.5 201t142 150.5t213.5 57.5q66 0 124.5 -21t95 -50.5t63.5 -59t39 -50.5l11 -21 l-125 -68q-3 5 -8.5 14t-24.5 31t-40.5 39t-56.5 31t-72 14q-117 0 -185.5 -78.5t-68.5 -189.5q0 -114 67 -191t187 -77q38 0 72.5 13.5t57 32.5t40 37.5t24.5 31.5l8 14l125 -68q-4 -8 -12 -22t-37.5 -49t-64.5 -61.5t-94 -48.5t-125 -22q-180 0 -292 120.5t-112 289.5z " />
|
||||
<glyph unicode="ª" horiz-adv-x="868" d="M152 543v116h561v-116h-561zM152 981q0 225 387 225h20v13q0 129 -131 129q-40 0 -82.5 -14.5t-65.5 -29.5l-22 -14l-59 101q4 3 11 8t31 18t50.5 23t68.5 18t86 8q127 0 194 -66.5t67 -191.5v-411h-140v94h-4q-2 -4 -6.5 -11.5t-21.5 -26.5t-36.5 -33t-53 -26t-70.5 -12 q-89 0 -156 53.5t-67 145.5zM301 991q0 -37 28 -62.5t77 -25.5q66 0 108.5 56.5t42.5 125.5v17h-22q-234 0 -234 -111z" />
|
||||
<glyph unicode="«" horiz-adv-x="1148" d="M88 578l336 421h199l-336 -421l336 -420h-199zM502 578l336 421h198l-336 -421l336 -420h-198z" />
|
||||
<glyph unicode="¬" horiz-adv-x="1216" d="M100 696v160h977v-547h-166v387h-811z" />
|
||||
<glyph unicode="­" horiz-adv-x="974" d="M188 496v176h598v-176h-598z" />
|
||||
<glyph unicode="®" horiz-adv-x="1642" d="M92 723q0 153 57.5 291.5t154.5 238.5t231.5 158.5t283.5 58.5q201 0 369.5 -99.5t266 -271t97.5 -376.5q0 -153 -57.5 -292t-155.5 -238.5t-234 -158.5t-286 -59q-149 0 -283.5 59t-231.5 158.5t-154.5 238.5t-57.5 292zM242 723q0 -126 44.5 -239t121.5 -194t184 -128 t227 -47q97 0 187 30t161.5 85.5t124.5 130.5t82 168t29 194t-29 194t-82 168t-124.5 130.5t-161.5 85.5t-187 30q-120 0 -227 -47t-184 -128t-121.5 -194t-44.5 -239zM569 340v772h297q109 0 176.5 -64t67.5 -171q0 -82 -43.5 -136.5t-97.5 -68.5v-4q8 -8 26 -43l148 -285 h-160l-143 299h-125v-299h-146zM715 745h123q57 0 91 35.5t34 96.5q0 59 -33.5 91.5t-91.5 32.5h-123v-256z" />
|
||||
<glyph unicode="¯" horiz-adv-x="1021" d="M250 1606v145h522v-145h-522z" />
|
||||
<glyph unicode="°" horiz-adv-x="800" d="M90 1167q0 125 90 214t219 89t220.5 -89t91.5 -214q0 -126 -91.5 -214.5t-220.5 -88.5t-219 88.5t-90 214.5zM250 1167q0 -63 43 -107t106 -44q64 0 109 44t45 107t-45 108.5t-109 45.5q-63 0 -106 -45.5t-43 -108.5z" />
|
||||
<glyph unicode="±" horiz-adv-x="1255" d="M86 504v160h459v503h168v-503h456v-160h-456v-504h-168v504h-459zM119 -195h1018v-159h-1018v159z" />
|
||||
<glyph unicode="²" horiz-adv-x="763" d="M68 948q0 67 24 123.5t63 96t85.5 74t93 64t85.5 58.5t63 65.5t24 77.5q0 57 -41.5 95t-104.5 38q-45 0 -88.5 -24.5t-64.5 -49.5l-21 -24l-100 92q4 6 11.5 16t34.5 35.5t58 45t80.5 35.5t102.5 16q129 0 209 -73.5t80 -188.5q0 -71 -31.5 -129t-78.5 -95t-103 -74 t-104 -66.5t-81.5 -72t-36.5 -90.5h322v105h129v-232h-602q-8 51 -8 82z" />
|
||||
<glyph unicode="³" horiz-adv-x="765" d="M63 981l87 104q3 -4 8.5 -11t25 -24.5t41.5 -31t58 -24.5t75 -11q68 0 119 45t51 111q0 68 -53.5 106.5t-126.5 38.5h-65l-33 78l194 235q10 11 21.5 21.5t17.5 15.5l6 4v7q-28 -7 -61 -7h-205v-108h-129v231h574v-98l-230 -266q49 -7 91.5 -25t78 -48t56 -76.5 t20.5 -104.5q0 -122 -90 -209.5t-229 -87.5q-57 0 -109.5 14t-86 34t-59 39.5t-36.5 33.5z" />
|
||||
<glyph unicode="´" horiz-adv-x="1021" d="M295 1546l213 260h227l-254 -260h-186z" />
|
||||
<glyph unicode="¶" horiz-adv-x="1220" d="M72 971q0 131 65.5 241t176.5 172t241 62h557v-176h-401v-1372h-154v596q-130 0 -241.5 62.5t-177.5 173t-66 241.5zM838 -102v1255h151v-1255h-151z" />
|
||||
<glyph unicode="·" horiz-adv-x="573" d="M182 485v217h209v-217h-209z" />
|
||||
<glyph unicode="¸" horiz-adv-x="1021" d="M342 -322q39 -12 90 -12q105 0 105 66q0 35 -34 52t-87 17h-35l65 250l105 -20v-17l-33 -129q69 -5 115.5 -47t46.5 -106q0 -89 -65.5 -132.5t-161.5 -43.5q-27 0 -55 3.5t-42 6.5l-14 4v108z" />
|
||||
<glyph unicode="¹" horiz-adv-x="688" d="M63 1530l240 231h137v-768h209v-127h-573v127h211v506q0 16 1.5 32t3.5 24l1 8h-4q-10 -19 -33 -37l-98 -96z" />
|
||||
<glyph unicode="º" horiz-adv-x="964" d="M131 1130q0 144 102 241t246 97q148 0 250 -96.5t102 -241.5q0 -149 -101.5 -246.5t-248.5 -97.5t-248.5 97.5t-101.5 246.5zM164 543v116h639v-116h-639zM279 1130q0 -92 58 -151t144 -59q85 0 143 59t58 151q0 90 -58.5 148.5t-142.5 58.5q-86 0 -144 -58.5t-58 -148.5 z" />
|
||||
<glyph unicode="»" horiz-adv-x="1146" d="M113 158l336 420l-336 421h198l336 -421l-336 -420h-198zM524 158l336 420l-336 421h199l336 -421l-336 -420h-199z" />
|
||||
<glyph unicode="¼" horiz-adv-x="1959" d="M102 1214l240 232h137v-768h209v-127h-573v127h211v506q0 16 1.5 32t2.5 24l2 7h-4q-10 -19 -33 -37l-98 -96zM549 0l688 1446h154l-686 -1446h-156zM1182 223v99l411 573h166v-551h127v-121h-127v-223h-151v223h-426zM1339 344h269v299q0 18 2 41t4 37l2 14h-6 q-18 -45 -43 -80l-228 -307v-4z" />
|
||||
<glyph unicode="½" horiz-adv-x="1927" d="M88 1214l240 232h137v-768h209v-127h-574v127h211v506q0 16 1.5 32t3.5 24l1 7h-4q-9 -19 -32 -37l-99 -96zM539 0l688 1446h153l-686 -1446h-155zM1227 82q0 67 24 123.5t63 96t85.5 74t93 64t85.5 58.5t63 65.5t24 77.5q0 57 -41 95t-104 38q-45 0 -88.5 -24.5 t-64.5 -49.5l-21 -24l-101 92q4 6 11.5 16t34.5 35t58 44.5t80.5 35.5t102.5 16q129 0 209 -73.5t80 -188.5q0 -61 -23.5 -112.5t-61 -87.5t-83 -67.5t-91.5 -59t-84.5 -56t-64 -65t-27.5 -78.5h322v104h129v-231h-602q-8 51 -8 82z" />
|
||||
<glyph unicode="¾" horiz-adv-x="1986" d="M94 666l86 104q3 -4 8.5 -11t25 -24.5t42 -31t58.5 -24.5t75 -11q68 0 119 44.5t51 110.5q0 68 -53.5 107t-126.5 39h-66l-32 78l194 235q10 11 21.5 21.5t17.5 14.5l6 5v6q-28 -6 -61 -6h-205v-109h-129v232h573v-98l-229 -267q49 -7 91.5 -25t78 -48t56 -76.5 t20.5 -104.5q0 -122 -90.5 -209.5t-229.5 -87.5q-57 0 -109.5 14t-85.5 34t-58.5 40t-36.5 34zM569 0l688 1446h154l-686 -1446h-156zM1204 223v99l412 573h166v-551h127v-121h-127v-223h-152v223h-426zM1362 344h268v299q0 18 2 41t4 37l2 14h-6q-18 -45 -43 -80l-227 -307 v-4z" />
|
||||
<glyph unicode="¿" horiz-adv-x="952" d="M98 -57q0 69 20 127.5t52 100.5t71 79.5t77.5 71.5t70.5 68.5t52 78.5t20 94v76h192v-88q0 -63 -19 -118t-50 -95t-68 -76.5t-74 -70t-68 -67t-50 -76t-19 -89.5q0 -87 67.5 -146t168.5 -59q57 0 115.5 22t87.5 44l30 22l109 -141q-5 -5 -15.5 -14t-45.5 -31.5t-74 -40 t-99.5 -31.5t-122.5 -14q-180 0 -304 103.5t-124 269.5zM455 836v200h204v-200h-204z" />
|
||||
<glyph unicode="À" horiz-adv-x="1480" d="M25 0v160h139l461 1286h231l461 -1286h139v-160h-502v160h154l-113 321h-512l-112 -321h155v-160h-501zM420 1806h229l211 -260h-186zM535 645h409l-176 502q-9 26 -15 53.5t-8 41.5l-2 15h-6q-6 -51 -24 -110z" />
|
||||
<glyph unicode="Á" horiz-adv-x="1476" d="M23 0v160h139l461 1286h231l461 -1286h139v-160h-502v160h154l-113 321h-512l-112 -321h155v-160h-501zM532 645h410l-176 502q-9 26 -15 53.5t-8 41.5l-2 15h-6q-6 -51 -24 -110zM612 1546l213 260h228l-254 -260h-187z" />
|
||||
<glyph unicode="Â" horiz-adv-x="1476" d="M23 0v160h139l461 1286h231l461 -1286h139v-160h-502v160h154l-113 321h-512l-112 -321h155v-160h-501zM449 1546l180 260h215l180 -260h-178l-109 164h-4l-106 -164h-178zM532 645h410l-176 502q-9 26 -15 53.5t-8 41.5l-2 15h-6q-6 -51 -24 -110z" />
|
||||
<glyph unicode="Ã" horiz-adv-x="1476" d="M23 0v160h139l461 1286h231l461 -1286h139v-160h-502v160h154l-113 321h-512l-112 -321h155v-160h-501zM389 1548q0 260 209 260q41 0 75 -14t56.5 -34t42.5 -40.5t41.5 -34.5t44.5 -14q45 0 63.5 38.5t18.5 92.5h147q0 -260 -208 -260q-41 0 -75 14t-57 34t-42.5 40.5 t-41.5 34.5t-45 14q-81 0 -81 -131h-148zM532 645h410l-176 502q-9 26 -15 53.5t-8 41.5l-2 15h-6q-6 -51 -24 -110z" />
|
||||
<glyph unicode="Ä" horiz-adv-x="1476" d="M23 0v160h139l461 1286h231l461 -1286h139v-160h-502v160h154l-113 321h-512l-112 -321h155v-160h-501zM444 1599v207h177v-207h-177zM532 645h410l-176 502q-9 26 -15 53.5t-8 41.5l-2 15h-6q-6 -51 -24 -110zM854 1599v207h176v-207h-176z" />
|
||||
<glyph unicode="Å" horiz-adv-x="1476" d="M23 0v160h139l461 1286h231l461 -1286h139v-160h-502v160h154l-113 321h-512l-112 -321h155v-160h-501zM532 645h410l-176 502q-9 26 -15 53.5t-8 41.5l-2 15h-6q-6 -51 -24 -110zM549 1677q0 77 55.5 123.5t132.5 46.5q78 0 135.5 -47t57.5 -123q0 -73 -58 -118.5 t-135 -45.5t-132.5 45t-55.5 119zM664 1677q0 -33 20 -53t53 -20q35 0 55.5 20t20.5 53q0 37 -20.5 58.5t-55.5 21.5q-33 0 -53 -22t-20 -58z" />
|
||||
<glyph unicode="Æ" horiz-adv-x="1927" d="M25 0v160h129l464 1128h-157v158h1327v-336h-170v168h-485v-465h507v-168h-507v-477h520v170h170v-338h-1071v160h176v487h-369l-199 -487h156v-160h-491zM621 807h307v471h-115z" />
|
||||
<glyph unicode="Ç" horiz-adv-x="1523" d="M100 731q0 209 97.5 378.5t267 265t375.5 95.5q58 0 124.5 -8t144 -29t139 -52t102.5 -82t41 -115v-176h-191v112q0 45 -35.5 80.5t-91 54.5t-113.5 29t-112 10q-233 0 -385 -155.5t-152 -399.5q0 -255 156 -420t393 -165q45 0 100.5 8.5t117 26t102.5 53t41 82.5v112 h190v-176q0 -73 -54.5 -129.5t-140 -88.5t-173 -48.5t-171.5 -18.5l-20 -90q68 -5 115 -47t47 -106q0 -60 -34.5 -101.5t-84 -58t-109.5 -16.5q-28 0 -56 3.5t-42 6.5l-14 4v108q39 -12 92 -12q102 0 102 66q0 35 -32.5 52t-85.5 17h-37l47 179q-290 31 -475 243t-185 508z " />
|
||||
<glyph unicode="È" horiz-adv-x="1294" d="M109 0v160h180v1128h-180v158h1046v-336h-178v168h-483v-465h512v-168h-512v-477h518v174h178v-342h-1081zM348 1806h230l210 -260h-186z" />
|
||||
<glyph unicode="É" horiz-adv-x="1294" d="M109 0v160h180v1128h-180v158h1046v-336h-178v168h-483v-465h512v-168h-512v-477h518v174h178v-342h-1081zM545 1546l213 260h227l-254 -260h-186z" />
|
||||
<glyph unicode="Ê" horiz-adv-x="1294" d="M109 0v160h180v1128h-180v158h1046v-336h-178v168h-483v-465h512v-168h-512v-477h518v174h178v-342h-1081zM381 1546l180 260h215l180 -260h-178l-108 164h-4l-107 -164h-178z" />
|
||||
<glyph unicode="Ë" horiz-adv-x="1294" d="M109 0v160h180v1128h-180v158h1046v-336h-178v168h-483v-465h512v-168h-512v-477h518v174h178v-342h-1081zM375 1599v207h176v-207h-176zM784 1599v207h177v-207h-177z" />
|
||||
<glyph unicode="Ì" horiz-adv-x="782" d="M74 1806h229l211 -260h-186zM109 0v160h180v1128h-180v158h567v-158h-182v-1128h182v-160h-567z" />
|
||||
<glyph unicode="Í" horiz-adv-x="782" d="M109 0v160h180v1128h-180v158h567v-158h-182v-1128h182v-160h-567zM268 1546l213 260h228l-254 -260h-187z" />
|
||||
<glyph unicode="Î" horiz-adv-x="782" d="M104 1546l181 260h215l180 -260h-178l-109 164h-4l-106 -164h-179zM109 0v160h180v1128h-180v158h567v-158h-182v-1128h182v-160h-567z" />
|
||||
<glyph unicode="Ï" horiz-adv-x="782" d="M98 1599v207h176v-207h-176zM109 0v160h180v1128h-180v158h567v-158h-182v-1128h182v-160h-567zM508 1599v207h176v-207h-176z" />
|
||||
<glyph unicode="Ð" horiz-adv-x="1611" d="M109 0v160h180v479h-154v168h154v481h-180v158h663q221 0 386 -84t256 -248t91 -389q0 -340 -198.5 -532.5t-534.5 -192.5h-663zM494 168h264q246 0 390 145t144 412q0 264 -145 408.5t-389 144.5h-264v-471h317v-168h-317v-471z" />
|
||||
<glyph unicode="Ñ" horiz-adv-x="1716" d="M109 0v160h180v1128h-180v158h383l710 -1036q11 -18 23.5 -44.5t18.5 -43.5l7 -17h6q-10 72 -10 117v866h-184v158h571v-158h-182v-1288h-201l-710 1036q-12 18 -24 44.5t-19 43.5l-6 17h-7q1 -8 3 -21t4.5 -44.5t1.5 -51.5v-864h186v-160h-571zM520 1548q0 260 209 260 q41 0 75 -14t56.5 -34t42.5 -40.5t41.5 -34.5t44.5 -14q45 0 63.5 38.5t18.5 92.5h148q0 -260 -209 -260q-41 0 -75 14t-56.5 34t-42.5 40.5t-41.5 34.5t-44.5 14q-82 0 -82 -131h-148z" />
|
||||
<glyph unicode="Ò" horiz-adv-x="1683" d="M98 733q0 153 57.5 290t156.5 235t237 155t293 57q206 0 376.5 -97t268.5 -266t98 -374q0 -210 -98 -384t-268.5 -274t-376.5 -100q-155 0 -293 59t-237 160t-156.5 241.5t-57.5 297.5zM309 733q0 -160 71.5 -292.5t193.5 -207.5t268 -75q108 0 206 44.5t169 120.5 t113 183t42 227q0 155 -71 283t-192.5 201t-266.5 73q-146 0 -268 -73t-193.5 -201t-71.5 -283zM522 1806h230l211 -260h-187z" />
|
||||
<glyph unicode="Ó" horiz-adv-x="1683" d="M98 733q0 153 57.5 290t156.5 235t237 155t293 57q206 0 376.5 -97t268.5 -266t98 -374q0 -210 -98 -384t-268.5 -274t-376.5 -100q-155 0 -293 59t-237 160t-156.5 241.5t-57.5 297.5zM309 733q0 -160 71.5 -292.5t193.5 -207.5t268 -75q108 0 206 44.5t169 120.5 t113 183t42 227q0 155 -71 283t-192.5 201t-266.5 73q-146 0 -268 -73t-193.5 -201t-71.5 -283zM717 1546l213 260h227l-254 -260h-186z" />
|
||||
<glyph unicode="Ô" horiz-adv-x="1683" d="M98 733q0 153 57.5 290t156.5 235t237 155t293 57q206 0 376.5 -97t268.5 -266t98 -374q0 -210 -98 -384t-268.5 -274t-376.5 -100q-155 0 -293 59t-237 160t-156.5 241.5t-57.5 297.5zM309 733q0 -160 71.5 -292.5t193.5 -207.5t268 -75q108 0 206 44.5t169 120.5 t113 183t42 227q0 155 -71 283t-192.5 201t-266.5 73q-146 0 -268 -73t-193.5 -201t-71.5 -283zM553 1546l180 260h215l180 -260h-178l-108 164h-4l-107 -164h-178z" />
|
||||
<glyph unicode="Õ" horiz-adv-x="1683" d="M98 733q0 153 57.5 290t156.5 235t237 155t293 57q206 0 376.5 -97t268.5 -266t98 -374q0 -210 -98 -384t-268.5 -274t-376.5 -100q-155 0 -293 59t-237 160t-156.5 241.5t-57.5 297.5zM309 733q0 -160 71.5 -292.5t193.5 -207.5t268 -75q108 0 206 44.5t169 120.5 t113 183t42 227q0 155 -71 283t-192.5 201t-266.5 73q-146 0 -268 -73t-193.5 -201t-71.5 -283zM494 1548q0 260 208 260q41 0 75 -14t57 -34t42.5 -40.5t41.5 -34.5t45 -14q81 0 81 131h148q0 -260 -209 -260q-41 0 -75 14t-56.5 34t-42.5 40.5t-41.5 34.5t-44.5 14 q-82 0 -82 -131h-147z" />
|
||||
<glyph unicode="Ö" horiz-adv-x="1683" d="M98 733q0 153 57.5 290t156.5 235t237 155t293 57q206 0 376.5 -97t268.5 -266t98 -374q0 -210 -98 -384t-268.5 -274t-376.5 -100q-155 0 -293 59t-237 160t-156.5 241.5t-57.5 297.5zM309 733q0 -160 71.5 -292.5t193.5 -207.5t268 -75q108 0 206 44.5t169 120.5 t113 183t42 227q0 155 -71 283t-192.5 201t-266.5 73q-146 0 -268 -73t-193.5 -201t-71.5 -283zM549 1599v207h176v-207h-176zM958 1599v207h177v-207h-177z" />
|
||||
<glyph unicode="×" horiz-adv-x="1255" d="M94 113l424 471l-424 471l113 112l420 -467l420 467l112 -112l-426 -471l426 -471l-112 -113l-420 465l-420 -465z" />
|
||||
<glyph unicode="Ø" horiz-adv-x="1681" d="M98 733q0 205 98 374t268.5 266t375.5 97q209 0 381 -102l92 131l100 -69l-92 -130q123 -103 192.5 -250.5t69.5 -316.5q0 -210 -98 -384t-268.5 -274t-376.5 -100q-214 0 -391 111l-99 -137l-100 69l100 140q-119 106 -185.5 254.5t-66.5 320.5zM307 733q0 -121 43 -227 t119 -182l637 886q-123 74 -266 74q-146 0 -268 -71.5t-193.5 -198.5t-71.5 -281zM561 244q124 -82 279 -82q110 0 208.5 44t170 119t113.5 181.5t42 226.5t-45.5 225.5t-124.5 178.5z" />
|
||||
<glyph unicode="Ù" horiz-adv-x="1632" d="M63 1288v158h570v-158h-182v-747q0 -148 55 -236q44 -70 125.5 -108.5t185.5 -38.5t185.5 39t125.5 112q56 94 56 234v745h-183v158h568v-158h-180v-749q0 -209 -101 -353q-72 -102 -196 -156.5t-275 -54.5q-153 0 -277 55.5t-198 155.5q-96 130 -96 353v749h-183z M498 1806h229l211 -260h-186z" />
|
||||
<glyph unicode="Ú" horiz-adv-x="1632" d="M63 1288v158h570v-158h-182v-747q0 -148 55 -236q44 -70 125.5 -108.5t185.5 -38.5t185.5 39t125.5 112q56 94 56 234v745h-183v158h568v-158h-180v-749q0 -209 -101 -353q-72 -102 -196 -156.5t-275 -54.5q-153 0 -277 55.5t-198 155.5q-96 130 -96 353v749h-183z M692 1546l213 260h228l-254 -260h-187z" />
|
||||
<glyph unicode="Û" horiz-adv-x="1632" d="M63 1288v158h570v-158h-182v-747q0 -148 55 -236q44 -70 125.5 -108.5t185.5 -38.5t185.5 39t125.5 112q56 94 56 234v745h-183v158h568v-158h-180v-749q0 -209 -101 -353q-72 -102 -196 -156.5t-275 -54.5q-153 0 -277 55.5t-198 155.5q-96 130 -96 353v749h-183z M528 1546l181 260h215l180 -260h-178l-109 164h-4l-106 -164h-179z" />
|
||||
<glyph unicode="Ü" horiz-adv-x="1632" d="M63 1288v158h570v-158h-182v-747q0 -148 55 -236q44 -70 125.5 -108.5t185.5 -38.5t185.5 39t125.5 112q56 94 56 234v745h-183v158h568v-158h-180v-749q0 -209 -101 -353q-72 -102 -196 -156.5t-275 -54.5q-153 0 -277 55.5t-198 155.5q-96 130 -96 353v749h-183z M524 1599v207h176v-207h-176zM934 1599v207h176v-207h-176z" />
|
||||
<glyph unicode="Ý" horiz-adv-x="1331" d="M20 1288v158h498v-158h-151l268 -454l29 -62h4q12 31 30 62l269 454h-150v158h494v-158h-137l-406 -676v-452h182v-160h-569v160h182v452l-405 676h-138zM545 1546l213 260h227l-254 -260h-186z" />
|
||||
<glyph unicode="Þ" horiz-adv-x="1331" d="M109 0v160h180v1128h-180v158h567v-158h-184v-147h342q199 0 318.5 -105.5t119.5 -287.5q0 -185 -120.5 -294.5t-320.5 -109.5h-339v-184h184v-160h-567zM492 504h299q131 0 202.5 63.5t71.5 180.5q0 114 -71 173.5t-201 59.5h-301v-477z" />
|
||||
<glyph unicode="ß" horiz-adv-x="1273" d="M66 0v154h163v931q0 91 37.5 166t100.5 121.5t141.5 72t163.5 25.5q168 0 278.5 -95.5t110.5 -233.5q0 -55 -21.5 -103.5t-51.5 -82.5t-60.5 -64.5t-52 -64t-21.5 -66.5q0 -30 27 -61.5t68 -58t88.5 -63t88.5 -73.5t68 -91.5t27 -115.5q0 -100 -50.5 -172.5 t-128.5 -105.5t-172 -33q-84 0 -156 15t-102 29l-30 15v176q13 -7 36 -17.5t92.5 -28t137.5 -17.5q74 0 123 37t49 110q0 45 -38 88t-92 79.5t-107.5 75.5t-91.5 92.5t-38 113.5q0 47 21 90t51 76.5t60.5 66t51.5 72t21 80.5q0 65 -51 112t-143 47q-97 0 -167.5 -59 t-70.5 -168v-1071h-360z" />
|
||||
<glyph unicode="à" d="M68 289q0 67 25 121.5t64 90t95.5 62t109 40.5t116 22t106 10t88.5 2h65v39q0 221 -221 221q-73 0 -147 -25t-112 -50l-38 -25l-80 141q6 5 17.5 13.5t51 29.5t82 37t108.5 29.5t134 13.5q198 0 301 -101.5t103 -297.5v-463q0 -45 45 -45h104v-154h-206q-129 0 -129 113 v14q0 18 2 35t4 25l2 8h-4q-4 -9 -11.5 -24t-36.5 -52.5t-64.5 -66.5t-97 -53t-132.5 -24q-90 0 -166 33t-127 106t-51 175zM219 1446h230l210 -260h-186zM268 305q0 -73 50.5 -124.5t136.5 -51.5q84 0 150.5 52t100 128t33.5 156v43h-51q-29 0 -53.5 -0.5t-70 -5 t-81.5 -11.5t-78.5 -22.5t-70.5 -36t-47 -53.5t-19 -74z" />
|
||||
<glyph unicode="á" d="M68 289q0 67 25 121.5t64 90t95.5 62t109 40.5t116 22t106 10t88.5 2h65v39q0 221 -221 221q-73 0 -147 -25t-112 -50l-38 -25l-80 141q6 5 17.5 13.5t51 29.5t82 37t108.5 29.5t134 13.5q198 0 301 -101.5t103 -297.5v-463q0 -45 45 -45h104v-154h-206q-129 0 -129 113 v14q0 18 2 35t4 25l2 8h-4q-4 -9 -11.5 -24t-36.5 -52.5t-64.5 -66.5t-97 -53t-132.5 -24q-90 0 -166 33t-127 106t-51 175zM268 305q0 -73 50.5 -124.5t136.5 -51.5q84 0 150.5 52t100 128t33.5 156v43h-51q-29 0 -53.5 -0.5t-70 -5t-81.5 -11.5t-78.5 -22.5t-70.5 -36 t-47 -53.5t-19 -74zM414 1186l213 260h227l-254 -260h-186z" />
|
||||
<glyph unicode="â" d="M68 289q0 67 25 121.5t64 90t95.5 62t109 40.5t116 22t106 10t88.5 2h65v39q0 221 -221 221q-73 0 -147 -25t-112 -50l-38 -25l-80 141q6 5 17.5 13.5t51 29.5t82 37t108.5 29.5t134 13.5q198 0 301 -101.5t103 -297.5v-463q0 -45 45 -45h104v-154h-206q-129 0 -129 113 v14q0 18 2 35t4 25l2 8h-4q-4 -9 -11.5 -24t-36.5 -52.5t-64.5 -66.5t-97 -53t-132.5 -24q-90 0 -166 33t-127 106t-51 175zM250 1186l180 260h215l180 -260h-178l-108 164h-4l-107 -164h-178zM268 305q0 -73 50.5 -124.5t136.5 -51.5q84 0 150.5 52t100 128t33.5 156v43 h-51q-29 0 -53.5 -0.5t-70 -5t-81.5 -11.5t-78.5 -22.5t-70.5 -36t-47 -53.5t-19 -74z" />
|
||||
<glyph unicode="ã" d="M68 289q0 67 25 121.5t64 90t95.5 62t109 40.5t116 22t106 10t88.5 2h65v39q0 221 -221 221q-73 0 -147 -25t-112 -50l-38 -25l-80 141q6 5 17.5 13.5t51 29.5t82 37t108.5 29.5t134 13.5q198 0 301 -101.5t103 -297.5v-463q0 -45 45 -45h104v-154h-206q-129 0 -129 113 v14q0 18 2 35t4 25l2 8h-4q-4 -9 -11.5 -24t-36.5 -52.5t-64.5 -66.5t-97 -53t-132.5 -24q-90 0 -166 33t-127 106t-51 175zM190 1188q0 260 209 260q41 0 75 -14t56.5 -34t42.5 -40.5t41.5 -34.5t44.5 -14q45 0 63.5 38.5t18.5 92.5h148q0 -260 -209 -260q-41 0 -75 14 t-56.5 34t-42.5 40.5t-41.5 34.5t-44.5 14q-82 0 -82 -131h-148zM268 305q0 -73 50.5 -124.5t136.5 -51.5q84 0 150.5 52t100 128t33.5 156v43h-51q-29 0 -53.5 -0.5t-70 -5t-81.5 -11.5t-78.5 -22.5t-70.5 -36t-47 -53.5t-19 -74z" />
|
||||
<glyph unicode="ä" d="M68 289q0 67 25 121.5t64 90t95.5 62t109 40.5t116 22t106 10t88.5 2h65v39q0 221 -221 221q-73 0 -147 -25t-112 -50l-38 -25l-80 141q6 5 17.5 13.5t51 29.5t82 37t108.5 29.5t134 13.5q198 0 301 -101.5t103 -297.5v-463q0 -45 45 -45h104v-154h-206q-129 0 -129 113 v14q0 18 2 35t4 25l2 8h-4q-4 -9 -11.5 -24t-36.5 -52.5t-64.5 -66.5t-97 -53t-132.5 -24q-90 0 -166 33t-127 106t-51 175zM246 1239v207h176v-207h-176zM268 305q0 -73 50.5 -124.5t136.5 -51.5q84 0 150.5 52t100 128t33.5 156v43h-51q-29 0 -53.5 -0.5t-70 -5 t-81.5 -11.5t-78.5 -22.5t-70.5 -36t-47 -53.5t-19 -74zM655 1239v207h176v-207h-176z" />
|
||||
<glyph unicode="å" d="M68 289q0 67 25 121.5t64 90t95.5 62t109 40.5t116 22t106 10t88.5 2h65v39q0 221 -221 221q-73 0 -147 -25t-112 -50l-38 -25l-80 141q6 5 17.5 13.5t51 29.5t82 37t108.5 29.5t134 13.5q198 0 301 -101.5t103 -297.5v-463q0 -45 45 -45h104v-154h-206q-129 0 -129 113 v14q0 18 2 35t4 25l2 8h-4q-4 -9 -11.5 -24t-36.5 -52.5t-64.5 -66.5t-97 -53t-132.5 -24q-90 0 -166 33t-127 106t-51 175zM268 305q0 -73 50.5 -124.5t136.5 -51.5q84 0 150.5 52t100 128t33.5 156v43h-51q-29 0 -53.5 -0.5t-70 -5t-81.5 -11.5t-78.5 -22.5t-70.5 -36 t-47 -53.5t-19 -74zM350 1317q0 76 56 123t133 47t134.5 -47t57.5 -123q0 -73 -57.5 -118.5t-134.5 -45.5t-133 45t-56 119zM465 1317q0 -33 20.5 -53.5t53.5 -20.5q35 0 55 20.5t20 53.5q0 37 -20 58.5t-55 21.5q-33 0 -53.5 -22t-20.5 -58z" />
|
||||
<glyph unicode="æ" horiz-adv-x="1767" d="M70 289q0 67 23.5 121t59.5 89.5t91.5 61t106 38.5t117.5 21t112.5 9.5t103.5 1.5h55v35q0 231 -227 231q-73 0 -146.5 -25t-111.5 -50l-37 -25l-80 141q6 5 17.5 13.5t50.5 29.5t81 37t108 29.5t134 13.5q256 0 336 -182h4q126 182 369 182q138 0 240.5 -65.5 t153 -173.5t50.5 -244l-6 -76h-743q7 -172 104 -266.5t242 -94.5q49 0 98.5 12.5t85 30.5t64 35.5t42.5 30.5l15 12l82 -139q-6 -6 -18 -16t-51.5 -35.5t-83 -45t-110.5 -35.5t-136 -16q-154 0 -269 68.5t-178 192.5h-4q-7 -21 -21.5 -48t-47 -66.5t-73.5 -70.5 t-106.5 -53.5t-140.5 -22.5q-149 0 -252.5 84.5t-103.5 229.5zM268 299q0 -70 51.5 -119t141.5 -49q81 0 147 51.5t99.5 127t33.5 155.5v37h-96q-377 0 -377 -203zM940 631h541q-4 128 -75.5 200t-172.5 72q-116 0 -194 -71t-99 -201z" />
|
||||
<glyph unicode="ç" horiz-adv-x="1132" d="M82 516q0 156 72.5 281t198 194.5t278.5 69.5q49 0 101.5 -7t107.5 -25t98 -44t70.5 -67.5t27.5 -92.5v-127h-176v72q0 55 -71.5 87t-151.5 32q-157 0 -254.5 -102t-97.5 -267q0 -171 104.5 -272t259.5 -101q165 0 324 128q3 2 4.5 3.5t3.5 2.5l76 -146 q-23 -21 -54 -42.5t-82.5 -49.5t-121 -47t-142.5 -21l-20 -90q68 -5 115 -47t47 -106q0 -60 -34.5 -101.5t-84 -58t-109.5 -16.5q-27 0 -55 3.5t-42 6.5l-15 4v108q41 -12 92 -12q102 0 102 66q0 35 -32.5 52t-85.5 17h-37l49 183q-201 29 -333 172t-132 360z" />
|
||||
<glyph unicode="è" d="M84 518q0 244 146.5 393.5t371.5 149.5q143 0 246.5 -66.5t153 -174.5t49.5 -245l-7 -75h-757q9 -165 111 -259t247 -94q50 0 100.5 12t86.5 29t64.5 34.5t43.5 29.5l14 12l82 -145q-6 -6 -18 -15.5t-52 -34.5t-84 -44t-112 -34.5t-137 -15.5q-160 0 -286 71.5 t-194.5 195t-68.5 276.5zM285 1446h229l211 -260h-186zM295 627h551q-4 131 -74.5 203.5t-173.5 72.5q-116 0 -199 -73.5t-104 -202.5z" />
|
||||
<glyph unicode="é" d="M84 518q0 244 146.5 393.5t371.5 149.5q143 0 246.5 -66.5t153 -174.5t49.5 -245l-7 -75h-757q9 -165 111 -259t247 -94q50 0 100.5 12t86.5 29t64.5 34.5t43.5 29.5l14 12l82 -145q-6 -6 -18 -15.5t-52 -34.5t-84 -44t-112 -34.5t-137 -15.5q-160 0 -286 71.5 t-194.5 195t-68.5 276.5zM295 627h551q-4 131 -74.5 203.5t-173.5 72.5q-116 0 -199 -73.5t-104 -202.5zM479 1186l213 260h228l-254 -260h-187z" />
|
||||
<glyph unicode="ê" d="M84 518q0 244 146.5 393.5t371.5 149.5q143 0 246.5 -66.5t153 -174.5t49.5 -245l-7 -75h-757q9 -165 111 -259t247 -94q50 0 100.5 12t86.5 29t64.5 34.5t43.5 29.5l14 12l82 -145q-6 -6 -18 -15.5t-52 -34.5t-84 -44t-112 -34.5t-137 -15.5q-160 0 -286 71.5 t-194.5 195t-68.5 276.5zM295 627h551q-4 131 -74.5 203.5t-173.5 72.5q-116 0 -199 -73.5t-104 -202.5zM315 1186l181 260h215l180 -260h-178l-109 164h-4l-106 -164h-179z" />
|
||||
<glyph unicode="ë" d="M84 518q0 244 146.5 393.5t371.5 149.5q143 0 246.5 -66.5t153 -174.5t49.5 -245l-7 -75h-757q9 -165 111 -259t247 -94q50 0 100.5 12t86.5 29t64.5 34.5t43.5 29.5l14 12l82 -145q-6 -6 -18 -15.5t-52 -34.5t-84 -44t-112 -34.5t-137 -15.5q-160 0 -286 71.5 t-194.5 195t-68.5 276.5zM295 627h551q-4 131 -74.5 203.5t-173.5 72.5q-116 0 -199 -73.5t-104 -202.5zM311 1239v207h176v-207h-176zM721 1239v207h176v-207h-176z" />
|
||||
<glyph unicode="ì" horiz-adv-x="661" d="M27 1446h229l211 -260h-186zM92 883v153h354v-882h150v-154h-500v154h152v729h-156z" />
|
||||
<glyph unicode="í" horiz-adv-x="661" d="M92 883v153h354v-882h150v-154h-500v154h152v729h-156zM221 1186l213 260h228l-254 -260h-187z" />
|
||||
<glyph unicode="î" horiz-adv-x="661" d="M57 1186l181 260h215l180 -260h-178l-109 164h-4l-106 -164h-179zM92 883v153h354v-882h150v-154h-500v154h152v729h-156z" />
|
||||
<glyph unicode="ï" horiz-adv-x="661" d="M72 1239v207h176v-207h-176zM92 883v153h354v-882h150v-154h-500v154h152v729h-156zM426 1239v207h176v-207h-176z" />
|
||||
<glyph unicode="ð" horiz-adv-x="1208" d="M88 481q0 92 32 176t91 151t152.5 106.5t207.5 39.5q46 0 89.5 -9t71.5 -21.5t49.5 -25t31.5 -21.5l10 -9h4q-64 170 -227 279l-364 -160l-21 107l264 118q-137 69 -274 99l55 162q250 -58 434 -170l273 122l20 -108l-194 -88q138 -113 218.5 -282t80.5 -384 q0 -86 -17.5 -167.5t-58 -158.5t-99 -134.5t-147.5 -92.5t-197 -35q-113 0 -206.5 43t-153.5 114.5t-92.5 161.5t-32.5 187zM289 477q0 -135 77 -232.5t212 -97.5q80 0 142.5 34.5t98.5 90.5t54 121.5t18 134.5q0 117 -79.5 192t-209.5 75q-150 0 -231.5 -93.5t-81.5 -224.5 z" />
|
||||
<glyph unicode="ñ" horiz-adv-x="1411" d="M88 883v153h234q131 0 131 -114v-54q0 -15 -1.5 -29.5t-3.5 -22.5l-2 -7h5q7 20 24 47.5t51.5 64.5t78 67.5t109.5 51.5t140 21q177 0 260.5 -98.5t83.5 -298.5v-510h164v-154h-363v618q0 60 -7.5 103t-27 81t-59.5 57.5t-100 19.5q-101 0 -181.5 -56.5t-122.5 -147 t-42 -194.5v-327h164v-154h-525v154h162v684q0 45 -45 45h-127zM397 1188q0 260 209 260q41 0 75 -14t56.5 -34t42.5 -40.5t41.5 -34.5t44.5 -14q45 0 63.5 38.5t18.5 92.5h148q0 -260 -209 -260q-41 0 -75 14t-56.5 34t-42.5 40.5t-41.5 34.5t-44.5 14q-82 0 -82 -131h-148 z" />
|
||||
<glyph unicode="ò" horiz-adv-x="1282" d="M82 520q0 115 44 216t119.5 172t178 112t217.5 41t217.5 -41t178 -112t119.5 -172t44 -216q0 -154 -75 -279.5t-203 -195.5t-281 -70t-281 70t-203 195.5t-75 279.5zM285 520q0 -161 103 -267t253 -106q148 0 252 106t104 267q0 159 -104 264t-252 105q-150 0 -253 -105 t-103 -264zM322 1446h229l211 -260h-187z" />
|
||||
<glyph unicode="ó" horiz-adv-x="1282" d="M82 520q0 115 44 216t119.5 172t178 112t217.5 41t217.5 -41t178 -112t119.5 -172t44 -216q0 -154 -75 -279.5t-203 -195.5t-281 -70t-281 70t-203 195.5t-75 279.5zM285 520q0 -161 103 -267t253 -106q148 0 252 106t104 267q0 159 -104 264t-252 105q-150 0 -253 -105 t-103 -264zM518 1186l213 260h227l-253 -260h-187z" />
|
||||
<glyph unicode="ô" horiz-adv-x="1282" d="M82 520q0 115 44 216t119.5 172t178 112t217.5 41t217.5 -41t178 -112t119.5 -172t44 -216q0 -154 -75 -279.5t-203 -195.5t-281 -70t-281 70t-203 195.5t-75 279.5zM285 520q0 -161 103 -267t253 -106q148 0 252 106t104 267q0 159 -104 264t-252 105q-150 0 -253 -105 t-103 -264zM354 1186l181 260h215l180 -260h-178l-109 164h-4l-107 -164h-178z" />
|
||||
<glyph unicode="õ" horiz-adv-x="1282" d="M82 520q0 115 44 216t119.5 172t178 112t217.5 41t217.5 -41t178 -112t119.5 -172t44 -216q0 -154 -75 -279.5t-203 -195.5t-281 -70t-281 70t-203 195.5t-75 279.5zM285 520q0 -161 103 -267t253 -106q148 0 252 106t104 267q0 159 -104 264t-252 105q-150 0 -253 -105 t-103 -264zM293 1188q0 260 209 260q41 0 75 -14t56.5 -34t42.5 -40.5t41.5 -34.5t44.5 -14q45 0 63.5 38.5t18.5 92.5h147q0 -260 -209 -260q-41 0 -75 14t-56.5 34t-42.5 40.5t-41.5 34.5t-44.5 14q-82 0 -82 -131h-147z" />
|
||||
<glyph unicode="ö" horiz-adv-x="1282" d="M82 520q0 115 44 216t119.5 172t178 112t217.5 41t217.5 -41t178 -112t119.5 -172t44 -216q0 -154 -75 -279.5t-203 -195.5t-281 -70t-281 70t-203 195.5t-75 279.5zM285 520q0 -161 103 -267t253 -106q148 0 252 106t104 267q0 159 -104 264t-252 105q-150 0 -253 -105 t-103 -264zM348 1239v207h176v-207h-176zM758 1239v207h176v-207h-176z" />
|
||||
<glyph unicode="÷" horiz-adv-x="1255" d="M111 504v160h1034v-160h-1034zM530 90v186h193v-186h-193zM530 891v186h193v-186h-193z" />
|
||||
<glyph unicode="ø" horiz-adv-x="1282" d="M84 520q0 153 74.5 277.5t202 194t280.5 69.5q150 0 281 -72l82 113l88 -62l-80 -110q87 -74 137.5 -181t50.5 -229q0 -154 -75 -279.5t-203 -195.5t-281 -70q-140 0 -266 66l-80 -115l-88 64l76 108q-93 73 -146 183.5t-53 238.5zM285 520q0 -151 110 -266l422 588 q-89 47 -176 47q-148 0 -252 -105t-104 -264zM481 188q77 -41 160 -41q150 0 253 106t103 267q0 144 -98 252z" />
|
||||
<glyph unicode="ù" horiz-adv-x="1361" d="M41 883v153h373v-622q0 -47 4 -82.5t16.5 -70t33.5 -56.5t56.5 -35.5t83.5 -13.5q100 0 178 58.5t118 149.5t40 195v324h-174v153h373v-839q0 -45 45 -45h108v-152h-215q-131 0 -131 115v45l4 61h-4q-7 -20 -23.5 -47t-50.5 -63t-76 -65.5t-107 -50t-138 -20.5 q-169 0 -254.5 97.5t-85.5 300.5v510h-174zM334 1446h229l211 -260h-186z" />
|
||||
<glyph unicode="ú" horiz-adv-x="1361" d="M41 883v153h373v-622q0 -47 4 -82.5t16.5 -70t33.5 -56.5t56.5 -35.5t83.5 -13.5q100 0 178 58.5t118 149.5t40 195v324h-174v153h373v-839q0 -45 45 -45h108v-152h-215q-131 0 -131 115v45l4 61h-4q-7 -20 -23.5 -47t-50.5 -63t-76 -65.5t-107 -50t-138 -20.5 q-169 0 -254.5 97.5t-85.5 300.5v510h-174zM530 1186l213 260h228l-254 -260h-187z" />
|
||||
<glyph unicode="û" horiz-adv-x="1361" d="M41 883v153h373v-622q0 -47 4 -82.5t16.5 -70t33.5 -56.5t56.5 -35.5t83.5 -13.5q100 0 178 58.5t118 149.5t40 195v324h-174v153h373v-839q0 -45 45 -45h108v-152h-215q-131 0 -131 115v45l4 61h-4q-7 -20 -23.5 -47t-50.5 -63t-76 -65.5t-107 -50t-138 -20.5 q-169 0 -254.5 97.5t-85.5 300.5v510h-174zM365 1186l180 260h215l180 -260h-178l-109 164h-4l-106 -164h-178z" />
|
||||
<glyph unicode="ü" horiz-adv-x="1361" d="M41 883v153h373v-622q0 -47 4 -82.5t16.5 -70t33.5 -56.5t56.5 -35.5t83.5 -13.5q100 0 178 58.5t118 149.5t40 195v324h-174v153h373v-839q0 -45 45 -45h108v-152h-215q-131 0 -131 115v45l4 61h-4q-7 -20 -23.5 -47t-50.5 -63t-76 -65.5t-107 -50t-138 -20.5 q-169 0 -254.5 97.5t-85.5 300.5v510h-174zM360 1239v207h177v-207h-177zM770 1239v207h176v-207h-176z" />
|
||||
<glyph unicode="ý" horiz-adv-x="1208" d="M18 883v153h474v-153h-138l232 -617q6 -20 10.5 -42.5t5.5 -35.5l2 -12h6q9 45 25 90l229 617h-133v153h459v-153h-129l-410 -1047q-52 -130 -147 -198t-217 -68q-59 0 -115 16t-82 32l-27 17l68 150q7 -5 19.5 -13.5t51 -22t77.5 -13.5q64 0 113 39.5t77 103.5l43 103 l-362 901h-132zM492 1186l213 260h227l-254 -260h-186z" />
|
||||
<glyph unicode="þ" horiz-adv-x="1245" d="M6 1292v154h367v-475l-4 -86h4q3 7 10 19t34 42.5t60.5 53.5t93.5 42t129 19q208 0 333.5 -152t125.5 -391t-130 -391t-335 -152q-67 0 -125 18t-92.5 43.5t-59 51.5t-34.5 44l-10 18h-4q4 -38 4 -91v-315h162v-154h-525v154h164v1548h-168zM367 516q0 -163 80.5 -266 t216.5 -103q128 0 211 103t83 268t-80 268t-210 103q-131 0 -216 -92t-85 -281z" />
|
||||
<glyph unicode="ÿ" horiz-adv-x="1208" d="M18 883v153h474v-153h-138l232 -617q6 -20 10.5 -42.5t5.5 -35.5l2 -12h6q9 45 25 90l229 617h-133v153h459v-153h-129l-410 -1047q-52 -130 -147 -198t-217 -68q-59 0 -115 16t-82 32l-27 17l68 150q7 -5 19.5 -13.5t51 -22t77.5 -13.5q64 0 113 39.5t77 103.5l43 103 l-362 901h-132zM322 1239v207h176v-207h-176zM731 1239v207h176v-207h-176z" />
|
||||
<glyph unicode="Œ" horiz-adv-x="1994" d="M100 725q0 205 97.5 374.5t269.5 267t383 97.5q52 0 134.5 -9t115.5 -9h755v-336h-169v168h-486v-467h506v-166h-506v-477h520v170h170v-338h-788q-33 0 -116.5 -9t-135.5 -9q-210 0 -382.5 98t-270 268.5t-97.5 376.5zM309 725q0 -160 68 -290t192.5 -205.5t280.5 -75.5 q36 0 72.5 4t54.5 8l18 4v1108q-63 14 -145 14q-156 0 -280.5 -75.5t-192.5 -204.5t-68 -287z" />
|
||||
<glyph unicode="œ" horiz-adv-x="2048" d="M82 516q0 160 75 285.5t200 192.5t276 67t265.5 -65t184.5 -181h4q63 118 171 182t255 64q142 0 245.5 -66.5t153.5 -175t50 -244.5l-6 -77h-756q12 -167 113 -261t243 -94q50 0 100 12.5t86 29.5t64.5 34.5t43.5 30.5l14 12l82 -139q-6 -6 -18 -16t-52.5 -35.5t-84 -45 t-111 -35.5t-136.5 -16q-157 0 -272 67t-180 185h-5q-70 -119 -184.5 -185.5t-267.5 -66.5q-152 0 -277.5 66t-200.5 190.5t-75 284.5zM285 516q0 -165 102.5 -267t251.5 -102t252.5 103.5t103.5 271.5q0 163 -104.5 265t-251.5 102q-148 0 -251 -104t-103 -269zM1206 627 h553q-4 128 -74.5 202t-173.5 74q-117 0 -200.5 -73.5t-104.5 -202.5z" />
|
||||
<glyph unicode="Ÿ" horiz-adv-x="1331" d="M20 1288v158h498v-158h-151l268 -454l29 -62h4q12 31 30 62l269 454h-150v158h494v-158h-137l-406 -676v-452h182v-160h-569v160h182v452l-405 676h-138zM375 1599v207h176v-207h-176zM784 1599v207h177v-207h-177z" />
|
||||
<glyph unicode="ˆ" horiz-adv-x="1021" d="M223 1546l180 260h215l181 -260h-178l-109 164h-4l-107 -164h-178z" />
|
||||
<glyph unicode="˜" horiz-adv-x="1021" d="M162 1548q0 260 209 260q41 0 75 -14t56.5 -34t42.5 -40.5t41.5 -34.5t44.5 -14q45 0 63.5 38.5t18.5 92.5h147q0 -260 -209 -260q-41 0 -75 14t-56.5 34t-42.5 40.5t-41.5 34.5t-44.5 14q-82 0 -82 -131h-147z" />
|
||||
<glyph unicode="–" horiz-adv-x="1462" d="M193 504v160h1077v-160h-1077z" />
|
||||
<glyph unicode="—" horiz-adv-x="1871" d="M193 504v160h1486v-160h-1486z" />
|
||||
<glyph unicode="‘" horiz-adv-x="468" d="M96 1022l146 446h147l-100 -446h-193z" />
|
||||
<glyph unicode="’" horiz-adv-x="456" d="M102 1022l101 446h192l-145 -446h-148z" />
|
||||
<glyph unicode="‚" horiz-adv-x="503" d="M74 -231l100 446h188l-145 -446h-143z" />
|
||||
<glyph unicode="“" horiz-adv-x="772" d="M96 1022l146 446h147l-98 -446h-195zM397 1022l146 446h147l-98 -446h-195z" />
|
||||
<glyph unicode="”" horiz-adv-x="757" d="M102 1022l101 446h192l-145 -446h-148zM403 1022l101 446h192l-145 -446h-148z" />
|
||||
<glyph unicode="„" horiz-adv-x="798" d="M74 -231l100 446h188l-145 -446h-143zM371 -231l100 446h186l-145 -446h-141z" />
|
||||
<glyph unicode="•" horiz-adv-x="845" d="M106 596q0 132 92.5 224.5t223.5 92.5q132 0 224.5 -92.5t92.5 -224.5t-92.5 -224.5t-224.5 -92.5q-131 0 -223.5 92.5t-92.5 224.5z" />
|
||||
<glyph unicode="…" horiz-adv-x="1581" d="M156 0v215h206v-215h-206zM686 0v215h209v-215h-209zM1219 0v215h206v-215h-206z" />
|
||||
<glyph unicode="‹" horiz-adv-x="735" d="M88 578l336 421h199l-336 -421l336 -420h-199z" />
|
||||
<glyph unicode="›" horiz-adv-x="735" d="M113 158l336 420l-336 421h198l336 -421l-336 -420h-198z" />
|
||||
<glyph unicode="€" horiz-adv-x="1226" d="M90 512v125h113q-11 85 0 188h-113v127h135q64 228 252.5 373t437.5 145q50 0 102 -6t79 -12l26 -6l-47 -176q-80 20 -164 20q-169 0 -294 -92t-177 -246h574l-27 -127h-575q-10 -79 0 -188h542l-26 -125h-482q48 -159 175.5 -256.5t296.5 -97.5q46 0 93 7t71 14l24 7 l39 -176q-101 -35 -230 -35q-258 0 -445 149.5t-247 387.5h-133z" />
|
||||
<glyph unicode="™" horiz-adv-x="1953" d="M57 1309v137h781v-137h-314v-764h-153v764h-314zM901 545l72 901h143l213 -471q7 -16 14 -37.5t10 -35.5l3 -13h4q13 49 29 86l213 471h143l70 -901h-156l-41 538l2 62h-4l-195 -434h-125l-194 434h-4l2 -62l-43 -538h-156z" />
|
||||
<glyph unicode="" horiz-adv-x="1034" d="M0 0v1034h1034v-1034h-1034z" />
|
||||
</font>
|
||||
</defs></svg>
|
After Width: | Height: | Size: 62 KiB |
BIN
public/fonts/museo-slab-500.ttf
Normal file
BIN
public/fonts/museo-slab-500.woff
Normal file
BIN
public/img/hires/1.jpg
Normal file
After Width: | Height: | Size: 166 KiB |
BIN
public/img/hires/2.jpg
Normal file
After Width: | Height: | Size: 275 KiB |
BIN
public/img/noisy.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
public/img/tweed.png
Normal file
After Width: | Height: | Size: 21 KiB |
10
public/index.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="css/app.bundle.css">
|
||||
</head>
|
||||
<body>
|
||||
<script src="js/app.bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
18
public/js/app.bundle.min.js
vendored
Normal file
26
src/app.coffee
Normal file
@ -0,0 +1,26 @@
|
||||
Ractive = require 'ractive'
|
||||
|
||||
# Load Ractive transitions and adapters.
|
||||
require 'ractive-transitions-fade'
|
||||
require 'ractive-ractive'
|
||||
|
||||
# Lodash mixins.
|
||||
require './utils/mixins.coffee'
|
||||
# Will load projects from localStorage.
|
||||
require './models/projects.coffee'
|
||||
|
||||
Header = require './views/header.coffee'
|
||||
Notify = require './views/notify.coffee'
|
||||
router = require './modules/router.coffee'
|
||||
|
||||
new Ractive
|
||||
|
||||
'template': require './templates/app.html'
|
||||
|
||||
'el': 'body'
|
||||
|
||||
'components': { Header, Notify }
|
||||
|
||||
onrender: ->
|
||||
# Start the router.
|
||||
router.init '/'
|
35
src/models/config.coffee
Normal file
@ -0,0 +1,35 @@
|
||||
Model = require '../utils/ractive/model.coffee'
|
||||
|
||||
module.exports = new Model
|
||||
|
||||
'name': 'models/config'
|
||||
|
||||
"data":
|
||||
# Firebase app name.
|
||||
"firebase": "burnchart"
|
||||
# Data source provider.
|
||||
"provider": "github"
|
||||
# Fields to keep from GH responses.
|
||||
"fields":
|
||||
"milestone": [
|
||||
"closed_issues"
|
||||
"created_at"
|
||||
"description"
|
||||
"due_on"
|
||||
"number"
|
||||
"open_issues"
|
||||
"title"
|
||||
"updated_at"
|
||||
]
|
||||
# Chart configuration.
|
||||
"chart":
|
||||
# Days we are not working. Mon = 1
|
||||
"off_days": [ ]
|
||||
# How do we parse GitHub dates?
|
||||
"datetime": /^(\d{4}-\d{2}-\d{2})T(.*)/
|
||||
# How does a size label look like?
|
||||
"size_label": /^size (\d+)$/
|
||||
# How do we specify which user/repo/(milestone) we want?
|
||||
"location": /^#!((\/[^\/]+){2,3})$/
|
||||
# Process all issues as one size (ONE_SIZE) or use labels (LABELS).
|
||||
"points": 'ONE_SIZE'
|
42
src/models/firebase.coffee
Normal file
@ -0,0 +1,42 @@
|
||||
Firebase = require 'firebase'
|
||||
|
||||
Model = require '../utils/ractive/model.coffee'
|
||||
user = require './user.coffee'
|
||||
config = require './config.coffee'
|
||||
|
||||
module.exports = new Model
|
||||
|
||||
'name': 'models/firebase'
|
||||
|
||||
# Login a user.
|
||||
login: (cb) ->
|
||||
cb 'Not ready yet' unless @data.client
|
||||
|
||||
@data.client.authWithOAuthPopup "github", (err, authData) =>
|
||||
return @publish '!app/notify', {
|
||||
'text': do err.toString
|
||||
'type': 'alert'
|
||||
'system': yes
|
||||
} if err
|
||||
|
||||
@onAuth authData
|
||||
,
|
||||
'rememberMe': yes
|
||||
'scope': 'private_repo'
|
||||
|
||||
onAuth: (authData) ->
|
||||
# Save user.
|
||||
user.set authData
|
||||
# Say we are done.
|
||||
user.set 'ready', yes
|
||||
|
||||
# Logout a user.
|
||||
logout: ->
|
||||
throw 'Implement'
|
||||
|
||||
onrender: ->
|
||||
# Setup a new client.
|
||||
@set 'client', client = new Firebase "https://#{config.data.firebase}.firebaseio.com"
|
||||
|
||||
# When user is authenticated.
|
||||
client.onAuth @onAuth
|
172
src/models/projects.coffee
Normal file
@ -0,0 +1,172 @@
|
||||
_ = require 'lodash'
|
||||
lscache = require 'lscache'
|
||||
sortedIndex = require 'sortedindex-compare'
|
||||
semver = require 'semver'
|
||||
|
||||
Model = require '../utils/ractive/model.coffee'
|
||||
config = require '../models/config.coffee'
|
||||
stats = require '../modules/stats.coffee'
|
||||
date = require '../utils/date.coffee'
|
||||
user = require './user.coffee'
|
||||
|
||||
module.exports = new Model
|
||||
|
||||
'name': 'models/projects'
|
||||
|
||||
'data':
|
||||
# Current sort order.
|
||||
'sortBy': 'priority'
|
||||
# Sort functions.
|
||||
'sortFns': [ 'progress', 'priority', 'name' ]
|
||||
|
||||
# Return a sort order comparator.
|
||||
comparator: ->
|
||||
{ list, sortBy } = @data
|
||||
|
||||
# Convert existing index into actual project milestone.
|
||||
deIdx = (fn) =>
|
||||
([ i, j ], rest...) =>
|
||||
fn.apply @, [ [ list[i], list[i].milestones[j] ] ].concat rest
|
||||
|
||||
# Set default fields, in place.
|
||||
defaults = (arr, hash) ->
|
||||
for item in arr
|
||||
for k, v of hash
|
||||
ref = item
|
||||
for p, i in keys = k.split '.'
|
||||
if i is keys.length - 1
|
||||
ref[p] ?= v
|
||||
else
|
||||
ref = ref[p] ?= {}
|
||||
|
||||
# The actual fn selection.
|
||||
switch sortBy
|
||||
# From highest progress points.
|
||||
when 'progress' then deIdx ([ aP, aM ], [ bP, bM ]) ->
|
||||
defaults [ aM, bM ], { 'stats.progress.points': 0 }
|
||||
# Simple points difference.
|
||||
aM.stats.progress.points - bM.stats.progress.points
|
||||
|
||||
# From most delayed in days.
|
||||
when 'priority' then deIdx ([ aP, aM ], [ bP, bM ]) ->
|
||||
# Milestones with no deadline are always at the "beginning".
|
||||
defaults [ aM, bM ], { 'stats.progress.time': 0, 'stats.days': 1e3 }
|
||||
# % difference in progress times the number of days ahead or behind.
|
||||
[ $a, $b ] = _.map [ aM, bM ], ({ stats }) ->
|
||||
(stats.progress.points - stats.progress.time) * stats.days
|
||||
|
||||
$b - $a
|
||||
|
||||
# Based on project then milestone name including semver.
|
||||
when 'name' then deIdx ([ aP, aM ], [ bP, bM ]) ->
|
||||
return owner if owner = bP.owner.localeCompare aP.owner
|
||||
return name if name = bP.name.localeCompare aP.name
|
||||
# Try semver.
|
||||
if semver.valid(bM.title) and semver.valid(aM.title)
|
||||
semver.gt bM.title, aM.title
|
||||
# Back to string compare.
|
||||
else
|
||||
bM.title.localeCompare aM.title
|
||||
|
||||
# The "whatever" sort order...
|
||||
else -> 0
|
||||
|
||||
find: (project) ->
|
||||
_.find @data.list, project
|
||||
|
||||
exists: ->
|
||||
!!@find.apply @, arguments
|
||||
|
||||
# Push to the stack unless it exists already.
|
||||
add: (project) ->
|
||||
@push 'list', project unless @exists project
|
||||
|
||||
# Find index of a project.
|
||||
findIndex: ({ owner, name }) ->
|
||||
_.findIndex @data.list, { owner, name }
|
||||
|
||||
# Add a milestone for a project.
|
||||
addMilestone: (project, milestone) ->
|
||||
# Add in the stats.
|
||||
_.extend milestone, { 'stats': stats(milestone) }
|
||||
# We are supposed to exist already.
|
||||
throw 500 if (i = @findIndex(project)) < 0
|
||||
|
||||
# Have milestones already?
|
||||
if project.milestones?
|
||||
@push "list.#{i}.milestones", milestone
|
||||
j = @data.list[i].milestones.length - 1 # index in milestones
|
||||
else
|
||||
@set "list.#{i}.milestones", [ milestone ]
|
||||
j = 0 # index in milestones
|
||||
|
||||
# Now index this milestone.
|
||||
@sort [ i, j ], [ project, milestone ]
|
||||
|
||||
# Save an error from loading milestones or issues
|
||||
saveError: (project, err) ->
|
||||
if (idx = @findIndex(project)) > -1
|
||||
if project.errors?
|
||||
@push "list.#{idx}.errors", err
|
||||
else
|
||||
@set "list.#{idx}.errors", [ err ]
|
||||
else
|
||||
# We are supposed to exist already.
|
||||
throw 500
|
||||
|
||||
demo: ->
|
||||
@set 'list': [
|
||||
{ 'owner': 'mbostock', 'name': 'd3' }
|
||||
{ 'owner': 'medic', 'name': 'medic-webapp' }
|
||||
{ 'owner': 'ractivejs', 'name': 'ractive' }
|
||||
{ 'owner': 'radekstepan', 'name': 'disposable' }
|
||||
{ 'owner': 'rails', 'name': 'rails' }
|
||||
{ 'owner': 'rails', 'name': 'spring' }
|
||||
], 'index': []
|
||||
|
||||
clear: ->
|
||||
@set 'list': [], 'index': []
|
||||
|
||||
# Sort/or insert into an already sorted index.
|
||||
sort: (ref, data) ->
|
||||
# Get or initialize the index.
|
||||
index = @data.index or []
|
||||
|
||||
# Do one.
|
||||
if ref
|
||||
idx = sortedIndex index, data, do @comparator
|
||||
index.splice idx, 0, ref
|
||||
# Do all.
|
||||
else
|
||||
for p, i in @data.list
|
||||
# TODO: need to show projects that failed too...
|
||||
continue unless p.milestones?
|
||||
for m, j in p.milestones
|
||||
# Run a comparator here inserting into index.
|
||||
idx = sortedIndex index, [ p, m ], do @comparator
|
||||
# Log.
|
||||
index.splice idx, 0, [ i, j ]
|
||||
|
||||
# Save the index.
|
||||
@set 'index', index
|
||||
|
||||
onconstruct: ->
|
||||
@subscribe '!projects/add', @add, @
|
||||
@subscribe '!projects/demo', @demo, @
|
||||
|
||||
onrender: ->
|
||||
# Init the projects.
|
||||
@set 'list', lscache.get('projects') or []
|
||||
|
||||
# Persist projects in local storage (sans milestones).
|
||||
@observe 'list', (projects) ->
|
||||
lscache.set 'projects', _.pluckMany projects, [ 'owner', 'name' ]
|
||||
, 'init': no
|
||||
|
||||
# Reset our index and re-sort.
|
||||
@observe 'sortBy', ->
|
||||
# Use pop as Ractive is glitchy when resetting arrays.
|
||||
@set 'index', null
|
||||
# Run the sort again.
|
||||
do @sort
|
||||
, 'init': no
|
19
src/models/system.coffee
Normal file
@ -0,0 +1,19 @@
|
||||
Model = require '../utils/ractive/model.coffee'
|
||||
|
||||
# System state.
|
||||
system = new Model
|
||||
|
||||
'name': 'models/system'
|
||||
|
||||
'data':
|
||||
'loading': no
|
||||
|
||||
counter = 0
|
||||
async = ->
|
||||
counter += 1
|
||||
system.set 'loading', yes
|
||||
->
|
||||
counter -= 1
|
||||
system.set 'loading', +counter
|
||||
|
||||
module.exports = { system, async }
|
6
src/models/user.coffee
Normal file
@ -0,0 +1,6 @@
|
||||
Model = require '../utils/ractive/model.coffee'
|
||||
|
||||
# Currently logged-in user.
|
||||
module.exports = new Model
|
||||
|
||||
'name': 'models/user'
|
20
src/modules/chart/axes.coffee
Normal file
@ -0,0 +1,20 @@
|
||||
d3 = require 'd3'
|
||||
|
||||
module.exports =
|
||||
|
||||
horizontal: (height, x) ->
|
||||
d3.svg.axis().scale(x)
|
||||
.orient("bottom")
|
||||
# Show vertical lines...
|
||||
.tickSize(-height)
|
||||
# ...with day of the month...
|
||||
.tickFormat( (d) -> d.getDate() )
|
||||
# ...and give us a spacer.
|
||||
.tickPadding(10)
|
||||
|
||||
vertical: (width, y) ->
|
||||
d3.svg.axis().scale(y)
|
||||
.orient("left")
|
||||
.tickSize(-width)
|
||||
.ticks(5)
|
||||
.tickPadding(10)
|
134
src/modules/chart/lines.coffee
Normal file
@ -0,0 +1,134 @@
|
||||
_ = require 'lodash'
|
||||
d3 = require 'd3'
|
||||
|
||||
config = require '../../models/config.coffee'
|
||||
|
||||
module.exports =
|
||||
|
||||
# A graph of closed issues.
|
||||
# `issues`: issues list
|
||||
# `created_at`: milestone start date
|
||||
# `total`: total number of points (open & closed issues)
|
||||
actual: (issues, created_at, total) ->
|
||||
head = [ {
|
||||
'date': new Date created_at
|
||||
'points': total
|
||||
} ]
|
||||
|
||||
min = +Infinity ; max = -Infinity
|
||||
|
||||
# Generate the actual closes.
|
||||
rest = _.map issues, (issue) ->
|
||||
{ size, closed_at } = issue
|
||||
# Determine the range.
|
||||
min = size if size < min
|
||||
max = size if size > max
|
||||
|
||||
# Dropping points remaining.
|
||||
issue.date = new Date closed_at
|
||||
issue.points = total -= size
|
||||
issue
|
||||
|
||||
# Now add a radius in a range (will be used for a circle).
|
||||
range = d3.scale.linear().domain([ min, max ]).range([ 5, 8 ])
|
||||
|
||||
rest = _.map rest, (issue) ->
|
||||
issue.radius = range issue.size
|
||||
issue
|
||||
|
||||
[].concat head, rest
|
||||
|
||||
# A graph of an ideal progression..
|
||||
# `a`: milestone start date
|
||||
# `b`: milestone end date
|
||||
# `total`: total number of points (open & closed issues)
|
||||
ideal: (a, b, total) ->
|
||||
# Swap?
|
||||
[ b, a ] = [ a, b ] if b < a
|
||||
|
||||
# We start here adding days to `d`.
|
||||
[ y, m, d ] = _.map a.match(config.data.chart.datetime)[1].split('-'), (v) -> parseInt v
|
||||
# We want to end here.
|
||||
cutoff = new Date(b)
|
||||
|
||||
# Go through the beginning to the end skipping off days.
|
||||
days = [] ; length = 0
|
||||
do once = (inc = 0) ->
|
||||
# A new day.
|
||||
day = new Date y, m - 1, d + inc
|
||||
|
||||
# Does this day count?
|
||||
day_of = 7 if !day_of = day.getDay()
|
||||
if day_of in config.data.chart.off_days
|
||||
days.push { date: day, off_day: yes }
|
||||
else
|
||||
length += 1
|
||||
days.push { date: day }
|
||||
|
||||
# Go again?
|
||||
once(inc + 1) unless day > cutoff
|
||||
|
||||
# Map points on the array of days now.
|
||||
velocity = total / (length - 1)
|
||||
|
||||
days = _.map days, (day, i) ->
|
||||
day.points = total
|
||||
total -= velocity if days[i] and not days[i].off_day
|
||||
day
|
||||
|
||||
# Do we need to make a link to right now?
|
||||
days.push { date: now, points: 0 } if (now = new Date) > cutoff
|
||||
|
||||
days
|
||||
|
||||
# Graph representing a trendling of actual issues.
|
||||
trend: (actual, created_at, due_on) ->
|
||||
return [] unless actual.length
|
||||
|
||||
start = +actual[0].date
|
||||
|
||||
# Values is a list of time from the start and points remaining.
|
||||
values = _.map actual, ({ date, points }) ->
|
||||
[ +date - start, points ]
|
||||
|
||||
# Now is an actual point too.
|
||||
last = actual[actual.length - 1]
|
||||
values.push [ + new Date - start, last.points ]
|
||||
|
||||
# http://classroom.synonym.com/calculate-trendline-2709.html
|
||||
b1 = 0 ; e = 0 ; c1 = 0
|
||||
a = (l = values.length) * _.reduce(values, (sum, [ a, b ]) ->
|
||||
b1 += a ; e += b
|
||||
c1 += Math.pow(a, 2)
|
||||
sum + (a * b)
|
||||
, 0)
|
||||
|
||||
slope = (a - (b1 * e)) / ((l * c1) - (Math.pow(b1, 2)))
|
||||
intercept = (e - (slope * b1)) / l
|
||||
fn = (x) -> slope * x + intercept
|
||||
|
||||
# Milestone always has a creation date.
|
||||
created_at = new Date created_at
|
||||
|
||||
now = new Date
|
||||
# Due date specified.
|
||||
if due_on
|
||||
due_on = new Date due_on
|
||||
# In the past?
|
||||
due_on = now if now > due_on
|
||||
# No due date
|
||||
else
|
||||
due_on = now
|
||||
|
||||
a = created_at - start
|
||||
b = due_on - start
|
||||
|
||||
[
|
||||
{
|
||||
'date': created_at
|
||||
'points': fn(a)
|
||||
}, {
|
||||
'date': due_on
|
||||
'points': fn(b)
|
||||
}
|
||||
]
|
69
src/modules/github/issues.coffee
Normal file
@ -0,0 +1,69 @@
|
||||
_ = require 'lodash'
|
||||
async = require 'async'
|
||||
|
||||
config = require '../../models/config.coffee'
|
||||
request = require './request.coffee'
|
||||
|
||||
module.exports =
|
||||
|
||||
# Fetch issues for a milestone.
|
||||
fetchAll: (repo, cb) ->
|
||||
# Calculate size of either open or closed issues.
|
||||
# Modifies issues by ref.
|
||||
calcSize = (list, cb) ->
|
||||
switch config.data.chart.points
|
||||
when 'ONE_SIZE'
|
||||
size = list.length
|
||||
|
||||
( issue.size = 1 for issue in list )
|
||||
|
||||
cb null, { list, size }
|
||||
|
||||
when 'LABELS'
|
||||
size = 0
|
||||
|
||||
list = _.filter list, (issue) ->
|
||||
# Skip if no labels exist.
|
||||
return no unless labels = issue.labels
|
||||
|
||||
# Determine the total issue size from all labels.
|
||||
issue.size = _.reduce labels, (sum, label) ->
|
||||
# Not matching.
|
||||
return sum unless matches = label.name.match config.data.chart.size_label
|
||||
# Increase sum.
|
||||
sum += parseInt matches[1]
|
||||
, 0
|
||||
|
||||
# Increase the total.
|
||||
size += issue.size
|
||||
|
||||
# Are we saving it?
|
||||
!!issue.size
|
||||
|
||||
cb null, { list, size }
|
||||
|
||||
# For each state...
|
||||
oneStatus = (state, cb) ->
|
||||
# Concat them here.
|
||||
results = []
|
||||
|
||||
# One pageful fetch (next pages in series).
|
||||
do fetchPage = (page=1) ->
|
||||
request.allIssues repo, { state, page }, (err, data) ->
|
||||
# Errors?
|
||||
return cb err if err
|
||||
# Empty?
|
||||
return cb null, results unless data.length
|
||||
# Concat sorted (api does not sort on closed_at!).
|
||||
results = results.concat _.sortBy data, 'closed_at'
|
||||
# < 100 results?
|
||||
return cb null, results if data.length < 100
|
||||
# Fetch the next page then.
|
||||
fetchPage page + 1
|
||||
|
||||
# For each `open` and `closed` issues in parallel.
|
||||
async.parallel [
|
||||
_.partial async.waterfall, [ _.partial(oneStatus, 'open'), calcSize ]
|
||||
_.partial async.waterfall, [ _.partial(oneStatus, 'closed'), calcSize ]
|
||||
], (err, [ open, closed ]) ->
|
||||
cb err, { open, closed }
|
28
src/modules/github/milestones.coffee
Normal file
@ -0,0 +1,28 @@
|
||||
request = require './request.coffee'
|
||||
|
||||
module.exports =
|
||||
|
||||
# Fetch a milestone.
|
||||
'fetch': request.oneMilestone
|
||||
|
||||
# Fetch all milestones.
|
||||
'fetchAll': request.allMilestones
|
||||
|
||||
# # Get the current milestone out of many.
|
||||
# else
|
||||
# request.allMilestones repo, (err, data) ->
|
||||
# # Errors?
|
||||
# return cb err if err
|
||||
# # Empty warning?
|
||||
# return cb null, "No open milestones for repo #{repo.path}" unless data.length
|
||||
# # The first milestone should be ending soonest.
|
||||
# m = data[0]
|
||||
# # Filter milestones without due date.
|
||||
# m = _.rest data, { 'due_on' : null }
|
||||
# # The first milestone should be ending soonest. Prefer milestones with due dates.
|
||||
# m = if m[0] then m[0] else data[0]
|
||||
# # Empty milestone?
|
||||
# if m.open_issues + m.closed_issues is 0
|
||||
# return cb null, "No issues for milestone `#{m.title}`"
|
||||
|
||||
# cb null, null, m
|
164
src/modules/github/request.coffee
Normal file
@ -0,0 +1,164 @@
|
||||
_ = require 'lodash'
|
||||
superagent = require 'superagent'
|
||||
|
||||
user = require '../../models/user.coffee'
|
||||
|
||||
# Custom JSON parser.
|
||||
superagent.parse =
|
||||
'application/json': (res) ->
|
||||
try
|
||||
JSON.parse res
|
||||
catch e
|
||||
{} # it was not to be...
|
||||
|
||||
# Default args.
|
||||
defaults =
|
||||
'github':
|
||||
'host': 'api.github.com'
|
||||
'protocol': 'https'
|
||||
|
||||
# Public api.
|
||||
module.exports =
|
||||
|
||||
# Get a repo.
|
||||
repo: ({ owner, name }, cb) ->
|
||||
return cb 'Request is malformed' unless isValid { owner, name }
|
||||
|
||||
ready ->
|
||||
data = _.defaults
|
||||
'path': "/repos/#{owner}/#{name}"
|
||||
'headers': headers user.data.accessToken
|
||||
, defaults.github
|
||||
|
||||
request data, cb
|
||||
|
||||
# Get all open milestones.
|
||||
allMilestones: ({ owner, name }, cb) ->
|
||||
return cb 'Request is malformed' unless isValid { owner, name }
|
||||
|
||||
ready ->
|
||||
data = _.defaults
|
||||
'path': "/repos/#{owner}/#{name}/milestones"
|
||||
'query': { 'state': 'open', 'sort': 'due_date', 'direction': 'asc' }
|
||||
'headers': headers user.data.accessToken
|
||||
, defaults.github
|
||||
|
||||
request data, cb
|
||||
|
||||
# Get one open milestone.
|
||||
oneMilestone: ({ owner, name, milestone }, cb) ->
|
||||
return cb 'Request is malformed' unless isValid { owner, name, milestone }
|
||||
|
||||
ready ->
|
||||
data = _.defaults
|
||||
'path': "/repos/#{owner}/#{name}/milestones/#{milestone}"
|
||||
'query': { 'state': 'open', 'sort': 'due_date', 'direction': 'asc' }
|
||||
'headers': headers user.data.accessToken
|
||||
, defaults.github
|
||||
|
||||
request data, cb
|
||||
|
||||
# Get all issues for a state.
|
||||
allIssues: ({ owner, name, milestone }, query, cb) ->
|
||||
return cb 'Request is malformed' unless isValid { owner, name, milestone }
|
||||
|
||||
ready ->
|
||||
data = _.defaults
|
||||
'path': "/repos/#{owner}/#{name}/issues"
|
||||
'query': _.extend query, { milestone, 'per_page': '100' }
|
||||
'headers': headers user.data.accessToken
|
||||
, defaults.github
|
||||
|
||||
request data, cb
|
||||
|
||||
# Make a request using SuperAgent.
|
||||
request = ({ protocol, host, path, query, headers }, cb) ->
|
||||
exited = no
|
||||
|
||||
# Make the query params.
|
||||
q = if query then '?' + ( "#{k}=#{v}" for k, v of query ).join('&') else ''
|
||||
|
||||
# The URI.
|
||||
req = superagent.get("#{protocol}://#{host}#{path}#{q}")
|
||||
# Add headers.
|
||||
( req.set(k, v) for k, v of headers )
|
||||
|
||||
# Timeout for requests that do not finish... see #32.
|
||||
timeout = setTimeout ->
|
||||
exited = yes
|
||||
cb 'Request has timed out'
|
||||
, 1e4 # give us 10s
|
||||
|
||||
# Send.
|
||||
req.end (err, data) ->
|
||||
# Arrived too late.
|
||||
return if exited
|
||||
# All fine.
|
||||
exited = yes
|
||||
clearTimeout timeout
|
||||
# Actually process the response.
|
||||
response err, data, cb
|
||||
|
||||
# How do we respond to a response?
|
||||
response = (err, data, cb) ->
|
||||
return cb error err if err
|
||||
# 2xx?
|
||||
if data.statusType isnt 2
|
||||
# Do we have a message from GitHub?
|
||||
return cb data.body.message if data?.body?.message?
|
||||
# Use SA one.
|
||||
return cb data.error.message
|
||||
# All good.
|
||||
cb null, data.body
|
||||
|
||||
# Give us headers.
|
||||
headers = (token) ->
|
||||
# The defaults.
|
||||
h =
|
||||
'Content-Type': 'application/json'
|
||||
'Accept': 'application/vnd.github.v3'
|
||||
# Add token?
|
||||
h.Authorization = "token #{token}" if token?
|
||||
h
|
||||
|
||||
isValid = (obj) ->
|
||||
rules =
|
||||
'owner': (val) -> val?
|
||||
'name': (val) -> val?
|
||||
'milestone': (val) -> _.isInt val
|
||||
|
||||
( return no for key, val of obj when key of rules and not rules[key](val) )
|
||||
|
||||
yes
|
||||
|
||||
# Switch when user is ready.
|
||||
isReady = user.data.ready
|
||||
|
||||
# A stack of requests to execute once ready.
|
||||
stack = []
|
||||
ready = (cb) ->
|
||||
if isReady then do cb else stack.push cb
|
||||
|
||||
# Observe user's readiness.
|
||||
user.observe 'ready', (val) ->
|
||||
isReady = val
|
||||
# Clear the stack?
|
||||
( do stack.shift() while stack.length ) if val
|
||||
|
||||
# Parse an error.
|
||||
error = (err) ->
|
||||
switch
|
||||
when _.isString err
|
||||
message = err
|
||||
when _.isArray err
|
||||
message = err[1]
|
||||
when _.isObject(err) and _.isString(err.message)
|
||||
message = err.message
|
||||
|
||||
unless message
|
||||
try
|
||||
message = JSON.stringify err
|
||||
catch
|
||||
message = do err.toString
|
||||
|
||||
message
|
5
src/modules/mediator.coffee
Normal file
@ -0,0 +1,5 @@
|
||||
Ractive = require 'ractive'
|
||||
|
||||
Mediator = Ractive.extend {}
|
||||
|
||||
module.exports = new Mediator()
|
49
src/modules/router.coffee
Normal file
@ -0,0 +1,49 @@
|
||||
_ = require 'lodash'
|
||||
director = require 'director'
|
||||
|
||||
mediator = require './mediator.coffee'
|
||||
system = require '../models/system.coffee'
|
||||
|
||||
el = '#page'
|
||||
|
||||
pages =
|
||||
"index": require "../views/pages/index.coffee"
|
||||
"milestone": require "../views/pages/milestone.coffee"
|
||||
"new": require "../views/pages/new.coffee"
|
||||
"project": require "../views/pages/project.coffee"
|
||||
|
||||
# Add a project from a route.
|
||||
addProject = (page, owner, name) ->
|
||||
mediator.fire '!projects/add', { owner, name }
|
||||
|
||||
# Preapply all functions with our page name/context.
|
||||
c = (name, fns=[]) ->
|
||||
( _.partial fn, name for fn in fns )
|
||||
|
||||
view = null
|
||||
route = (page, args...) ->
|
||||
# Unrender the previous one.
|
||||
do view?.teardown
|
||||
# Hide any notifications.
|
||||
mediator.fire '!app/notify/hide'
|
||||
# Require the new one.
|
||||
Page = pages[page]
|
||||
# Render it.
|
||||
view = new Page { el, 'data': { 'route': args } }
|
||||
|
||||
routes =
|
||||
'/': c 'index', [ route ]
|
||||
'/new/project': c 'new', [ route ]
|
||||
# The following two routes add a project in the background.
|
||||
'/:owner/:name': c 'project', [ addProject, route ]
|
||||
'/:owner/:name/:milestone': c 'milestone', [ addProject, route ]
|
||||
# TODO: remove in production.
|
||||
'/demo': ->
|
||||
mediator.fire '!projects/demo'
|
||||
window.location.hash = '#'
|
||||
|
||||
# Flatiron Director router.
|
||||
module.exports = director.Router(routes).configure
|
||||
'strict': no # allow trailing slashes
|
||||
notfound: ->
|
||||
throw 404
|
42
src/modules/stats.coffee
Normal file
@ -0,0 +1,42 @@
|
||||
moment = require 'moment'
|
||||
|
||||
# Progress in %.
|
||||
progress = (a, b) ->
|
||||
if a + b is 0 then 0 else 100 * (a / (b + a))
|
||||
|
||||
# Calculate the stats for a milestone.
|
||||
# Is it on time? What is the progress?
|
||||
module.exports = (milestone) ->
|
||||
isDone = no ; isOnTime = yes ; isOverdue = no ; isEmpty = yes; points = 0
|
||||
|
||||
# Progress in points.
|
||||
a = milestone.issues.closed.size
|
||||
b = milestone.issues.open.size
|
||||
if a + b > 0
|
||||
isEmpty = no
|
||||
points = progress a, b
|
||||
isDone = yes if points is 100
|
||||
|
||||
# Milestones with no due date are always on track.
|
||||
return { isOverdue, isOnTime, isDone, isEmpty, 'progress': { points } } unless milestone.due_on
|
||||
|
||||
a = +new Date milestone.created_at
|
||||
b = +new Date
|
||||
c = +new Date milestone.due_on
|
||||
|
||||
# Overdue?
|
||||
isOverdue = yes if b > c
|
||||
|
||||
# Progress in time.
|
||||
time = progress b - a, c - b
|
||||
|
||||
# How many days is 1% of the time?
|
||||
days = (moment(b).diff(moment(a), 'days')) / 100
|
||||
|
||||
# Are we on time?
|
||||
isOnTime = points > time
|
||||
|
||||
{
|
||||
isDone, days, isOnTime, isOverdue
|
||||
'progress': { points, time }
|
||||
}
|
410
src/styles/app.styl
Normal file
@ -0,0 +1,410 @@
|
||||
@import 'nib'
|
||||
|
||||
$serif_font = 'MuseoSlab500Regular', serif
|
||||
$sans_serif_font = 'MuseoSans500Regular', sans-serif
|
||||
|
||||
$strong_color = #C1041C
|
||||
$highlight_color = #FFBB2A
|
||||
|
||||
html, body
|
||||
margin: 0
|
||||
padding: 0
|
||||
height: 100%
|
||||
|
||||
body
|
||||
color: #3E4457
|
||||
font-family: $sans_serif_font
|
||||
|
||||
#app
|
||||
position: relative
|
||||
height: auto !important
|
||||
min-height: 100%
|
||||
|
||||
a
|
||||
text-decoration: none
|
||||
color: #AAAFBF
|
||||
cursor: pointer
|
||||
|
||||
h1, h2, h3, p
|
||||
margin: 0
|
||||
|
||||
ul
|
||||
list-style-type: none
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
li
|
||||
display: inline-block
|
||||
|
||||
.wrap
|
||||
width: 800px
|
||||
margin: 0 auto
|
||||
|
||||
#notify
|
||||
position: fixed
|
||||
top: -68px // hide from view
|
||||
z-index: 1
|
||||
width: 100%
|
||||
background: #FCFCFC
|
||||
color: #AAAFBF
|
||||
border-top: 3px solid #AAAFBF
|
||||
border-bottom: 1px solid #F3F4F8
|
||||
|
||||
.close
|
||||
float: right
|
||||
font-size: 16px
|
||||
padding: 22px
|
||||
cursor: pointer
|
||||
|
||||
&:before
|
||||
content: "\d7"
|
||||
display: block
|
||||
|
||||
// system-wide notification
|
||||
&.system
|
||||
top: 0% // hide from view
|
||||
left: 50%
|
||||
transform: translateX(-50%) translateY(-50%)
|
||||
width: 500px
|
||||
|
||||
p
|
||||
padding-top: 20px
|
||||
|
||||
&.success, &.ok, &.good
|
||||
border-top-color: #00B361
|
||||
color: #00B361
|
||||
|
||||
&.warn, &.trouble
|
||||
border-top-color: #EA9712
|
||||
color: #EA9712
|
||||
|
||||
&.alert, &.bad, &.fucked
|
||||
border-top-color: $strong_color
|
||||
color: $strong_color
|
||||
|
||||
.icon, p
|
||||
display: block
|
||||
|
||||
.icon
|
||||
font-size: 26px
|
||||
padding: 18px
|
||||
width: 38px
|
||||
float: left
|
||||
|
||||
p
|
||||
padding: 22px 20px 20px 74px
|
||||
text-align: justify
|
||||
|
||||
#head
|
||||
background: $strong_color
|
||||
height: 64px
|
||||
|
||||
#icon
|
||||
font-size: 26px
|
||||
margin: 0
|
||||
padding: 10px 0
|
||||
line-height: 44px
|
||||
height: 44px
|
||||
width: 74px
|
||||
background: #77000E
|
||||
display: inline-block
|
||||
color: $strong_color
|
||||
margin: 0
|
||||
text-align: center
|
||||
|
||||
.q
|
||||
position: relative
|
||||
display: inline-block
|
||||
margin: 13px 20px 0 20px
|
||||
vertical-align: top
|
||||
|
||||
.icon
|
||||
position: absolute
|
||||
color: $strong_color
|
||||
|
||||
&.search
|
||||
top: 8px
|
||||
left: 12px
|
||||
|
||||
&.down-open
|
||||
top: 8px
|
||||
right: 12px
|
||||
|
||||
input
|
||||
background: #77000E
|
||||
border: 0
|
||||
padding: 10px 12px 10px 36px
|
||||
font-size: 14px
|
||||
border-radius: 2px
|
||||
color: #FFF
|
||||
width: 220px
|
||||
|
||||
ul
|
||||
display: inline-block
|
||||
|
||||
li
|
||||
margin-left: 30px
|
||||
|
||||
a
|
||||
color: #E0808D
|
||||
font-weight: bold
|
||||
|
||||
&.active, &:hover
|
||||
color: #FFF
|
||||
|
||||
.right
|
||||
float: right
|
||||
margin-right: 20px
|
||||
line-height: 64px
|
||||
color: #E0808D
|
||||
|
||||
a
|
||||
border-radius: 2px
|
||||
background: $highlight_color
|
||||
color: $strong_color
|
||||
padding: 11px 20px
|
||||
|
||||
#title
|
||||
border-bottom: 3px solid #F3F4F8
|
||||
white-space: nowrap
|
||||
line-height: 52px // outer height of tallest element
|
||||
margin-top: 20px
|
||||
|
||||
.title
|
||||
float: left
|
||||
border-bottom: 3px solid #AAAFBF
|
||||
margin-bottom: -3px
|
||||
|
||||
.sub
|
||||
float: left
|
||||
font-size: 16px
|
||||
font-weight: bold
|
||||
padding: 0 20px
|
||||
|
||||
.description
|
||||
overflow: hidden
|
||||
font-family: $serif_font
|
||||
color: #B1B6C4
|
||||
|
||||
&:after
|
||||
display: block
|
||||
clear: both
|
||||
content: ""
|
||||
|
||||
#page
|
||||
padding-bottom: 80px // height of the footer
|
||||
|
||||
#content
|
||||
padding: 20px
|
||||
margin-top: 20px
|
||||
margin-bottom: 40px
|
||||
|
||||
#hero
|
||||
background: url('../img/hires/2.jpg') center
|
||||
background-size: cover
|
||||
border-radius: 2px
|
||||
margin-bottom: 30px
|
||||
|
||||
.content
|
||||
border-radius: 2px
|
||||
color: #FFF
|
||||
padding: 30px
|
||||
background: rgba(#000, 30%)
|
||||
box-shadow: inset 0 1px 2px rgba(#000, 20%)
|
||||
|
||||
h2
|
||||
margin-bottom: 20px
|
||||
margin-left: 140px
|
||||
|
||||
p
|
||||
font-family: $serif_font
|
||||
font-size: 18px
|
||||
line-height: 24px
|
||||
margin-left: 140px
|
||||
text-align: justify
|
||||
text-justify: inter-word
|
||||
|
||||
.address
|
||||
font-size: 120px
|
||||
float: left
|
||||
|
||||
.cta
|
||||
text-align: center
|
||||
margin-top: 10px
|
||||
|
||||
a
|
||||
font-family: $serif_font
|
||||
padding: 11px 20px
|
||||
border-radius: 2px
|
||||
display: inline-block
|
||||
margin: 0 4px
|
||||
|
||||
&.primary
|
||||
font-weight: bold
|
||||
background: $strong_color
|
||||
color: #FFF
|
||||
|
||||
&.secondary
|
||||
background: #FFF
|
||||
color: $strong_color
|
||||
|
||||
#add
|
||||
h2
|
||||
color: #3E4457
|
||||
|
||||
p
|
||||
font-family: $serif_font
|
||||
color: #B1B6C4
|
||||
margin-top: 10px
|
||||
line-height: 20px
|
||||
text-align: justify
|
||||
text-justify: inter-word
|
||||
|
||||
a
|
||||
color: #3E4457
|
||||
|
||||
.form
|
||||
margin-top: 20px
|
||||
|
||||
table
|
||||
width: 100%
|
||||
|
||||
tr
|
||||
td
|
||||
&:first-child
|
||||
width: 100%
|
||||
|
||||
input
|
||||
box-sizing: border-box
|
||||
padding: 10px
|
||||
width: 100%
|
||||
border-radius: 2px 0 0 2px
|
||||
border: 1px solid #DDE1ED
|
||||
border-right: 0
|
||||
box-shadow: inset 0 1px 2px rgba(#000, 20%)
|
||||
|
||||
a
|
||||
margin-left: -2px
|
||||
font-family: $serif_font
|
||||
padding: 11px 20px
|
||||
border-radius: 0 2px 2px 0
|
||||
display: inline-block
|
||||
font-weight: bold
|
||||
background: $strong_color
|
||||
color: #FFF
|
||||
|
||||
#projects
|
||||
border: 1px solid #CDCECF
|
||||
border-radius: 2px
|
||||
|
||||
h2
|
||||
color: #3E4457
|
||||
display: inline-block
|
||||
|
||||
.sort
|
||||
float: right
|
||||
line-height: 30px
|
||||
|
||||
table
|
||||
width: 100%
|
||||
|
||||
tr
|
||||
td
|
||||
background: #FCFCFC
|
||||
padding: 20px 30px
|
||||
border-bottom: 1px solid #EAECF2
|
||||
|
||||
.project
|
||||
color: inherit
|
||||
|
||||
.error
|
||||
cursor: help
|
||||
color: $strong_color
|
||||
|
||||
a.project
|
||||
font-weight: bold
|
||||
|
||||
.milestone
|
||||
.icon
|
||||
font-size: 10px
|
||||
margin: 0
|
||||
|
||||
.progress
|
||||
width: 200px
|
||||
|
||||
.percent, .due
|
||||
color: darken(#C1C4D0, 20%)
|
||||
font-size: 13px
|
||||
|
||||
.percent
|
||||
float: right
|
||||
|
||||
.bar
|
||||
border-radius: 4px
|
||||
background: #EAECF2
|
||||
height: 10px
|
||||
width: 100%
|
||||
|
||||
&.inner
|
||||
box-shadow: inset 0 1px 2px rgba(#000, 20%)
|
||||
|
||||
&.red
|
||||
background: $strong_color
|
||||
|
||||
&.green
|
||||
background: #00B361
|
||||
|
||||
.due
|
||||
&.red
|
||||
color: $strong_color
|
||||
font-weight: bold
|
||||
|
||||
&:first-child
|
||||
color: #3E4457
|
||||
|
||||
&:nth-child(even)
|
||||
td
|
||||
background: lighten(#FCFCFC, 60%)
|
||||
|
||||
&:last-child
|
||||
td
|
||||
border: 0
|
||||
|
||||
&.done
|
||||
td
|
||||
background: #EBF6F1
|
||||
|
||||
.milestone, .percent, .due
|
||||
color: #00B361
|
||||
|
||||
.header, .footer
|
||||
padding: 20px 30px
|
||||
|
||||
.header
|
||||
box-shadow: 0 1px 2px rgba(#DDE1ED, 50%)
|
||||
margin-bottom: 2px
|
||||
border-bottom: 1px solid #DDE1ED
|
||||
|
||||
a
|
||||
font-family: $serif_font
|
||||
|
||||
.footer
|
||||
background: #F9FAFB
|
||||
color: #AAAFBF
|
||||
box-shadow: inset 0 1px 2px rgba(#DDE1ED, 20%)
|
||||
border-top: 1px solid #DDE1ED
|
||||
text-align: right
|
||||
font-family: $serif_font
|
||||
|
||||
.icon
|
||||
color: #AAAFBF
|
||||
|
||||
#footer
|
||||
position: absolute
|
||||
width: 100%
|
||||
bottom: 0
|
||||
box-sizing: border-box
|
||||
border-top: 1px solid #F3F4F8
|
||||
text-align: center
|
||||
padding: 30px
|
||||
font-family: $serif_font
|
95
src/styles/chart.styl
Normal file
@ -0,0 +1,95 @@
|
||||
@import 'nib'
|
||||
|
||||
// color definitions
|
||||
$closed = #4DAF7C
|
||||
$opened = #E55F3A
|
||||
$grey = #CACACA
|
||||
$brown = #64584C
|
||||
$background1 = #D7BCAB
|
||||
$background2 = #CC9485
|
||||
|
||||
// where D3 renders to
|
||||
#chart
|
||||
height: 300px
|
||||
position: relative
|
||||
|
||||
// position will be adjusted dynamically
|
||||
#tooltip
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
|
||||
svg
|
||||
path
|
||||
&.line
|
||||
fill: none
|
||||
stroke-width: 1px
|
||||
clip-path: url(#clip)
|
||||
|
||||
// actual progress
|
||||
&.actual
|
||||
stroke: $brown
|
||||
stroke-width: 3px
|
||||
|
||||
// ideal velocity throughout the sprint
|
||||
&.ideal
|
||||
stroke: $grey
|
||||
stroke-width: 3px
|
||||
|
||||
// trend of actual issue closures
|
||||
&.trendline
|
||||
stroke: $brown
|
||||
stroke-width: 1.5px
|
||||
stroke-dasharray: 5,5
|
||||
|
||||
// right now
|
||||
line
|
||||
&.today
|
||||
stroke: $grey
|
||||
stroke-width: 1px
|
||||
shape-rendering: crispEdges
|
||||
stroke-dasharray: 5,5
|
||||
|
||||
// represents one issue closed
|
||||
circle
|
||||
fill: $brown
|
||||
// make it easier to click
|
||||
stroke: transparent
|
||||
stroke-width: 15px
|
||||
cursor: pointer
|
||||
|
||||
// axes...
|
||||
.axis
|
||||
shape-rendering: crispEdges
|
||||
|
||||
line
|
||||
stroke: rgba($grey, 0.25)
|
||||
shape-rendering: crispEdges
|
||||
|
||||
text
|
||||
font-weight: bold
|
||||
fill: $grey
|
||||
|
||||
path
|
||||
display: none
|
||||
|
||||
// tooltips
|
||||
.d3-tip
|
||||
margin-top: -10px
|
||||
font-size: 11px
|
||||
padding: 8px 10px 7px 10px
|
||||
text-align: center
|
||||
background: rgba(0,0,0,0.75)
|
||||
color: #fff
|
||||
border-radius: 3px
|
||||
|
||||
&:after
|
||||
width: 100%
|
||||
color: rgba(0,0,0,0.8)
|
||||
content: "\25BC"
|
||||
position: absolute
|
||||
|
||||
&.n:after
|
||||
margin: -3px 0 0 0
|
||||
top: 100%
|
||||
left: 0
|
32
src/styles/fonts.styl
Normal file
@ -0,0 +1,32 @@
|
||||
@font-face {
|
||||
font-family: 'MuseoSlab500Regular';
|
||||
src: url('../fonts/museo-slab-500.eot');
|
||||
src: url('../fonts/museo-slab-500.eot?#iefix') format('embedded-opentype'),
|
||||
url('../fonts/museo-slab-500.woff') format('woff'),
|
||||
url('../fonts/museo-slab-500.ttf') format('truetype'),
|
||||
url('../fonts/museo-slab-500.svg#MuseoSlab500Regular') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'MuseoSans500Regular';
|
||||
src: url('../fonts/museo-sans-500.eot');
|
||||
src: url('../fonts/museo-sans-500.eot?#iefix') format('embedded-opentype'),
|
||||
url('../fonts/museo-sans-500.woff') format('woff'),
|
||||
url('../fonts/museo-sans-500.ttf') format('truetype'),
|
||||
url('../fonts/museo-sans-500.svg#MuseoSans500Regular') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Fontello';
|
||||
src: url('../fonts/fontello.eot?74672344');
|
||||
src: url('../fonts/fontello.eot?74672344#iefix') format('embedded-opentype'),
|
||||
url('../fonts/fontello.woff?74672344') format('woff'),
|
||||
url('../fonts/fontello.ttf?74672344') format('truetype'),
|
||||
url('../fonts/fontello.svg?74672344#fontello') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
32
src/styles/icons.styl
Normal file
@ -0,0 +1,32 @@
|
||||
@import 'nib'
|
||||
|
||||
.icon
|
||||
vertical-align: middle
|
||||
font-family: "Fontello"
|
||||
font-style: normal
|
||||
font-weight: normal
|
||||
speak: none
|
||||
|
||||
display: inline-block
|
||||
text-decoration: inherit
|
||||
text-align: center
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes */
|
||||
font-variant: normal
|
||||
text-transform: none
|
||||
|
||||
&[class^='spin'], &[class*=' spin']
|
||||
animation: spin 2s infinite linear
|
||||
|
||||
@-moz-keyframes spin {
|
||||
from { -moz-transform: rotate(0deg) }
|
||||
to { -moz-transform: rotate(360deg) }
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
from { -webkit-transform: rotate(0deg) }
|
||||
to { -webkit-transform: rotate(360deg) }
|
||||
}
|
||||
@keyframes spin {
|
||||
from { transform:rotate(0deg) }
|
||||
to { transform:rotate(360deg) }
|
||||
}
|
14
src/templates/app.html
Normal file
@ -0,0 +1,14 @@
|
||||
<div id="app">
|
||||
<Notify/>
|
||||
<Header/>
|
||||
|
||||
<div id="page">
|
||||
<!-- content loaded from a router -->
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
<div class="wrap">
|
||||
© 2012-2014 <a href="http://cloudfi.re">Cloudfire Systems</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
1
src/templates/chart.html
Normal file
@ -0,0 +1 @@
|
||||
<div id="chart"></div>
|
30
src/templates/header.html
Normal file
@ -0,0 +1,30 @@
|
||||
<div id="head">
|
||||
{{#with user}}
|
||||
{{#ready}}
|
||||
<div class="right" intro="fade">
|
||||
{{#uid}}
|
||||
{{github.displayName}} logged in
|
||||
{{else}}
|
||||
<a class="github" on-click="!login"><Icons icon="github"/> Sign In</a>
|
||||
{{/uid}}
|
||||
</div>
|
||||
{{/ready}}
|
||||
{{/with}}
|
||||
|
||||
<a id="icon" href="#">
|
||||
<Icons icon="{{icon}}"/>
|
||||
</a>
|
||||
|
||||
<!--
|
||||
<div class="q">
|
||||
<Icons icon="search"/>
|
||||
<Icons icon="down-open"/>
|
||||
<input type="text" placeholder="Jump to...">
|
||||
</div>
|
||||
-->
|
||||
|
||||
<ul>
|
||||
<li><a href="#new/project" class="add"><Icons icon="plus-circled"/> Add a Project</a></li>
|
||||
<li><a href="#demo"><Icons icon="download-cloud"/> Demo Projects</a></li>
|
||||
</ul>
|
||||
</div>
|
11
src/templates/hero.html
Normal file
@ -0,0 +1,11 @@
|
||||
<div id="hero">
|
||||
<div class="content">
|
||||
<Icons icon="address"/>
|
||||
<h2>See your project progress</h2>
|
||||
<p>Not sure where to start? Just add a demo repo to see a chart. There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable.</p>
|
||||
<div class="cta">
|
||||
<a href="#new/project" class="primary"><Icons icon="plus-circled"/> Add your project</a>
|
||||
<a href="#" class="secondary">Read the Guide</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
3
src/templates/icons.html
Normal file
@ -0,0 +1,3 @@
|
||||
{{#code}}
|
||||
<span class="icon {{icon}}">{{{ '&#' + code + ';' }}}</span>
|
||||
{{/code}}
|
14
src/templates/notify.html
Normal file
@ -0,0 +1,14 @@
|
||||
{{#text}}
|
||||
{{#system}}
|
||||
<div id="notify" class="{{type}} system" style="top:{{top}}%">
|
||||
<Icons icon="{{icon}}"/>
|
||||
<p>{{text}}</p>
|
||||
</div>
|
||||
{{else}}
|
||||
<div id="notify" class="{{type}}" style="top:{{-top}}px">
|
||||
<span class="close" on-click="close" />
|
||||
<Icons icon="{{icon}}"/>
|
||||
<p>{{text}}</p>
|
||||
</div>
|
||||
{{/system}}
|
||||
{{/text}}
|
11
src/templates/pages/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<div id="content" class="wrap">
|
||||
{{#if projects.list}}
|
||||
{{#ready}}
|
||||
<div intro="fade">
|
||||
<Projects projects="{{projects}}"/>
|
||||
</div>
|
||||
{{/ready}}
|
||||
{{else}}
|
||||
<Hero/>
|
||||
{{/if}}
|
||||
</div>
|
15
src/templates/pages/milestone.html
Normal file
@ -0,0 +1,15 @@
|
||||
{{#ready}}
|
||||
<div intro="fade">
|
||||
<div id="title">
|
||||
<div class="wrap">
|
||||
<h2 class="title">{{ format.title(milestone.title) }}</h2>
|
||||
<span class="sub">{{{ format.due(milestone.due_on) }}}</span>
|
||||
<div class="description">{{{ format.markdown(milestone.description) }}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content" class="wrap">
|
||||
<Chart milestone="{{milestone}}"/>
|
||||
</div>
|
||||
</div>
|
||||
{{/ready}}
|
29
src/templates/pages/new.html
Normal file
@ -0,0 +1,29 @@
|
||||
<div id="content" class="wrap">
|
||||
<div id="add">
|
||||
<div class="header">
|
||||
<h2>Add a Project</h2>
|
||||
<p>Type in the name of the repository as you would normally.
|
||||
{{#with user}}
|
||||
{{#ready}}
|
||||
{{^uid}}
|
||||
If you'd like to add a private GitHub project, <a on-click="!login">Sign In</a> first.
|
||||
{{/uid}}
|
||||
{{/ready}}
|
||||
{{/with}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="text" placeholder="user/repo" autocomplete="off" value="{{value}}" on-keyup="submit:{{value}}">
|
||||
</td>
|
||||
<td>
|
||||
<a on-click="submit:{{value}}">Add</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
13
src/templates/pages/project.html
Normal file
@ -0,0 +1,13 @@
|
||||
{{#ready}}
|
||||
<div intro="fade">
|
||||
<div id="title">
|
||||
<div class="wrap">
|
||||
<h2 class="title">{{route.join('/')}}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content" class="wrap">
|
||||
<Milestones project="{{project}}"/>
|
||||
</div>
|
||||
</div>
|
||||
{{/ready}}
|
39
src/templates/tables/milestones.html
Normal file
@ -0,0 +1,39 @@
|
||||
<div id="projects">
|
||||
<div class="header">
|
||||
<a class="sort" on-click="sortBy"><Icons icon="sort-alphabet"/> Sorted by {{projects.sortBy}}</a>
|
||||
<h2>Milestones</h2>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
{{#projects.index}}
|
||||
{{# { index: this } }}
|
||||
|
||||
{{# { p: projects.list[index[0]] } }}
|
||||
{{#if p.owner == project.owner && p.name == project.name }}
|
||||
{{# { milestone: project.milestones[index[1]] } }}
|
||||
<tr class="{{#if milestone.stats.isDone}}done{{/if}}">
|
||||
<td>
|
||||
<a class="milestone" href="#{{project.owner}}/{{project.name}}/{{milestone.number}}">{{ milestone.title }}</a>
|
||||
</td>
|
||||
<td style="width:1%">
|
||||
<div class="progress">
|
||||
<span class="percent">{{Math.floor(milestone.stats.progress.points)}}%</span>
|
||||
<span class="due {{#if milestone.stats.isOverdue}}red{{/if}}">{{{ format.due(milestone.due_on) }}}</span>
|
||||
<div class="outer bar">
|
||||
<div class="inner bar {{(milestone.stats.isOnTime) ? 'green' : 'red'}}" style="width:{{milestone.stats.progress.points}}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{/}}
|
||||
{{/if}}
|
||||
{{/}}
|
||||
|
||||
{{/}}
|
||||
{{/projects.index}}
|
||||
</table>
|
||||
|
||||
<div class="footer">
|
||||
<!--<a href="#"><Icons icon="cog"/> Edit</a>-->
|
||||
</div>
|
||||
</div>
|
52
src/templates/tables/projects.html
Normal file
@ -0,0 +1,52 @@
|
||||
<div id="projects">
|
||||
<div class="header">
|
||||
<a class="sort" on-click="sortBy"><Icons icon="sort-alphabet"/> Sorted by {{projects.sortBy}}</a>
|
||||
<h2>Projects</h2>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
{{#projects.list}}
|
||||
{{#if errors}}
|
||||
<tr>
|
||||
<td colspan="3" class="repo">
|
||||
<div class="project">{{owner}}/{{name}} <span class="error" title="{{errors.join('\n')}}"><Icons icon="attention"/></span></div>
|
||||
</td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
{{/projects.list}}
|
||||
|
||||
{{#projects.index}}
|
||||
{{# { index: this } }}
|
||||
|
||||
{{# { project: projects.list[index[0]] } }}
|
||||
{{#with project}}
|
||||
{{# { milestone: project.milestones[index[1]] } }}
|
||||
<tr class="{{#if milestone.stats.isDone}}done{{/if}}">
|
||||
<td class="repo">
|
||||
<a class="project" href="#{{owner}}/{{name}}">{{owner}}/{{name}}</a>
|
||||
</td>
|
||||
<td>
|
||||
<a class="milestone" href="#{{owner}}/{{name}}/{{milestone.number}}">{{ milestone.title }}</a>
|
||||
</td>
|
||||
<td style="width:1%">
|
||||
<div class="progress">
|
||||
<span class="percent">{{Math.floor(milestone.stats.progress.points)}}%</span>
|
||||
<span class="due {{#if milestone.stats.isOverdue}}red{{/if}}">{{{ format.due(milestone.due_on) }}}</span>
|
||||
<div class="outer bar">
|
||||
<div class="inner bar {{(milestone.stats.isOnTime) ? 'green' : 'red'}}" style="width:{{milestone.stats.progress.points}}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{/}}
|
||||
{{/with}}
|
||||
{{/}}
|
||||
|
||||
{{/}}
|
||||
{{/projects.index}}
|
||||
</table>
|
||||
|
||||
<div class="footer">
|
||||
<!--<a href="#"><Icons icon="cog"/> Edit</a>-->
|
||||
</div>
|
||||
</div>
|
2
src/utils/date.coffee
Normal file
@ -0,0 +1,2 @@
|
||||
module.exports =
|
||||
now: -> new Date().toJSON()
|
29
src/utils/format.coffee
Normal file
@ -0,0 +1,29 @@
|
||||
_ = require 'lodash'
|
||||
moment = require 'moment'
|
||||
marked = require 'marked'
|
||||
|
||||
module.exports =
|
||||
|
||||
# Time from now.
|
||||
fromNow: _.memoize (jsonDate) ->
|
||||
moment(new Date(jsonDate)).fromNow()
|
||||
|
||||
# When is a milestone due?
|
||||
due: (jsonDate) ->
|
||||
return ' ' unless jsonDate
|
||||
[ 'due', @fromNow jsonDate ].join(' ')
|
||||
|
||||
# Markdown formatting.
|
||||
markdown: (markup) ->
|
||||
marked markup
|
||||
|
||||
# Format milestone title.
|
||||
title: (text) ->
|
||||
if text.toLowerCase().indexOf('milestone') > -1
|
||||
text
|
||||
else
|
||||
[ 'Milestone', text ].join(' ')
|
||||
|
||||
# Hex to decimal.
|
||||
hexToDec: (hex) ->
|
||||
parseInt hex, 16
|
6
src/utils/key.coffee
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports =
|
||||
is: (evt) ->
|
||||
evt.original.type in [ 'keyup', 'keydown' ]
|
||||
|
||||
isEnter: (evt) ->
|
||||
evt.original.which is 13
|
13
src/utils/mixins.coffee
Normal file
@ -0,0 +1,13 @@
|
||||
_ = require 'lodash'
|
||||
|
||||
_.mixin
|
||||
'pluckMany': (source, keys) ->
|
||||
throw '`keys` needs to be an Array' unless _.isArray keys
|
||||
_.map source, (item) ->
|
||||
obj = {}
|
||||
_.each keys, (key) ->
|
||||
obj[key] = item[key]
|
||||
obj
|
||||
|
||||
'isInt': (val) ->
|
||||
not isNaN(val) and parseInt(Number(val)) is val and not isNaN(parseInt(val, 10))
|
27
src/utils/ractive/eventful.coffee
Normal file
@ -0,0 +1,27 @@
|
||||
_ = require 'lodash'
|
||||
Ractive = require 'ractive'
|
||||
|
||||
mediator = require '../../modules/mediator.coffee'
|
||||
|
||||
# An Ractive that subscribes and listens to messages on `mediator` event bus.
|
||||
# Usage: this.subscribe('!event', function() { /* listener */ }, context);
|
||||
module.exports = Ractive.extend
|
||||
|
||||
subscribe: (name, cb, ctx) ->
|
||||
ctx ?= @
|
||||
@_subs = [] unless _.isArray @_subs
|
||||
if _.isFunction cb
|
||||
@_subs.push mediator.on name, _.bind cb, ctx
|
||||
else
|
||||
console.log "Warning: `cb` is not a function"
|
||||
|
||||
publish: ->
|
||||
mediator.fire.apply mediator, arguments
|
||||
|
||||
onteardown: ->
|
||||
if _.isArray @_subs
|
||||
for sub in @_subs
|
||||
if _.isFunction sub.cancel
|
||||
do sub.cancel
|
||||
else
|
||||
console.log "Warning: `sub.cancel` is not a function"
|
7
src/utils/ractive/model.coffee
Normal file
@ -0,0 +1,7 @@
|
||||
Eventful = require './eventful.coffee'
|
||||
|
||||
module.exports = (opts) ->
|
||||
Model = Eventful.extend(opts)
|
||||
model = new Model()
|
||||
model.render()
|
||||
model
|
138
src/views/chart.coffee
Normal file
@ -0,0 +1,138 @@
|
||||
Ractive = require 'ractive'
|
||||
d3 = require 'd3'
|
||||
|
||||
require('d3-tip')(d3)
|
||||
|
||||
lines = require '../modules/chart/lines.coffee'
|
||||
axes = require '../modules/chart/axes.coffee'
|
||||
|
||||
module.exports = Ractive.extend
|
||||
|
||||
'name': 'views/chart'
|
||||
|
||||
'template': require '../templates/chart.html'
|
||||
|
||||
oncomplete: ->
|
||||
milestone = @data.milestone
|
||||
issues = milestone.issues
|
||||
# Total number of points in the milestone.
|
||||
total = issues.open.size + issues.closed.size
|
||||
|
||||
|
||||
# An issue may have been closed before the start of a milestone.
|
||||
head = issues.closed.list[0].closed_at
|
||||
if issues.length and milestone.created_at > head
|
||||
# This is the new start.
|
||||
milestone.created_at = head
|
||||
|
||||
# Actual, ideal & trend lines.
|
||||
actual = lines.actual issues.closed.list, milestone.created_at, total
|
||||
ideal = lines.ideal milestone.created_at, milestone.due_on, total
|
||||
trend = lines.trend actual, milestone.created_at, milestone.due_on
|
||||
|
||||
# Get available space.
|
||||
{ height, width } = do @el.getBoundingClientRect
|
||||
|
||||
margin = { 'top': 30, 'right': 30, 'bottom': 40, 'left': 50 }
|
||||
width -= margin.left + margin.right
|
||||
height -= margin.top + margin.bottom
|
||||
|
||||
# Scales.
|
||||
x = d3.time.scale().range([ 0, width ])
|
||||
y = d3.scale.linear().range([ height, 0 ])
|
||||
|
||||
# Axes.
|
||||
xAxis = axes.horizontal height, x
|
||||
yAxis = axes.vertical width, y
|
||||
|
||||
# Line generator.
|
||||
line = d3.svg.line()
|
||||
.interpolate("linear")
|
||||
.x( (d) -> x(d.date) )
|
||||
.y( (d) -> y(d.points) )
|
||||
|
||||
# Get the minimum and maximum date, and initial points.
|
||||
x.domain([ ideal[0].date, ideal[ideal.length - 1].date ])
|
||||
y.domain([ 0, ideal[0].points ]).nice()
|
||||
|
||||
# Add an SVG element with the desired dimensions and margin.
|
||||
svg = d3.select(this.el.querySelector('#chart')).append("svg")
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
.attr("height", height + margin.top + margin.bottom)
|
||||
.append("g")
|
||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
|
||||
|
||||
# Add the days x-axis.
|
||||
svg.append("g")
|
||||
.attr("class", "x axis day")
|
||||
.attr("transform", "translate(0,#{height})")
|
||||
.call(xAxis)
|
||||
|
||||
# Add the months x-axis.
|
||||
m = [
|
||||
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||||
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
|
||||
]
|
||||
|
||||
mAxis = xAxis
|
||||
.orient("top")
|
||||
.tickSize(height)
|
||||
.tickFormat( (d) -> m[d.getMonth()] )
|
||||
.ticks(2)
|
||||
|
||||
svg.append("g")
|
||||
.attr("class", "x axis month")
|
||||
.attr("transform", "translate(0,#{height})")
|
||||
.call(mAxis)
|
||||
|
||||
# Add the y-axis.
|
||||
svg.append("g")
|
||||
.attr("class", "y axis")
|
||||
.call(yAxis)
|
||||
|
||||
# Add a line showing where we are now.
|
||||
svg.append("svg:line")
|
||||
.attr("class", "today")
|
||||
.attr("x1", x(new Date()))
|
||||
.attr("y1", 0)
|
||||
.attr("x2", x(new Date()))
|
||||
.attr("y2", height)
|
||||
|
||||
# Add the ideal line path.
|
||||
svg.append("path")
|
||||
.attr("class", "ideal line")
|
||||
# Piecewise linear segments, as in a polyline.
|
||||
.attr("d", line.interpolate("linear")(ideal))
|
||||
|
||||
# Add the trendline path.
|
||||
svg.append("path")
|
||||
.attr("class", "trendline line")
|
||||
# Piecewise linear segments, as in a polyline.
|
||||
.attr("d", line.interpolate("linear")(trend))
|
||||
|
||||
# Add the actual line path.
|
||||
svg.append("path")
|
||||
.attr("class", "actual line")
|
||||
# Piecewise linear segments, as in a polyline.
|
||||
.attr("d", line.interpolate("linear").y( (d) -> y(d.points) )(actual))
|
||||
|
||||
# Collect the tooltip here.
|
||||
tooltip = d3.tip().attr('class', 'd3-tip').html ({ number, title }) ->
|
||||
"##{number}: #{title}"
|
||||
|
||||
svg.call(tooltip)
|
||||
|
||||
# Show when we closed an issue.
|
||||
svg.selectAll("a.issue")
|
||||
.data(actual.slice(1)) # skip the starting point
|
||||
.enter()
|
||||
# A wrapping link.
|
||||
.append('svg:a')
|
||||
.attr("xlink:href", ({ html_url }) -> html_url )
|
||||
.attr("xlink:show", 'new')
|
||||
.append('svg:circle')
|
||||
.attr("cx", ({ date }) -> x date )
|
||||
.attr("cy", ({ points }) -> y points )
|
||||
.attr("r", ({ radius }) -> 5 ) # fixed for now
|
||||
.on('mouseover', tooltip.show)
|
||||
.on('mouseout', tooltip.hide)
|
31
src/views/header.coffee
Normal file
@ -0,0 +1,31 @@
|
||||
Ractive = require 'ractive'
|
||||
|
||||
{ system } = require '../models/system.coffee'
|
||||
firebase = require '../models/firebase.coffee'
|
||||
user = require '../models/user.coffee'
|
||||
Icons = require './icons.coffee'
|
||||
|
||||
module.exports = Ractive.extend
|
||||
|
||||
'name': 'views/header'
|
||||
|
||||
'template': require '../templates/header.html'
|
||||
|
||||
'data':
|
||||
'user': user
|
||||
# Default app icon.
|
||||
'icon': 'fire-station'
|
||||
|
||||
'components': { Icons }
|
||||
|
||||
'adapt': [ Ractive.adaptors.Ractive ]
|
||||
|
||||
onconstruct: ->
|
||||
# Login user.
|
||||
@on '!login', ->
|
||||
do firebase.login
|
||||
|
||||
onrender: ->
|
||||
# Switch loading icon with app icon.
|
||||
system.observe 'loading', (ya) =>
|
||||
@set 'icon', if ya then 'spinner1' else 'fire-station'
|
13
src/views/hero.coffee
Normal file
@ -0,0 +1,13 @@
|
||||
Ractive = require 'ractive'
|
||||
|
||||
Icons = require './icons.coffee'
|
||||
|
||||
module.exports = Ractive.extend
|
||||
|
||||
'name': 'views/hero'
|
||||
|
||||
'template': require '../templates/hero.html'
|
||||
|
||||
'components': { Icons }
|
||||
|
||||
'adapt': [ Ractive.adaptors.Ractive ]
|
35
src/views/icons.coffee
Normal file
@ -0,0 +1,35 @@
|
||||
Ractive = require 'ractive'
|
||||
|
||||
format = require '../utils/format.coffee'
|
||||
|
||||
# Fontello icon hex codes.
|
||||
codes =
|
||||
'cog': '\e800'
|
||||
'search': '\e801'
|
||||
'github': '\e802'
|
||||
'address': '\e803'
|
||||
'plus-circled': '\e804'
|
||||
'fire-station': '\e805'
|
||||
'sort-alphabet': '\e806'
|
||||
'down-open': '\e807'
|
||||
'spin6': '\e808'
|
||||
'megaphone': '\e809'
|
||||
'spin4': '\e80a'
|
||||
'spinner1': '\e80b'
|
||||
'attention': '\e80c'
|
||||
'download-cloud': '\e80d'
|
||||
|
||||
module.exports = Ractive.extend
|
||||
|
||||
'name': 'views/icons'
|
||||
|
||||
'template': require '../templates/icons.html'
|
||||
|
||||
'isolated': yes
|
||||
|
||||
onrender: ->
|
||||
@observe 'icon', (icon) ->
|
||||
if icon and hex = codes[icon]
|
||||
@set 'code', format.hexToDec hex
|
||||
else
|
||||
@set 'code', null
|
65
src/views/notify.coffee
Normal file
@ -0,0 +1,65 @@
|
||||
_ = require 'lodash'
|
||||
Ractive = require 'ractive'
|
||||
d3 = require 'd3'
|
||||
|
||||
Eventful = require '../utils/ractive/eventful.coffee'
|
||||
Icons = require './icons.coffee'
|
||||
|
||||
HEIGHT = 68 # height of div in px
|
||||
|
||||
module.exports = Eventful.extend
|
||||
|
||||
'name': 'views/notify'
|
||||
|
||||
'template': require '../templates/notify.html'
|
||||
|
||||
'data':
|
||||
'top': HEIGHT
|
||||
'hidden': yes
|
||||
'defaults':
|
||||
'text': ''
|
||||
'type': '' # bland grey style
|
||||
'system': no
|
||||
'icon': 'megaphone'
|
||||
'ttl': 5e3
|
||||
|
||||
'components': { Icons }
|
||||
|
||||
'adapt': [ Ractive.adaptors.Ractive ]
|
||||
|
||||
# Show a notification.
|
||||
show: (opts) ->
|
||||
@set 'hidden', no
|
||||
# Set the opts.
|
||||
@set opts = _.defaults opts, @data.defaults
|
||||
# Which position to slide to?
|
||||
pos = [ 0, 50 ][ +opts.system ] # 0px or 50% from top
|
||||
# Slide into view.
|
||||
@animate 'top', pos,
|
||||
'easing': d3.ease('bounce')
|
||||
'duration': 800
|
||||
|
||||
# If no ttl then show permanently.
|
||||
return unless opts.ttl
|
||||
|
||||
# Slide out of the view.
|
||||
_.delay _.bind(@hide, @), opts.ttl
|
||||
|
||||
# Hide a notification.
|
||||
hide: ->
|
||||
return if @data.hidden
|
||||
@set 'hidden', yes
|
||||
|
||||
@animate 'top', HEIGHT,
|
||||
'easing': d3.ease('back')
|
||||
'complete': =>
|
||||
# Reset the text when all is done.
|
||||
@set 'text', null
|
||||
|
||||
onconstruct: ->
|
||||
# On outside messages.
|
||||
@subscribe '!app/notify', @show, @
|
||||
@subscribe '!app/notify/hide', @hide, @
|
||||
|
||||
# Close us prematurely...
|
||||
@on 'close', @hide
|
77
src/views/pages/index.coffee
Normal file
@ -0,0 +1,77 @@
|
||||
_ = require 'lodash'
|
||||
Ractive = require 'ractive'
|
||||
async = require 'async'
|
||||
|
||||
Hero = require '../hero.coffee'
|
||||
Projects = require '../tables/projects.coffee'
|
||||
|
||||
projects = require '../../models/projects.coffee'
|
||||
system = require '../../models/system.coffee'
|
||||
milestones = require '../../modules/github/milestones.coffee'
|
||||
issues = require '../../modules/github/issues.coffee'
|
||||
|
||||
module.exports = Ractive.extend
|
||||
|
||||
'name': 'views/pages/index'
|
||||
|
||||
'template': require '../../templates/pages/index.html'
|
||||
|
||||
'components': { Hero, Projects }
|
||||
|
||||
'data':
|
||||
'projects': projects
|
||||
'ready': no
|
||||
|
||||
'adapt': [ Ractive.adaptors.Ractive ]
|
||||
|
||||
cb: ->
|
||||
@set 'ready', yes
|
||||
|
||||
onrender: ->
|
||||
document.title = 'Burnchart: GitHub Burndown Chart as a Service'
|
||||
|
||||
# Quit if we have no projects.
|
||||
return do @cb unless projects.list.length
|
||||
|
||||
# ---
|
||||
|
||||
done = do system.async
|
||||
|
||||
# For all projects.
|
||||
async.map projects.data.list, (project, cb) ->
|
||||
# Fetch their milestones.
|
||||
milestones.fetchAll project, (err, list) ->
|
||||
# Save the error if project does not exist.
|
||||
if err
|
||||
projects.saveError project, err
|
||||
return do cb
|
||||
|
||||
# Now add in the issues.
|
||||
async.each list, (milestone, cb) ->
|
||||
# Do we have this milestone already?
|
||||
return cb null if _.find project.milestones, ({ number }) ->
|
||||
milestone.number is number
|
||||
|
||||
# OK fetch all the issues for this milestone then.
|
||||
issues.fetchAll
|
||||
'owner': project.owner
|
||||
'name': project.name
|
||||
'milestone': milestone.number
|
||||
, (err, obj) ->
|
||||
# Save any errors on the project.
|
||||
if err
|
||||
projects.saveError project, err
|
||||
return do cb
|
||||
|
||||
# Add in the issues to the milestone.
|
||||
_.extend milestone, { 'issues': obj }
|
||||
# Save the milestone.
|
||||
projects.addMilestone project, milestone
|
||||
# Done
|
||||
do cb
|
||||
|
||||
, cb
|
||||
|
||||
, =>
|
||||
do done
|
||||
do @cb
|
100
src/views/pages/milestone.coffee
Normal file
@ -0,0 +1,100 @@
|
||||
_ = require 'lodash'
|
||||
async = require 'async'
|
||||
|
||||
Chart = require '../chart.coffee'
|
||||
|
||||
Eventful = require '../../utils/ractive/eventful.coffee'
|
||||
projects = require '../../models/projects.coffee'
|
||||
system = require '../../models/system.coffee'
|
||||
milestones = require '../../modules/github/milestones.coffee'
|
||||
issues = require '../../modules/github/issues.coffee'
|
||||
format = require '../../utils/format.coffee'
|
||||
|
||||
module.exports = Eventful.extend
|
||||
|
||||
'name': 'views/pages/chart'
|
||||
|
||||
'template': require '../../templates/pages/milestone.html'
|
||||
|
||||
'components': { Chart }
|
||||
|
||||
'data':
|
||||
'format': format
|
||||
'ready': no
|
||||
|
||||
# Callback when we have data.
|
||||
cb: (err, data) ->
|
||||
return @publish '!app/notify', {
|
||||
'text': do err.toString
|
||||
'type': 'alert'
|
||||
'system': yes
|
||||
'ttl': null
|
||||
} if err
|
||||
|
||||
# No issues?
|
||||
return @publish '!app/notify', {
|
||||
'text': 'The milestone has no issues'
|
||||
'type': 'warn'
|
||||
'system': yes
|
||||
'ttl': null
|
||||
} if data.stats.isEmpty
|
||||
|
||||
# Done?
|
||||
@publish '!app/notify', {
|
||||
'text': 'The milestone is complete'
|
||||
'type': 'success'
|
||||
} if data.stats.isDone
|
||||
|
||||
# Overdue?
|
||||
@publish '!app/notify', {
|
||||
'text': 'The milestone is overdue'
|
||||
'type': 'warn'
|
||||
} if data.stats.isOverdue
|
||||
|
||||
# Show the page.
|
||||
@set
|
||||
'milestone': data
|
||||
'ready': yes
|
||||
|
||||
onrender: ->
|
||||
[ owner, name, milestone ] = @get 'route'
|
||||
|
||||
milestone = parseInt milestone
|
||||
|
||||
document.title = "#{owner}/#{name}/#{milestone}"
|
||||
|
||||
# Get the associated project.
|
||||
project = projects.find { owner, name }
|
||||
|
||||
# Should not happen...
|
||||
return @cb 'Project not found' unless project
|
||||
|
||||
# Do we have this milestone already?
|
||||
data = _.find project.milestones, { 'number': milestone }
|
||||
return @cb null, data if data?
|
||||
|
||||
# ---
|
||||
|
||||
# We are loading the milestones then.
|
||||
done = do system.async
|
||||
|
||||
fetchMilestone = (cb) ->
|
||||
milestones.fetch { owner, name, milestone }, cb
|
||||
|
||||
fetchIssues = (data, cb) ->
|
||||
issues.fetchAll { owner, name, milestone }, (err, obj) ->
|
||||
cb err, _.extend data, { 'issues': obj }
|
||||
|
||||
async.waterfall [
|
||||
# Get the milestone.
|
||||
fetchMilestone,
|
||||
# Then all its issues.
|
||||
fetchIssues
|
||||
], (err, data) =>
|
||||
do done
|
||||
|
||||
# Save the milestone with issues.
|
||||
projects.addMilestone project, data unless err
|
||||
|
||||
# Pass to callback.
|
||||
@cb.apply @, arguments
|
50
src/views/pages/new.coffee
Normal file
@ -0,0 +1,50 @@
|
||||
_ = require 'lodash'
|
||||
Ractive = require 'ractive'
|
||||
|
||||
Eventful = require '../../utils/ractive/eventful.coffee'
|
||||
firebase = require '../../models/firebase.coffee'
|
||||
system = require '../../models/system.coffee'
|
||||
user = require '../../models/user.coffee'
|
||||
key = require '../../utils/key.coffee'
|
||||
|
||||
module.exports = Eventful.extend
|
||||
|
||||
'name': 'views/pages/new'
|
||||
|
||||
'template': require '../../templates/pages/new.html'
|
||||
|
||||
'data': { 'value': 'radekstepan/disposable', user }
|
||||
|
||||
'adapt': [ Ractive.adaptors.Ractive ]
|
||||
|
||||
# Listen to Enter keypress or Submit button click.
|
||||
submit: (evt, value) ->
|
||||
return if key.is(evt) and not key.isEnter(evt)
|
||||
|
||||
[ owner, name ] = value.split '/'
|
||||
|
||||
# Save repo.
|
||||
@publish '!projects/add', { owner, name }
|
||||
|
||||
# Redirect to the dashboard.
|
||||
# TODO: trigger a named route
|
||||
window.location.hash = '#'
|
||||
|
||||
onconstruct: ->
|
||||
# Login user.
|
||||
@on '!login', ->
|
||||
do firebase.login
|
||||
|
||||
onrender: ->
|
||||
document.title = 'Add a new project'
|
||||
|
||||
# TODO: autocomplete on our username if we are logged in or based
|
||||
# on repos we already have.
|
||||
autocomplete = (value) ->
|
||||
|
||||
@observe 'value', _.debounce(autocomplete, 200), { 'init': no }
|
||||
|
||||
# Focus on the input field.
|
||||
do @el.querySelector('input').focus
|
||||
|
||||
@on 'submit', @submit
|
82
src/views/pages/project.coffee
Normal file
@ -0,0 +1,82 @@
|
||||
_ = require 'lodash'
|
||||
async = require 'async'
|
||||
|
||||
Milestones = require '../tables/milestones.coffee'
|
||||
|
||||
Eventful = require '../../utils/ractive/eventful.coffee'
|
||||
projects = require '../../models/projects.coffee'
|
||||
system = require '../../models/system.coffee'
|
||||
milestones = require '../../modules/github/milestones.coffee'
|
||||
issues = require '../../modules/github/issues.coffee'
|
||||
|
||||
module.exports = Eventful.extend
|
||||
|
||||
'name': 'views/pages/project'
|
||||
|
||||
'template': require '../../templates/pages/project.html'
|
||||
|
||||
'components': { Milestones }
|
||||
|
||||
'data':
|
||||
'projects': projects
|
||||
'ready': no
|
||||
|
||||
cb: (err) ->
|
||||
return @publish '!app/notify', {
|
||||
'text': do err.toString
|
||||
'type': 'alert'
|
||||
'system': yes
|
||||
'ttl': null
|
||||
} if err
|
||||
|
||||
# Say we are ready.
|
||||
@set 'ready', yes
|
||||
|
||||
onrender: ->
|
||||
[ owner, name ] = @get 'route'
|
||||
|
||||
document.title = "#{owner}/#{name}"
|
||||
|
||||
# Get the associated project.
|
||||
@set 'project', project = projects.find { owner, name }
|
||||
|
||||
# Should not happen...
|
||||
return @cb 'Project not found' unless project
|
||||
|
||||
# ---
|
||||
|
||||
# We don't know if we have all milestones, so fetch them.
|
||||
done = do system.async
|
||||
|
||||
findMilestone = (number) ->
|
||||
_.find project.milestones or [], { number }
|
||||
|
||||
fetchMilestones = (cb) ->
|
||||
milestones.fetchAll project, cb
|
||||
|
||||
fetchIssues = (allMilestones, cb) ->
|
||||
return cb 'The project has no milestones' unless allMilestones.length
|
||||
|
||||
async.each allMilestones, (milestone, cb) ->
|
||||
# Maybe we have this milestone already?
|
||||
return cb null if findMilestone milestone.number
|
||||
# Need to fetch the issues then.
|
||||
issues.fetchAll { owner, name, 'milestone': milestone.number }, (err, obj) ->
|
||||
return cb err if err
|
||||
# Save the milestone with issues.
|
||||
projects.addMilestone project, _.extend milestone, { 'issues': obj }
|
||||
# Next.
|
||||
do cb
|
||||
, cb
|
||||
|
||||
# Run it.
|
||||
async.waterfall [
|
||||
# First get all the milestones.
|
||||
fetchMilestones,
|
||||
# Then all the issues per milestone.
|
||||
fetchIssues
|
||||
], (err) =>
|
||||
do done
|
||||
|
||||
# Pass to callback.
|
||||
@cb.apply @, arguments
|
7
src/views/tables/milestones.coffee
Normal file
@ -0,0 +1,7 @@
|
||||
Table = require './table.coffee'
|
||||
|
||||
module.exports = Table.extend
|
||||
|
||||
'name': 'views/milestones'
|
||||
|
||||
'template': require '../../templates/tables/milestones.html'
|
7
src/views/tables/projects.coffee
Normal file
@ -0,0 +1,7 @@
|
||||
Table = require './table.coffee'
|
||||
|
||||
module.exports = Table.extend
|
||||
|
||||
'name': 'views/projects'
|
||||
|
||||
'template': require '../../templates/tables/projects.html'
|
25
src/views/tables/table.coffee
Normal file
@ -0,0 +1,25 @@
|
||||
Ractive = require 'ractive'
|
||||
|
||||
format = require '../../utils/format.coffee'
|
||||
Icons = require '../icons.coffee'
|
||||
projects = require '../../models/projects.coffee'
|
||||
|
||||
module.exports = Ractive.extend
|
||||
|
||||
'name': 'views/table'
|
||||
|
||||
'data': { format }
|
||||
|
||||
'components': { Icons }
|
||||
|
||||
'adapt': [ Ractive.adaptors.Ractive ]
|
||||
|
||||
onconstruct: ->
|
||||
# Change sort order.
|
||||
@on 'sortBy', ->
|
||||
fns = projects.data.sortFns
|
||||
|
||||
idx = 1 + fns.indexOf projects.data.sortBy
|
||||
idx = 0 if idx is fns.length
|
||||
|
||||
projects.set 'sortBy', fns[idx]
|
196
test/issues.coffee.bak
Normal file
@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env coffee
|
||||
proxy = do require('proxyquire').noCallThru
|
||||
assert = require 'assert'
|
||||
path = require 'path'
|
||||
|
||||
req = {}
|
||||
|
||||
regex = require path.resolve(__dirname, '../src/modules/regex.coffee')
|
||||
|
||||
issues = proxy path.resolve(__dirname, '../src/modules/issues.coffee'),
|
||||
'./request': req
|
||||
'./require':
|
||||
'_': require 'lodash'
|
||||
'superagent': null
|
||||
'd3': null
|
||||
'async': require 'async'
|
||||
'marked': null
|
||||
|
||||
repo = { 'milestone': { 'number': no } }
|
||||
|
||||
module.exports =
|
||||
|
||||
'issues - all empty': (done) ->
|
||||
called = 0
|
||||
req.all_issues = (repo, opts, cb) ->
|
||||
called += 1
|
||||
cb null, []
|
||||
|
||||
issues.get_all repo, (err, [ open, closed ]) ->
|
||||
assert.ifError err
|
||||
assert.equal called, 2
|
||||
assert.equal open.length, 0
|
||||
assert.equal closed.length, 0
|
||||
do done
|
||||
|
||||
'issues - open empty': (done) ->
|
||||
called = 0
|
||||
req.all_issues = (repo, opts, cb) ->
|
||||
called += 1
|
||||
cb null, if called is 1 then [] else [
|
||||
{ number: 1 }
|
||||
]
|
||||
|
||||
issues.get_all repo, (err, [ open, closed ]) ->
|
||||
assert.ifError err
|
||||
assert.equal called, 2
|
||||
assert.equal open.length, 0
|
||||
assert.equal closed.length, 1
|
||||
do done
|
||||
|
||||
'issues - closed empty': (done) ->
|
||||
called = 0
|
||||
req.all_issues = (repo, opts, cb) ->
|
||||
called += 1
|
||||
cb null, if called is 2 then [] else [
|
||||
{ number: 1 }
|
||||
]
|
||||
|
||||
issues.get_all repo, (err, [ open, closed ]) ->
|
||||
assert.ifError err
|
||||
assert.equal called, 2
|
||||
assert.equal open.length, 1
|
||||
assert.equal closed.length, 0
|
||||
do done
|
||||
|
||||
'issues - both not empty': (done) ->
|
||||
called = 0
|
||||
req.all_issues = (repo, opts, cb) ->
|
||||
called += 1
|
||||
cb null, [ { number: 1 } ]
|
||||
|
||||
issues.get_all repo, (err, [ open, closed ]) ->
|
||||
assert.ifError err
|
||||
assert.equal called, 2
|
||||
assert.equal open.length, 1
|
||||
assert.equal closed.length, 1
|
||||
do done
|
||||
|
||||
'issues - 99 results on a page': (done) ->
|
||||
called = 0
|
||||
req.all_issues = (repo, opts, cb) ->
|
||||
called += 1
|
||||
cb null, ( { number: i } for i in [ 0...99 ] )
|
||||
|
||||
issues.get_all repo, (err, [ open, closed ]) ->
|
||||
assert.ifError err
|
||||
assert.equal called, 2
|
||||
assert.equal open.length, 99
|
||||
assert.equal closed.length, 99
|
||||
do done
|
||||
|
||||
'issues - 100 results on a page': (done) ->
|
||||
called = 0
|
||||
req.all_issues = (repo, opts, cb) ->
|
||||
called += 1
|
||||
assert opts.page in [ 1, 2 ]
|
||||
cb null, if opts.page is 1 then ( { number: i } for i in [ 0...100 ] ) else []
|
||||
|
||||
issues.get_all repo, (err, [ open, closed ]) ->
|
||||
assert.ifError err
|
||||
assert.equal called, 4
|
||||
assert.equal open.length, 100
|
||||
assert.equal closed.length, 100
|
||||
do done
|
||||
|
||||
'issues - 101 total results': (done) ->
|
||||
called = 0
|
||||
req.all_issues = (repo, opts, cb) ->
|
||||
called += 1
|
||||
assert opts.page in [ 1, 2 ]
|
||||
cb null, if opts.page is 1
|
||||
( { number: i } for i in [ 0...100 ] )
|
||||
else
|
||||
[ { number: 100 } ]
|
||||
|
||||
issues.get_all repo, (err, [ open, closed ]) ->
|
||||
assert.ifError err
|
||||
assert.equal called, 4
|
||||
assert.equal open.length, 101
|
||||
assert.equal closed.length, 101
|
||||
assert.deepEqual open[100], { number: 100 }
|
||||
assert.deepEqual closed[100], { number: 100 }
|
||||
do done
|
||||
|
||||
'issues - 201 total results': (done) ->
|
||||
called = 0
|
||||
req.all_issues = (repo, opts, cb) ->
|
||||
called += 1
|
||||
assert opts.page in [ 1, 2, 3 ]
|
||||
cb null, if opts.page in [ 1, 2 ]
|
||||
( { number: i } for i in [ (h = 100 * (opts.page - 1))...h + 100 ] )
|
||||
else
|
||||
[ { number: 200 } ]
|
||||
|
||||
issues.get_all repo, (err, [ open, closed ]) ->
|
||||
assert.ifError err
|
||||
assert.equal called, 6
|
||||
assert.equal open.length, 201
|
||||
assert.equal closed.length, 201
|
||||
for i in [ open, closed ]
|
||||
for j in [ 100, 200 ]
|
||||
assert.deepEqual i[j], { number: j }
|
||||
do done
|
||||
|
||||
'issues - get all when not found': (done) ->
|
||||
called = 0
|
||||
req.all_issues = (repo, opts, cb) ->
|
||||
called += 1
|
||||
cb 'Not Found'
|
||||
|
||||
issues.get_all repo, (err, [ open, closed ]) ->
|
||||
assert.equal err, 'Not Found'
|
||||
assert.equal called, 1
|
||||
do done
|
||||
|
||||
'issues - filter on existing label regex': (done) ->
|
||||
issues.filter [ { labels: [ { name: 'size 15' } ] } ]
|
||||
, regex.size_label, (err, data) ->
|
||||
assert.ifError err
|
||||
assert.equal data.length, 1
|
||||
assert.equal data[0].size, 15
|
||||
do done
|
||||
|
||||
'issues - filter when no labels': (done) ->
|
||||
issues.filter [ { } ]
|
||||
, regex.size_label, (err, data) ->
|
||||
assert.ifError err
|
||||
assert.equal data.length, 0
|
||||
do done
|
||||
|
||||
'issues - filter when empty labels': (done) ->
|
||||
issues.filter [ { labels: [] } ]
|
||||
, regex.size_label, (err, data) ->
|
||||
assert.ifError err
|
||||
assert.equal data.length, 0
|
||||
do done
|
||||
|
||||
'issues - filter when not matching regex': (done) ->
|
||||
issues.filter [ { labels: [ { name: 'size 1A' } ] } ]
|
||||
, regex.size_label, (err, data) ->
|
||||
assert.ifError err
|
||||
assert.equal data.length, 0
|
||||
do done
|
||||
|
||||
'issues - filter when multiple match the regex': (done) ->
|
||||
issues.filter [
|
||||
{ labels: [ { name: 'size 1' }, { name: 'size 6' } ] }
|
||||
{ labels: [ { name: 'size really big' }, { name: 'size 4' } ] }
|
||||
]
|
||||
, regex.size_label, (err, data) ->
|
||||
assert.ifError err
|
||||
assert.equal data.length, 2
|
||||
[ a, b ] = data
|
||||
assert.equal a.size, 7
|
||||
assert.equal b.size, 4
|
||||
do done
|
188
test/milestones.coffee.bak
Normal file
@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env coffee
|
||||
proxy = do require('proxyquire').noCallThru
|
||||
assert = require 'assert'
|
||||
path = require 'path'
|
||||
|
||||
req = {}
|
||||
|
||||
milestones = proxy path.resolve(__dirname, '../src/modules/milestones.coffee'),
|
||||
'./request': req
|
||||
'./require':
|
||||
'_': require 'lodash'
|
||||
'superagent': null
|
||||
'd3': null
|
||||
'async': null
|
||||
'marked': require 'marked'
|
||||
|
||||
module.exports =
|
||||
|
||||
'milestones - get current from 1': (done) ->
|
||||
req.all_milestones = (opts, cb) ->
|
||||
cb null, [
|
||||
{
|
||||
'number': 1
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': '2013-02-01T00:00:00Z'
|
||||
}
|
||||
]
|
||||
|
||||
milestones {}, (err, warn, milestone) ->
|
||||
assert.ifError err
|
||||
assert.equal milestone.number, 1
|
||||
do done
|
||||
|
||||
'milestones - get current from 1 when milestone has no due date': (done) ->
|
||||
req.all_milestones = (opts, cb) ->
|
||||
cb null, [
|
||||
{
|
||||
'number': 1
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': null
|
||||
}
|
||||
]
|
||||
|
||||
milestones {}, (err, warn, milestone) ->
|
||||
assert.ifError err
|
||||
assert.equal milestone.number, 1
|
||||
do done
|
||||
|
||||
# We always take from head because of request params.
|
||||
'milestones - get current from > 1': (done) ->
|
||||
req.all_milestones = (opts, cb) ->
|
||||
cb null, [
|
||||
{
|
||||
'number': 2
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': '2013-01-15T00:00:00Z'
|
||||
}
|
||||
{
|
||||
'number': 1
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': '2013-02-01T00:00:00Z'
|
||||
}
|
||||
{
|
||||
'number': 3
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': '2013-02-15T00:00:00Z'
|
||||
}
|
||||
]
|
||||
|
||||
milestones {}, (err, warn, milestone) ->
|
||||
assert.ifError err
|
||||
assert.equal milestone.number, 2
|
||||
do done
|
||||
|
||||
'milestones - get current from > 1 when there are milestones without due date': (done) ->
|
||||
req.all_milestones = (opts, cb) ->
|
||||
cb null, [
|
||||
{
|
||||
'number': 2
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': null
|
||||
}
|
||||
{
|
||||
'number': 1
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': '2013-02-01T00:00:00Z'
|
||||
}
|
||||
{
|
||||
'number': 3
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': '2013-02-15T00:00:00Z'
|
||||
}
|
||||
]
|
||||
|
||||
milestones {}, (err, warn, milestone) ->
|
||||
assert.ifError err
|
||||
assert.equal milestone.number, 1
|
||||
do done
|
||||
|
||||
'milestones - get current when empty': (done) ->
|
||||
req.all_milestones = (opts, cb) ->
|
||||
cb null, []
|
||||
|
||||
milestones { 'path': 'some/repo' }, (err, warn, milestone) ->
|
||||
assert.ifError err
|
||||
assert.equal warn, 'No open milestones for repo some/repo'
|
||||
do done
|
||||
|
||||
'milestones - get current when not found': (done) ->
|
||||
req.all_milestones = (opts, cb) ->
|
||||
cb 'Not Found'
|
||||
|
||||
milestones {}, (err, warn, milestone) ->
|
||||
assert.equal err, 'Not Found'
|
||||
do done
|
||||
|
||||
'milestones - get current when no issues': (done) ->
|
||||
req.all_milestones = (opts, cb) ->
|
||||
cb null, [
|
||||
{
|
||||
'title': 'No issues'
|
||||
'number': 1
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': '2013-02-01T00:00:00Z',
|
||||
'open_issues': 0,
|
||||
'closed_issues': 0
|
||||
}
|
||||
]
|
||||
|
||||
milestones {}, (err, warn, milestone) ->
|
||||
assert.ifError err
|
||||
assert.equal warn, 'No issues for milestone `No issues`'
|
||||
do done
|
||||
|
||||
'milestones - get one': (done) ->
|
||||
m =
|
||||
'number': 1
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': '2013-02-01T00:00:00Z'
|
||||
|
||||
req.one_milestone = (opts, number, cb) ->
|
||||
cb null, m
|
||||
|
||||
milestones { 'milestone': 1 }, (err, warn, milestone) ->
|
||||
assert.ifError err
|
||||
assert.equal warn, null
|
||||
assert.deepEqual milestone, m
|
||||
do done
|
||||
|
||||
'milestones - get one (404)': (done) ->
|
||||
req.one_milestone = (opts, number, cb) ->
|
||||
cb 'Not Found'
|
||||
|
||||
milestones { 'milestone': 9 }, (err, warn, milestone) ->
|
||||
assert.equal err, 'Not Found'
|
||||
do done
|
||||
|
||||
'milestones - get one when no issues': (done) ->
|
||||
req.one_milestone = (opts, number, cb) ->
|
||||
cb null, {
|
||||
'title': 'No issues'
|
||||
'number': 1
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': '2013-02-01T00:00:00Z',
|
||||
'open_issues': 0,
|
||||
'closed_issues': 0
|
||||
}
|
||||
|
||||
milestones { 'milestone': 9 }, (err, warn, milestone) ->
|
||||
assert.ifError err
|
||||
assert.equal warn, 'No issues for milestone `No issues`'
|
||||
do done
|
||||
|
||||
'milestones - has description': (done) ->
|
||||
req.all_milestones = (opts, cb) ->
|
||||
cb null, [
|
||||
{
|
||||
'number': 1
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': '2013-02-01T00:00:00Z'
|
||||
'description': 'A description of this <strong>milestone</strong> goes *here*'
|
||||
}
|
||||
]
|
||||
|
||||
milestones {}, (err, warn, milestone) ->
|
||||
assert.ifError err
|
||||
assert.equal milestone.description, 'A description of this <strong>milestone</strong> goes <em>here</em>'
|
||||
do done
|
108
test/request.coffee.bak
Normal file
@ -0,0 +1,108 @@
|
||||
proxy = do require('proxyquire').noCallThru
|
||||
assert = require 'assert'
|
||||
path = require 'path'
|
||||
|
||||
class Sa
|
||||
|
||||
# How soon do we call back?
|
||||
timeout: 1
|
||||
|
||||
# Save the uri.
|
||||
get: (uri) ->
|
||||
@params = { uri }
|
||||
@
|
||||
|
||||
# Save the key-value pair.
|
||||
set: (key, value) ->
|
||||
@params[key] = value
|
||||
@
|
||||
|
||||
# Call back with the response.
|
||||
end: (cb) ->
|
||||
setTimeout =>
|
||||
cb null, @response
|
||||
, @timeout
|
||||
|
||||
request = proxy path.resolve(__dirname, '../src/modules/github/request.coffee'),
|
||||
'../vendor.coffee':
|
||||
'superagent': new Sa()
|
||||
|
||||
module.exports =
|
||||
|
||||
'request - all milestones (ok)': (done) ->
|
||||
sa.response =
|
||||
'statusType': 2
|
||||
'error': no
|
||||
'body': [ null ]
|
||||
|
||||
request.allMilestones {}, (err, data) ->
|
||||
assert.ifError err
|
||||
assert.deepEqual sa.params,
|
||||
'uri': 'undefined://undefined/repos/undefined/milestones?state=open&sort=due_date&direction=asc'
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/vnd.github.v3'
|
||||
assert.deepEqual data, [ null ]
|
||||
do done
|
||||
|
||||
'request - one milestone (ok)': (done) ->
|
||||
sa.response =
|
||||
'statusType': 2
|
||||
'error': no
|
||||
'body': [ null ]
|
||||
|
||||
request.oneMilestone {}, 1, (err, data) ->
|
||||
assert.ifError err
|
||||
assert.deepEqual sa.params,
|
||||
'uri': 'undefined://undefined/repos/undefined/milestones/1?state=open&sort=due_date&direction=asc'
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/vnd.github.v3'
|
||||
assert.deepEqual data, [ null ]
|
||||
do done
|
||||
|
||||
'request - one milestone (404)': (done) ->
|
||||
sa.response =
|
||||
'statusType': 4
|
||||
'error': Error "cannot GET undefined (404)"
|
||||
'body':
|
||||
'documentation_url': "http://developer.github.com/v3"
|
||||
'message': "Not Found"
|
||||
|
||||
request.oneMilestone {}, 9, (err) ->
|
||||
assert.equal err, 'Not Found'
|
||||
do done
|
||||
|
||||
'request - one milestone (500)': (done) ->
|
||||
sa.response =
|
||||
'statusType': 5
|
||||
'error': Error "Error"
|
||||
'body': null
|
||||
|
||||
request.oneMilestone {}, 9, (err) ->
|
||||
assert.equal err, 'Error'
|
||||
do done
|
||||
|
||||
'request - all issues (ok)': (done) ->
|
||||
sa.response =
|
||||
'statusType': 2
|
||||
'error': no
|
||||
'body': [ null ]
|
||||
|
||||
request.allIssues {}, {}, (err, data) ->
|
||||
assert.ifError err
|
||||
assert.deepEqual sa.params,
|
||||
'uri': 'undefined://undefined/repos/undefined/issues?per_page=100'
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/vnd.github.v3'
|
||||
assert.deepEqual data, [ null ]
|
||||
do done
|
||||
|
||||
'request - timeout': (done) ->
|
||||
sa.timeout = 10001
|
||||
sa.response =
|
||||
'statusType': 2
|
||||
'error': no
|
||||
'body': [ null ]
|
||||
|
||||
request.allIssues {}, {}, (err) ->
|
||||
assert.equal err, 'Request has timed out'
|
||||
do done
|