Compare commits
No commits in common. "v2-dev" and "v1.0.0" have entirely different histories.
6
.gitignore
vendored
|
|
@ -1,6 +0,0 @@
|
||||||
deploy.sh
|
|
||||||
deploy-excludes
|
|
||||||
composer.lock
|
|
||||||
.idea
|
|
||||||
vendor
|
|
||||||
cache/*
|
|
||||||
26
README.md
|
|
@ -1,25 +1,3 @@
|
||||||
# Subcon Town Frontpage
|
# subcon.town
|
||||||
|
|
||||||
This project contains the complete code and assets used by the Subcon Town frontpage.
|
The subcon.town frontpage.
|
||||||
|
|
||||||
## Licensing
|
|
||||||
|
|
||||||
All code is licensed under the BOML-1.0.0 license (Blue Oak Model License).
|
|
||||||
See the LICENSE file for more details.
|
|
||||||
|
|
||||||
The "Subcon Town" branding and its associated assets (located in public_html/assets/subcon)
|
|
||||||
are licensed under the Creative Commons BY-NC-ND license. You may share and redistribute
|
|
||||||
these works, but please do not edit them or use them for commercial purposes. For more
|
|
||||||
details, read the LICENSE file in public_html/assets/subcon.
|
|
||||||
|
|
||||||
### Third party works
|
|
||||||
|
|
||||||
The fonts and background image used on subcon.town are not owned by Subcon Town. Subcon
|
|
||||||
Town does not claim any rights to these original works unless otherwise specified by their
|
|
||||||
respective licensing.
|
|
||||||
|
|
||||||
### Complains
|
|
||||||
|
|
||||||
If you feel any material is incorrectly used in this project, or otherwise infringes on
|
|
||||||
your rights, please file a complaint with fristi@subcon.town. Please allow up to 48 hours
|
|
||||||
for a response.
|
|
||||||
BIN
assets/background1.jpg
Normal file
|
After Width: | Height: | Size: 470 KiB |
BIN
assets/baloo_thambi_2/BalooThambi2-Bold.ttf
Normal file
BIN
assets/baloo_thambi_2/BalooThambi2-Medium.ttf
Normal file
93
assets/baloo_thambi_2/OFL.txt
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright (c) 2015 Ek Type (www.ektype.in)
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
BIN
assets/duck_hunt/duckhunt.eot
Normal file
532
assets/duck_hunt/duckhunt.svg
Normal file
|
|
@ -0,0 +1,532 @@
|
||||||
|
<?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>
|
||||||
|
<metadata>
|
||||||
|
Created by FontForge 20110222 at Mon Mar 7 13:22:36 2011
|
||||||
|
By www-data
|
||||||
|
Copyright (c) Joseph Spicer, 2004. All rights reserved.
|
||||||
|
</metadata>
|
||||||
|
<defs>
|
||||||
|
<font id="DuckHunt" horiz-adv-x="629" >
|
||||||
|
<font-face
|
||||||
|
font-family="Duck Hunt"
|
||||||
|
font-weight="400"
|
||||||
|
font-stretch="normal"
|
||||||
|
units-per-em="1000"
|
||||||
|
panose-1="2 11 0 0 0 0 0 0 0 0"
|
||||||
|
ascent="800"
|
||||||
|
descent="-200"
|
||||||
|
x-height="559"
|
||||||
|
cap-height="699"
|
||||||
|
bbox="18 -200 1062 800.09"
|
||||||
|
underline-thickness="50"
|
||||||
|
underline-position="-50"
|
||||||
|
unicode-range="U+0020-2122"
|
||||||
|
/>
|
||||||
|
<missing-glyph />
|
||||||
|
<glyph glyph-name="space" unicode=" "
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="space" unicode=" "
|
||||||
|
/>
|
||||||
|
<glyph glyph-name="H" unicode="H"
|
||||||
|
d="M310 0h-280v699h280v-206h152v206h137v-699h-137v277h-152v-277z" />
|
||||||
|
<glyph glyph-name="N" unicode="N"
|
||||||
|
d="M310 0h-280v699h280v-131q23 0 47 -8.5t44.5 -23t36.5 -35t24 -44.5v242h137v-699h-137v91q0 70 -18 109t-42.5 57.5t-50 22.5t-41.5 4v-284z" />
|
||||||
|
<glyph glyph-name="T" unicode="T"
|
||||||
|
d="M457 0h-280v550h-147v149h569v-149h-142v-550z" />
|
||||||
|
<glyph glyph-name="I" unicode="I"
|
||||||
|
d="M599 149v-149h-569v149h147v401h-147v149h569v-149h-142v-401h142z" />
|
||||||
|
<glyph glyph-name="L" unicode="L"
|
||||||
|
d="M310 286h289v-286h-569v699h280v-413z" />
|
||||||
|
<glyph glyph-name="O" unicode="O"
|
||||||
|
d="M30 570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-437q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v437zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5t-22 106t-54 33t-54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="A" unicode="A"
|
||||||
|
d="M462 0v252h-152v-252h-280v570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-570h-137zM462 424q0 73 -22 106t-54 33t-54 -33t-22 -106v-16h152v16z" />
|
||||||
|
<glyph glyph-name="P" unicode="P"
|
||||||
|
d="M310 424q0 -73 22 -106t54 -33t54 33t22 106t-22 106t-54 33t-54 -33t-22 -106zM310 149v-149h-280v699h434q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-292q0 -36 -12 -60.5t-31.5 -40t-43.5 -22t-48 -6.5h-154z" />
|
||||||
|
<glyph glyph-name="J" unicode="J"
|
||||||
|
d="M319 699h280v-566q0 -60 -38 -96.5t-110 -36.5h-421v286h213q32 0 54 32.5t22 105.5v275z" />
|
||||||
|
<glyph glyph-name="one" unicode="1"
|
||||||
|
d="M599 149v-149h-569v149h147v401l-147 -50v149l147 50h280v-550h142z" />
|
||||||
|
<glyph glyph-name="zero" unicode="0"
|
||||||
|
d="M30 570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-437q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v437zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5t-22 106t-54 33t-54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="Z" unicode="Z"
|
||||||
|
d="M599 149v-149h-569v149l289 401h-289v149h569v-149l-289 -401h289z" />
|
||||||
|
<glyph glyph-name="F" unicode="F"
|
||||||
|
d="M599 418v-136h-289v-282h-280v699h569v-136h-289v-145h289z" />
|
||||||
|
<glyph glyph-name="a" unicode="a" horiz-adv-x="503"
|
||||||
|
d="M370 0v202h-122v-202h-224v456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-456h-109zM370 339q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85v-13h122v13z" />
|
||||||
|
<glyph glyph-name="c" unicode="c" horiz-adv-x="503"
|
||||||
|
d="M248 339q0 -58 17.5 -84t43.5 -26q22 0 38.5 20t20.5 65h111v-208q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v350q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-92h-111q-4 45 -20.5 65.5t-38.5 20.5
|
||||||
|
q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="d" unicode="d" horiz-adv-x="503"
|
||||||
|
d="M24 559h347q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-350q0 -48 -30 -77t-88 -29h-337v559zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="f" unicode="f" horiz-adv-x="503"
|
||||||
|
d="M479 334v-108h-231v-226h-224v559h455v-109h-231v-116h231z" />
|
||||||
|
<glyph glyph-name="h" unicode="h" horiz-adv-x="503"
|
||||||
|
d="M248 0h-224v559h224v-165h122v165h109v-559h-109v222h-122v-222z" />
|
||||||
|
<glyph glyph-name="i" unicode="i" horiz-adv-x="503"
|
||||||
|
d="M479 119v-119h-455v119h118v321h-118v119h455v-119h-113v-321h113z" />
|
||||||
|
<glyph glyph-name="j" unicode="j" horiz-adv-x="503"
|
||||||
|
d="M255 559h224v-453q0 -48 -30 -77t-88 -29h-337v229h170q26 0 43.5 26t17.5 84v220z" />
|
||||||
|
<glyph glyph-name="k" unicode="k" horiz-adv-x="503"
|
||||||
|
d="M248 0h-224v559h224v-223q16 0 37 4.5t40 20.5t32 45.5t13 79.5v73h109v-85q0 -60 -19 -89.5t-58 -48.5q33 -12 55 -41t22 -80v-215h-109v73q0 56 -12 87t-30 46t-39.5 18t-40.5 3v-227z" />
|
||||||
|
<glyph glyph-name="l" unicode="l" horiz-adv-x="503"
|
||||||
|
d="M248 229h231v-229h-455v559h224v-330z" />
|
||||||
|
<glyph glyph-name="n" unicode="n" horiz-adv-x="503"
|
||||||
|
d="M248 0h-224v559h224v-105q19 0 38 -6.5t35.5 -18.5t29.5 -28t19 -35v193h109v-559h-109v73q0 56 -14.5 87t-34 46t-40 18t-33.5 3v-227z" />
|
||||||
|
<glyph glyph-name="o" unicode="o" horiz-adv-x="503"
|
||||||
|
d="M24 456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-350q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v350zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="p" unicode="p" horiz-adv-x="503"
|
||||||
|
d="M248 339q0 -58 17.5 -84.5t43.5 -26.5q25 0 43 26.5t18 84.5q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85zM248 119v-119h-224v559h347q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-234q0 -28 -9.5 -48t-25 -32t-35 -17.5t-38.5 -5.5h-123z" />
|
||||||
|
<glyph glyph-name="t" unicode="t" horiz-adv-x="503"
|
||||||
|
d="M366 0h-224v440h-118v119h455v-119h-113v-440z" />
|
||||||
|
<glyph glyph-name="u" unicode="u" horiz-adv-x="503"
|
||||||
|
d="M248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84v220h109v-453q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v453h224v-220z" />
|
||||||
|
<glyph glyph-name="z" unicode="z" horiz-adv-x="503"
|
||||||
|
d="M479 119v-119h-455v119l231 321h-231v119h455v-119l-231 -321h231z" />
|
||||||
|
<glyph glyph-name="E" unicode="E"
|
||||||
|
d="M599 136v-136h-569v699h569v-136h-289v-145h289v-136h-289v-146h289z" />
|
||||||
|
<glyph glyph-name="e" unicode="e" horiz-adv-x="503"
|
||||||
|
d="M479 109v-109h-455v559h455v-109h-231v-116h231v-108h-231v-117h231z" />
|
||||||
|
<glyph glyph-name="X" unicode="X"
|
||||||
|
d="M410 0l-95 175l-95 -175h-190l190 350l-189 349h190l94 -174l94 174h190l-189 -349l190 -350h-190z" />
|
||||||
|
<glyph glyph-name="x" unicode="x" horiz-adv-x="503"
|
||||||
|
d="M328 0l-76 140l-76 -140h-152l152 280l-151 279h152l75 -139l75 139h152l-151 -279l152 -280h-152z" />
|
||||||
|
<glyph glyph-name="R" unicode="R"
|
||||||
|
d="M310 0h-280v699h434q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-182q0 -55 -26.5 -84t-62.5 -39q17 -4 33 -19.5t28.5 -37t20 -47.5t7.5 -52v-109h-137v61q0 55 -18 88t-42.5 51t-50 23.5t-41.5 5.5v-229zM310 464q0 -51 22 -75t54 -24t54 24t22 75t-22 75t-54 24
|
||||||
|
t-54 -24t-22 -75z" />
|
||||||
|
<glyph glyph-name="r" unicode="r" horiz-adv-x="503"
|
||||||
|
d="M248 0h-224v559h347q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-146q0 -44 -21 -67t-50 -31q14 -3 27 -15.5t22.5 -30t15.5 -38t6 -41.5v-87h-109v49q0 44 -14.5 70.5t-34 40.5t-40 18.5t-33.5 4.5v-183zM248 371q0 -40 17.5 -59.5t43.5 -19.5q25 0 43 19.5t18 59.5
|
||||||
|
q0 41 -18 60t-43 19q-26 0 -43.5 -19t-17.5 -60z" />
|
||||||
|
<glyph glyph-name="Y" unicode="Y"
|
||||||
|
d="M177 0v378l-146 321h190l94 -224l94 224h190l-142 -312v-387h-280z" />
|
||||||
|
<glyph glyph-name="y" unicode="y" horiz-adv-x="503"
|
||||||
|
d="M142 0v302l-117 257h152l75 -179l75 179h152l-113 -249v-310h-224z" />
|
||||||
|
<glyph glyph-name="V" unicode="V"
|
||||||
|
d="M386 286l76 413h137l-148 -699h-273l-148 699h280z" />
|
||||||
|
<glyph glyph-name="W" unicode="W" horiz-adv-x="1061"
|
||||||
|
d="M818 286l76 413h137l-148 -699h-273l-80 375l-79 -375h-273l-148 699h280l76 -413l76 413h280z" />
|
||||||
|
<glyph glyph-name="v" unicode="v" horiz-adv-x="503"
|
||||||
|
d="M309 229l61 330h109l-118 -559h-219l-118 559h224z" />
|
||||||
|
<glyph glyph-name="w" unicode="w" horiz-adv-x="849"
|
||||||
|
d="M654 229l61 330h110l-119 -559h-218l-64 300l-63 -300h-219l-118 559h224l61 -330l61 330h224z" />
|
||||||
|
<glyph glyph-name="B" unicode="B"
|
||||||
|
d="M502 353q25 -10 43 -23t30 -30.5t18 -41.5t6 -57v-68q0 -60 -38 -96.5t-110 -36.5h-421v699h434q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-65q0 -67 -23.5 -102.5t-73.5 -49.5zM310 491q0 -43 22 -58.5t54 -15.5t54 15.5t22 58.5t-22 57.5t-54 14.5t-54 -14.5
|
||||||
|
t-22 -57.5zM310 210q0 -43 22 -63.5t54 -20.5t54 20.5t22 63.5t-22 62.5t-54 19.5t-54 -19.5t-22 -62.5z" />
|
||||||
|
<glyph glyph-name="b" unicode="b" horiz-adv-x="503"
|
||||||
|
d="M402 282q39 -16 58 -42t19 -79v-55q0 -48 -30 -77t-88 -29h-337v559h347q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-52q0 -54 -19 -82.5t-58 -39.5zM248 393q0 -35 17.5 -47t43.5 -12q25 0 43 12t18 47q0 34 -18 45.5t-43 11.5q-26 0 -43.5 -11.5t-17.5 -45.5z
|
||||||
|
M248 168q0 -35 17.5 -51t43.5 -16q25 0 43 16t18 51t-18 50.5t-43 15.5q-26 0 -43.5 -15.5t-17.5 -50.5z" />
|
||||||
|
<glyph glyph-name="G" unicode="G"
|
||||||
|
d="M310 424q0 -73 22 -105.5t54 -32.5q28 0 48.5 25t25.5 82h139v-393h-210v60q0 -8 -9.5 -18.5t-24 -19.5t-31.5 -15.5t-32 -6.5h-114q-72 0 -110 36.5t-38 96.5v437q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-115h-139
|
||||||
|
q-5 57 -25.5 82.5t-48.5 25.5q-32 0 -54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="g" unicode="g" horiz-adv-x="503"
|
||||||
|
d="M248 339q0 -58 17.5 -84t43.5 -26q22 0 38.5 20t20.5 65h111v-314h-168v48q0 -7 -7.5 -15t-19 -15.5t-25 -12.5t-25.5 -5h-92q-57 0 -87.5 29t-30.5 77v350q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-92h-111
|
||||||
|
q-4 45 -20.5 65.5t-38.5 20.5q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="M" unicode="M" horiz-adv-x="1061"
|
||||||
|
d="M243 413l-76 -413h-137l148 699h273l80 -375l79 375h273l148 -699h-280l-76 413l-76 -413h-280z" />
|
||||||
|
<glyph glyph-name="m" unicode="m" horiz-adv-x="849"
|
||||||
|
d="M194 330l-60 -330h-110l118 559h219l64 -300l63 300h218l119 -559h-224l-61 330l-61 -330h-224z" />
|
||||||
|
<glyph glyph-name="Q" unicode="Q"
|
||||||
|
d="M30 570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-437q0 -60 -38 -96.5t-110 -36.5h-31l110 -200h-190l-111 200h-51q-72 0 -110 36.5t-38 96.5v437zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5t-22 106t-54 33
|
||||||
|
t-54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="q" unicode="q" horiz-adv-x="503"
|
||||||
|
d="M24 456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-350q0 -48 -30 -77t-88 -29h-25l88 -160h-152l-89 160h-41q-57 0 -87.5 29t-30.5 77v350zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84q0 59 -18 85t-43 26
|
||||||
|
q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="S" unicode="S"
|
||||||
|
d="M165 295q-24 0 -48 6.5t-43.5 22t-31.5 40t-12 60.5v146q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-115h-139q-5 57 -25.5 82.5t-48.5 25.5q-32 0 -54 -24t-22 -75q0 -21 8 -33t26 -18t47.5 -7.5t72.5 -1.5q24 0 48 -6.5
|
||||||
|
t43.5 -22t31.5 -40t12 -60.5v-146q0 -36 -12 -60.5t-31.5 -40t-43.5 -22t-48 -6.5h-299q-24 0 -48 6.5t-43.5 22t-31.5 40t-12 60.5v115h139q5 -57 25.5 -82.5t48.5 -25.5q32 0 54 24t22 75q0 21 -8 33t-26 18t-47.5 7.5t-72.5 1.5z" />
|
||||||
|
<glyph glyph-name="s" unicode="s" horiz-adv-x="503"
|
||||||
|
d="M132 236q-19 0 -38.5 5.5t-35 17.5t-25 31.5t-9.5 48.5v117q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-92h-111q-4 45 -20.5 65.5t-38.5 20.5q-26 0 -43.5 -19t-17.5 -60q0 -17 6.5 -26.5t21 -14.5t38 -6t57.5 -1
|
||||||
|
q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-117q0 -29 -9.5 -48.5t-25 -31.5t-35 -17.5t-38.5 -5.5h-239q-19 0 -38.5 5.5t-35 17.5t-25 31.5t-9.5 48.5v92h111q4 -45 20.5 -65.5t38.5 -20.5q26 0 43.5 19t17.5 60q0 17 -6.5 26.5t-21 14.5t-38 6t-57.5 1z" />
|
||||||
|
<glyph glyph-name="five" unicode="5"
|
||||||
|
d="M30 345v354h569v-136h-289v-109h154q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-196q0 -36 -12 -60.5t-31.5 -40t-43.5 -22t-48 -6.5h-299q-24 0 -48 6.5t-43.5 22t-31.5 40t-12 60.5v115h139q5 -57 25.5 -82.5t48.5 -25.5q32 0 54 24t22 75q0 21 -4 41t-19 35t-46 24.5
|
||||||
|
t-85 9.5h-135z" />
|
||||||
|
<glyph glyph-name="six" unicode="6"
|
||||||
|
d="M30 129v441q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-115h-139q-5 57 -25.5 82.5t-48.5 25.5q-32 0 -54 -24t-22 -75q0 -21 8 -33t26 -18t47.5 -7.5t72.5 -1.5q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-146q0 -36 -12 -60.5
|
||||||
|
t-31.5 -40t-43.5 -22t-48 -6.5h-299q-24 0 -48 6.5t-43.5 22t-31.5 40t-12 60.5zM460 216q0 35 -22 57t-54 22q-28 0 -51 -19t-23 -60t23 -60.5t51 -19.5q32 0 54 22.5t22 57.5z" />
|
||||||
|
<glyph glyph-name="seven" unicode="7"
|
||||||
|
d="M110 0l209 550h-289v149h569v-149l-209 -550h-280z" />
|
||||||
|
<glyph glyph-name="eight" unicode="8"
|
||||||
|
d="M178 0q-72 0 -110 36.5t-38 96.5v68q0 33 6 57t18 41.5t30 30.5t43 23q-50 14 -73.5 49.5t-23.5 102.5v65q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-65q0 -67 -23.5 -102.5t-73.5 -49.5q25 -10 43 -23t30 -30.5t18 -41.5
|
||||||
|
t6 -57v-68q0 -60 -38 -96.5t-110 -36.5h-273zM310 491q0 -43 22 -58.5t54 -15.5t54 15.5t22 58.5t-22 57.5t-54 14.5t-54 -14.5t-22 -57.5zM310 210q0 -43 22 -63.5t54 -20.5t54 20.5t22 63.5t-22 62.5t-54 19.5t-54 -19.5t-22 -62.5z" />
|
||||||
|
<glyph glyph-name="nine" unicode="9"
|
||||||
|
d="M599 570v-441q0 -36 -12 -60.5t-31.5 -40t-43.5 -22t-48 -6.5h-299q-24 0 -48 6.5t-43.5 22t-31.5 40t-12 60.5v115h139q5 -57 25.5 -82.5t48.5 -25.5q32 0 54 24t22 75q0 21 -8 33t-26 18t-47.5 7.5t-72.5 1.5q-24 0 -48 6.5t-43.5 22t-31.5 40t-12 60.5v146
|
||||||
|
q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5zM169 483q0 -35 22 -57t54 -22q28 0 51 19t23 60t-23 60.5t-51 19.5q-32 0 -54 -22.5t-22 -57.5z" />
|
||||||
|
<glyph glyph-name="dollar" unicode="$"
|
||||||
|
d="M394 800v-101h70q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-115h-139q-5 57 -25.5 82.5t-48.5 25.5q-32 0 -54 -24t-22 -75q0 -21 8 -33t26 -18t47.5 -7.5t72.5 -1.5q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-146q0 -36 -12 -60.5t-31.5 -40t-43.5 -22t-48 -6.5h-70
|
||||||
|
v-101h-139v101h-90q-24 0 -48 6.5t-43.5 22t-31.5 40t-12 60.5v115h139q5 -57 25.5 -82.5t48.5 -25.5q32 0 54 24t22 75q0 21 -8 33t-26 18t-47.5 7.5t-72.5 1.5q-24 0 -48 6.5t-43.5 22t-31.5 40t-12 60.5v146q0 36 12 60.5t31.5 40t43.5 22t48 6.5h90v101h139z" />
|
||||||
|
<glyph glyph-name="three" unicode="3"
|
||||||
|
d="M243 136q32 0 54 14.5t22 57.5t-22 58.5t-54 15.5v125q32 0 54 19.5t22 62.5t-22 63.5t-54 20.5q-28 0 -48.5 -30.5t-25.5 -87.5h-139v115q0 36 12 60.5t31.5 40t43.5 22t48 6.5h286q72 0 110 -36.5t38 -96.5v-68q0 -33 -6 -57t-18 -41.5t-30 -30t-43 -23.5
|
||||||
|
q50 -14 73.5 -49.5t23.5 -102.5v-65q0 -36 -12 -60.5t-31 -40t-43.5 -22t-48.5 -6.5h-299q-24 0 -48 6.5t-43.5 22t-31.5 40t-12 60.5v115h139q5 -57 25.5 -82.5t48.5 -25.5z" />
|
||||||
|
<glyph glyph-name="four" unicode="4"
|
||||||
|
d="M319 699h280v-699h-280v295h-289v404h139v-295h150v295z" />
|
||||||
|
<glyph glyph-name="two" unicode="2"
|
||||||
|
d="M464 295q-43 0 -72.5 -1.5t-47.5 -7.5t-26 -18t-8 -33v-99h289v-136h-569v275q0 36 12 60.5t31.5 40t43.5 22t48 6.5q43 0 72.5 1.5t47.5 7.5t26 18t8 33q0 51 -22 75t-54 24q-28 0 -48.5 -25.5t-25.5 -82.5h-139v115q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299
|
||||||
|
q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-146q0 -36 -12 -60.5t-31.5 -40t-43.5 -22t-48 -6.5z" />
|
||||||
|
<glyph glyph-name="exclam" unicode="!" horiz-adv-x="280"
|
||||||
|
d="M230 277h-180l-20 422h220zM220 0h-160v161h160v-161z" />
|
||||||
|
<glyph glyph-name="colon" unicode=":" horiz-adv-x="280"
|
||||||
|
d="M220 0h-160v161h160v-161zM220 398h-160v161h160v-161z" />
|
||||||
|
<glyph glyph-name="comma" unicode="," horiz-adv-x="280"
|
||||||
|
d="M220 0l-40 -130h-60l20 130h-80v161h160v-161z" />
|
||||||
|
<glyph glyph-name="period" unicode="." horiz-adv-x="280"
|
||||||
|
d="M220 0h-160v161h160v-161z" />
|
||||||
|
<glyph glyph-name="question" unicode="?"
|
||||||
|
d="M410 0h-160v161h160v-161zM30 570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-96q0 -34 -12 -57.5t-29.5 -40t-38 -29t-38 -25t-29.5 -28t-12 -37.5h-210q0 33 6.5 53.5t16.5 34.5t21.5 24.5t21.5 22.5t16.5 28.5t6.5 43.5
|
||||||
|
q0 51 -22 75t-54 24q-28 0 -48.5 -25.5t-25.5 -82.5h-139v115z" />
|
||||||
|
<glyph glyph-name="equal" unicode="=" horiz-adv-x="409"
|
||||||
|
d="M30 508h349v-136h-349v136zM30 228h349v-136h-349v136z" />
|
||||||
|
<glyph glyph-name="less" unicode="<" horiz-adv-x="409"
|
||||||
|
d="M30 338l349 170v-136l-180 -72l180 -72v-136l-349 170v76z" />
|
||||||
|
<glyph glyph-name="greater" unicode=">" horiz-adv-x="409"
|
||||||
|
d="M379 262l-349 -170v136l180 72l-180 72v136l349 -170v-76z" />
|
||||||
|
<glyph glyph-name="numbersign" unicode="#" horiz-adv-x="642"
|
||||||
|
d="M502 699v-96h97v-126h-97v-124h97v-126h-97v-97h-126v97h-124v-97h-126v97h-96v126h96v124h-96v126h96v96h126v-96h124v96h126zM252 353h124v124h-124v-124z" />
|
||||||
|
<glyph glyph-name="quotedbl" unicode=""" horiz-adv-x="500"
|
||||||
|
d="M220 538l-40 -130h-60l20 130h-80v161h160v-161zM440 538l-40 -130h-60l20 130h-80v161h160v-161z" />
|
||||||
|
<glyph glyph-name="quotesingle" unicode="'" horiz-adv-x="280"
|
||||||
|
d="M220 538l-40 -130h-60l20 130h-80v161h160v-161z" />
|
||||||
|
<glyph glyph-name="quotesinglbase" unicode="‚" horiz-adv-x="280"
|
||||||
|
d="M220 0l-40 -130h-60l20 130h-80v161h160v-161z" />
|
||||||
|
<glyph glyph-name="quotedblbase" unicode="„" horiz-adv-x="500"
|
||||||
|
d="M220 0l-40 -130h-60l20 130h-80v161h160v-161zM440 0l-40 -130h-60l20 130h-80v161h160v-161z" />
|
||||||
|
<glyph glyph-name="quoteright" unicode="’" horiz-adv-x="280"
|
||||||
|
d="M220 538l-40 -130h-60l20 130h-80v161h160v-161z" />
|
||||||
|
<glyph glyph-name="quoteleft" unicode="‘" horiz-adv-x="280"
|
||||||
|
d="M60 569l40 130h60l-20 -130h80v-161h-160v161z" />
|
||||||
|
<glyph glyph-name="quotedblright" unicode="”" horiz-adv-x="500"
|
||||||
|
d="M220 538l-40 -130h-60l20 130h-80v161h160v-161zM440 538l-40 -130h-60l20 130h-80v161h160v-161z" />
|
||||||
|
<glyph glyph-name="quotedblleft" unicode="“" horiz-adv-x="500"
|
||||||
|
d="M280 569l40 130h60l-20 -130h80v-161h-160v161zM60 569l40 130h60l-20 -130h80v-161h-160v161z" />
|
||||||
|
<glyph glyph-name="acute" unicode="´" horiz-adv-x="280"
|
||||||
|
d="M120 598h-60l30 101h160z" />
|
||||||
|
<glyph glyph-name="aacute" unicode="á" horiz-adv-x="503"
|
||||||
|
d="M370 0v202h-122v-202h-224v456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-456h-109zM370 339q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85v-13h122v13zM285 598h-60l30 101h160z" />
|
||||||
|
<glyph glyph-name="eacute" unicode="é" horiz-adv-x="503"
|
||||||
|
d="M479 109v-109h-455v559h455v-109h-231v-116h231v-108h-231v-117h231zM273 598h-60l30 101h160z" />
|
||||||
|
<glyph glyph-name="iacute" unicode="í" horiz-adv-x="503"
|
||||||
|
d="M273 598h-60l30 101h160zM479 119v-119h-455v119h118v321h-118v119h455v-119h-113v-321h113z" />
|
||||||
|
<glyph glyph-name="oacute" unicode="ó" horiz-adv-x="503"
|
||||||
|
d="M273 598h-60l30 101h160zM24 456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-350q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v350zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84q0 59 -18 85t-43 26
|
||||||
|
q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="uacute" unicode="ú" horiz-adv-x="503"
|
||||||
|
d="M273 598h-60l30 101h160zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84v220h109v-453q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v453h224v-220z" />
|
||||||
|
<glyph glyph-name="grave" unicode="`" horiz-adv-x="280"
|
||||||
|
d="M60 699h160l30 -101h-60z" />
|
||||||
|
<glyph glyph-name="agrave" unicode="à" horiz-adv-x="503"
|
||||||
|
d="M370 0v202h-122v-202h-224v456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-456h-109zM370 339q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85v-13h122v13zM135 699h160l30 -101h-60z" />
|
||||||
|
<glyph glyph-name="egrave" unicode="è" horiz-adv-x="503"
|
||||||
|
d="M479 109v-109h-455v559h455v-109h-231v-116h231v-108h-231v-117h231zM123 699h160l30 -101h-60z" />
|
||||||
|
<glyph glyph-name="igrave" unicode="ì" horiz-adv-x="503"
|
||||||
|
d="M123 699h160l30 -101h-60zM479 119v-119h-455v119h118v321h-118v119h455v-119h-113v-321h113z" />
|
||||||
|
<glyph glyph-name="ograve" unicode="ò" horiz-adv-x="503"
|
||||||
|
d="M123 699h160l30 -101h-60zM24 456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-350q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v350zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84q0 59 -18 85t-43 26
|
||||||
|
q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="ugrave" unicode="ù" horiz-adv-x="503"
|
||||||
|
d="M123 699h160l30 -101h-60zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84v220h109v-453q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v453h224v-220z" />
|
||||||
|
<glyph glyph-name="circumflex" unicode="ˆ" horiz-adv-x="440"
|
||||||
|
d="M220 699l190 -101h-130l-60 41l-60 -41h-130z" />
|
||||||
|
<glyph glyph-name="asciicircum" unicode="^" horiz-adv-x="500"
|
||||||
|
d="M250 699l220 -371h-130l-90 191l-90 -191h-130z" />
|
||||||
|
<glyph glyph-name="acircumflex" unicode="â" horiz-adv-x="503"
|
||||||
|
d="M370 0v202h-122v-202h-224v456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-456h-109zM370 339q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85v-13h122v13zM260 699l190 -101h-130l-60 41l-60 -41h-130z" />
|
||||||
|
<glyph glyph-name="ecircumflex" unicode="ê" horiz-adv-x="503"
|
||||||
|
d="M260 699l190 -101h-130l-60 41l-60 -41h-130zM479 109v-109h-455v559h455v-109h-231v-116h231v-108h-231v-117h231z" />
|
||||||
|
<glyph glyph-name="icircumflex" unicode="î" horiz-adv-x="503"
|
||||||
|
d="M260 699l190 -101h-130l-60 41l-60 -41h-130zM479 119v-119h-455v119h118v321h-118v119h455v-119h-113v-321h113z" />
|
||||||
|
<glyph glyph-name="ocircumflex" unicode="ô" horiz-adv-x="503"
|
||||||
|
d="M260 699l190 -101h-130l-60 41l-60 -41h-130zM24 456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-350q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v350zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84
|
||||||
|
q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="ucircumflex" unicode="û" horiz-adv-x="503"
|
||||||
|
d="M260 699l190 -101h-130l-60 41l-60 -41h-130zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84v220h109v-453q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v453h224v-220z" />
|
||||||
|
<glyph glyph-name="slash" unicode="/"
|
||||||
|
d="M220 -200h-190l379 1000h190z" />
|
||||||
|
<glyph glyph-name="backslash" unicode="\"
|
||||||
|
d="M30 800h190l379 -1000h-190z" />
|
||||||
|
<glyph glyph-name="semicolon" unicode=";" horiz-adv-x="280"
|
||||||
|
d="M220 0l-40 -130h-60l20 130h-80v161h160v-161zM220 398h-160v161h160v-161z" />
|
||||||
|
<glyph glyph-name="semicolon" unicode=";" horiz-adv-x="280"
|
||||||
|
d="M220 0l-40 -130h-60l20 130h-80v161h160v-161zM220 398h-160v161h160v-161z" />
|
||||||
|
<glyph glyph-name="underscore" unicode="_" horiz-adv-x="349"
|
||||||
|
d="M30 -60h289v-76h-289v76z" />
|
||||||
|
<glyph glyph-name="OE" unicode="Œ" horiz-adv-x="918"
|
||||||
|
d="M888 136v-136h-710q-72 0 -110 36.5t-38 96.5v437q0 36 12 60.5t31.5 40t43.5 22t48 6.5h723v-136h-289v-145h289v-136h-289v-146h289zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5t-22 106t-54 33t-54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="oe" unicode="œ" horiz-adv-x="734"
|
||||||
|
d="M710 109v-109h-568q-57 0 -87.5 29t-30.5 77v350q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h578v-109h-231v-116h231v-108h-231v-117h231zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="bracketleft" unicode="[" horiz-adv-x="429"
|
||||||
|
d="M220 -64h179v-136h-369v1000h369v-136h-179v-728z" />
|
||||||
|
<glyph glyph-name="bracketright" unicode="]" horiz-adv-x="429"
|
||||||
|
d="M209 664h-179v136h369v-1000h-369v136h179v728z" />
|
||||||
|
<glyph glyph-name="plus" unicode="+" horiz-adv-x="449"
|
||||||
|
d="M272 484v-146h147v-96h-147v-147h-96v147h-146v96h146v146h96z" />
|
||||||
|
<glyph glyph-name="parenleft" unicode="(" horiz-adv-x="429"
|
||||||
|
d="M220 35q0 -51 22 -75t54 -24h103v-136h-221q-72 0 -110 36.5t-38 96.5v738q0 36 12 60.5t31.5 40t43.5 22t48 6.5h234v-136h-103q-32 0 -54 -24t-22 -75v-530z" />
|
||||||
|
<glyph glyph-name="parenright" unicode=")" horiz-adv-x="429"
|
||||||
|
d="M209 565q0 51 -22 75t-54 24h-103v136h234q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-738q0 -60 -38 -96.5t-110 -36.5h-221v136h103q32 0 54 24t22 75v530z" />
|
||||||
|
<glyph glyph-name="percent" unicode="%"
|
||||||
|
d="M30 590q0 23 8.5 42.5t23.5 34.5t35 23.5t42 8.5q23 0 42.5 -8.5t34.5 -23.5t23.5 -34.5t8.5 -42.5q0 -22 -8.5 -42t-23.5 -35t-34.5 -23.5t-42.5 -8.5q-22 0 -42 8.5t-35 23.5t-23.5 35t-8.5 42zM80 590q0 -25 17 -42t42 -17t42 17t17 42t-17 42t-42 17t-42 -17t-17 -42
|
||||||
|
zM381 109q0 23 8.5 42.5t23.5 34.5t35 23.5t42 8.5q23 0 42.5 -8.5t34.5 -23.5t23.5 -34.5t8.5 -42.5q0 -22 -8.5 -42t-23.5 -35t-34.5 -23.5t-42.5 -8.5q-22 0 -42 8.5t-35 23.5t-23.5 35t-8.5 42zM431 109q0 -25 17 -42t42 -17t42 17t17 42t-17 42t-42 17t-42 -17t-17 -42
|
||||||
|
zM160 0h-110l419 700h110z" />
|
||||||
|
<glyph glyph-name="guilsinglleft" unicode="‹" horiz-adv-x="409"
|
||||||
|
d="M30 318l349 241v-96l-180 -183l180 -184v-96l-349 242v76z" />
|
||||||
|
<glyph glyph-name="guilsinglright" unicode="›" horiz-adv-x="409"
|
||||||
|
d="M379 242l-349 -242v96l180 184l-180 183v96l349 -241v-76z" />
|
||||||
|
<glyph glyph-name="guillemotleft" unicode="«" horiz-adv-x="509"
|
||||||
|
d="M30 318l209 241v-96l-100 -183l100 -184v-96l-209 242v76zM270 318l209 241v-96l-100 -183l100 -184v-96l-209 242v76z" />
|
||||||
|
<glyph glyph-name="guillemotright" unicode="»" horiz-adv-x="509"
|
||||||
|
d="M479 242l-209 -242v96l100 184l-100 183v96l209 -241v-76zM239 242l-209 -242v96l100 184l-100 183v96l209 -241v-76z" />
|
||||||
|
<glyph glyph-name="sterling" unicode="£"
|
||||||
|
d="M30 368h50v202q0 36 12 60.5t31.5 40t43.5 22t48 6.5h249q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-115h-139q-5 57 -25.5 82.5t-48.5 25.5q-32 0 -54 -24t-22 -75v-96h109v-96h-109v-86h289v-186h-569v186h50v86h-50v96z" />
|
||||||
|
<glyph glyph-name="Oslash" unicode="Ø"
|
||||||
|
d="M30 570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h257l47 101h110l-53 -113q31 -12 52 -40.5t21 -76.5v-437q0 -60 -38 -96.5t-110 -36.5h-245l-46 -100h-110l53 114q-36 16 -54.5 46.5t-18.5 72.5v437zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5t-22 106t-54 33
|
||||||
|
t-54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="cent" unicode="¢" horiz-adv-x="503"
|
||||||
|
d="M248 339q0 -58 17.5 -84t43.5 -26q22 0 38.5 20t20.5 65h111v-208q0 -48 -30 -77t-88 -29h-196l-37 -80h-88l42 91q-29 13 -43.5 37.5t-14.5 57.5v350q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h206l37 81h88l-42 -90q25 -10 41.5 -33t16.5 -61v-92h-111q-4 45 -20.5 65.5
|
||||||
|
t-38.5 20.5q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="oslash" unicode="ø" horiz-adv-x="503"
|
||||||
|
d="M24 456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h206l37 81h88l-42 -90q25 -10 41.5 -33t16.5 -61v-350q0 -48 -30 -77t-88 -29h-196l-37 -80h-88l42 91q-29 13 -43.5 37.5t-14.5 57.5v350zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84q0 59 -18 85t-43 26
|
||||||
|
q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="Agrave" unicode="À"
|
||||||
|
d="M462 0v252h-152v-252h-280v570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-570h-137zM462 424q0 73 -22 106t-54 33t-54 -33t-22 -106v-16h152v16zM230 799.711h160l30 -92h-60z" />
|
||||||
|
<glyph glyph-name="Aacute" unicode="Á"
|
||||||
|
d="M462 0v252h-152v-252h-280v570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-570h-137zM462 424q0 73 -22 106t-54 33t-54 -33t-22 -106v-16h152v16zM359.37 707.711h-59.6846l29.8418 92h159.16z" />
|
||||||
|
<glyph glyph-name="Acircumflex" unicode="Â"
|
||||||
|
d="M462 0v252h-152v-252h-280v570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-570h-137zM462 424q0 73 -22 106t-54 33t-54 -33t-22 -106v-16h152v16zM347 799.889l190 -90.0029h-130l-60 36.5361l-60 -36.5361h-130z" />
|
||||||
|
<glyph glyph-name="Egrave" unicode="È"
|
||||||
|
d="M230 799.711h160l30 -92h-60zM599 136v-136h-569v699h569v-136h-289v-145h289v-136h-289v-146h289z" />
|
||||||
|
<glyph glyph-name="Eacute" unicode="É"
|
||||||
|
d="M359.37 707.711h-59.6846l29.8418 92h159.16zM599 136v-136h-569v699h569v-136h-289v-145h289v-136h-289v-146h289z" />
|
||||||
|
<glyph glyph-name="Ecircumflex" unicode="Ê"
|
||||||
|
d="M347 799.889l190 -90.0029h-130l-60 36.5361l-60 -36.5361h-130zM599 136v-136h-569v699h569v-136h-289v-145h289v-136h-289v-146h289z" />
|
||||||
|
<glyph glyph-name="Ograve" unicode="Ò"
|
||||||
|
d="M230 799.711h160l30 -92h-60zM30 570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-437q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v437zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5t-22 106t-54 33
|
||||||
|
t-54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="Oacute" unicode="Ó"
|
||||||
|
d="M359.37 707.711h-59.6846l29.8418 92h159.16zM30 570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-437q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v437zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5
|
||||||
|
t-22 106t-54 33t-54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="Ocircumflex" unicode="Ô"
|
||||||
|
d="M347 799.889l190 -90.0029h-130l-60 36.5361l-60 -36.5361h-130zM30 570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-437q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v437zM310 424q0 -73 22 -105.5t54 -32.5
|
||||||
|
t54 32.5t22 105.5t-22 106t-54 33t-54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="Ugrave" unicode="Ù"
|
||||||
|
d="M230 799.711h160l30 -92h-60zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5v275h137v-566q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v566h280v-275z" />
|
||||||
|
<glyph glyph-name="Uacute" unicode="Ú"
|
||||||
|
d="M359.37 707.711h-59.6846l29.8418 92h159.16zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5v275h137v-566q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v566h280v-275z" />
|
||||||
|
<glyph glyph-name="Ucircumflex" unicode="Û"
|
||||||
|
d="M347 799.889l190 -90.0029h-130l-60 36.5361l-60 -36.5361h-130zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5v275h137v-566q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v566h280v-275z" />
|
||||||
|
<glyph glyph-name="AE" unicode="Æ" horiz-adv-x="918"
|
||||||
|
d="M888 136v-136h-426v252h-152v-252h-280v570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h723v-136h-289v-145h289v-136h-289v-146h289zM462 424q0 73 -22 106t-54 33t-54 -33t-22 -106v-16h152v16z" />
|
||||||
|
<glyph glyph-name="ae" unicode="æ" horiz-adv-x="734"
|
||||||
|
d="M710 109v-109h-340v202h-122v-202h-224v456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h578v-109h-231v-116h231v-108h-231v-117h231zM370 339q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85v-13h122v13z" />
|
||||||
|
<glyph glyph-name="questiondown" unicode="¿"
|
||||||
|
d="M219 699h160v-161h-160v161zM599 244h-139q-5 -57 -25.5 -82.5t-48.5 -25.5q-32 0 -54 24t-22 75q0 27 6.5 43.5t16.5 28.5t21.5 22.5t21.5 24.5t16.5 34.5t6.5 53.5h-210q0 -22 -12 -37.5t-29.5 -28t-38 -25t-38 -29t-29.5 -40t-12 -57.5v-96q0 -36 12 -60.5t31.5 -40
|
||||||
|
t43.5 -22t48 -6.5h299q24 0 48 6.5t43.5 22t31.5 40t12 60.5v115z" />
|
||||||
|
<glyph glyph-name="exclamdown" unicode="¡" horiz-adv-x="280"
|
||||||
|
d="M50 422h180l20 -422h-220zM60 699h160v-161h-160v161z" />
|
||||||
|
<glyph glyph-name="florin" unicode="ƒ" horiz-adv-x="634"
|
||||||
|
d="M205 389v305q0 48 30 77t88 29h287v-119h-120q-26 0 -43.5 -26t-17.5 -84v-182h181v-119h-181v-364q0 -48 -30 -77t-88 -29h-287v119h120q26 0 43.5 26t17.5 84v241h-181v119h181z" />
|
||||||
|
<glyph glyph-name="dieresis" unicode="¨" horiz-adv-x="440"
|
||||||
|
d="M140 588h-110v111h110v-111zM410 588h-110v111h110v-111z" />
|
||||||
|
<glyph glyph-name="Adieresis" unicode="Ä"
|
||||||
|
d="M462 0v252h-152v-252h-280v570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-570h-137zM462 424q0 73 -22 106t-54 33t-54 -33t-22 -106v-16h152v16zM275.109 709.745h-88.8721v89.998h88.8721v-89.998zM493.248 709.745h-88.8711
|
||||||
|
v89.998h88.8711v-89.998z" />
|
||||||
|
<glyph glyph-name="Edieresis" unicode="Ë"
|
||||||
|
d="M275.109 709.745h-88.8721v89.998h88.8721v-89.998zM493.248 709.745h-88.8711v89.998h88.8711v-89.998zM599 136v-136h-569v699h569v-136h-289v-145h289v-136h-289v-146h289z" />
|
||||||
|
<glyph glyph-name="Idieresis" unicode="Ï"
|
||||||
|
d="M255.109 709.745h-88.8721v89.998h88.8721v-89.998zM473.248 709.745h-88.8711v89.998h88.8711v-89.998zM599 149v-149h-569v149h147v401h-147v149h569v-149h-142v-401h142z" />
|
||||||
|
<glyph glyph-name="Odieresis" unicode="Ö"
|
||||||
|
d="M275.109 709.745h-88.8721v89.998h88.8721v-89.998zM493.248 709.745h-88.8711v89.998h88.8711v-89.998zM30 570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-437q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v437
|
||||||
|
zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5t-22 106t-54 33t-54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="Udieresis" unicode="Ü"
|
||||||
|
d="M275.109 709.745h-88.8721v89.998h88.8721v-89.998zM493.248 709.745h-88.8711v89.998h88.8711v-89.998zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5v275h137v-566q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v566h280v-275z" />
|
||||||
|
<glyph glyph-name="Igrave" unicode="Ì"
|
||||||
|
d="M200 799.711h160l30 -92h-60zM599 149v-149h-569v149h147v401h-147v149h569v-149h-142v-401h142z" />
|
||||||
|
<glyph glyph-name="Iacute" unicode="Í"
|
||||||
|
d="M349.37 707.711h-59.6846l29.8418 92h159.16zM599 149v-149h-569v149h147v401h-147v149h569v-149h-142v-401h142z" />
|
||||||
|
<glyph glyph-name="Icircumflex" unicode="Î"
|
||||||
|
d="M337 799.889l190 -90.0029h-130l-60 36.5361l-60 -36.5361h-130zM599 149v-149h-569v149h147v401h-147v149h569v-149h-142v-401h142z" />
|
||||||
|
<glyph glyph-name="adieresis" unicode="ä" horiz-adv-x="503"
|
||||||
|
d="M370 0v202h-122v-202h-224v456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-456h-109zM370 339q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85v-13h122v13zM180 588h-110v111h110v-111zM450 588h-110v111h110v-111z" />
|
||||||
|
<glyph glyph-name="edieresis" unicode="ë" horiz-adv-x="503"
|
||||||
|
d="M180 588h-110v111h110v-111zM450 588h-110v111h110v-111zM479 109v-109h-455v559h455v-109h-231v-116h231v-108h-231v-117h231z" />
|
||||||
|
<glyph glyph-name="idieresis" unicode="ï" horiz-adv-x="503"
|
||||||
|
d="M170 588h-110v111h110v-111zM440 588h-110v111h110v-111zM479 119v-119h-455v119h118v321h-118v119h455v-119h-113v-321h113z" />
|
||||||
|
<glyph glyph-name="odieresis" unicode="ö" horiz-adv-x="503"
|
||||||
|
d="M180 588h-110v111h110v-111zM450 588h-110v111h110v-111zM24 456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-350q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v350zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26
|
||||||
|
t18 84q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="udieresis" unicode="ü" horiz-adv-x="503"
|
||||||
|
d="M180 588h-110v111h110v-111zM450 588h-110v111h110v-111zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84v220h109v-453q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v453h224v-220z" />
|
||||||
|
<glyph glyph-name="ydieresis" unicode="ÿ" horiz-adv-x="503"
|
||||||
|
d="M180 588h-110v111h110v-111zM450 588h-110v111h110v-111zM142 0v302l-117 257h152l75 -179l75 179h152l-113 -249v-310h-224z" />
|
||||||
|
<glyph glyph-name="Ydieresis" unicode="Ÿ"
|
||||||
|
d="M265.109 709.745h-88.8721v89.998h88.8721v-89.998zM483.248 709.745h-88.8711v89.998h88.8711v-89.998zM177 0v378l-146 321h190l94 -224l94 224h190l-142 -312v-387h-280z" />
|
||||||
|
<glyph glyph-name="endash" unicode="–"
|
||||||
|
d="M30 338h569v-96h-569v96z" />
|
||||||
|
<glyph glyph-name="emdash" unicode="—" horiz-adv-x="861"
|
||||||
|
d="M30 338h801v-96h-801v96z" />
|
||||||
|
<glyph glyph-name="K" unicode="K"
|
||||||
|
d="M310 0h-280v699h280v-279q20 0 46 6t49.5 25.5t40 56.5t16.5 100v91h137v-107q0 -74 -23.5 -111.5t-73.5 -60.5q42 -15 69.5 -51.5t27.5 -99.5v-269h-137v91q0 70 -15 109t-37.5 57.5t-49.5 22.5t-50 4v-284z" />
|
||||||
|
<glyph glyph-name="hyphen" unicode="-" horiz-adv-x="349"
|
||||||
|
d="M30 358h289v-136h-289v136z" />
|
||||||
|
<glyph glyph-name="bar" unicode="|" horiz-adv-x="250"
|
||||||
|
d="M220 -200h-190v1000h190v-1000z" />
|
||||||
|
<glyph glyph-name="braceleft" unicode="{" horiz-adv-x="541"
|
||||||
|
d="M30 217v186h36q32 0 54 24t22 75v169q0 36 12 60.5t31.5 40t43.5 22t48 6.5h234v-136h-103q-32 0 -54 -24t-22 -75v-530q0 -51 22 -75t54 -24h103v-136h-221q-72 0 -110 36.5t-38 96.5v185q0 51 -22 75t-54 24h-36z" />
|
||||||
|
<glyph glyph-name="braceright" unicode="}" horiz-adv-x="541"
|
||||||
|
d="M475 217q-32 0 -54 -24t-22 -75v-185q0 -60 -38 -96.5t-110 -36.5h-221v136h103q32 0 54 24t22 75v530q0 51 -22 75t-54 24h-103v136h234q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-169q0 -51 22 -75t54 -24h36v-186h-36z" />
|
||||||
|
<glyph glyph-name="yen" unicode="¥"
|
||||||
|
d="M177 0v152h-147v86h147v94h-147v86h129l-128 281h190l94 -224l94 224h190l-128 -281h128v-86h-142v-94h142v-86h-142v-152h-280z" />
|
||||||
|
<glyph glyph-name="at" unicode="@" horiz-adv-x="822"
|
||||||
|
d="M587 112v365q0 23 -7.5 38.5t-20 25.5t-28 14t-30.5 4h-191q-15 0 -30.5 -4t-28 -14t-20.5 -25.5t-8 -38.5v-365h179v162h98v-162h87zM500 373h-98v10q0 48 14.5 68.5t34.5 20.5t34.5 -20.5t14.5 -68.5v-10zM20 333q0 81 30.5 152t84 124.5t124.5 84t152 30.5t152 -30.5
|
||||||
|
t124.5 -84t84 -124.5t30.5 -152t-30.5 -152t-84 -124.5t-124.5 -84t-152 -30.5t-152 30.5t-124.5 84t-84 124.5t-30.5 152z" />
|
||||||
|
<glyph glyph-name="asterisk" unicode="*" horiz-adv-x="468"
|
||||||
|
d="M282 699v-429h-96v429h96zM282 699v-429h-96v429h96zM396 633l48 -83l-371 -214l-48 83zM72 633l371 -214l-48 -83l-371 214z" />
|
||||||
|
<glyph glyph-name="logicalnot" unicode="¬" horiz-adv-x="449"
|
||||||
|
d="M30 388h389v-216h-79v120h-310v96z" />
|
||||||
|
<glyph glyph-name="D" unicode="D"
|
||||||
|
d="M30 699h434q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-437q0 -60 -38 -96.5t-110 -36.5h-421v699zM310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5t-22 106t-54 33t-54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="U" unicode="U"
|
||||||
|
d="M310 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5v275h137v-566q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v566h280v-275z" />
|
||||||
|
<glyph glyph-name="C" unicode="C"
|
||||||
|
d="M310 424q0 -73 22 -105.5t54 -32.5q28 0 48.5 25t25.5 82h139v-260q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v437q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-115h-139q-5 57 -25.5 82.5t-48.5 25.5
|
||||||
|
q-32 0 -54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="trademark" unicode="™" horiz-adv-x="1082"
|
||||||
|
d="M293 252h-179v352h-95v95h364v-95h-90v-352zM558 516l-48 -264h-88l94 447h175l51 -240l51 240h174l95 -447h-179l-49 264l-48 -264h-180z" />
|
||||||
|
<glyph glyph-name="mu" unicode="µ" horiz-adv-x="503"
|
||||||
|
d="M248 -160h-224v719h224v-220q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84v220h109v-559h-231v-160z" />
|
||||||
|
<glyph glyph-name="mu" unicode="μ" horiz-adv-x="503"
|
||||||
|
d="M248 -160h-224v719h224v-220q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84v220h109v-559h-231v-160z" />
|
||||||
|
<glyph glyph-name="ordmasculine" unicode="º" horiz-adv-x="402"
|
||||||
|
d="M19 617q0 23 8 38.5t20.5 25.5t28 14t30.5 4h191q15 0 30.5 -4t28 -14t20 -25.5t7.5 -38.5v-280q0 -38 -24 -61.5t-70 -23.5h-175q-46 0 -70.5 23.5t-24.5 61.5v280zM198 523q0 -46 14.5 -67t34.5 -21t34.5 21t14.5 67q0 48 -14.5 68.5t-34.5 20.5t-34.5 -20.5
|
||||||
|
t-14.5 -68.5z" />
|
||||||
|
<glyph glyph-name="ordfeminine" unicode="ª" horiz-adv-x="402"
|
||||||
|
d="M296 252v162h-98v-162h-179v365q0 23 8 38.5t20.5 25.5t28 14t30.5 4h191q15 0 30.5 -4t28 -14t20 -25.5t7.5 -38.5v-365h-87zM296 523q0 48 -14.5 68.5t-34.5 20.5t-34.5 -20.5t-14.5 -68.5v-10h98v10z" />
|
||||||
|
<glyph glyph-name="copyright" unicode="©" horiz-adv-x="822"
|
||||||
|
d="M402 383q0 48 14.5 68.5t34.5 20.5q17 0 30.5 -16.5t16.5 -52.5h89v74q0 23 -7.5 38.5t-20 25.5t-28 14t-30.5 4h-191q-15 0 -30.5 -4t-28 -14t-20.5 -25.5t-8 -38.5v-280q0 -38 24.5 -61.5t70.5 -23.5h175q46 0 70 23.5t24 61.5v166h-89q-3 -36 -16.5 -52t-30.5 -16
|
||||||
|
q-20 0 -34.5 21t-14.5 67zM20 333q0 81 30.5 152t84 124.5t124.5 84t152 30.5t152 -30.5t124.5 -84t84 -124.5t30.5 -152t-30.5 -152t-84 -124.5t-124.5 -84t-152 -30.5t-152 30.5t-124.5 84t-84 124.5t-30.5 152z" />
|
||||||
|
<glyph glyph-name="registered" unicode="®" horiz-adv-x="822"
|
||||||
|
d="M402 258q11 0 27.5 -3.5t32 -14.5t27 -32.5t11.5 -56.5v-39h87v70q0 17 -4.5 33.5t-12.5 30t-18.5 23.5t-21.5 13q23 6 40 24.5t17 53.5v117q0 23 -7.5 38.5t-20 25.5t-28 14t-30.5 4h-278v-447h179v146zM402 409q0 32 14.5 47.5t34.5 15.5t34.5 -15.5t14.5 -47.5
|
||||||
|
t-14.5 -47.5t-34.5 -15.5t-34.5 15.5t-14.5 47.5zM20 333q0 81 30.5 152t84 124.5t124.5 84t152 30.5t152 -30.5t124.5 -84t84 -124.5t30.5 -152t-30.5 -152t-84 -124.5t-124.5 -84t-152 -30.5t-152 30.5t-124.5 84t-84 124.5t-30.5 152z" />
|
||||||
|
<glyph glyph-name="degree" unicode="°" horiz-adv-x="278"
|
||||||
|
d="M30 590q0 23 8.5 42.5t23.5 34.5t35 23.5t42 8.5q23 0 42.5 -8.5t34.5 -23.5t23.5 -34.5t8.5 -42.5q0 -22 -8.5 -42t-23.5 -35t-34.5 -23.5t-42.5 -8.5q-22 0 -42 8.5t-35 23.5t-23.5 35t-8.5 42zM80 590q0 -25 17 -42t42 -17t42 17t17 42t-17 42t-42 17t-42 -17t-17 -42
|
||||||
|
z" />
|
||||||
|
<glyph glyph-name="periodcentered" unicode="·" horiz-adv-x="280"
|
||||||
|
d="M220 210h-160v161h160v-161z" />
|
||||||
|
<glyph glyph-name="periodcentered" unicode="∙" horiz-adv-x="280"
|
||||||
|
d="M220 210h-160v161h160v-161z" />
|
||||||
|
<glyph glyph-name="germandbls" unicode="ß" horiz-adv-x="1006"
|
||||||
|
d="M132 236q-19 0 -38.5 5.5t-35 17.5t-25 31.5t-9.5 48.5v117q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-92h-111q-4 45 -20.5 65.5t-38.5 20.5q-26 0 -43.5 -19t-17.5 -60q0 -17 6.5 -26.5t21 -14.5t38 -6t57.5 -1
|
||||||
|
q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-117q0 -29 -9.5 -48.5t-25 -31.5t-35 -17.5t-38.5 -5.5h-239q-19 0 -38.5 5.5t-35 17.5t-25 31.5t-9.5 48.5v92h111q4 -45 20.5 -65.5t38.5 -20.5q26 0 43.5 19t17.5 60q0 17 -6.5 26.5t-21 14.5t-38 6t-57.5 1zM635 236
|
||||||
|
q-19 0 -38.5 5.5t-35 17.5t-25 31.5t-9.5 48.5v117q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-92h-111q-4 45 -20.5 65.5t-38.5 20.5q-26 0 -43.5 -19t-17.5 -60q0 -17 6.5 -26.5t21 -14.5t38 -6t57.5 -1q19 0 38.5 -5.5
|
||||||
|
t35 -17.5t25 -31.5t9.5 -48.5v-117q0 -29 -9.5 -48.5t-25 -31.5t-35 -17.5t-38.5 -5.5h-239q-19 0 -38.5 5.5t-35 17.5t-25 31.5t-9.5 48.5v92h111q4 -45 20.5 -65.5t38.5 -20.5q26 0 43.5 19t17.5 60q0 17 -6.5 26.5t-21 14.5t-38 6t-57.5 1z" />
|
||||||
|
<glyph glyph-name="aring" unicode="å" horiz-adv-x="503"
|
||||||
|
d="M211 642q0 24 16.5 40.5t40.5 16.5q23 0 39.5 -16.5t16.5 -40.5q0 -23 -16.5 -39.5t-39.5 -16.5q-24 0 -40.5 16.5t-16.5 39.5zM237 642q0 -13 8.5 -21.5t22.5 -8.5q13 0 21.5 8.5t8.5 21.5q0 14 -8.5 22.5t-21.5 8.5q-14 0 -22.5 -8.5t-8.5 -22.5zM370 0v202h-122v-202
|
||||||
|
h-224v456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-456h-109zM370 339q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85v-13h122v13z" />
|
||||||
|
<glyph glyph-name="Aring" unicode="Å"
|
||||||
|
d="M324.425 753.683q0 19.54 13.4326 32.9736q13.4336 13.4336 32.9736 13.4336q18.7256 0 32.1582 -13.4336q13.4336 -13.4336 13.4336 -32.9736q0 -18.7246 -13.4336 -32.1582q-13.4326 -13.4336 -32.1582 -13.4336q-19.54 0 -32.9736 13.4336
|
||||||
|
q-13.4326 13.4336 -13.4326 32.1582zM345.592 753.683q0 -10.584 6.9209 -17.5039q6.91992 -6.91992 18.3184 -6.91992q10.584 0 17.5039 6.91992t6.91992 17.5039q0 11.3984 -6.91992 18.3184q-6.91992 6.9209 -17.5039 6.9209q-11.3984 0 -18.3184 -6.9209
|
||||||
|
q-6.9209 -6.91992 -6.9209 -18.3184zM462 0v252h-152v-252h-280v570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-570h-137zM462 424q0 73 -22 106t-54 33t-54 -33t-22 -106v-16h152v16z" />
|
||||||
|
<glyph glyph-name="divide" unicode="÷" horiz-adv-x="449"
|
||||||
|
d="M30 242h389v96h-389v-96zM280 0h-120v121h120v-121zM280 438h-120v121h120v-121z" />
|
||||||
|
<glyph glyph-name="plusminus" unicode="±" horiz-adv-x="449"
|
||||||
|
d="M30 208h389v-96h-389v96zM272 614v-146h147v-96h-147v-147h-96v147h-146v96h146v146h96z" />
|
||||||
|
<glyph glyph-name="perthousand" unicode="‰" horiz-adv-x="907"
|
||||||
|
d="M30 590q0 23 8.5 42.5t23.5 34.5t35 23.5t42 8.5q23 0 42.5 -8.5t34.5 -23.5t23.5 -34.5t8.5 -42.5q0 -22 -8.5 -42t-23.5 -35t-34.5 -23.5t-42.5 -8.5q-22 0 -42 8.5t-35 23.5t-23.5 35t-8.5 42zM80 590q0 -25 17 -42t42 -17t42 17t17 42t-17 42t-42 17t-42 -17t-17 -42
|
||||||
|
zM381 109q0 23 8.5 42.5t23.5 34.5t35 23.5t42 8.5q23 0 42.5 -8.5t34.5 -23.5t23.5 -34.5t8.5 -42.5q0 -22 -8.5 -42t-23.5 -35t-34.5 -23.5t-42.5 -8.5q-22 0 -42 8.5t-35 23.5t-23.5 35t-8.5 42zM431 109q0 -25 17 -42t42 -17t42 17t17 42t-17 42t-42 17t-42 -17t-17 -42
|
||||||
|
zM160 0h-110l419 700h110zM659 109q0 23 8.5 42.5t23.5 34.5t35 23.5t42 8.5q23 0 42.5 -8.5t34.5 -23.5t23.5 -34.5t8.5 -42.5q0 -22 -8.5 -42t-23.5 -35t-34.5 -23.5t-42.5 -8.5q-22 0 -42 8.5t-35 23.5t-23.5 35t-8.5 42zM709 109q0 -25 17 -42t42 -17t42 17t17 42
|
||||||
|
t-17 42t-42 17t-42 -17t-17 -42z" />
|
||||||
|
<glyph glyph-name="ampersand" unicode="&" horiz-adv-x="659"
|
||||||
|
d="M599 129q0 -36 -12 -60.5t-31.5 -40t-43.5 -22t-48 -6.5h-299q-24 0 -48.5 6.5t-43.5 22t-31 40t-12 60.5v65q0 67 23.5 102.5t73.5 49.5q-25 11 -43 23.5t-30 30t-18 41.5t-6 57v68q0 60 38 96.5t110 36.5h286q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-75h-139
|
||||||
|
q-5 42 -25.5 60t-48.5 18q-32 0 -54 -20.5t-22 -63.5t22 -62.5t54 -19.5h243v-125h-30v-153zM310 208q0 -43 22 -57.5t54 -14.5q28 0 49 21t25 77v48h-74q-32 0 -54 -15.5t-22 -58.5z" />
|
||||||
|
<glyph glyph-name="macron" unicode="¯" horiz-adv-x="503"
|
||||||
|
d="M24 699h455v-76h-455v76z" />
|
||||||
|
<glyph glyph-name="macron" unicode="ˉ" horiz-adv-x="503"
|
||||||
|
d="M24 699h455v-76h-455v76z" />
|
||||||
|
<glyph glyph-name="ellipsis" unicode="…" horiz-adv-x="840"
|
||||||
|
d="M220 0h-160v161h160v-161zM500 0h-160v161h160v-161zM780 0h-160v161h160v-161z" />
|
||||||
|
<glyph glyph-name="asciitilde" unicode="~" horiz-adv-x="664"
|
||||||
|
d="M71 418q15 57 48.5 85.5t77.5 28.5q39 0 71.5 -7.5t59.5 -16.5t49 -16.5t38 -7.5q32 0 51.5 15t25.5 38l11 42l131 -35l-41 -156q-15 -57 -48.5 -85.5t-77.5 -28.5q-39 0 -71.5 7.5t-59.5 17t-48.5 17t-38.5 7.5q-32 0 -51.5 -15.5t-25.5 -38.5l-11 -42l-131 35z" />
|
||||||
|
<glyph glyph-name="tilde" unicode="˜" horiz-adv-x="436"
|
||||||
|
d="M55 700q10 35 31 53t48 18q24 0 44.5 -4.5t37 -10.5t30 -10.5t23.5 -4.5q20 0 32 9.5t16 23.5l7 26l82 -22l-26 -97q-9 -35 -30 -53t-48 -18q-24 0 -44.5 5t-37 10.5t-30 10.5t-24.5 5q-20 0 -32 -10t-16 -24l-7 -26l-81 22z" />
|
||||||
|
<glyph glyph-name="atilde" unicode="ã" horiz-adv-x="503"
|
||||||
|
d="M370 0v202h-122v-202h-224v456q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-456h-109zM370 339q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85v-13h122v13zM85 700q10 35 31 53t48 18q24 0 44.5 -4.5t37 -10.5t30 -10.5
|
||||||
|
t23.5 -4.5q20 0 32 9.5t16 23.5l7 26l82 -22l-26 -97q-9 -35 -30 -53t-48 -18q-24 0 -44.5 5t-37 10.5t-30 10.5t-24.5 5q-20 0 -32 -10t-16 -24l-7 -26l-81 22z" />
|
||||||
|
<glyph glyph-name="ntilde" unicode="ñ" horiz-adv-x="503"
|
||||||
|
d="M85 700q10 35 31 53t48 18q24 0 44.5 -4.5t37 -10.5t30 -10.5t23.5 -4.5q20 0 32 9.5t16 23.5l7 26l82 -22l-26 -97q-9 -35 -30 -53t-48 -18q-24 0 -44.5 5t-37 10.5t-30 10.5t-24.5 5q-20 0 -32 -10t-16 -24l-7 -26l-81 22zM248 0h-224v559h224v-105q19 0 38 -6.5
|
||||||
|
t35.5 -18.5t29.5 -28t19 -35v193h109v-559h-109v73q0 56 -14.5 87t-34 46t-40 18t-33.5 3v-227z" />
|
||||||
|
<glyph glyph-name="otilde" unicode="õ" horiz-adv-x="503"
|
||||||
|
d="M85 700q10 35 31 53t48 18q24 0 44.5 -4.5t37 -10.5t30 -10.5t23.5 -4.5q20 0 32 9.5t16 23.5l7 26l82 -22l-26 -97q-9 -35 -30 -53t-48 -18q-24 0 -44.5 5t-37 10.5t-30 10.5t-24.5 5q-20 0 -32 -10t-16 -24l-7 -26l-81 22zM24 456q0 29 9.5 48.5t25 31.5t35 17.5
|
||||||
|
t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-350q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v350zM248 339q0 -58 17.5 -84t43.5 -26q25 0 43 26t18 84q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="cedilla" unicode="¸" horiz-adv-x="218"
|
||||||
|
d="M124 -116q0 15 -9 19t-24 4h-28q-15 0 -24 9t-9 24v97h70v-77h55q15 0 24 -9t9 -24v-93q0 -15 -9 -24t-24 -9h-124v55h60q15 0 24 4t9 19v5z" />
|
||||||
|
<glyph glyph-name="ccedilla" unicode="ç" horiz-adv-x="503"
|
||||||
|
d="M248 339q0 -58 17.5 -84t43.5 -26q22 0 38.5 20t20.5 65h111v-208q0 -48 -30 -77t-88 -29h-219q-57 0 -87.5 29t-30.5 77v350q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-92h-111q-4 45 -20.5 65.5t-38.5 20.5
|
||||||
|
q-26 0 -43.5 -26t-17.5 -85zM284 -116q0 15 -9 19t-24 4h-28q-15 0 -24 9t-9 24v97h70v-77h55q15 0 24 -9t9 -24v-93q0 -15 -9 -24t-24 -9h-124v55h60q15 0 24 4t9 19v5z" />
|
||||||
|
<glyph glyph-name="Ccedilla" unicode="Ç" horiz-adv-x="503"
|
||||||
|
d="M344 -116q0 15 -9 19t-24 4h-28q-15 0 -24 9t-9 24v97h70v-77h55q15 0 24 -9t9 -24v-93q0 -15 -9 -24t-24 -9h-124v55h60q15 0 24 4t9 19v5zM310 424q0 -73 22 -105.5t54 -32.5q28 0 48.5 25t25.5 82h139v-260q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5
|
||||||
|
v437q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-115h-139q-5 57 -25.5 82.5t-48.5 25.5q-32 0 -54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="Ntilde" unicode="Ñ"
|
||||||
|
d="M310 0h-280v699h280v-131q23 0 47 -8.5t44.5 -23t36.5 -35t24 -44.5v242h137v-699h-137v91q0 70 -18 109t-42.5 57.5t-50 22.5t-41.5 4v-284zM204.853 758.073q9.97266 14.7041 30.917 22.2656q20.9434 7.5625 47.8711 7.5625q23.9355 0 44.3799 -1.89062
|
||||||
|
q20.4453 -1.89062 36.9004 -4.41113q16.4561 -2.52051 29.9199 -4.41113t23.4365 -1.89062q19.9463 0 31.9141 3.99121q11.9678 3.99023 15.957 9.87207l6.98145 10.9229l81.7803 -9.24219l-25.9307 -40.75q-8.97559 -14.7041 -29.9189 -22.2656
|
||||||
|
q-20.9443 -7.5625 -47.8711 -7.5625q-23.9355 0 -44.3809 2.10059t-36.9004 4.41113q-16.4561 2.31055 -29.9199 4.41113t-24.4336 2.10059q-19.9473 0 -31.9141 -4.20117q-11.9688 -4.20117 -15.957 -10.082l-6.98145 -10.9229l-80.7822 9.24219z" />
|
||||||
|
<glyph glyph-name="Atilde" unicode="Ã"
|
||||||
|
d="M164.853 758.073q9.97266 14.7041 30.917 22.2656q20.9434 7.5625 47.8711 7.5625q23.9355 0 44.3799 -1.89062q20.4453 -1.89062 36.9004 -4.41113q16.4561 -2.52051 29.9199 -4.41113t23.4365 -1.89062q19.9463 0 31.9141 3.99121q11.9678 3.99023 15.957 9.87207
|
||||||
|
l6.98145 10.9229l81.7803 -9.24219l-25.9307 -40.75q-8.97559 -14.7041 -29.9189 -22.2656q-20.9443 -7.5625 -47.8711 -7.5625q-23.9355 0 -44.3809 2.10059t-36.9004 4.41113q-16.4561 2.31055 -29.9199 4.41113t-24.4336 2.10059q-19.9473 0 -31.9141 -4.20117
|
||||||
|
q-11.9688 -4.20117 -15.957 -10.082l-6.98145 -10.9229l-80.7822 9.24219zM462 0v252h-152v-252h-280v570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-570h-137zM462 424q0 73 -22 106t-54 33t-54 -33t-22 -106v-16h152v16z" />
|
||||||
|
<glyph glyph-name="Otilde" unicode="Õ"
|
||||||
|
d="M164.853 758.073q9.97266 14.7041 30.917 22.2656q20.9434 7.5625 47.8711 7.5625q23.9355 0 44.3799 -1.89062q20.4453 -1.89062 36.9004 -4.41113q16.4561 -2.52051 29.9199 -4.41113t23.4365 -1.89062q19.9463 0 31.9141 3.99121q11.9678 3.99023 15.957 9.87207
|
||||||
|
l6.98145 10.9229l81.7803 -9.24219l-25.9307 -40.75q-8.97559 -14.7041 -29.9189 -22.2656q-20.9443 -7.5625 -47.8711 -7.5625q-23.9355 0 -44.3809 2.10059t-36.9004 4.41113q-16.4561 2.31055 -29.9199 4.41113t-24.4336 2.10059q-19.9473 0 -31.9141 -4.20117
|
||||||
|
q-11.9688 -4.20117 -15.957 -10.082l-6.98145 -10.9229l-80.7822 9.24219zM30 570q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-437q0 -60 -38 -96.5t-110 -36.5h-273q-72 0 -110 36.5t-38 96.5v437zM310 424q0 -73 22 -105.5
|
||||||
|
t54 -32.5t54 32.5t22 105.5t-22 106t-54 33t-54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="bullet" unicode="•" horiz-adv-x="292"
|
||||||
|
d="M30 404q0 36 9.5 62.5t25.5 43.5t37 25t44 8t44 -8t37 -25t25.5 -43.5t9.5 -62.5t-9.5 -62.5t-25.5 -43t-37 -24.5t-44 -8t-44 8t-37 24.5t-25.5 43t-9.5 62.5z" />
|
||||||
|
<glyph glyph-name="dagger" unicode="†" horiz-adv-x="634"
|
||||||
|
d="M205 609v191h224v-191h181v-119h-184l-27 -690h-164l-28 690h-183v119h181z" />
|
||||||
|
<glyph glyph-name="daggerdbl" unicode="‡" horiz-adv-x="634"
|
||||||
|
d="M205 609v191h224v-191h181v-119h-189l-22 -190l22 -190h189v-119h-181v-191h-224v191h-181v119h189l22 190l-22 190h-189v119h181z" />
|
||||||
|
<glyph glyph-name="section" unicode="§" horiz-adv-x="503"
|
||||||
|
d="M24 520v177q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-92h-111q-4 45 -20.5 65.5t-38.5 20.5q-26 0 -43.5 -19t-17.5 -60q0 -57 27 -82.5t96 -25.5q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-202q0 -36 -16 -60
|
||||||
|
q16 -24 16 -59v-177q0 -29 -9.5 -48.5t-25 -31.5t-35 -17.5t-38.5 -5.5h-239q-19 0 -38.5 5.5t-35 17.5t-25 31.5t-9.5 48.5v92h111q4 -45 20.5 -65.5t38.5 -20.5q26 0 43.5 19t17.5 60q0 57 -27 82.5t-96 25.5q-19 0 -38.5 5.5t-35 17.5t-25 31.5t-9.5 48.5v202q0 18 4 33
|
||||||
|
t11 26q-7 11 -11 26t-4 34zM327 301q0 35 -22 57t-54 22q-28 0 -51 -19t-23 -60t23 -60.5t51 -19.5q32 0 54 22.5t22 57.5z" />
|
||||||
|
<glyph glyph-name="Thorn" unicode="Þ"
|
||||||
|
d="M310 364q0 -73 22 -106t54 -33t54 33t22 106t-22 106t-54 33t-54 -33t-22 -106zM310 89v-89h-280v699h280v-60h154q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-292q0 -36 -12 -60.5t-31.5 -40t-43.5 -22t-48 -6.5h-154z" />
|
||||||
|
<glyph glyph-name="thorn" unicode="þ" horiz-adv-x="503"
|
||||||
|
d="M248 291q0 -58 17.5 -84.5t43.5 -26.5q25 0 43 26.5t18 84.5q0 59 -18 85t-43 26q-26 0 -43.5 -26t-17.5 -85zM248 71v-71h-224v559h224v-48h123q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-234q0 -28 -9.5 -48t-25 -32t-35 -17.5t-38.5 -5.5h-123z" />
|
||||||
|
<glyph glyph-name="yacute" unicode="ý" horiz-adv-x="503"
|
||||||
|
d="M273 598h-60l30 101h160zM142 0v302l-117 257h152l75 -179l75 179h152l-113 -249v-310h-224z" />
|
||||||
|
<glyph glyph-name="Euro" unicode="€"
|
||||||
|
d="M30 318h100v54h-80v86h80v112q0 36 12 60.5t31.5 40t43.5 22t48 6.5h186q72 0 110 -36.5t38 -96.5v-77h-120q0 25 -5 41.5t-17 26t-32.5 13t-51.5 3.5q-50 0 -74.5 -30t-29.5 -85h140v-86h-140v-54h120v-86h-119q6 -51 30.5 -73.5t72.5 -22.5q31 0 51.5 3t32.5 11.5
|
||||||
|
t17 22.5t5 35h120v-79q0 -36 -12 -60.5t-31.5 -40t-43.5 -22t-48 -6.5h-199q-24 0 -48 6.5t-43.5 22t-31.5 40t-12 60.5v103h-100v86z" />
|
||||||
|
<glyph glyph-name="Yacute" unicode="Ý"
|
||||||
|
d="M359.37 707.711h-59.6846l29.8418 92h159.16zM177 0v378l-146 321h190l94 -224l94 224h190l-142 -312v-387h-280z" />
|
||||||
|
<glyph glyph-name="Eth" unicode="Ð" horiz-adv-x="730"
|
||||||
|
d="M30 455h101v244h434q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-437q0 -60 -38 -96.5t-110 -36.5h-421v319h-101v136zM411 424q0 -73 22 -105.5t54 -32.5t54 32.5t22 105.5t-22 106t-54 33t-54 -33t-22 -106z" />
|
||||||
|
<glyph glyph-name="eth" unicode="ð" horiz-adv-x="584"
|
||||||
|
d="M24 364h81v195h347q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-350q0 -48 -30.5 -77t-87.5 -29h-337v255h-81v109zM329 339q0 -58 17.5 -84t43.5 -26q25 0 42.5 26t17.5 84q0 59 -17.5 85t-42.5 26q-26 0 -43.5 -26t-17.5 -85z" />
|
||||||
|
<glyph glyph-name="Zcaron" unicode="Ž"
|
||||||
|
d="M157 799.889h130l60 -36.5361l60 36.5361h130l-190 -90.0029zM599 149v-149h-569v149l289 401h-289v149h569v-149l-289 -401h289z" />
|
||||||
|
<glyph glyph-name="zcaron" unicode="ž" horiz-adv-x="503"
|
||||||
|
d="M70 699h130l60 -41l60 41h130l-190 -101zM479 119v-119h-455v119l231 321h-231v119h455v-119l-231 -321h231z" />
|
||||||
|
<glyph glyph-name="Scaron" unicode="Š"
|
||||||
|
d="M157 799.889h130l60 -36.5361l60 36.5361h130l-190 -90.0029zM165 295q-24 0 -48 6.5t-43.5 22t-31.5 40t-12 60.5v146q0 36 12 60.5t31.5 40t43.5 22t48 6.5h299q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-115h-139q-5 57 -25.5 82.5t-48.5 25.5q-32 0 -54 -24t-22 -75
|
||||||
|
q0 -21 8 -33t26 -18t47.5 -7.5t72.5 -1.5q24 0 48 -6.5t43.5 -22t31.5 -40t12 -60.5v-146q0 -36 -12 -60.5t-31.5 -40t-43.5 -22t-48 -6.5h-299q-24 0 -48 6.5t-43.5 22t-31.5 40t-12 60.5v115h139q5 -57 25.5 -82.5t48.5 -25.5q32 0 54 24t22 75q0 21 -8 33t-26 18
|
||||||
|
t-47.5 7.5t-72.5 1.5z" />
|
||||||
|
<glyph glyph-name="scaron" unicode="š" horiz-adv-x="503"
|
||||||
|
d="M70 699h130l60 -41l60 41h130l-190 -101zM132 236q-19 0 -38.5 5.5t-35 17.5t-25 31.5t-9.5 48.5v117q0 29 9.5 48.5t25 31.5t35 17.5t38.5 5.5h239q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-92h-111q-4 45 -20.5 65.5t-38.5 20.5q-26 0 -43.5 -19t-17.5 -60
|
||||||
|
q0 -17 6.5 -26.5t21 -14.5t38 -6t57.5 -1q19 0 38.5 -5.5t35 -17.5t25 -31.5t9.5 -48.5v-117q0 -29 -9.5 -48.5t-25 -31.5t-35 -17.5t-38.5 -5.5h-239q-19 0 -38.5 5.5t-35 17.5t-25 31.5t-9.5 48.5v92h111q4 -45 20.5 -65.5t38.5 -20.5q26 0 43.5 19t17.5 60
|
||||||
|
q0 17 -6.5 26.5t-21 14.5t-38 6t-57.5 1z" />
|
||||||
|
<glyph glyph-name="twosuperior" unicode="²" horiz-adv-x="402"
|
||||||
|
d="M297 441q-55 0 -77 -6t-22 -33v-63h185v-87h-364v176q0 23 8 39t20.5 25.5t28 13.5t30.5 4q54 0 76 6t22 33q0 32 -14.5 47.5t-34.5 15.5q-17 0 -30.5 -16.5t-16.5 -52.5h-89v74q0 23 8 38.5t20.5 25.5t28 14t30.5 4h191q15 0 30.5 -4t28 -14t20 -25.5t7.5 -38.5v-94
|
||||||
|
q0 -23 -7.5 -38.5t-20 -25.5t-28 -14t-30.5 -4z" />
|
||||||
|
<glyph glyph-name="threesuperior" unicode="³" horiz-adv-x="402"
|
||||||
|
d="M155 339q20 0 34.5 9.5t14.5 36.5q0 28 -14.5 38t-34.5 10v80q20 0 34.5 12.5t14.5 39.5q0 28 -14.5 40.5t-34.5 12.5q-17 0 -30.5 -19.5t-16.5 -55.5h-89v74q0 23 8 38.5t20.5 25.5t28 14t30.5 4h183q46 0 70 -23.5t24 -61.5v-44q0 -42 -15 -62.5t-46 -33.5
|
||||||
|
q31 -9 46 -32t15 -66v-42q0 -23 -7.5 -38.5t-20 -25.5t-28 -14t-30.5 -4h-191q-15 0 -30.5 4t-28 14t-20.5 25.5t-8 38.5v74h89q3 -36 16.5 -52.5t30.5 -16.5z" />
|
||||||
|
<glyph glyph-name="onesuperior" unicode="¹" horiz-adv-x="402"
|
||||||
|
d="M383 347v-95h-364v95h95v257l-95 -32v95l95 32h179v-352h90z" />
|
||||||
|
<glyph glyph-name="brokenbar" unicode="¦" horiz-adv-x="250"
|
||||||
|
d="M220 -200h-190v420h190v-420zM30 800h190v-420h-190v420z" />
|
||||||
|
<glyph glyph-name="multiply" unicode="×" horiz-adv-x="449"
|
||||||
|
d="M86 496l138 -138l140 139l67 -68l-139 -139l139 -140l-67 -67l-140 139l-138 -139l-68 68l138 139l-138 138z" />
|
||||||
|
</font>
|
||||||
|
</defs></svg>
|
||||||
|
After Width: | Height: | Size: 54 KiB |
BIN
assets/duck_hunt/duckhunt.ttf
Normal file
BIN
assets/duck_hunt/duckhunt.woff
Normal file
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
|
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"name": "subcon/frontpage",
|
|
||||||
"description": "Subcon town frontpage",
|
|
||||||
"type": "project",
|
|
||||||
"license": "BOML-1.0.0",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Subcon\\Frontpage\\": "src/",
|
|
||||||
"Subcon\\Zap\\": "libs/zap/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Fristi",
|
|
||||||
"email": "fristi@subcon.town"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"minimum-stability": "stable",
|
|
||||||
"require": {
|
|
||||||
"league/commonmark": "^2.4",
|
|
||||||
"symfony/yaml": "^6.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
<?php return [
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Application configuration
|
|
||||||
*
|
|
||||||
* These settings contain the base configuration of your application.
|
|
||||||
* It is recommended that you set encryption.key as this key will be used
|
|
||||||
* to provide data encryption to your application.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'application' => [
|
|
||||||
'name' => 'Subcon Town Frontpage',
|
|
||||||
'url' => 'http://localhost',
|
|
||||||
'debug' => false
|
|
||||||
],
|
|
||||||
|
|
||||||
'encryption' => [
|
|
||||||
'key' => ''
|
|
||||||
],
|
|
||||||
|
|
||||||
'frontpage' => [
|
|
||||||
'articles' => [
|
|
||||||
'2023/frontpage_updates_and_more.md',
|
|
||||||
'2023/plans_for_the_year.md'
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
138
index.html
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Subcon.town - Happy Dreams!</title>
|
||||||
|
|
||||||
|
<link rel="shortcut icon" type="image/jpg" href="assets/subcon/favicon_16.png" sizes="16x16"/>
|
||||||
|
<link rel="shortcut icon" type="image/jpg" href="assets/subcon/favicon_32.png" sizes="32x32"/>
|
||||||
|
|
||||||
|
<link href="style.css?v=1.0.0" rel="stylesheet"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<header>
|
||||||
|
<img src="assets/subcon/logo_128.png" alt="Subcon Town" />
|
||||||
|
<ul>
|
||||||
|
<li><a href="#home">Home</a></li>
|
||||||
|
<li><a href="#services">Services</a></li>
|
||||||
|
<li><a href="#faq">FAQ</a></li>
|
||||||
|
<li><a href="#contact">Contact</a></li>
|
||||||
|
</ul>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div class="content" id="home">
|
||||||
|
<p>
|
||||||
|
Welcome to subcon.town! Subcon is a small server ran by <a href="#">@fristi</a> that
|
||||||
|
hosts some personal and small community services.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="content" id="services">
|
||||||
|
<h1>Services</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Subcon.town currently hosts the following services:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr> <td>Bookstack wiki:</td> <td><a href="https://wiki.subcon.town">wiki.subcon.town</a></td> </tr>
|
||||||
|
<tr> <td>Gitea:</td> <td><a href="https://vcs.subcon.town">vcs.subcon.town</a></td> </tr>
|
||||||
|
<tr> <td>Minecraft:</td> <td class="muted">OFFLINE</td> </tr>
|
||||||
|
<tr> <td>Minecraft map:</td> <td class="muted">OFFLINE</td> </tr>
|
||||||
|
<tr> <td>Nextcloud:</td> <td><a href="https://cloud.subcon.town">cloud.subcon.town</a></td> </tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Additionally, subcon.town also serves the webpages for <a href="https://comfitu.re">comfitu.re</a>
|
||||||
|
and its subdomains.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="content" id="faq">
|
||||||
|
<h1>FAQ</h1>
|
||||||
|
<p>
|
||||||
|
<strong>Q</strong>: <em>What is Subcon Town?</em>
|
||||||
|
<br/>
|
||||||
|
<strong>A</strong>: This server you're talking to. <br/>
|
||||||
|
<strong>Better answer</strong>: Subcon Town is the little me-space on the web where I live;
|
||||||
|
it is themed after the concept of a subconscious dreamscape.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Q</strong>: <em>Can I get an account on one of your services?</em>
|
||||||
|
<br/>
|
||||||
|
<strong>A</strong>: No. Subcon is currently not open for new people, so it's a little
|
||||||
|
local club for close friends only at the moment.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Q</strong>: <em>Didn't you also run kartoffel.cafe?</em>
|
||||||
|
<br/>
|
||||||
|
<strong>A</strong>: Yes, but a recent change of plans made running an activitypub
|
||||||
|
instance not very feasible, so I made the difficult choice of closing
|
||||||
|
the instance, for good. I may run a new instance in the future though.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Q</strong>: <em>Is that the Duck Hunt font?</em>
|
||||||
|
<br/>
|
||||||
|
<strong>A</strong>: Yes.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Q</strong>: <em>What do you intend to run in the future?</em>
|
||||||
|
<br/>
|
||||||
|
<strong>A</strong>: That's not yet certain. But I've had the idea to
|
||||||
|
start converting the server into a <a href="https://tildeverse.org/">tilde community</a>
|
||||||
|
and offering more community-tailored services. I won't offer e-mail hosting though.
|
||||||
|
<em>Fuck e-mail servers.</em>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="content" id="contact">
|
||||||
|
<h1>Contact</h1>
|
||||||
|
<p>
|
||||||
|
Feel free to drop me a line if you have a question or just wanna talk to me. I can be
|
||||||
|
contacted at:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Email: <a href="mailto:info@subcon.town">info@subcon.town</a></li>
|
||||||
|
<li>Fediverse: <a href="https://mk.toast.cafe/@fristi">@fristi@mk.toast.cafe</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="content" id="copyright">
|
||||||
|
<h1>Copyright</h1>
|
||||||
|
<p>
|
||||||
|
Media used on this website, including images, videos, audio and fonts, fall under their
|
||||||
|
own respective licenses. The Subcon branding, including the logo and favicons, fall under
|
||||||
|
the <a target="_blank" href="assets/subcon/LICENSE">CC BY-NC-ND</a> license.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The remaining content and website source code are licensed under the
|
||||||
|
<a target="_blank" href="LICENSE">Blue Oak Model License</a>. The website source code
|
||||||
|
can be found <a target="_blank" href="https://vcs.subcon.town/fristi/subcon.town">here</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div style="text-align: right">
|
||||||
|
© 2021 Subcon Town.
|
||||||
|
<a href="#copyright">License details</a>
|
||||||
|
<a target="_blank" href="https://vcs.subcon.town/fristi/subcon.town">Source</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -1,106 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Subcon\Zap;
|
|
||||||
use Subcon\Zap\Config\Repository;
|
|
||||||
use Subcon\Zap\ErrorHandling\Handler;
|
|
||||||
use Subcon\Zap\Http\Response;
|
|
||||||
use Subcon\Zap\Routing\Router;
|
|
||||||
|
|
||||||
class Application
|
|
||||||
{
|
|
||||||
const VERSION = '2.0.0';
|
|
||||||
|
|
||||||
protected static $instance;
|
|
||||||
|
|
||||||
protected string $basePath;
|
|
||||||
|
|
||||||
protected Repository $config;
|
|
||||||
|
|
||||||
protected Router $router;
|
|
||||||
|
|
||||||
|
|
||||||
public function __construct(string $basePath = null)
|
|
||||||
{
|
|
||||||
if(!$basePath || !file_exists($basePath) || !is_dir($basePath)) {
|
|
||||||
$basePath = implode('/', array_slice(explode('/', $_SERVER['SCRIPT_NAME']), 0, -2)) . '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
//Initialize paths and load up environment and config files.
|
|
||||||
static::$instance = $this;
|
|
||||||
$this->setBasePath($basePath);
|
|
||||||
$this->initConfiguration();
|
|
||||||
$this->initErrorHandling();
|
|
||||||
$this->initRouting();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getInstance(): static
|
|
||||||
{
|
|
||||||
return static::$instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBasePath($path = '')
|
|
||||||
{
|
|
||||||
return $this->basePath . (!empty($path) ? DIRECTORY_SEPARATOR.$path : '');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPublicPath($path = '')
|
|
||||||
{
|
|
||||||
return $this->basePath . DIRECTORY_SEPARATOR . 'public_html' . (!empty($path) ? DIRECTORY_SEPARATOR.$path : '');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getViewPath($path = '')
|
|
||||||
{
|
|
||||||
return $this->basePath . DIRECTORY_SEPARATOR . 'resources/views' . (!empty($path) ? DIRECTORY_SEPARATOR.$path : '');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getConfig()
|
|
||||||
{
|
|
||||||
return $this->config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function run()
|
|
||||||
{
|
|
||||||
if(!$this->router) {
|
|
||||||
(new Response('Could not get router instance, aborting.', 500))
|
|
||||||
->send();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->router->run();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function setBasePath($basePath): static
|
|
||||||
{
|
|
||||||
$this->basePath = rtrim($basePath, '\/');
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function initConfiguration()
|
|
||||||
{
|
|
||||||
$this->config = new Repository($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function initErrorHandling()
|
|
||||||
{
|
|
||||||
set_error_handler(function (int $nr, string $error, ?string $file, ?int $line) {
|
|
||||||
(new Handler($this))->reportError($nr, $error, $file, $line);
|
|
||||||
$this->sendErrorResponse();
|
|
||||||
});
|
|
||||||
|
|
||||||
set_exception_handler(function (\Throwable $e) {
|
|
||||||
(new Handler($this))->report($e);
|
|
||||||
$this->sendErrorResponse();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function initRouting()
|
|
||||||
{
|
|
||||||
$this->router = new Router($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function sendErrorResponse()
|
|
||||||
{
|
|
||||||
(new Response('Whoops, something went wrong.', 500))
|
|
||||||
->send();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Subcon\Zap\Config;
|
|
||||||
|
|
||||||
use Subcon\Zap\Application;
|
|
||||||
|
|
||||||
class Repository
|
|
||||||
{
|
|
||||||
protected array $items;
|
|
||||||
|
|
||||||
public function __construct(Application $app)
|
|
||||||
{
|
|
||||||
//Load from cache if it exists
|
|
||||||
if($this->loadFromCache(realpath($app->getBasePath('cache')))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Otherwise, load from config files
|
|
||||||
$this->loadConfigurationFiles(realpath($app->getBasePath('config')));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function get(string $key, $default = null)
|
|
||||||
{
|
|
||||||
$keys = explode('.', $key);
|
|
||||||
|
|
||||||
$value = $this->items;
|
|
||||||
foreach($keys as $index) {
|
|
||||||
if(!key_exists($index, $value)) return $default;
|
|
||||||
$value = $value[$index];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildCache()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function loadFromCache(string $cachePath): bool
|
|
||||||
{
|
|
||||||
if(!file_exists($cachePath) || !file_exists($cachePath . DIRECTORY_SEPARATOR . 'config-cache.php')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->items = require $cachePath . DIRECTORY_SEPARATOR . 'config-cache.php';
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function loadConfigurationFiles(string $configPath)
|
|
||||||
{
|
|
||||||
$files = glob($configPath . DIRECTORY_SEPARATOR . '*.php');
|
|
||||||
|
|
||||||
if($files === false || empty($files)) {
|
|
||||||
throw new \RuntimeException('Unable to load configuration, no configuration files found.');
|
|
||||||
} elseif(!in_array($configPath . DIRECTORY_SEPARATOR . 'application.php', $files)) {
|
|
||||||
throw new \RuntimeException('Unable to load the application configuration, app configuration file is missing.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->items = [];
|
|
||||||
foreach($files as $file) {
|
|
||||||
$items = require $file;
|
|
||||||
$this->items = array_merge($this->items, $items);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Subcon\Zap\ErrorHandling;
|
|
||||||
|
|
||||||
use Subcon\Zap\Application;
|
|
||||||
|
|
||||||
class Handler
|
|
||||||
{
|
|
||||||
protected $app;
|
|
||||||
|
|
||||||
public function __construct(Application $app)
|
|
||||||
{
|
|
||||||
$this->app = $app;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function report(\Throwable $e)
|
|
||||||
{
|
|
||||||
$resource = fopen('php://stderr', 'w');
|
|
||||||
fwrite($resource, "An error was thrown! {$e->getMessage()}");
|
|
||||||
fwrite($resource, "{$e->getTraceAsString()}");
|
|
||||||
//Log the error.
|
|
||||||
}
|
|
||||||
|
|
||||||
public function reportError(int $error_nr, string $error, ?string $file, ?int $line)
|
|
||||||
{
|
|
||||||
$resource = fopen('php://stderr', 'w');
|
|
||||||
fwrite($resource, "An error occurred! {$error}");
|
|
||||||
fwrite($resource, "Occurred in {$file}, at line {$line}.");
|
|
||||||
//Log the error.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,235 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Subcon\Zap\Http;
|
|
||||||
|
|
||||||
class Response
|
|
||||||
{
|
|
||||||
// HTTP Response codes (shamelessly stolen from Symfony's Response class)
|
|
||||||
public const HTTP_CONTINUE = 100;
|
|
||||||
public const HTTP_SWITCHING_PROTOCOLS = 101;
|
|
||||||
public const HTTP_PROCESSING = 102; // RFC2518
|
|
||||||
public const HTTP_EARLY_HINTS = 103; // RFC8297
|
|
||||||
public const HTTP_OK = 200;
|
|
||||||
public const HTTP_CREATED = 201;
|
|
||||||
public const HTTP_ACCEPTED = 202;
|
|
||||||
public const HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
|
|
||||||
public const HTTP_NO_CONTENT = 204;
|
|
||||||
public const HTTP_RESET_CONTENT = 205;
|
|
||||||
public const HTTP_PARTIAL_CONTENT = 206;
|
|
||||||
public const HTTP_MULTI_STATUS = 207; // RFC4918
|
|
||||||
public const HTTP_ALREADY_REPORTED = 208; // RFC5842
|
|
||||||
public const HTTP_IM_USED = 226; // RFC3229
|
|
||||||
public const HTTP_MULTIPLE_CHOICES = 300;
|
|
||||||
public const HTTP_MOVED_PERMANENTLY = 301;
|
|
||||||
public const HTTP_FOUND = 302;
|
|
||||||
public const HTTP_SEE_OTHER = 303;
|
|
||||||
public const HTTP_NOT_MODIFIED = 304;
|
|
||||||
public const HTTP_USE_PROXY = 305;
|
|
||||||
public const HTTP_RESERVED = 306;
|
|
||||||
public const HTTP_TEMPORARY_REDIRECT = 307;
|
|
||||||
public const HTTP_PERMANENTLY_REDIRECT = 308; // RFC7238
|
|
||||||
public const HTTP_BAD_REQUEST = 400;
|
|
||||||
public const HTTP_UNAUTHORIZED = 401;
|
|
||||||
public const HTTP_PAYMENT_REQUIRED = 402;
|
|
||||||
public const HTTP_FORBIDDEN = 403;
|
|
||||||
public const HTTP_NOT_FOUND = 404;
|
|
||||||
public const HTTP_METHOD_NOT_ALLOWED = 405;
|
|
||||||
public const HTTP_NOT_ACCEPTABLE = 406;
|
|
||||||
public const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
|
|
||||||
public const HTTP_REQUEST_TIMEOUT = 408;
|
|
||||||
public const HTTP_CONFLICT = 409;
|
|
||||||
public const HTTP_GONE = 410;
|
|
||||||
public const HTTP_LENGTH_REQUIRED = 411;
|
|
||||||
public const HTTP_PRECONDITION_FAILED = 412;
|
|
||||||
public const HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
|
|
||||||
public const HTTP_REQUEST_URI_TOO_LONG = 414;
|
|
||||||
public const HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
|
|
||||||
public const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
|
|
||||||
public const HTTP_EXPECTATION_FAILED = 417;
|
|
||||||
public const HTTP_I_AM_A_TEAPOT = 418; // RFC2324
|
|
||||||
public const HTTP_MISDIRECTED_REQUEST = 421; // RFC7540
|
|
||||||
public const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918
|
|
||||||
public const HTTP_LOCKED = 423; // RFC4918
|
|
||||||
public const HTTP_FAILED_DEPENDENCY = 424; // RFC4918
|
|
||||||
public const HTTP_TOO_EARLY = 425; // RFC-ietf-httpbis-replay-04
|
|
||||||
public const HTTP_UPGRADE_REQUIRED = 426; // RFC2817
|
|
||||||
public const HTTP_PRECONDITION_REQUIRED = 428; // RFC6585
|
|
||||||
public const HTTP_TOO_MANY_REQUESTS = 429; // RFC6585
|
|
||||||
public const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585
|
|
||||||
public const HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; // RFC7725
|
|
||||||
public const HTTP_INTERNAL_SERVER_ERROR = 500;
|
|
||||||
public const HTTP_NOT_IMPLEMENTED = 501;
|
|
||||||
public const HTTP_BAD_GATEWAY = 502;
|
|
||||||
public const HTTP_SERVICE_UNAVAILABLE = 503;
|
|
||||||
public const HTTP_GATEWAY_TIMEOUT = 504;
|
|
||||||
public const HTTP_VERSION_NOT_SUPPORTED = 505;
|
|
||||||
public const HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506; // RFC2295
|
|
||||||
public const HTTP_INSUFFICIENT_STORAGE = 507; // RFC4918
|
|
||||||
public const HTTP_LOOP_DETECTED = 508; // RFC5842
|
|
||||||
public const HTTP_NOT_EXTENDED = 510; // RFC2774
|
|
||||||
public const HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511; // RFC6585
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Status codes translation table.
|
|
||||||
*
|
|
||||||
* Shamelessly stolen from Symfony's Response class.
|
|
||||||
*
|
|
||||||
* The list of codes is complete according to the
|
|
||||||
* {@link https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml Hypertext Transfer Protocol (HTTP) Status Code Registry}
|
|
||||||
* (last updated 2021-10-01).
|
|
||||||
*
|
|
||||||
* Unless otherwise noted, the status code is defined in RFC2616.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public static $statusTexts = [
|
|
||||||
100 => 'Continue',
|
|
||||||
101 => 'Switching Protocols',
|
|
||||||
102 => 'Processing', // RFC2518
|
|
||||||
103 => 'Early Hints',
|
|
||||||
200 => 'OK',
|
|
||||||
201 => 'Created',
|
|
||||||
202 => 'Accepted',
|
|
||||||
203 => 'Non-Authoritative Information',
|
|
||||||
204 => 'No Content',
|
|
||||||
205 => 'Reset Content',
|
|
||||||
206 => 'Partial Content',
|
|
||||||
207 => 'Multi-Status', // RFC4918
|
|
||||||
208 => 'Already Reported', // RFC5842
|
|
||||||
226 => 'IM Used', // RFC3229
|
|
||||||
300 => 'Multiple Choices',
|
|
||||||
301 => 'Moved Permanently',
|
|
||||||
302 => 'Found',
|
|
||||||
303 => 'See Other',
|
|
||||||
304 => 'Not Modified',
|
|
||||||
305 => 'Use Proxy',
|
|
||||||
307 => 'Temporary Redirect',
|
|
||||||
308 => 'Permanent Redirect', // RFC7238
|
|
||||||
400 => 'Bad Request',
|
|
||||||
401 => 'Unauthorized',
|
|
||||||
402 => 'Payment Required',
|
|
||||||
403 => 'Forbidden',
|
|
||||||
404 => 'Not Found',
|
|
||||||
405 => 'Method Not Allowed',
|
|
||||||
406 => 'Not Acceptable',
|
|
||||||
407 => 'Proxy Authentication Required',
|
|
||||||
408 => 'Request Timeout',
|
|
||||||
409 => 'Conflict',
|
|
||||||
410 => 'Gone',
|
|
||||||
411 => 'Length Required',
|
|
||||||
412 => 'Precondition Failed',
|
|
||||||
413 => 'Content Too Large', // RFC-ietf-httpbis-semantics
|
|
||||||
414 => 'URI Too Long',
|
|
||||||
415 => 'Unsupported Media Type',
|
|
||||||
416 => 'Range Not Satisfiable',
|
|
||||||
417 => 'Expectation Failed',
|
|
||||||
418 => 'I\'m a teapot', // RFC2324
|
|
||||||
421 => 'Misdirected Request', // RFC7540
|
|
||||||
422 => 'Unprocessable Content', // RFC-ietf-httpbis-semantics
|
|
||||||
423 => 'Locked', // RFC4918
|
|
||||||
424 => 'Failed Dependency', // RFC4918
|
|
||||||
425 => 'Too Early', // RFC-ietf-httpbis-replay-04
|
|
||||||
426 => 'Upgrade Required', // RFC2817
|
|
||||||
428 => 'Precondition Required', // RFC6585
|
|
||||||
429 => 'Too Many Requests', // RFC6585
|
|
||||||
431 => 'Request Header Fields Too Large', // RFC6585
|
|
||||||
451 => 'Unavailable For Legal Reasons', // RFC7725
|
|
||||||
500 => 'Internal Server Error',
|
|
||||||
501 => 'Not Implemented',
|
|
||||||
502 => 'Bad Gateway',
|
|
||||||
503 => 'Service Unavailable',
|
|
||||||
504 => 'Gateway Timeout',
|
|
||||||
505 => 'HTTP Version Not Supported',
|
|
||||||
506 => 'Variant Also Negotiates', // RFC2295
|
|
||||||
507 => 'Insufficient Storage', // RFC4918
|
|
||||||
508 => 'Loop Detected', // RFC5842
|
|
||||||
510 => 'Not Extended', // RFC2774
|
|
||||||
511 => 'Network Authentication Required', // RFC6585
|
|
||||||
];
|
|
||||||
|
|
||||||
protected string $charset = 'UTF-8';
|
|
||||||
protected string $protocol = '1.1';
|
|
||||||
protected array $headers;
|
|
||||||
protected int $status;
|
|
||||||
protected string $content;
|
|
||||||
|
|
||||||
public function __construct($content = '', int $status = 200, array $headers = [])
|
|
||||||
{
|
|
||||||
$this->headers = $headers;
|
|
||||||
$this->status = $status;
|
|
||||||
$this->setContent($content);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setHeader($header, $content): static
|
|
||||||
{
|
|
||||||
$this->headers[$header] = $content;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setStatus(int $status): static
|
|
||||||
{
|
|
||||||
$this->status = $status;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setContent($content): static
|
|
||||||
{
|
|
||||||
//If our content is an array of data, convert it to a json response.
|
|
||||||
if($content instanceof \ArrayObject || is_array($content)) {
|
|
||||||
$this->setHeader('Content-Type', 'application/json');
|
|
||||||
$json = json_encode($content);
|
|
||||||
|
|
||||||
if($json === false) {
|
|
||||||
throw new \InvalidArgumentException(json_last_error_msg());
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = $json;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Otherwise look if it can be rendered.
|
|
||||||
/*elseif($content instanceof RenderableInterface) {
|
|
||||||
$content = $content->render();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
$this->content = $content;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setProtocol(string $protocol): static
|
|
||||||
{
|
|
||||||
$this->protocol = $protocol;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function send()
|
|
||||||
{
|
|
||||||
$this->prepare();
|
|
||||||
|
|
||||||
//Send headers
|
|
||||||
if(!headers_sent()) {
|
|
||||||
foreach($this->headers as $header => $content) {
|
|
||||||
header("{$header}: $content", false, $this->status);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: send cookies
|
|
||||||
|
|
||||||
$statusText = static::$statusTexts[$this->status] ?? '';
|
|
||||||
header("HTTP/{$this->protocol} {$this->status} {$statusText}", true, $this->status);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Send content (if any)
|
|
||||||
if(!empty($this->content)) {
|
|
||||||
echo $this->content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function prepare()
|
|
||||||
{
|
|
||||||
if(!key_exists('Content-Type', $this->headers)) {
|
|
||||||
$this->headers['Content-Type'] = 'text/html; charset='.$this->charset;
|
|
||||||
} elseif (stripos($this->headers['Content-Type'], 'text/') === 0 && stripos($this->headers['Content-Type'], 'charset') === false) {
|
|
||||||
$this->headers['Content-Type'] = $this->headers['Content-Type'] . '; charset='.$this->charset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Subcon\Zap\Routing;
|
|
||||||
|
|
||||||
class Repository
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private array $routes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RoutingRepository constructor.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->routes = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a new route.
|
|
||||||
*
|
|
||||||
* @param string $pattern The uri pattern to match
|
|
||||||
* @param array|string $methods One or more HTTP methods to match
|
|
||||||
* @param string|array|callable $callback A callback to run if this route is called
|
|
||||||
* @param array $middlewares List of extra middlewares to run for this route
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function register(string $pattern, array|string $methods, string|array|callable $callback, array $middlewares = []): void
|
|
||||||
{
|
|
||||||
$route = new Route($pattern, $methods, $callback, $middlewares);
|
|
||||||
|
|
||||||
foreach($route->getMethods() as $method) {
|
|
||||||
$this->routes[$method][] = $route;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function get(string $pattern, string|array|callable $callback, array $middlewares = []): void
|
|
||||||
{
|
|
||||||
$this->register($pattern, 'GET', $callback, $middlewares);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function post(string $pattern, string|array|callable $callback, array $middlewares = []): void
|
|
||||||
{
|
|
||||||
$this->register($pattern, 'POST', $callback, $middlewares);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function put(string $pattern, string|array|callable $callback, array $middlewares = []): void
|
|
||||||
{
|
|
||||||
$this->register($pattern, 'PUT', $callback, $middlewares);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete(string $pattern, string|array|callable $callback, array $middlewares = []): void
|
|
||||||
{
|
|
||||||
$this->register($pattern, 'DELETE', $callback, $middlewares);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function options(string $pattern, string|array|callable $callback, array $middlewares = []): void
|
|
||||||
{
|
|
||||||
$this->register($pattern, 'OPTIONS', $callback, $middlewares);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function patch(string $pattern, string|array|callable $callback, array $middlewares = []): void
|
|
||||||
{
|
|
||||||
$this->register($pattern, 'PATCH', $callback, $middlewares);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function head(string $pattern, string|array|callable $callback, array $middlewares = []): void
|
|
||||||
{
|
|
||||||
$this->register($pattern, 'HEAD', $callback, $middlewares);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the list of registered routes.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getRoutes(): array
|
|
||||||
{
|
|
||||||
return $this->routes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,190 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Subcon\Zap\Routing;
|
|
||||||
|
|
||||||
class Route
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private string $name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private string $pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|array|callable
|
|
||||||
*/
|
|
||||||
private $callback;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array<string>
|
|
||||||
*/
|
|
||||||
private array $methods = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array<string>
|
|
||||||
*/
|
|
||||||
private array $middlewares = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array<string>
|
|
||||||
*/
|
|
||||||
private array $vars = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Route constructor.
|
|
||||||
*/
|
|
||||||
public function __construct(string $pattern, string|array $methods, string|array|callable $callback, array $middlewares = [])
|
|
||||||
{
|
|
||||||
if ($methods === []) {
|
|
||||||
throw new \InvalidArgumentException('HTTP methods argument was empty; must contain at least one method');
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_string($methods)) $methods = [$methods];
|
|
||||||
foreach($methods as $key => $method) {
|
|
||||||
$methods[$key] = strtoupper($method);
|
|
||||||
if (!in_array($methods[$key], ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH', 'HEAD'])) {
|
|
||||||
throw new \InvalidArgumentException("Invalid method '{$method}' specified.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->pattern = $pattern;
|
|
||||||
$this->callback = $callback;
|
|
||||||
$this->methods = $methods;
|
|
||||||
$this->middlewares = $middlewares;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $path
|
|
||||||
* @param string $method
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function match(string $path, string $method): bool
|
|
||||||
{
|
|
||||||
$regex = $this->getPattern();
|
|
||||||
foreach ($this->getVarsNames() as $variable) {
|
|
||||||
$varName = trim($variable, '{\}');
|
|
||||||
$regex = str_replace($variable, '(?P<' . $varName . '>[^/]++)', $regex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array($method, $this->getMethods()) && preg_match('#^' . $regex . '$#sD', self::trimPath($path), $matches)) {
|
|
||||||
$values = array_filter($matches, static function ($key) {
|
|
||||||
return is_string($key);
|
|
||||||
}, ARRAY_FILTER_USE_KEY);
|
|
||||||
foreach ($values as $key => $value) {
|
|
||||||
$this->vars[$key] = $value;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getName(): string
|
|
||||||
{
|
|
||||||
return $this->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $name
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setName(string $name): static
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getPattern(): string
|
|
||||||
{
|
|
||||||
return $this->pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string|array|callable
|
|
||||||
*/
|
|
||||||
public function getCallback(): string|array|callable
|
|
||||||
{
|
|
||||||
return $this->callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array|string[]
|
|
||||||
*/
|
|
||||||
public function getMethods(): array
|
|
||||||
{
|
|
||||||
return $this->methods;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getVarsNames(): array
|
|
||||||
{
|
|
||||||
preg_match_all('/{[^}]*}/', $this->pattern, $matches);
|
|
||||||
return reset($matches) ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hasVars(): bool
|
|
||||||
{
|
|
||||||
return $this->getVarsNames() !== [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getVars(): array
|
|
||||||
{
|
|
||||||
return $this->vars;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getMiddlewares(): array
|
|
||||||
{
|
|
||||||
return $this->middlewares;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function run()
|
|
||||||
{
|
|
||||||
//TODO: middlewares
|
|
||||||
//TODO: allow for automatically injecting dependencies for function arguments
|
|
||||||
|
|
||||||
if(is_callable($this->callback)) {
|
|
||||||
return call_user_func_array($this->callback, $this->vars);
|
|
||||||
} elseif (is_array($this->callback) && [0,1] == array_keys($this->callback)) {
|
|
||||||
$class = $this->callback[0];
|
|
||||||
$method = $this->callback[1];
|
|
||||||
if(class_exists($class) && method_exists($class, $method)) {
|
|
||||||
$controller = new $class();
|
|
||||||
return $controller->$method(...$this->vars);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \RuntimeException("Could not resolve callable function for route.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $path
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function trimPath(string $path): string
|
|
||||||
{
|
|
||||||
return '/' . rtrim(ltrim(trim($path), '/'), '/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,230 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Subcon\Zap\Routing;
|
|
||||||
|
|
||||||
use Subcon\Zap\Application;
|
|
||||||
use Subcon\Zap\Http\Response;
|
|
||||||
|
|
||||||
class Router
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var Application
|
|
||||||
*/
|
|
||||||
private Application $app;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private array $routes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private string $requestUri;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private string $requestMethod;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private array $requestHeaders;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Application $app
|
|
||||||
*/
|
|
||||||
public function __construct(Application $app)
|
|
||||||
{
|
|
||||||
$this->app = $app;
|
|
||||||
|
|
||||||
//Load routes from cache, or fall back to loading from file
|
|
||||||
if($this->loadFromCache(realpath($app->getBasePath('cache')))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->loadFromRouteFile(realpath($app->getBasePath('routes')));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function run(): void
|
|
||||||
{
|
|
||||||
//Parse request
|
|
||||||
$this->requestUri = $this->getRequestUri();
|
|
||||||
$this->requestMethod = $this->getRequestMethod();
|
|
||||||
$this->requestHeaders ??= $this->getRequestHeaders();
|
|
||||||
|
|
||||||
//Find the first matching route. Only one route will ever be executed.
|
|
||||||
$route = $this->findRoute($this->requestUri, $this->requestMethod);
|
|
||||||
|
|
||||||
//If route was found, run it. Otherwise return a 404 response.
|
|
||||||
if($route) {
|
|
||||||
$response = $this->handleRoute($route);
|
|
||||||
} else {
|
|
||||||
$response = $this->handleNotFoundResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Send response.
|
|
||||||
if (!is_a($response, Response::class)) {
|
|
||||||
$response = new Response((string) $response);
|
|
||||||
}
|
|
||||||
$response->send();
|
|
||||||
|
|
||||||
//If the request was a HEAD request, empty the output buffer.
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'HEAD') {
|
|
||||||
ob_end_clean();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildCache()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define the current relative URI.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function getRequestUri(): string
|
|
||||||
{
|
|
||||||
$uri = rawurldecode($_SERVER['REQUEST_URI']);
|
|
||||||
|
|
||||||
// Don't take query params into account on the URL
|
|
||||||
if (strstr($uri, '?')) {
|
|
||||||
$uri = substr($uri, 0, strpos($uri, '?'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove trailing slash + enforce a slash at the start
|
|
||||||
return '/' . trim($uri, '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all request headers.
|
|
||||||
*
|
|
||||||
* @return array The request headers
|
|
||||||
*/
|
|
||||||
protected function getRequestHeaders(): array
|
|
||||||
{
|
|
||||||
if(!empty($this->requestHeaders)) return $this->requestHeaders;
|
|
||||||
|
|
||||||
$headers = [];
|
|
||||||
|
|
||||||
// If getallheaders() is available, use that
|
|
||||||
if (function_exists('getallheaders')) {
|
|
||||||
$headers = getallheaders();
|
|
||||||
|
|
||||||
// getallheaders() can return false if something went wrong
|
|
||||||
if ($headers !== false) {
|
|
||||||
$this->requestHeaders = $headers;
|
|
||||||
return $headers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method getallheaders() not available or went wrong: manually extract them
|
|
||||||
foreach ($_SERVER as $name => $value) {
|
|
||||||
if ((substr($name, 0, 5) == 'HTTP_') || ($name == 'CONTENT_TYPE') || ($name == 'CONTENT_LENGTH')) {
|
|
||||||
$headers[str_replace([' ', 'Http'], ['-', 'HTTP'], ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->requestHeaders = $headers;
|
|
||||||
return $headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the request method used, taking overrides into account.
|
|
||||||
*
|
|
||||||
* @return string The request method to handle
|
|
||||||
*/
|
|
||||||
protected function getRequestMethod(): string
|
|
||||||
{
|
|
||||||
// Take the method as found in $_SERVER
|
|
||||||
$method = $_SERVER['REQUEST_METHOD'];
|
|
||||||
|
|
||||||
// If it's a HEAD request override it to being GET and prevent any output, as per HTTP Specification
|
|
||||||
// @url http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'HEAD') {
|
|
||||||
ob_start();
|
|
||||||
$method = 'GET';
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it's a POST request, check for a method override header
|
|
||||||
elseif ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
|
||||||
$headers = $this->getRequestHeaders();
|
|
||||||
if (isset($headers['X-HTTP-Method-Override']) && in_array($headers['X-HTTP-Method-Override'], array('PUT', 'DELETE', 'PATCH'))) {
|
|
||||||
$method = $headers['X-HTTP-Method-Override'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $method;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function loadFromCache(string $cachePath): bool
|
|
||||||
{
|
|
||||||
if(!file_exists($cachePath) || !file_exists($cachePath . DIRECTORY_SEPARATOR . 'route-cache.php')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->routes = require $cachePath . DIRECTORY_SEPARATOR . 'route-cache.php';
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function loadFromRouteFile(string $routePath): void
|
|
||||||
{
|
|
||||||
if(!file_exists($routePath) || !file_exists($routePath . DIRECTORY_SEPARATOR . 'routes.php')) {
|
|
||||||
throw new \RuntimeException('Unable to initialize routes: route file not found.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$repository = new Repository();
|
|
||||||
$routes = require $routePath . DIRECTORY_SEPARATOR . 'routes.php';
|
|
||||||
|
|
||||||
if(!is_callable($routes)) {
|
|
||||||
throw new \RuntimeException('Unable to initialize routes: route file does not contain callable function.');
|
|
||||||
}
|
|
||||||
|
|
||||||
//Initialize routes
|
|
||||||
call_user_func($routes, $repository);
|
|
||||||
$this->routes = $repository->getRoutes();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function findRoute(string $path, string $method): ?Route
|
|
||||||
{
|
|
||||||
$method = strtoupper($method);
|
|
||||||
|
|
||||||
if(key_exists($method, $this->routes)) {
|
|
||||||
foreach($this->routes[$method] as $route) {
|
|
||||||
if($route->match($path, $method)) {
|
|
||||||
return $route;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function handleRoute(Route $route)
|
|
||||||
{
|
|
||||||
//Todo: run route middleware and route handler.
|
|
||||||
|
|
||||||
return $route->run();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function handleNotFoundResponse()
|
|
||||||
{
|
|
||||||
//Do we have an error template?
|
|
||||||
$template = $this->app->getViewPath('errors/404.html');
|
|
||||||
if(file_exists($template)) {
|
|
||||||
ob_start();
|
|
||||||
require $template;
|
|
||||||
$response = ob_get_clean();
|
|
||||||
|
|
||||||
return new Response($response, 404);
|
|
||||||
} else {
|
|
||||||
return new Response('Whoops! Could not find that file.', 404);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
RewriteEngine on
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-d
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
|
||||||
RewriteRule . index.php [L]
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
# Blue Oak Model License
|
|
||||||
|
|
||||||
Version 1.0.0
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
This license gives everyone as much permission to work with
|
|
||||||
this software as possible, while protecting contributors
|
|
||||||
from liability.
|
|
||||||
|
|
||||||
## Acceptance
|
|
||||||
|
|
||||||
In order to receive this license, you must agree to its
|
|
||||||
rules. The rules of this license are both obligations
|
|
||||||
under that agreement and conditions to your license.
|
|
||||||
You must not do anything with this software that triggers
|
|
||||||
a rule that you cannot or will not follow.
|
|
||||||
|
|
||||||
## Copyright
|
|
||||||
|
|
||||||
Each contributor licenses you to do everything with this
|
|
||||||
software that would otherwise infringe that contributor's
|
|
||||||
copyright in it.
|
|
||||||
|
|
||||||
## Notices
|
|
||||||
|
|
||||||
You must ensure that everyone who gets a copy of
|
|
||||||
any part of this software from you, with or without
|
|
||||||
changes, also gets the text of this license or a link to
|
|
||||||
<https://blueoakcouncil.org/license/1.0.0>.
|
|
||||||
|
|
||||||
## Excuse
|
|
||||||
|
|
||||||
If anyone notifies you in writing that you have not
|
|
||||||
complied with [Notices](#notices), you can keep your
|
|
||||||
license by taking all practical steps to comply within 30
|
|
||||||
days after the notice. If you do not do so, your license
|
|
||||||
ends immediately.
|
|
||||||
|
|
||||||
## Patent
|
|
||||||
|
|
||||||
Each contributor licenses you to do everything with this
|
|
||||||
software that would otherwise infringe any patent claims
|
|
||||||
they can license or become able to license.
|
|
||||||
|
|
||||||
## Reliability
|
|
||||||
|
|
||||||
No contributor can revoke this license.
|
|
||||||
|
|
||||||
## No Liability
|
|
||||||
|
|
||||||
***As far as the law allows, this software comes as is,
|
|
||||||
without any warranty or condition, and no contributor
|
|
||||||
will be liable to anyone for any damages related to this
|
|
||||||
software or this license, under any kind of legal claim.***
|
|
||||||
|
Before Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 396 B |
|
Before Width: | Height: | Size: 545 B |
|
Before Width: | Height: | Size: 922 B |
|
|
@ -1,187 +0,0 @@
|
||||||
@font-face {
|
|
||||||
font-family: 'yoster_islandregular';
|
|
||||||
src: url('../fonts/yoster-web.woff2') format('woff2'),
|
|
||||||
url('../fonts/yoster-web.woff') format('woff');
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Variables */
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--font: "yoster_islandregular", monospace;
|
|
||||||
--font-size: 16px;
|
|
||||||
--line-height: 24px;
|
|
||||||
--spacing-normal: var(--font-size);
|
|
||||||
--spacing-large: var(--line-height);
|
|
||||||
--fg-color: rgba(255, 255, 255, 1);
|
|
||||||
--fg-shadow: 0px 2px 0px rgba(0,0,0, 0.4);
|
|
||||||
--bg-color: rgba(0, 0, 0, 0.3);
|
|
||||||
--bg-backdrop: saturate(300%) contrast(30%);
|
|
||||||
--link-color: rgba(215, 215, 109, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Structure */
|
|
||||||
|
|
||||||
html, body {
|
|
||||||
margin:0;
|
|
||||||
padding:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-image: url("../background3.png");
|
|
||||||
background-position: center center;
|
|
||||||
background-size: cover;
|
|
||||||
background-attachment: fixed;
|
|
||||||
overflow: hidden;
|
|
||||||
font-size: var(--font-size);
|
|
||||||
line-height: var(--line-height);
|
|
||||||
font-family: var(--font);
|
|
||||||
color: var(--fg-color);
|
|
||||||
text-shadow: var(--fg-shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
position: absolute;
|
|
||||||
left:0;
|
|
||||||
right:0;
|
|
||||||
height: 100%;
|
|
||||||
max-width: 640px;
|
|
||||||
padding: 0 10px;
|
|
||||||
margin: auto;
|
|
||||||
display:flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
background-color: var(--bg-color);
|
|
||||||
/*backdrop-filter: var(--bg-backdrop);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
display: flex;
|
|
||||||
margin: var(--spacing-large);
|
|
||||||
flex: 0 0 auto;
|
|
||||||
align-items: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
header img {
|
|
||||||
width: 265px;
|
|
||||||
object-fit: contain;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
header ul {
|
|
||||||
display: flex;
|
|
||||||
position: relative;
|
|
||||||
padding: 0;
|
|
||||||
height: 80px;
|
|
||||||
list-style: none;
|
|
||||||
font-size: 0;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
header ul li {
|
|
||||||
position: relative;
|
|
||||||
width: 50%;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
header ul li a{
|
|
||||||
display: block;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: normal;
|
|
||||||
line-height: 36px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
header ul li a:hover:before {
|
|
||||||
content: "> ";
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
height: 488px;
|
|
||||||
padding: var(--spacing-large);
|
|
||||||
border: 32px solid transparent;
|
|
||||||
border-image: url('../border2x2.png') 32 fill round;
|
|
||||||
overflow-y: auto;
|
|
||||||
scrollbar-color: #fff transparent;
|
|
||||||
scrollbar-width: thin;
|
|
||||||
}
|
|
||||||
|
|
||||||
main .inner-main {
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
|
|
||||||
main .inner-main::-webkit-scrollbar { width: 3px; }
|
|
||||||
main .inner-main::-webkit-scrollbar-track { background: transparent; }
|
|
||||||
main .inner-main::-webkit-scrollbar-thumb { background: #fff; }
|
|
||||||
|
|
||||||
footer {
|
|
||||||
margin: var(--spacing-large);
|
|
||||||
height: var(--line-height);
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Element styling */
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: var(--spacing-large) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
color: rgba(255, 255, 255, 0.5);
|
|
||||||
margin: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 24px;
|
|
||||||
text-align: center;
|
|
||||||
margin: 24px 0 36px 0;
|
|
||||||
text-shadow: 0px 3px 0px rgba(0,0,0, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: var(--font-size);
|
|
||||||
margin: var(--spacing-large) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2:before {
|
|
||||||
content: "* ";
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--link-color);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not(header a):before, a:not(header a):after { color: var(--link-color); }
|
|
||||||
a:not(header a):before { content:"["; margin-right: 6px; }
|
|
||||||
a:not(header a):after { content:"]"; margin-left: 6px; }
|
|
||||||
|
|
||||||
table tbody tr td:first-child {
|
|
||||||
padding: 0 3em 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-stub p {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-stub-end {
|
|
||||||
text-align: right;
|
|
||||||
margin-bottom: var(--spacing-large);
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
(function(gogo){
|
|
||||||
let loading = false;
|
|
||||||
let elContent;
|
|
||||||
let elMain;
|
|
||||||
|
|
||||||
function loadContent(href, ignoreHistory = false)
|
|
||||||
{
|
|
||||||
if(!loading) {
|
|
||||||
loading = true;
|
|
||||||
gogo.ajax(href, 'GET')
|
|
||||||
.then((response) => {
|
|
||||||
if('error' in response) {
|
|
||||||
replaceContent(response.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if('content' in response) {
|
|
||||||
replaceContent(response.content);
|
|
||||||
if(!ignoreHistory) {
|
|
||||||
window.history.pushState(null, '', href);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loading = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function replaceContent(content)
|
|
||||||
{
|
|
||||||
if(elContent) {
|
|
||||||
elContent.innerHTML = content;
|
|
||||||
elMain.scrollTo(0, 0);
|
|
||||||
showAddresses()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showAddresses() {
|
|
||||||
let a = 'fristi';
|
|
||||||
let b = 'subcon.town';
|
|
||||||
let c = 'akkos.fritu.re';
|
|
||||||
|
|
||||||
gogo.getAll('.em').forEach( element => {
|
|
||||||
element.innerHTML = a + '@' + b;
|
|
||||||
element.setAttribute('href', 'mailto:' + a + '@' + b);
|
|
||||||
});
|
|
||||||
|
|
||||||
gogo.getAll('.fv').forEach( element => {
|
|
||||||
element.innerHTML = a + '@' + c;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('load', function(){
|
|
||||||
elContent = gogo.get('.content');
|
|
||||||
elMain = gogo.get('main');
|
|
||||||
gogo.get('.container').addEventListener('click', event => {
|
|
||||||
if(!event.target.classList.contains('page-link')) return;
|
|
||||||
loadContent(event.target.getAttribute('href'));
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
showAddresses();
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener('popstate', event => {
|
|
||||||
loadContent(document.location, true);
|
|
||||||
});
|
|
||||||
})(gogo);
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
/*!
|
|
||||||
* Subcon GoGo Tools v1.0.0
|
|
||||||
* Licensed under BOML-1.0.0 license.
|
|
||||||
*/
|
|
||||||
(function (root, factory) {
|
|
||||||
if (typeof define === "function" && define.amd) { //AMD
|
|
||||||
define(factory);
|
|
||||||
} else if (typeof exports === "object") { //CommonJS
|
|
||||||
module.exports = factory();
|
|
||||||
} else { //Browser global
|
|
||||||
root.gogo = factory();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Let everything know the library is ready
|
|
||||||
const event = new Event("gogoReady");
|
|
||||||
document.dispatchEvent(event);
|
|
||||||
}(this, function () {
|
|
||||||
let gogo = {};
|
|
||||||
|
|
||||||
//Query selectors
|
|
||||||
gogo.get = function(selector) {
|
|
||||||
return document.querySelector(selector);
|
|
||||||
};
|
|
||||||
|
|
||||||
gogo.getAll = function(selector) {
|
|
||||||
return document.querySelectorAll(selector);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Ajax
|
|
||||||
gogo.ajax = async function(url = '', method = 'GET', data = {}) {
|
|
||||||
//Set up fetch settings
|
|
||||||
let settings = {
|
|
||||||
method: method, // *GET, POST, PUT, DELETE, etc.
|
|
||||||
mode: 'cors', // no-cors, *cors, same-origin
|
|
||||||
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
|
|
||||||
credentials: 'same-origin', // include, *same-origin, omit
|
|
||||||
headers: {
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
// 'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
//'X-CSRF-TOKEN': qs('meta[name="csrf-token"]').getAttribute('content'),
|
|
||||||
'X-Requested-With': 'XMLHttpRequest' //Allow laravel to properly detect this as an AJAX request
|
|
||||||
},
|
|
||||||
redirect: 'follow', // manual, *follow, error
|
|
||||||
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
|
|
||||||
}
|
|
||||||
|
|
||||||
//If method is get or head, prepare data as query string
|
|
||||||
if(method === 'GET' || method === 'HEAD') {
|
|
||||||
if(Object.keys(data).length !== 0) {
|
|
||||||
let query = new URLSearchParams(data).toString()
|
|
||||||
url = url + '?' + query;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
settings['body'] = JSON.stringify(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Fetch
|
|
||||||
const response = await fetch(url, settings);
|
|
||||||
|
|
||||||
if(!response.ok || response.headers.get('content-type').indexOf('application/json') === -1) {
|
|
||||||
return {
|
|
||||||
'error': 'An error occurred while trying to fetch page data. Please refresh and try again.'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Return response (uses Promise API)
|
|
||||||
return response.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Used to allow injecting html and javascript from ajax requests
|
|
||||||
gogo.setHTML = function (element, html) {
|
|
||||||
element.innerHTML = html;
|
|
||||||
|
|
||||||
Array.from(element.querySelectorAll("script"))
|
|
||||||
.forEach( oldScriptEl => {
|
|
||||||
const newScriptEl = document.createElement("script");
|
|
||||||
|
|
||||||
Array.from(oldScriptEl.attributes).forEach( attr => {
|
|
||||||
newScriptEl.setAttribute(attr.name, attr.value)
|
|
||||||
});
|
|
||||||
|
|
||||||
const scriptText = document.createTextNode(oldScriptEl.innerHTML);
|
|
||||||
newScriptEl.appendChild(scriptText);
|
|
||||||
|
|
||||||
oldScriptEl.parentNode.replaceChild(newScriptEl, oldScriptEl);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return gogo;
|
|
||||||
}));
|
|
||||||
|
Before Width: | Height: | Size: 2 KiB |
|
|
@ -1,12 +0,0 @@
|
||||||
<?php
|
|
||||||
define('APP_START', microtime(true));
|
|
||||||
|
|
||||||
// Autoload classes
|
|
||||||
require __DIR__.'/../vendor/autoload.php';
|
|
||||||
|
|
||||||
// Boot application
|
|
||||||
$app = new \Subcon\Zap\Application(dirname(__DIR__));
|
|
||||||
|
|
||||||
//TODO: Console mode compatibility.
|
|
||||||
|
|
||||||
$app->run();
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
User-agent: *
|
|
||||||
Disallow: /
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
---
|
|
||||||
title: Introducing Funkwhale
|
|
||||||
author: Fristi
|
|
||||||
date: 2022-11
|
|
||||||
description: After some fiddling around on the server, I have managed to finally get a Funkwhale instance set up!
|
|
||||||
---
|
|
||||||
|
|
||||||
# Introducing Funkwhale
|
|
||||||
|
|
||||||
*November 2022, by Fristi*
|
|
||||||
|
|
||||||
After some fiddling around on the server, I have managed to finally get a Funkwhale instance
|
|
||||||
set up! Funkwhale is a piece of software that will let us host our music libraries. You can listen
|
|
||||||
to your and others' music from the web interface, or use any compatible app on your phone or tablet.
|
|
||||||
Besides that, Funkwhale federates, much like our Akkoma instance. You will be able to listen to the
|
|
||||||
libraries of people on other instances as well!
|
|
||||||
|
|
||||||
On a technical note, getting Funkwhale to work took a little bit of doing; it has been manually
|
|
||||||
set up according to the installation instructions for Arch Linux, adapted here and there to suit
|
|
||||||
Fedora. One remaining irk because of this, is that Funkwhale was not made with SELinux in mind.
|
|
||||||
One remaining problem that you might run into is that freshly uploaded music may not play initially;
|
|
||||||
this is caused by incorrect SELinux permissions. I have currently added a cronjob that will check
|
|
||||||
these permissions and fix them every few minutes. If your music does not play, please wait a few
|
|
||||||
minutes and try again.
|
|
||||||
|
|
||||||
For the time being, users will be limited to 5GB libraries. If needed, you may request to have this
|
|
||||||
limit changed. Please do check before uploading if your music has already been uploaded by others;
|
|
||||||
preventing duplicate uploads will help conserve space on the server.
|
|
||||||
|
|
||||||
Happy listening!
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
---
|
|
||||||
title: Phasing out Gitea and introducing Fossil SCM
|
|
||||||
author: Fristi
|
|
||||||
date: 2022-11
|
|
||||||
description: Recently it has come to my attention that the owners of Gitea have been making some changes...
|
|
||||||
---
|
|
||||||
|
|
||||||
# Phasing out Gitea and introducing Fossil SCM
|
|
||||||
|
|
||||||
*November 2022, by Fristi*
|
|
||||||
|
|
||||||
Recently it has come to my attention that the owners of Gitea have been making some changes
|
|
||||||
in their project management, mainly in the form of providing support to businesses. For more
|
|
||||||
information, view [the Gitea blog](https://blog.gitea.io/2022/10/open-source-sustainment-and-the-future-of-gitea/).
|
|
||||||
|
|
||||||
Unfortunately, with the way things have gone, the community seems to be weary and distrustful of a
|
|
||||||
number of moves made by the current owners. My personal concerns are about one of the owners using
|
|
||||||
Gitea is a lucrative money-making scheme. To me, that's a deal breaker, as I don't know if I can
|
|
||||||
still trust the project after this. Unfortunate, since I know Gitea is supposed to be a community-run
|
|
||||||
effort.
|
|
||||||
|
|
||||||
As such, I have decided to deprecate the Gitea service on Subcon Town. It will no longer be updated,
|
|
||||||
but will be kept alive for a while until all projects have been migrated. I am additionally looking
|
|
||||||
into migrating the data to a Gogs installation, continuing a git hosting service that way. Meanwhile,
|
|
||||||
I have opted to set up Fossil as an alternative. Fossil SCM is a slightly different VCS, similar to git,
|
|
||||||
but more geared towards tightly nit development groups that work closer together.
|
|
||||||
|
|
||||||
While fossil may feel a bit more old-fashioned, I think it's also a bit more of a fit with Subcon's
|
|
||||||
pubnix feel. Users will be able to set up and manage their fossil repositories from their home
|
|
||||||
directories, in the new "public_fossil" directory. To create new repositories, you can use the
|
|
||||||
"mkfossil <filename>" command. This is a wrapper around "fossil init" that helps set the
|
|
||||||
correct file permissions. If done right, your new repo will pop up at
|
|
||||||
[museum.subcon.town](https://museum.subcon.town) from where you'll be able to administrate it.
|
|
||||||
|
|
||||||
With the introduction of new commands and functions for users, I plan on writing a wiki article
|
|
||||||
that lists all available functions and how to use them. This should help new users settle in.
|
|
||||||
Note that the README files in your home directories will be kept updated as well.
|
|
||||||
|
|
||||||
Hope to see you soon on Subcon Town!
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
---
|
|
||||||
title: Frontpage updates and more
|
|
||||||
author: fristi
|
|
||||||
date: 2023-06
|
|
||||||
description: It's been quiet for half a year. Subcon has been chucking along
|
|
||||||
quite well with nothing special happening. Even the dreaded Fedora 38 update
|
|
||||||
did not prove too much of a headache. All has been moseying along easily.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Frontpage updates and more
|
|
||||||
|
|
||||||
*June 2023, by Fristi*
|
|
||||||
|
|
||||||
It's been quiet for half a year. Subcon has been chucking along quite well with
|
|
||||||
nothing special happening. Even the dreaded Fedora 38 update did not prove too
|
|
||||||
much of a headache. All has been moseying along easily.
|
|
||||||
|
|
||||||
Actually, I've just not been in the mood to work much on the server recently
|
|
||||||
because of life stuff. I've recently quit my job as a programmer and took a much
|
|
||||||
needed hiatus away from programming to clear my head of stuff. I think this was
|
|
||||||
good, because I've slowly regained my interest in programming and maintaining my
|
|
||||||
server again.
|
|
||||||
|
|
||||||
And that means updates! The website has been updated; not much new on the front,
|
|
||||||
but it's now a PHP-powered website with actual pages. It even has fancy ajax
|
|
||||||
page loading now (but the website will also work without javascript). This means
|
|
||||||
people can now properly link to different pages as well as the news articles.
|
|
||||||
|
|
||||||
Besides the website, I've also set up Radicale, a caldav and carddav server, as
|
|
||||||
a potential replacement for Nextcloud's calendars and addressbooks. With recent
|
|
||||||
Nextcloud updates it has become clear that updating it usually leads to downtime
|
|
||||||
and issues, which for me defeats the purpose of having such a fully-featured
|
|
||||||
groupware service. As such I will also be searching for a replacement for
|
|
||||||
Nextcloud's file hosting and syncing.
|
|
||||||
|
|
||||||
Up on the todo list are to update Funkwhale, which I hope isn't gonna spit in my
|
|
||||||
face. Also I will be picking up work on the custom artwork for the subcon
|
|
||||||
frontpage; parts of it have already been finished, so I really wanna get it all
|
|
||||||
over and done with. Other than that, I'll be busy with just the usual. Keep tabs
|
|
||||||
on the [wiki](https://library.subcon.town) for any new guides and stuff; I will
|
|
||||||
be adding one for using Radicale.
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
---
|
|
||||||
title: Plans for the year
|
|
||||||
author: fristi
|
|
||||||
date: 2023-01
|
|
||||||
description: Happy new year! Subcon has come a long way since the change of the
|
|
||||||
year. The server is now powered by an Odroid H3 board. With that, a number of
|
|
||||||
other changes have been made as well.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Plans for the year
|
|
||||||
|
|
||||||
*Januari 2023, by Fristi*
|
|
||||||
|
|
||||||
Happy new year! Subcon has come a long way since the change of the year. First
|
|
||||||
off: we have moved to new hardware! The server is now powered by an Odroid H3
|
|
||||||
board. With that, a number of other changes have been made as well.
|
|
||||||
|
|
||||||
Storage on the server has been totally reworked; the old storage media have been
|
|
||||||
replaced with a 2TB NVMe drive that will, for one, house the user home
|
|
||||||
directories, and a 4TB SATA SSD that will house all variable data; user
|
|
||||||
repositories, websites, databases, the lot. All of this has been set up with
|
|
||||||
convenient LVM partitions that can be easily resized if more space is required
|
|
||||||
in the future.
|
|
||||||
|
|
||||||
Many services have been updated. The gitea server has been replaced with a new
|
|
||||||
gogs server, now hosted at [factory.subcon.town](https://factory.subcon.town).
|
|
||||||
The old snikket server has also been replaced with a new prosody setup, offering
|
|
||||||
most of the same xmpp services at [jab.subcon.town](https://jab.subcon.town).
|
|
||||||
Note that old snikket accounts are thus gone. The fedora installation has also
|
|
||||||
been updated to fedora 37.
|
|
||||||
|
|
||||||
The most notable change however will be the decrease in processing power. While
|
|
||||||
we still have about 75% of the processing power, the upside is that the system
|
|
||||||
as a whole is seriously more power efficient. We are now running at a fraction
|
|
||||||
of the power the old server needed, going from 60Wh on average to a mere 6Wh.
|
|
||||||
Serious power savings like that will lower upkeep cost, which I can in turn
|
|
||||||
invest in improving other things, such as my god awful internet bandwidth.
|
|
||||||
|
|
||||||
Remember that even with all these changes done, the server is, and will likely
|
|
||||||
forever, be a work in progress. There are still some rough edges needing work,
|
|
||||||
further configuring of services, and for the current while, a lot of work
|
|
||||||
writing wiki pages at [library.subcon.town](https://library.subcon.town).
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
---
|
|
||||||
title: Service Updates
|
|
||||||
author: fristi
|
|
||||||
date: 2023-11
|
|
||||||
description: Hello villagers! Just a short update regarding some chances made on the server
|
|
||||||
recently. Upcoming will also be the upgrade to Fedora 39; if all goes well, we
|
|
||||||
should not be having any issues with this update.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Service Updates
|
|
||||||
|
|
||||||
*November 2023, by Fristi*
|
|
||||||
|
|
||||||
Hello villagers! Just a short update regarding some chances made on the server
|
|
||||||
recently. Upcoming will also be the upgrade to Fedora 39; if all goes well, we
|
|
||||||
should not be having any issues with this update.
|
|
||||||
|
|
||||||
First off, I unfortunately had to shut down the *Funkwhale* service. This is mainly
|
|
||||||
due to technical issues in keeping the instance updated; it seems Funkwhale is just
|
|
||||||
not compatible enough with Fedora to keep it running without issues. As such, the
|
|
||||||
service is offline and will not be back for the foreseeable future. In the meantime
|
|
||||||
I will see if I can find a suitable alternative.
|
|
||||||
|
|
||||||
Additionally, the gogs service has been replaced with [Forgejo](https://forgejo.org/).
|
|
||||||
This is a fork of the popular (but now infamous) Gitea project that we used in the
|
|
||||||
past. I have decided to host this new instance on a different subdomain,
|
|
||||||
[forge.subcon.town](https://forge.subcon.town). The gogs service will no longer be
|
|
||||||
available.
|
|
||||||
|
|
||||||
Near the end of the month I will start migrating the server to *Fedora 39*. Preparations
|
|
||||||
have already been made, so that everything will hopefully go without any issues.
|
|
||||||
Fingers crossed.
|
|
||||||
|
|
||||||
Some more plans are currently in the works after the migration has been dealt with.
|
|
||||||
I've currently been testing a *web IRC client* that has been working very favorably.
|
|
||||||
Together with that, I've been planning to set up an *IRC server* of our own to pair
|
|
||||||
it with. To further boost the options we have for communication, I've also been
|
|
||||||
looking into hosting a *Matrix* server. However this one is still in the works and
|
|
||||||
will depend a lot on if *Conduit* or *Dendrite* end up working as advertised.
|
|
||||||
|
|
||||||
That is all for now, happy hacking!
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title><?php if(isset($title)) echo "{$title} - "; ?>Welcome to Subcon Town!</title>
|
|
||||||
|
|
||||||
<?php if(isset($meta) && is_array($meta)) {
|
|
||||||
foreach($meta as $key => $value) { ?>
|
|
||||||
<meta name="<?php echo $key; ?>" content="<?php echo $value; ?>">
|
|
||||||
<?php }} ?>
|
|
||||||
|
|
||||||
<link rel="shortcut icon" type="image/jpg" href="/assets/subcon/favicon_16.png" sizes="16x16"/>
|
|
||||||
<link rel="shortcut icon" type="image/jpg" href="/assets/subcon/favicon_32.png" sizes="32x32"/>
|
|
||||||
<link href="/assets/css/style.css?v=<?php echo \Subcon\Zap\Application::VERSION ?>" rel="stylesheet"/>
|
|
||||||
|
|
||||||
<script src="/assets/js/gogo.js" type="text/javascript"></script>
|
|
||||||
<script src="/assets/js/app.js?v=<?php echo \Subcon\Zap\Application::VERSION ?>" type="text/javascript"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<header>
|
|
||||||
<img src="/assets/subcon/logo_128.png" alt="Subcon Town" />
|
|
||||||
<ul>
|
|
||||||
<li><a class="page-link" href="/">Home</a></li>
|
|
||||||
<li><a target="_blank" href="https://library.subcon.town/">Wiki</a></li>
|
|
||||||
<li><a class="page-link" href="/services">Services</a></li>
|
|
||||||
<li><a class="page-link" href="/faq">FAQ</a></li>
|
|
||||||
</ul>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div class="inner-main">
|
|
||||||
<div class="content">
|
|
||||||
<?php echo $content; ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<div style="text-align: right">
|
|
||||||
© 2021-<?php echo date("Y"); ?> Subcon Town.
|
|
||||||
<a class="page-link" href="/copyright">License</a>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>404 - Not Found</title>
|
|
||||||
<link type="text/css" rel="stylesheet" href="https://cdn.subcon.town/system/page.css" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<div class="col">
|
|
||||||
<h1>404 - Not found!</h1>
|
|
||||||
<p>
|
|
||||||
Whoops! Looks like we don't have that thing you're looking for. Maybe it got
|
|
||||||
moved or deleted, we don't know. Sorry!
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<a href="/"><< Back to the homepage</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="col right">
|
|
||||||
<img style="max-height: 300px;" src="https://cdn.subcon.town/system/img/404.jpg" alt="Internet Explorer" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<h1>Copyright notice</h1>
|
|
||||||
<p>
|
|
||||||
The "Subcon Town" branding, including logos and icons used on this website, are
|
|
||||||
licensed as CC BY-NC-ND. You may share and redistribute these works, but please do not edit them or use them for
|
|
||||||
commercial purposes. For more details, read the <a target="_blank" href="./assets/subcon/LICENSE">license</a>.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
The source code of this website is licensed under the Blue Oak Model License 1.0.0.
|
|
||||||
You may use this source code as you wish.
|
|
||||||
For more details, read the <a target="_blank" href="./LICENSE">license</a>.
|
|
||||||
The source code of this website may be viewed <a target="_blank" href="https://factory.subcon.town/fristi/subcon.town">here</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2>Third party works</h2>
|
|
||||||
<p>
|
|
||||||
The fonts and background image used on this website are not owned by Subcon Town. Subcon Town does
|
|
||||||
not claim any rights to these original works unless otherwise specified by their respective licensing.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2>Complaints</h2>
|
|
||||||
<p>
|
|
||||||
If you feel any material is incorrectly used on this website, or otherwise infringes on your rights,
|
|
||||||
feel free to file a complaint with <a class="em" href="#">fristi「AT」subcon.town</a>. Please allow up
|
|
||||||
to 48 hours for a response.
|
|
||||||
</p>
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
<h1>FAQ</h1>
|
|
||||||
<p>
|
|
||||||
<strong>Q</strong>: <em>What is a tilde community?</em>
|
|
||||||
<br/>
|
|
||||||
<strong>A</strong>: Tilde communities are pubnixes, <i>public access unix systems</i>. We took our inspiration
|
|
||||||
from older such servers like <a target="_blank" href="http://tilde.club">tilde.club</a>
|
|
||||||
and the tildes from <a target="_blank" href="https://tildeverse.org">tildeverse.org</a>.
|
|
||||||
Put simply, a pubnix is a public server that is being shared by a number of people, that
|
|
||||||
use it simply for fun, or for purpose.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Q</strong>: <em>Why would I join a tilde community?</em>
|
|
||||||
<br/>
|
|
||||||
<strong>A</strong>: Good question! Ultimately that depends on you. Do you like
|
|
||||||
doing computer stuff? Do you like bonding with people over computers? Or do you
|
|
||||||
just like having a little space on the web to do stuff? Then you might like it.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Q</strong>: <em>Is Subcon Town open for new users?</em>
|
|
||||||
<br/>
|
|
||||||
<strong>A</strong>: Yes, but keep in mind we're an invite-only community. You can always ask
|
|
||||||
for an invite, and we don't mind giving people a chance, but we do like to run a tight ship.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Q</strong>: <em>Are there more open and public tilde communities?</em>
|
|
||||||
<br/>
|
|
||||||
<strong>A</strong>: Yes, many of the tilde communities we took inspiration from are open to new
|
|
||||||
users. For example, <a target="_blank" href="http://tilde.club">tilde.club</a> or some of the
|
|
||||||
communities on <a target="_blank" href="https://tildeverse.org">tildeverse.org</a> will readily
|
|
||||||
accept new members. Some communities are themed around a subject, so you might find one that fits you.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>Q</strong>: <em>Can I get an account on one of your services?</em>
|
|
||||||
<br/>
|
|
||||||
<strong>A</strong>: Only as an existing member. If you're already a member, ask
|
|
||||||
<a target="_blank" href="https://akkos.fritu.re/fristi">@fristi</a> for an account.
|
|
||||||
</p>
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<h1>Hello world!</h1>
|
|
||||||
<p>
|
|
||||||
Welcome to Subcon Town! We are a small tilde community, hosted for friends and family.
|
|
||||||
We offer SSH access, hosting of websites, gopher holes and gemini pods, alongside
|
|
||||||
other services like cloud services, git and fossil hosting and an activitypub server.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
To find out more about this system and its services, view the <a class="page-link" href="/faq">faq</a> or visit
|
|
||||||
the <a target="_blank" href="https://library.subcon.town/">wiki</a>!
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<h1>News</h1>
|
|
||||||
<!-- List of article stubs -->
|
|
||||||
<?php foreach($articles as $article) { ?>
|
|
||||||
<h2><?php echo $article->getTitle(); ?></h2>
|
|
||||||
<div class="article-stub">
|
|
||||||
<p><?php echo $article->getDescription(); ?></p>
|
|
||||||
|
|
||||||
<div class="article-stub-end">
|
|
||||||
<a class="page-link" href="/news/<?php echo $article->getSlug(); ?>">Read more</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?php } ?>
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
<h1>Services</h1>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
We provide the following services for our members:
|
|
||||||
</p>
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>Akkoma:</td>
|
|
||||||
<td><a title="A federated microblogging server powered by Akkoma." target="_blank" href="https://akkos.fritu.re">akkos.fritu.re</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Fossil SCM:</td>
|
|
||||||
<td><a title="A Fossil repository hosting server, powered by... Fossil." target="_blank" href="https://museum.subcon.town">museum.subcon.town</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Git:</td>
|
|
||||||
<td><a title="A Git respository hosting server powered by Forgejo." target="_blank" href="https://forge.subcon.town">forge.subcon.town</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>IRC:</td>
|
|
||||||
<td><a title="Our internet relay chat server powered by Ergo." target="_blank" href="https://cal.subcon.town/radicale">lounge.subcon.town</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Matrix:</td>
|
|
||||||
<td><a title="A Matrix IM chat server powered by Conduit." target="_blank" href="https://cal.subcon.town/radicale">matrix.subcon.town</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Nextcloud:</td>
|
|
||||||
<td><a title="A cloud file hosting server powered by Nextcloud." target="_blank" href="https://cloud.subcon.town">cloud.subcon.town</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Radicale:</td>
|
|
||||||
<td><a title="A caldav and carddav hosting server powered by Radicale." target="_blank" href="https://cal.subcon.town/radicale">cal.subcon.town</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Wiki:</td>
|
|
||||||
<td><a title="A wiki hosting server powered by DokuWiki." target="_blank" href="https://library.subcon.town">library.subcon.town</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>XMPP:</td>
|
|
||||||
<td><a title="A Jabber/XMPP IM chat server powered by Prosody." target="_blank" href="https://jab.subcon.town">jab.subcon.town</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
We also host member websites, gopher holes and gemini pods. User websites are listed below,
|
|
||||||
for gopher holes and gemini pods, visit <a target="_blank" href="gopher://subcon.town">gopher://subcon.town</a> and
|
|
||||||
<a target="_blank" href="gemini://subcon.town">gemini://subcon.town</a> respectively using a compatible browser.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<h1>User tildes:</h1>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td width="50%"><a target="_blank" href="/~fristi">fristi</a></td>
|
|
||||||
<td width="50%"></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Subcon\Frontpage\Controllers\FrontpageController;
|
|
||||||
use Subcon\Zap\Routing\Repository;
|
|
||||||
|
|
||||||
return function (Repository $routes) {
|
|
||||||
//Frontpage routes
|
|
||||||
$routes->get('/', [FrontpageController::class, 'index']);
|
|
||||||
$routes->get('/news/{slug}', [FrontpageController::class, 'article']);
|
|
||||||
$routes->get('/services', [FrontpageController::class, 'services']);
|
|
||||||
$routes->get('/faq', [FrontpageController::class, 'faq']);
|
|
||||||
$routes->get('/copyright', [FrontpageController::class, 'copyright']);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,106 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Subcon\Frontpage\Controllers;
|
|
||||||
use League\CommonMark\Environment\Environment;
|
|
||||||
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
|
|
||||||
use League\CommonMark\Extension\FrontMatter\Data\SymfonyYamlFrontMatterParser;
|
|
||||||
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
|
|
||||||
use League\CommonMark\Extension\FrontMatter\FrontMatterParser;
|
|
||||||
use League\CommonMark\MarkdownConverter;
|
|
||||||
use Subcon\Frontpage\Models\Article;
|
|
||||||
use Subcon\Zap\Application;
|
|
||||||
use Subcon\Zap\Http\Response;
|
|
||||||
|
|
||||||
class FrontpageController
|
|
||||||
{
|
|
||||||
private Application $app;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->app = Application::getInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function index()
|
|
||||||
{
|
|
||||||
$articles = Article::getNewestArticles(3);
|
|
||||||
return $this->loadPage('index', ['articles' => $articles]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function article(string $slug)
|
|
||||||
{
|
|
||||||
$article = Article::getArticle($slug);
|
|
||||||
if(!$article) {
|
|
||||||
return $this->notFoundError();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->loadArticle($article);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function services()
|
|
||||||
{
|
|
||||||
return $this->loadPage('services');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function faq()
|
|
||||||
{
|
|
||||||
return $this->loadPage('faq');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function copyright()
|
|
||||||
{
|
|
||||||
return $this->loadPage('copyright');
|
|
||||||
}
|
|
||||||
|
|
||||||
private function loadPage(string $page, array $data = [])
|
|
||||||
{
|
|
||||||
if(isset($_SERVER['HTTP_ACCEPT']) && $_SERVER['HTTP_ACCEPT'] == 'application/json') {
|
|
||||||
//Only load content without the main template, return as array
|
|
||||||
$content = $this->toBuffer($this->app->getViewPath("pages/{$page}.php"), $data);
|
|
||||||
return new Response([
|
|
||||||
'content' => $content
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
$content = $this->toBuffer($this->app->getViewPath("pages/{$page}.php"), $data);
|
|
||||||
$view = $this->toBuffer($this->app->getViewPath('_layout/layout.php'), array_merge($data, ['content' => $content]));
|
|
||||||
return new Response($view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function loadArticle(Article $article)
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'content' => $article->getRender()->getContent(),
|
|
||||||
'meta' => [
|
|
||||||
'title' => $article->getTitle(),
|
|
||||||
'author' => $article->getAuthor(),
|
|
||||||
'date' => date('F Y', $article->getTimestamp()),
|
|
||||||
'description' => $article->getDescription()
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
if(isset($_SERVER['HTTP_ACCEPT']) && $_SERVER['HTTP_ACCEPT'] == 'application/json') {
|
|
||||||
//Only load content without the main template, return as array
|
|
||||||
return new Response($data);
|
|
||||||
} else {
|
|
||||||
$view = $this->toBuffer($this->app->getViewPath('_layout/layout.php'), $data);
|
|
||||||
return new Response($view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function toBuffer($path, array $data = [])
|
|
||||||
{
|
|
||||||
ob_start();
|
|
||||||
if(!empty($data)) {
|
|
||||||
extract($data);
|
|
||||||
}
|
|
||||||
require $path;
|
|
||||||
return ob_get_clean();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function notFoundError()
|
|
||||||
{
|
|
||||||
$html = $this->toBuffer($this->app->getViewPath('errors/404.html'));
|
|
||||||
return new Response($html, 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,259 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Subcon\Frontpage\Models;
|
|
||||||
|
|
||||||
use League\CommonMark\Environment\Environment;
|
|
||||||
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
|
|
||||||
use League\CommonMark\Extension\FrontMatter\Data\SymfonyYamlFrontMatterParser;
|
|
||||||
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
|
|
||||||
use League\CommonMark\Extension\FrontMatter\FrontMatterParser;
|
|
||||||
use League\CommonMark\MarkdownConverter;
|
|
||||||
use League\CommonMark\Output\RenderedContentInterface;
|
|
||||||
use Subcon\Zap\Application;
|
|
||||||
|
|
||||||
class Article
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private string $path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private string $title;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
private int $timestamp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private string $description;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private string $author;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var RenderedContentInterface
|
|
||||||
*/
|
|
||||||
private RenderedContentInterface $render;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize reference to main application instance.
|
|
||||||
* @param string $path Full path of the article this model will represent.
|
|
||||||
*/
|
|
||||||
public function __construct(string $path, array $cacheData = [])
|
|
||||||
{
|
|
||||||
$this->path = $path;
|
|
||||||
|
|
||||||
if(!empty($cacheData)) {
|
|
||||||
foreach($cacheData as $property => $value) {
|
|
||||||
switch ($property) {
|
|
||||||
case 'title':
|
|
||||||
case 'author':
|
|
||||||
case 'description':
|
|
||||||
$this->$property = $value ?? '';
|
|
||||||
break;
|
|
||||||
case 'date':
|
|
||||||
$this->timestamp = $value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an article
|
|
||||||
* @param string $slug
|
|
||||||
* @return static|null
|
|
||||||
*/
|
|
||||||
public static function getArticle(string $slug): ?static
|
|
||||||
{
|
|
||||||
$app = Application::getInstance();
|
|
||||||
if(!$app) throw new \RuntimeException('Unable to get articles; Application not yet initialized.');
|
|
||||||
|
|
||||||
if(!file_exists($app->getBasePath('cache/articles/cache.php'))) {
|
|
||||||
self::createArticleCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache = require $app->getBasePath('cache/articles/cache.php');
|
|
||||||
if(key_exists($slug, $cache)) {
|
|
||||||
$article = $cache[$slug];
|
|
||||||
return new Article($article['path'], $article);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of Article instances for each article on file.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function getArticles(int $amount = -1): array
|
|
||||||
{
|
|
||||||
$app = Application::getInstance();
|
|
||||||
if(!$app) throw new \RuntimeException('Unable to get articles; Application not yet initialized.');
|
|
||||||
|
|
||||||
if(!file_exists($app->getBasePath('cache/articles/cache.php'))) {
|
|
||||||
self::createArticleCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
$articles = [];
|
|
||||||
$cache = require $app->getBasePath('cache/articles/cache.php');
|
|
||||||
foreach($cache as $article) {
|
|
||||||
$articles[] = new Article($article['path'], $article);
|
|
||||||
$amount--;
|
|
||||||
|
|
||||||
if($amount == 0) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $articles;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of Article instances for the newest articles, optionally specifying
|
|
||||||
* the amount of articles.
|
|
||||||
*
|
|
||||||
* @param int $amount The amount of articles to load, defaults to 5.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function getNewestArticles(int $amount = 5): array
|
|
||||||
{
|
|
||||||
return self::getArticles($amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an article cache containing a sorted list of article file paths and their metadata.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function createArticleCache()
|
|
||||||
{
|
|
||||||
$app = Application::getInstance();
|
|
||||||
if(!$app) throw new \RuntimeException('Unable to cache articles; Application not yet initialized.');
|
|
||||||
|
|
||||||
$cache = [];
|
|
||||||
|
|
||||||
//Init frontmatter parser
|
|
||||||
$parser = new FrontMatterParser(new SymfonyYamlFrontMatterParser());
|
|
||||||
|
|
||||||
$paths = glob(Application::getInstance()->getBasePath("resources/articles") . '/*/*.md');
|
|
||||||
foreach ($paths as $path) {
|
|
||||||
$content = file_get_contents($path);
|
|
||||||
$result = $parser->parse($content);
|
|
||||||
$yaml = $result->getFrontMatter();
|
|
||||||
|
|
||||||
$article = [
|
|
||||||
'path' => $path,
|
|
||||||
'slug' => str_replace('_', '-', basename($path, '.md'))
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach($yaml as $property => $value) {
|
|
||||||
switch ($property) {
|
|
||||||
case 'date': //Convert to timestamp for easier handling and sorting
|
|
||||||
$article['date'] = strtotime($value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$article[$property] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache[$article['slug']] = $article;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Sort cache by timestamp
|
|
||||||
uasort($cache, function ($a, $b) {
|
|
||||||
return $b['date'] <=> $a['date'];
|
|
||||||
});
|
|
||||||
|
|
||||||
//Check if directories exist
|
|
||||||
if(!file_exists($app->getBasePath('cache/articles'))) {
|
|
||||||
mkdir($app->getBasePath('cache/articles'), 0755, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Write to file
|
|
||||||
$php = '<?php return ' . var_export($cache, true) . ';' ;
|
|
||||||
file_put_contents($app->getBasePath('cache/articles/cache.php'), $php);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getPath(): string
|
|
||||||
{
|
|
||||||
return $this->path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getSlug(): string
|
|
||||||
{
|
|
||||||
return str_replace('_', '-', basename($this->path, '.md'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getTitle(): string
|
|
||||||
{
|
|
||||||
return $this->title;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getTimestamp(): int
|
|
||||||
{
|
|
||||||
return $this->timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getDescription(): string
|
|
||||||
{
|
|
||||||
return $this->description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getAuthor(): string
|
|
||||||
{
|
|
||||||
return $this->author;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return RenderedContentInterface
|
|
||||||
*/
|
|
||||||
public function getRender(): RenderedContentInterface
|
|
||||||
{
|
|
||||||
if(!isset($this->render)) {
|
|
||||||
$this->parseContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return void
|
|
||||||
* @throws \League\CommonMark\Exception\CommonMarkException
|
|
||||||
*/
|
|
||||||
private function parseContent()
|
|
||||||
{
|
|
||||||
$environment = new Environment([]);
|
|
||||||
$environment->addExtension(new CommonMarkCoreExtension());
|
|
||||||
$environment->addExtension(new FrontMatterExtension());
|
|
||||||
|
|
||||||
$converter = new MarkdownConverter($environment);
|
|
||||||
$markdown = file_get_contents($this->path);
|
|
||||||
$this->render = $converter->convert($markdown);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
168
style.css
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
/* @font-face kit by Fonts2u (https://fonts2u.com) */
|
||||||
|
@font-face {
|
||||||
|
font-family:"Duck Hunt";
|
||||||
|
src:url("assets/duck_hunt/duckhunt.eot?") format("eot"),
|
||||||
|
url("assets/duck_hunt/duckhunt.woff") format("woff"),
|
||||||
|
url("assets/duck_hunt/duckhunt.ttf") format("truetype"),
|
||||||
|
url("assets/duck_hunt/duckhunt.svg#DuckHunt") format("svg");
|
||||||
|
font-weight:normal;
|
||||||
|
font-style:normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family:"Baloo Thambi 2";
|
||||||
|
src:url("assets/baloo_thambi_2/BalooThambi2-Medium.ttf") format("truetype");
|
||||||
|
font-weight:normal;
|
||||||
|
font-style:normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family:"Baloo Thambi 2";
|
||||||
|
src:url("assets/baloo_thambi_2/BalooThambi2-Bold.ttf") format("truetype");
|
||||||
|
font-weight:bold;
|
||||||
|
font-style:normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Common Elements */
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
margin:0;
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-image: url("assets/background1.jpg");
|
||||||
|
background-position: center center;
|
||||||
|
background-size: cover;
|
||||||
|
background-attachment: fixed;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-family: 'Baloo Thambi 2', cursive;
|
||||||
|
|
||||||
|
color: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
color: rgba(255, 255, 255, 0.3);
|
||||||
|
margin: 2.5em 5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-family: "Duck Hunt", sans-serif;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #fff;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
table tbody tr td:first-child {
|
||||||
|
padding: 0 3em 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Containers */
|
||||||
|
|
||||||
|
.container {
|
||||||
|
position: absolute;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
height: 100%;
|
||||||
|
max-width: 550px;
|
||||||
|
padding: 0 20px;
|
||||||
|
margin:auto;
|
||||||
|
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
|
||||||
|
display:flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
margin: 40px 0 20px 0;
|
||||||
|
text-align: center;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin-right: -14px;
|
||||||
|
padding-right: 14px;
|
||||||
|
scrollbar-color: #fff transparent;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
}
|
||||||
|
|
||||||
|
main::-webkit-scrollbar {
|
||||||
|
width: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
main::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
main::-webkit-scrollbar-thumb {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
margin: 20px 0 0 0;
|
||||||
|
height: 30px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Custom styling */
|
||||||
|
|
||||||
|
header ul {
|
||||||
|
position: relative;
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
font-family: "Duck Hunt", sans-serif;
|
||||||
|
list-style: none;
|
||||||
|
margin: 10px 0 0 0;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
header ul li {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
header ul li a {
|
||||||
|
display: block;
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
padding:10px 0 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
header ul li a:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.muted {
|
||||||
|
font-style: italic;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||