aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore13
-rw-r--r--.well-known/button.json2
-rw-r--r--Parsedown.php1994
-rw-r--r--blog/posts/building_a_cooler_body_2/index.md3
-rw-r--r--blog/posts/guide_sorcery_git/index.md183
-rw-r--r--blog/posts/guide_sorcery_git/index.php1
-rw-r--r--blog/posts/invaluable_contributions/bg.pngbin0 -> 367568 bytes
-rw-r--r--blog/posts/invaluable_contributions/index.md37
-rw-r--r--blog/posts/invaluable_contributions/index.php (renamed from blog/posts/building_a_cooler_body_2/index.php)0
-rw-r--r--footer.php8
-rw-r--r--header.php8
-rw-r--r--images/isopodgaming.pngbin0 -> 14853 bytes
-rw-r--r--music/index.php89
-rw-r--r--stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Bold.ttfbin0 -> 54444 bytes
-rw-r--r--stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-BoldItalic.ttfbin0 -> 54608 bytes
-rw-r--r--stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Italic.ttfbin0 -> 54200 bytes
-rw-r--r--stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Regular.ttfbin0 -> 53504 bytes
-rw-r--r--stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Bold.ttfbin0 -> 34268 bytes
-rw-r--r--stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-BoldItalic.ttfbin0 -> 35684 bytes
-rw-r--r--stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Italic.ttfbin0 -> 35668 bytes
-rw-r--r--stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Regular.ttfbin0 -> 34320 bytes
-rw-r--r--stuff/fonts/Atkinson_Hyperlegible/OFL.txt93
-rw-r--r--stuff/fonts/B612/B612-Bold.ttfbin0 -> 90928 bytes
-rw-r--r--stuff/fonts/B612/B612-BoldItalic.ttfbin0 -> 93968 bytes
-rw-r--r--stuff/fonts/B612/B612-Italic.ttfbin0 -> 94960 bytes
-rw-r--r--stuff/fonts/B612/B612-Regular.ttfbin0 -> 142720 bytes
-rw-r--r--stuff/fonts/B612/OFL.txt93
-rw-r--r--stuff/fonts/B612_Mono/B612Mono-Bold.ttfbin0 -> 135904 bytes
-rw-r--r--stuff/fonts/B612_Mono/B612Mono-BoldItalic.ttfbin0 -> 121732 bytes
-rw-r--r--stuff/fonts/B612_Mono/B612Mono-Italic.ttfbin0 -> 118888 bytes
-rw-r--r--stuff/fonts/B612_Mono/B612Mono-Regular.ttfbin0 -> 136712 bytes
-rw-r--r--stuff/fonts/B612_Mono/OFL.txt93
-rw-r--r--stuff/fonts/DS-DIGI.ttfbin0 -> 24448 bytes
-rw-r--r--stuff/fonts/Google_Sans/GoogleSans-Bold.ttfbin0 -> 2001624 bytes
-rw-r--r--stuff/fonts/Google_Sans/GoogleSans-BoldItalic.ttfbin0 -> 2062592 bytes
-rw-r--r--stuff/fonts/Google_Sans/GoogleSans-Italic.ttfbin0 -> 2060680 bytes
-rw-r--r--stuff/fonts/Google_Sans/GoogleSans-Regular.ttfbin0 -> 1999328 bytes
-rw-r--r--stuff/fonts/Google_Sans/GoogleSansCode-Bold.ttfbin0 -> 99680 bytes
-rw-r--r--stuff/fonts/Google_Sans/GoogleSansCode-BoldItalic.ttfbin0 -> 100560 bytes
-rw-r--r--stuff/fonts/Google_Sans/GoogleSansCode-Italic.ttfbin0 -> 100016 bytes
-rw-r--r--stuff/fonts/Google_Sans/GoogleSansCode-Regular.ttfbin0 -> 99180 bytes
-rw-r--r--stuff/fonts/Google_Sans/OFL.txt91
-rw-r--r--stuff/fonts/Noto_Serif/NotoSansMono-Bold.ttfbin0 -> 405596 bytes
-rw-r--r--stuff/fonts/Noto_Serif/NotoSansMono-Regular.ttfbin0 -> 405892 bytes
-rw-r--r--stuff/fonts/Noto_Serif/NotoSerif-Bold.ttfbin0 -> 506864 bytes
-rw-r--r--stuff/fonts/Noto_Serif/NotoSerif-BoldItalic.ttfbin0 -> 534540 bytes
-rw-r--r--stuff/fonts/Noto_Serif/NotoSerif-Italic.ttfbin0 -> 534156 bytes
-rw-r--r--stuff/fonts/Noto_Serif/NotoSerif-Regular.ttfbin0 -> 504932 bytes
-rw-r--r--stuff/fonts/Noto_Serif/OFL.txt93
-rw-r--r--stuff/fonts/OpenDyslexic/OpenDyslexic-Bold.otfbin0 -> 184004 bytes
-rw-r--r--stuff/fonts/OpenDyslexic/OpenDyslexic-BoldItalic.otfbin0 -> 234364 bytes
-rw-r--r--stuff/fonts/OpenDyslexic/OpenDyslexic-Italic.otfbin0 -> 189768 bytes
-rw-r--r--stuff/fonts/OpenDyslexic/OpenDyslexic-Regular.otfbin0 -> 175808 bytes
-rw-r--r--stuff/fonts/OpenDyslexic/OpenDyslexicMono-Regular.otfbin0 -> 51548 bytes
-rw-r--r--stuff/fonts/Ubuntu/Ubuntu-Bold.ttfbin0 -> 270164 bytes
-rw-r--r--stuff/fonts/Ubuntu/Ubuntu-BoldItalic.ttfbin0 -> 283444 bytes
-rw-r--r--stuff/fonts/Ubuntu/Ubuntu-Italic.ttfbin0 -> 326932 bytes
-rw-r--r--stuff/fonts/Ubuntu/Ubuntu-Regular.ttfbin0 -> 299684 bytes
-rw-r--r--stuff/fonts/Ubuntu/UbuntuMono-Bold.ttfbin0 -> 174860 bytes
-rw-r--r--stuff/fonts/Ubuntu/UbuntuMono-BoldItalic.ttfbin0 -> 199044 bytes
-rw-r--r--stuff/fonts/Ubuntu/UbuntuMono-Italic.ttfbin0 -> 193936 bytes
-rw-r--r--stuff/fonts/Ubuntu/UbuntuMono-Regular.ttfbin0 -> 189892 bytes
-rw-r--r--stuff/fonts/atkinsonhyperlegible.css54
-rw-r--r--stuff/fonts/atkinsonhyperlegiblemono.css29
-rw-r--r--stuff/fonts/b612.css54
-rw-r--r--stuff/fonts/b612mono.css29
-rw-r--r--stuff/fonts/browserdefault.css9
-rw-r--r--stuff/fonts/cafe.ttfbin0 -> 32020 bytes
-rw-r--r--stuff/fonts/firsttimewriting.ttfbin0 -> 641428 bytes
-rw-r--r--stuff/fonts/googlesans.css54
-rw-r--r--stuff/fonts/googlesanscode.css29
-rw-r--r--stuff/fonts/notoserif.css41
-rw-r--r--stuff/fonts/opendyslexic.css35
-rw-r--r--stuff/fonts/silkscreen.css16
-rw-r--r--stuff/fonts/slkscr.ttfbin0 -> 7636 bytes
-rw-r--r--stuff/fonts/slkscrb.ttfbin0 -> 6604 bytes
-rw-r--r--stuff/fonts/ubuntu.css54
-rw-r--r--stuff/webgarden/index.php4
-rw-r--r--style.css9
-rw-r--r--uses/cumulonimbus/index.php13
-rw-r--r--uses/servy586/index.php17
81 files changed, 2959 insertions, 289 deletions
diff --git a/.gitignore b/.gitignore
index 03ddfe5..896df6f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,2 @@
-pronouns.txt
-blog/posts/invaluable_contributions
-Parsedown.php
-/stuff/fonts/*
-guestbook/bannedwords.json
-ditherizer.sh
-posts.json
-blog/posts/noterook/
-blog/posts/fedi_explainer/
-blog/posts/syscovery/
-blog/posts/building_a_partscaster/
+blog/posts/__WIP__/
+blog/__WIP__/
diff --git a/.well-known/button.json b/.well-known/button.json
index c9037f4..4545c93 100644
--- a/.well-known/button.json
+++ b/.well-known/button.json
@@ -4,7 +4,7 @@
"buttons": [
{
"id": "bugwo.men",
- "uri": "https://bugwo.men/etc/buttons/isopodhours.png",
+ "uri": "https://bugwo.men/images/buttons/isopodhours.png",
"alt": "bugwo.men button",
"link": "https://bugwo.men/",
"sha256": "0a18cabc99db5a98a9b1d0ca69fd22783919c8e2e3996290a18780cfb3a54646"
diff --git a/Parsedown.php b/Parsedown.php
new file mode 100644
index 0000000..ae0cbde
--- /dev/null
+++ b/Parsedown.php
@@ -0,0 +1,1994 @@
+<?php
+
+#
+#
+# Parsedown
+# http://parsedown.org
+#
+# (c) Emanuil Rusev
+# http://erusev.com
+#
+# For the full license information, view the LICENSE file that was distributed
+# with this source code.
+#
+#
+
+class Parsedown
+{
+ # ~
+
+ const version = '1.8.0-beta-7';
+
+ # ~
+
+ function text($text)
+ {
+ $Elements = $this->textElements($text);
+
+ # convert to markup
+ $markup = $this->elements($Elements);
+
+ # trim line breaks
+ $markup = trim($markup, "\n");
+
+ return $markup;
+ }
+
+ protected function textElements($text)
+ {
+ # make sure no definitions are set
+ $this->DefinitionData = array();
+
+ # standardize line breaks
+ $text = str_replace(array("\r\n", "\r"), "\n", $text);
+
+ # remove surrounding line breaks
+ $text = trim($text, "\n");
+
+ # split text into lines
+ $lines = explode("\n", $text);
+
+ # iterate through lines to identify blocks
+ return $this->linesElements($lines);
+ }
+
+ #
+ # Setters
+ #
+
+ function setBreaksEnabled($breaksEnabled)
+ {
+ $this->breaksEnabled = $breaksEnabled;
+
+ return $this;
+ }
+
+ protected $breaksEnabled;
+
+ function setMarkupEscaped($markupEscaped)
+ {
+ $this->markupEscaped = $markupEscaped;
+
+ return $this;
+ }
+
+ protected $markupEscaped;
+
+ function setUrlsLinked($urlsLinked)
+ {
+ $this->urlsLinked = $urlsLinked;
+
+ return $this;
+ }
+
+ protected $urlsLinked = true;
+
+ function setSafeMode($safeMode)
+ {
+ $this->safeMode = (bool) $safeMode;
+
+ return $this;
+ }
+
+ protected $safeMode;
+
+ function setStrictMode($strictMode)
+ {
+ $this->strictMode = (bool) $strictMode;
+
+ return $this;
+ }
+
+ protected $strictMode;
+
+ protected $safeLinksWhitelist = array(
+ 'http://',
+ 'https://',
+ 'ftp://',
+ 'ftps://',
+ 'mailto:',
+ 'tel:',
+ 'data:image/png;base64,',
+ 'data:image/gif;base64,',
+ 'data:image/jpeg;base64,',
+ 'irc:',
+ 'ircs:',
+ 'git:',
+ 'ssh:',
+ 'news:',
+ 'steam:',
+ );
+
+ #
+ # Lines
+ #
+
+ protected $BlockTypes = array(
+ '#' => array('Header'),
+ '*' => array('Rule', 'List'),
+ '+' => array('List'),
+ '-' => array('SetextHeader', 'Table', 'Rule', 'List'),
+ '0' => array('List'),
+ '1' => array('List'),
+ '2' => array('List'),
+ '3' => array('List'),
+ '4' => array('List'),
+ '5' => array('List'),
+ '6' => array('List'),
+ '7' => array('List'),
+ '8' => array('List'),
+ '9' => array('List'),
+ ':' => array('Table'),
+ '<' => array('Comment', 'Markup'),
+ '=' => array('SetextHeader'),
+ '>' => array('Quote'),
+ '[' => array('Reference'),
+ '_' => array('Rule'),
+ '`' => array('FencedCode'),
+ '|' => array('Table'),
+ '~' => array('FencedCode'),
+ );
+
+ # ~
+
+ protected $unmarkedBlockTypes = array(
+ 'Code',
+ );
+
+ #
+ # Blocks
+ #
+
+ protected function lines(array $lines)
+ {
+ return $this->elements($this->linesElements($lines));
+ }
+
+ protected function linesElements(array $lines)
+ {
+ $Elements = array();
+ $CurrentBlock = null;
+
+ foreach ($lines as $line)
+ {
+ if (chop($line) === '')
+ {
+ if (isset($CurrentBlock))
+ {
+ $CurrentBlock['interrupted'] = (isset($CurrentBlock['interrupted'])
+ ? $CurrentBlock['interrupted'] + 1 : 1
+ );
+ }
+
+ continue;
+ }
+
+ while (($beforeTab = strstr($line, "\t", true)) !== false)
+ {
+ $shortage = 4 - mb_strlen($beforeTab, 'utf-8') % 4;
+
+ $line = $beforeTab
+ . str_repeat(' ', $shortage)
+ . substr($line, strlen($beforeTab) + 1)
+ ;
+ }
+
+ $indent = strspn($line, ' ');
+
+ $text = $indent > 0 ? substr($line, $indent) : $line;
+
+ # ~
+
+ $Line = array('body' => $line, 'indent' => $indent, 'text' => $text);
+
+ # ~
+
+ if (isset($CurrentBlock['continuable']))
+ {
+ $methodName = 'block' . $CurrentBlock['type'] . 'Continue';
+ $Block = $this->$methodName($Line, $CurrentBlock);
+
+ if (isset($Block))
+ {
+ $CurrentBlock = $Block;
+
+ continue;
+ }
+ else
+ {
+ if ($this->isBlockCompletable($CurrentBlock['type']))
+ {
+ $methodName = 'block' . $CurrentBlock['type'] . 'Complete';
+ $CurrentBlock = $this->$methodName($CurrentBlock);
+ }
+ }
+ }
+
+ # ~
+
+ $marker = $text[0];
+
+ # ~
+
+ $blockTypes = $this->unmarkedBlockTypes;
+
+ if (isset($this->BlockTypes[$marker]))
+ {
+ foreach ($this->BlockTypes[$marker] as $blockType)
+ {
+ $blockTypes []= $blockType;
+ }
+ }
+
+ #
+ # ~
+
+ foreach ($blockTypes as $blockType)
+ {
+ $Block = $this->{"block$blockType"}($Line, $CurrentBlock);
+
+ if (isset($Block))
+ {
+ $Block['type'] = $blockType;
+
+ if ( ! isset($Block['identified']))
+ {
+ if (isset($CurrentBlock))
+ {
+ $Elements[] = $this->extractElement($CurrentBlock);
+ }
+
+ $Block['identified'] = true;
+ }
+
+ if ($this->isBlockContinuable($blockType))
+ {
+ $Block['continuable'] = true;
+ }
+
+ $CurrentBlock = $Block;
+
+ continue 2;
+ }
+ }
+
+ # ~
+
+ if (isset($CurrentBlock) and $CurrentBlock['type'] === 'Paragraph')
+ {
+ $Block = $this->paragraphContinue($Line, $CurrentBlock);
+ }
+
+ if (isset($Block))
+ {
+ $CurrentBlock = $Block;
+ }
+ else
+ {
+ if (isset($CurrentBlock))
+ {
+ $Elements[] = $this->extractElement($CurrentBlock);
+ }
+
+ $CurrentBlock = $this->paragraph($Line);
+
+ $CurrentBlock['identified'] = true;
+ }
+ }
+
+ # ~
+
+ if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type']))
+ {
+ $methodName = 'block' . $CurrentBlock['type'] . 'Complete';
+ $CurrentBlock = $this->$methodName($CurrentBlock);
+ }
+
+ # ~
+
+ if (isset($CurrentBlock))
+ {
+ $Elements[] = $this->extractElement($CurrentBlock);
+ }
+
+ # ~
+
+ return $Elements;
+ }
+
+ protected function extractElement(array $Component)
+ {
+ if ( ! isset($Component['element']))
+ {
+ if (isset($Component['markup']))
+ {
+ $Component['element'] = array('rawHtml' => $Component['markup']);
+ }
+ elseif (isset($Component['hidden']))
+ {
+ $Component['element'] = array();
+ }
+ }
+
+ return $Component['element'];
+ }
+
+ protected function isBlockContinuable($Type)
+ {
+ return method_exists($this, 'block' . $Type . 'Continue');
+ }
+
+ protected function isBlockCompletable($Type)
+ {
+ return method_exists($this, 'block' . $Type . 'Complete');
+ }
+
+ #
+ # Code
+
+ protected function blockCode($Line, $Block = null)
+ {
+ if (isset($Block) and $Block['type'] === 'Paragraph' and ! isset($Block['interrupted']))
+ {
+ return;
+ }
+
+ if ($Line['indent'] >= 4)
+ {
+ $text = substr($Line['body'], 4);
+
+ $Block = array(
+ 'element' => array(
+ 'name' => 'pre',
+ 'element' => array(
+ 'name' => 'code',
+ 'text' => $text,
+ ),
+ ),
+ );
+
+ return $Block;
+ }
+ }
+
+ protected function blockCodeContinue($Line, $Block)
+ {
+ if ($Line['indent'] >= 4)
+ {
+ if (isset($Block['interrupted']))
+ {
+ $Block['element']['element']['text'] .= str_repeat("\n", $Block['interrupted']);
+
+ unset($Block['interrupted']);
+ }
+
+ $Block['element']['element']['text'] .= "\n";
+
+ $text = substr($Line['body'], 4);
+
+ $Block['element']['element']['text'] .= $text;
+
+ return $Block;
+ }
+ }
+
+ protected function blockCodeComplete($Block)
+ {
+ return $Block;
+ }
+
+ #
+ # Comment
+
+ protected function blockComment($Line)
+ {
+ if ($this->markupEscaped or $this->safeMode)
+ {
+ return;
+ }
+
+ if (strpos($Line['text'], '<!--') === 0)
+ {
+ $Block = array(
+ 'element' => array(
+ 'rawHtml' => $Line['body'],
+ 'autobreak' => true,
+ ),
+ );
+
+ if (strpos($Line['text'], '-->') !== false)
+ {
+ $Block['closed'] = true;
+ }
+
+ return $Block;
+ }
+ }
+
+ protected function blockCommentContinue($Line, array $Block)
+ {
+ if (isset($Block['closed']))
+ {
+ return;
+ }
+
+ $Block['element']['rawHtml'] .= "\n" . $Line['body'];
+
+ if (strpos($Line['text'], '-->') !== false)
+ {
+ $Block['closed'] = true;
+ }
+
+ return $Block;
+ }
+
+ #
+ # Fenced Code
+
+ protected function blockFencedCode($Line)
+ {
+ $marker = $Line['text'][0];
+
+ $openerLength = strspn($Line['text'], $marker);
+
+ if ($openerLength < 3)
+ {
+ return;
+ }
+
+ $infostring = trim(substr($Line['text'], $openerLength), "\t ");
+
+ if (strpos($infostring, '`') !== false)
+ {
+ return;
+ }
+
+ $Element = array(
+ 'name' => 'code',
+ 'text' => '',
+ );
+
+ if ($infostring !== '')
+ {
+ /**
+ * https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes
+ * Every HTML element may have a class attribute specified.
+ * The attribute, if specified, must have a value that is a set
+ * of space-separated tokens representing the various classes
+ * that the element belongs to.
+ * [...]
+ * The space characters, for the purposes of this specification,
+ * are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab),
+ * U+000A LINE FEED (LF), U+000C FORM FEED (FF), and
+ * U+000D CARRIAGE RETURN (CR).
+ */
+ $language = substr($infostring, 0, strcspn($infostring, " \t\n\f\r"));
+
+ $Element['attributes'] = array('class' => "language-$language");
+ }
+
+ $Block = array(
+ 'char' => $marker,
+ 'openerLength' => $openerLength,
+ 'element' => array(
+ 'name' => 'pre',
+ 'element' => $Element,
+ ),
+ );
+
+ return $Block;
+ }
+
+ protected function blockFencedCodeContinue($Line, $Block)
+ {
+ if (isset($Block['complete']))
+ {
+ return;
+ }
+
+ if (isset($Block['interrupted']))
+ {
+ $Block['element']['element']['text'] .= str_repeat("\n", $Block['interrupted']);
+
+ unset($Block['interrupted']);
+ }
+
+ if (($len = strspn($Line['text'], $Block['char'])) >= $Block['openerLength']
+ and chop(substr($Line['text'], $len), ' ') === ''
+ ) {
+ $Block['element']['element']['text'] = substr($Block['element']['element']['text'], 1);
+
+ $Block['complete'] = true;
+
+ return $Block;
+ }
+
+ $Block['element']['element']['text'] .= "\n" . $Line['body'];
+
+ return $Block;
+ }
+
+ protected function blockFencedCodeComplete($Block)
+ {
+ return $Block;
+ }
+
+ #
+ # Header
+
+ protected function blockHeader($Line)
+ {
+ $level = strspn($Line['text'], '#');
+
+ if ($level > 6)
+ {
+ return;
+ }
+
+ $text = trim($Line['text'], '#');
+
+ if ($this->strictMode and isset($text[0]) and $text[0] !== ' ')
+ {
+ return;
+ }
+
+ $text = trim($text, ' ');
+
+ $Block = array(
+ 'element' => array(
+ 'name' => 'h' . $level,
+ 'handler' => array(
+ 'function' => 'lineElements',
+ 'argument' => $text,
+ 'destination' => 'elements',
+ )
+ ),
+ );
+
+ return $Block;
+ }
+
+ #
+ # List
+
+ protected function blockList($Line, array $CurrentBlock = null)
+ {
+ list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]{1,9}+[.\)]');
+
+ if (preg_match('/^('.$pattern.'([ ]++|$))(.*+)/', $Line['text'], $matches))
+ {
+ $contentIndent = strlen($matches[2]);
+
+ if ($contentIndent >= 5)
+ {
+ $contentIndent -= 1;
+ $matches[1] = substr($matches[1], 0, -$contentIndent);
+ $matches[3] = str_repeat(' ', $contentIndent) . $matches[3];
+ }
+ elseif ($contentIndent === 0)
+ {
+ $matches[1] .= ' ';
+ }
+
+ $markerWithoutWhitespace = strstr($matches[1], ' ', true);
+
+ $Block = array(
+ 'indent' => $Line['indent'],
+ 'pattern' => $pattern,
+ 'data' => array(
+ 'type' => $name,
+ 'marker' => $matches[1],
+ 'markerType' => ($name === 'ul' ? $markerWithoutWhitespace : substr($markerWithoutWhitespace, -1)),
+ ),
+ 'element' => array(
+ 'name' => $name,
+ 'elements' => array(),
+ ),
+ );
+ $Block['data']['markerTypeRegex'] = preg_quote($Block['data']['markerType'], '/');
+
+ if ($name === 'ol')
+ {
+ $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0';
+
+ if ($listStart !== '1')
+ {
+ if (
+ isset($CurrentBlock)
+ and $CurrentBlock['type'] === 'Paragraph'
+ and ! isset($CurrentBlock['interrupted'])
+ ) {
+ return;
+ }
+
+ $Block['element']['attributes'] = array('start' => $listStart);
+ }
+ }
+
+ $Block['li'] = array(
+ 'name' => 'li',
+ 'handler' => array(
+ 'function' => 'li',
+ 'argument' => !empty($matches[3]) ? array($matches[3]) : array(),
+ 'destination' => 'elements'
+ )
+ );
+
+ $Block['element']['elements'] []= & $Block['li'];
+
+ return $Block;
+ }
+ }
+
+ protected function blockListContinue($Line, array $Block)
+ {
+ if (isset($Block['interrupted']) and empty($Block['li']['handler']['argument']))
+ {
+ return null;
+ }
+
+ $requiredIndent = ($Block['indent'] + strlen($Block['data']['marker']));
+
+ if ($Line['indent'] < $requiredIndent
+ and (
+ (
+ $Block['data']['type'] === 'ol'
+ and preg_match('/^[0-9]++'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches)
+ ) or (
+ $Block['data']['type'] === 'ul'
+ and preg_match('/^'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches)
+ )
+ )
+ ) {
+ if (isset($Block['interrupted']))
+ {
+ $Block['li']['handler']['argument'] []= '';
+
+ $Block['loose'] = true;
+
+ unset($Block['interrupted']);
+ }
+
+ unset($Block['li']);
+
+ $text = isset($matches[1]) ? $matches[1] : '';
+
+ $Block['indent'] = $Line['indent'];
+
+ $Block['li'] = array(
+ 'name' => 'li',
+ 'handler' => array(
+ 'function' => 'li',
+ 'argument' => array($text),
+ 'destination' => 'elements'
+ )
+ );
+
+ $Block['element']['elements'] []= & $Block['li'];
+
+ return $Block;
+ }
+ elseif ($Line['indent'] < $requiredIndent and $this->blockList($Line))
+ {
+ return null;
+ }
+
+ if ($Line['text'][0] === '[' and $this->blockReference($Line))
+ {
+ return $Block;
+ }
+
+ if ($Line['indent'] >= $requiredIndent)
+ {
+ if (isset($Block['interrupted']))
+ {
+ $Block['li']['handler']['argument'] []= '';
+
+ $Block['loose'] = true;
+
+ unset($Block['interrupted']);
+ }
+
+ $text = substr($Line['body'], $requiredIndent);
+
+ $Block['li']['handler']['argument'] []= $text;
+
+ return $Block;
+ }
+
+ if ( ! isset($Block['interrupted']))
+ {
+ $text = preg_replace('/^[ ]{0,'.$requiredIndent.'}+/', '', $Line['body']);
+
+ $Block['li']['handler']['argument'] []= $text;
+
+ return $Block;
+ }
+ }
+
+ protected function blockListComplete(array $Block)
+ {
+ if (isset($Block['loose']))
+ {
+ foreach ($Block['element']['elements'] as &$li)
+ {
+ if (end($li['handler']['argument']) !== '')
+ {
+ $li['handler']['argument'] []= '';
+ }
+ }
+ }
+
+ return $Block;
+ }
+
+ #
+ # Quote
+
+ protected function blockQuote($Line)
+ {
+ if (preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches))
+ {
+ $Block = array(
+ 'element' => array(
+ 'name' => 'blockquote',
+ 'handler' => array(
+ 'function' => 'linesElements',
+ 'argument' => (array) $matches[1],
+ 'destination' => 'elements',
+ )
+ ),
+ );
+
+ return $Block;
+ }
+ }
+
+ protected function blockQuoteContinue($Line, array $Block)
+ {
+ if (isset($Block['interrupted']))
+ {
+ return;
+ }
+
+ if ($Line['text'][0] === '>' and preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches))
+ {
+ $Block['element']['handler']['argument'] []= $matches[1];
+
+ return $Block;
+ }
+
+ if ( ! isset($Block['interrupted']))
+ {
+ $Block['element']['handler']['argument'] []= $Line['text'];
+
+ return $Block;
+ }
+ }
+
+ #
+ # Rule
+
+ protected function blockRule($Line)
+ {
+ $marker = $Line['text'][0];
+
+ if (substr_count($Line['text'], $marker) >= 3 and chop($Line['text'], " $marker") === '')
+ {
+ $Block = array(
+ 'element' => array(
+ 'name' => 'hr',
+ ),
+ );
+
+ return $Block;
+ }
+ }
+
+ #
+ # Setext
+
+ protected function blockSetextHeader($Line, array $Block = null)
+ {
+ if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted']))
+ {
+ return;
+ }
+
+ if ($Line['indent'] < 4 and chop(chop($Line['text'], ' '), $Line['text'][0]) === '')
+ {
+ $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2';
+
+ return $Block;
+ }
+ }
+
+ #
+ # Markup
+
+ protected function blockMarkup($Line)
+ {
+ if ($this->markupEscaped or $this->safeMode)
+ {
+ return;
+ }
+
+ if (preg_match('/^<[\/]?+(\w*)(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+(\/)?>/', $Line['text'], $matches))
+ {
+ $element = strtolower($matches[1]);
+
+ if (in_array($element, $this->textLevelElements))
+ {
+ return;
+ }
+
+ $Block = array(
+ 'name' => $matches[1],
+ 'element' => array(
+ 'rawHtml' => $Line['text'],
+ 'autobreak' => true,
+ ),
+ );
+
+ return $Block;
+ }
+ }
+
+ protected function blockMarkupContinue($Line, array $Block)
+ {
+ if (isset($Block['closed']) or isset($Block['interrupted']))
+ {
+ return;
+ }
+
+ $Block['element']['rawHtml'] .= "\n" . $Line['body'];
+
+ return $Block;
+ }
+
+ #
+ # Reference
+
+ protected function blockReference($Line)
+ {
+ if (strpos($Line['text'], ']') !== false
+ and preg_match('/^\[(.+?)\]:[ ]*+<?(\S+?)>?(?:[ ]+["\'(](.+)["\')])?[ ]*+$/', $Line['text'], $matches)
+ ) {
+ $id = strtolower($matches[1]);
+
+ $Data = array(
+ 'url' => $matches[2],
+ 'title' => isset($matches[3]) ? $matches[3] : null,
+ );
+
+ $this->DefinitionData['Reference'][$id] = $Data;
+
+ $Block = array(
+ 'element' => array(),
+ );
+
+ return $Block;
+ }
+ }
+
+ #
+ # Table
+
+ protected function blockTable($Line, array $Block = null)
+ {
+ if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted']))
+ {
+ return;
+ }
+
+ if (
+ strpos($Block['element']['handler']['argument'], '|') === false
+ and strpos($Line['text'], '|') === false
+ and strpos($Line['text'], ':') === false
+ or strpos($Block['element']['handler']['argument'], "\n") !== false
+ ) {
+ return;
+ }
+
+ if (chop($Line['text'], ' -:|') !== '')
+ {
+ return;
+ }
+
+ $alignments = array();
+
+ $divider = $Line['text'];
+
+ $divider = trim($divider);
+ $divider = trim($divider, '|');
+
+ $dividerCells = explode('|', $divider);
+
+ foreach ($dividerCells as $dividerCell)
+ {
+ $dividerCell = trim($dividerCell);
+
+ if ($dividerCell === '')
+ {
+ return;
+ }
+
+ $alignment = null;
+
+ if ($dividerCell[0] === ':')
+ {
+ $alignment = 'left';
+ }
+
+ if (substr($dividerCell, - 1) === ':')
+ {
+ $alignment = $alignment === 'left' ? 'center' : 'right';
+ }
+
+ $alignments []= $alignment;
+ }
+
+ # ~
+
+ $HeaderElements = array();
+
+ $header = $Block['element']['handler']['argument'];
+
+ $header = trim($header);
+ $header = trim($header, '|');
+
+ $headerCells = explode('|', $header);
+
+ if (count($headerCells) !== count($alignments))
+ {
+ return;
+ }
+
+ foreach ($headerCells as $index => $headerCell)
+ {
+ $headerCell = trim($headerCell);
+
+ $HeaderElement = array(
+ 'name' => 'th',
+ 'handler' => array(
+ 'function' => 'lineElements',
+ 'argument' => $headerCell,
+ 'destination' => 'elements',
+ )
+ );
+
+ if (isset($alignments[$index]))
+ {
+ $alignment = $alignments[$index];
+
+ $HeaderElement['attributes'] = array(
+ 'style' => "text-align: $alignment;",
+ );
+ }
+
+ $HeaderElements []= $HeaderElement;
+ }
+
+ # ~
+
+ $Block = array(
+ 'alignments' => $alignments,
+ 'identified' => true,
+ 'element' => array(
+ 'name' => 'table',
+ 'elements' => array(),
+ ),
+ );
+
+ $Block['element']['elements'] []= array(
+ 'name' => 'thead',
+ );
+
+ $Block['element']['elements'] []= array(
+ 'name' => 'tbody',
+ 'elements' => array(),
+ );
+
+ $Block['element']['elements'][0]['elements'] []= array(
+ 'name' => 'tr',
+ 'elements' => $HeaderElements,
+ );
+
+ return $Block;
+ }
+
+ protected function blockTableContinue($Line, array $Block)
+ {
+ if (isset($Block['interrupted']))
+ {
+ return;
+ }
+
+ if (count($Block['alignments']) === 1 or $Line['text'][0] === '|' or strpos($Line['text'], '|'))
+ {
+ $Elements = array();
+
+ $row = $Line['text'];
+
+ $row = trim($row);
+ $row = trim($row, '|');
+
+ preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]++`|`)++/', $row, $matches);
+
+ $cells = array_slice($matches[0], 0, count($Block['alignments']));
+
+ foreach ($cells as $index => $cell)
+ {
+ $cell = trim($cell);
+
+ $Element = array(
+ 'name' => 'td',
+ 'handler' => array(
+ 'function' => 'lineElements',
+ 'argument' => $cell,
+ 'destination' => 'elements',
+ )
+ );
+
+ if (isset($Block['alignments'][$index]))
+ {
+ $Element['attributes'] = array(
+ 'style' => 'text-align: ' . $Block['alignments'][$index] . ';',
+ );
+ }
+
+ $Elements []= $Element;
+ }
+
+ $Element = array(
+ 'name' => 'tr',
+ 'elements' => $Elements,
+ );
+
+ $Block['element']['elements'][1]['elements'] []= $Element;
+
+ return $Block;
+ }
+ }
+
+ #
+ # ~
+ #
+
+ protected function paragraph($Line)
+ {
+ return array(
+ 'type' => 'Paragraph',
+ 'element' => array(
+ 'name' => 'p',
+ 'handler' => array(
+ 'function' => 'lineElements',
+ 'argument' => $Line['text'],
+ 'destination' => 'elements',
+ ),
+ ),
+ );
+ }
+
+ protected function paragraphContinue($Line, array $Block)
+ {
+ if (isset($Block['interrupted']))
+ {
+ return;
+ }
+
+ $Block['element']['handler']['argument'] .= "\n".$Line['text'];
+
+ return $Block;
+ }
+
+ #
+ # Inline Elements
+ #
+
+ protected $InlineTypes = array(
+ '!' => array('Image'),
+ '&' => array('SpecialCharacter'),
+ '*' => array('Emphasis'),
+ ':' => array('Url'),
+ '<' => array('UrlTag', 'EmailTag', 'Markup'),
+ '[' => array('Link'),
+ '_' => array('Emphasis'),
+ '`' => array('Code'),
+ '~' => array('Strikethrough'),
+ '\\' => array('EscapeSequence'),
+ );
+
+ # ~
+
+ protected $inlineMarkerList = '!*_&[:<`~\\';
+
+ #
+ # ~
+ #
+
+ public function line($text, $nonNestables = array())
+ {
+ return $this->elements($this->lineElements($text, $nonNestables));
+ }
+
+ protected function lineElements($text, $nonNestables = array())
+ {
+ # standardize line breaks
+ $text = str_replace(array("\r\n", "\r"), "\n", $text);
+
+ $Elements = array();
+
+ $nonNestables = (empty($nonNestables)
+ ? array()
+ : array_combine($nonNestables, $nonNestables)
+ );
+
+ # $excerpt is based on the first occurrence of a marker
+
+ while ($excerpt = strpbrk($text, $this->inlineMarkerList))
+ {
+ $marker = $excerpt[0];
+
+ $markerPosition = strlen($text) - strlen($excerpt);
+
+ $Excerpt = array('text' => $excerpt, 'context' => $text);
+
+ foreach ($this->InlineTypes[$marker] as $inlineType)
+ {
+ # check to see if the current inline type is nestable in the current context
+
+ if (isset($nonNestables[$inlineType]))
+ {
+ continue;
+ }
+
+ $Inline = $this->{"inline$inlineType"}($Excerpt);
+
+ if ( ! isset($Inline))
+ {
+ continue;
+ }
+
+ # makes sure that the inline belongs to "our" marker
+
+ if (isset($Inline['position']) and $Inline['position'] > $markerPosition)
+ {
+ continue;
+ }
+
+ # sets a default inline position
+
+ if ( ! isset($Inline['position']))
+ {
+ $Inline['position'] = $markerPosition;
+ }
+
+ # cause the new element to 'inherit' our non nestables
+
+
+ $Inline['element']['nonNestables'] = isset($Inline['element']['nonNestables'])
+ ? array_merge($Inline['element']['nonNestables'], $nonNestables)
+ : $nonNestables
+ ;
+
+ # the text that comes before the inline
+ $unmarkedText = substr($text, 0, $Inline['position']);
+
+ # compile the unmarked text
+ $InlineText = $this->inlineText($unmarkedText);
+ $Elements[] = $InlineText['element'];
+
+ # compile the inline
+ $Elements[] = $this->extractElement($Inline);
+
+ # remove the examined text
+ $text = substr($text, $Inline['position'] + $Inline['extent']);
+
+ continue 2;
+ }
+
+ # the marker does not belong to an inline
+
+ $unmarkedText = substr($text, 0, $markerPosition + 1);
+
+ $InlineText = $this->inlineText($unmarkedText);
+ $Elements[] = $InlineText['element'];
+
+ $text = substr($text, $markerPosition + 1);
+ }
+
+ $InlineText = $this->inlineText($text);
+ $Elements[] = $InlineText['element'];
+
+ foreach ($Elements as &$Element)
+ {
+ if ( ! isset($Element['autobreak']))
+ {
+ $Element['autobreak'] = false;
+ }
+ }
+
+ return $Elements;
+ }
+
+ #
+ # ~
+ #
+
+ protected function inlineText($text)
+ {
+ $Inline = array(
+ 'extent' => strlen($text),
+ 'element' => array(),
+ );
+
+ $Inline['element']['elements'] = self::pregReplaceElements(
+ $this->breaksEnabled ? '/[ ]*+\n/' : '/(?:[ ]*+\\\\|[ ]{2,}+)\n/',
+ array(
+ array('name' => 'br'),
+ array('text' => "\n"),
+ ),
+ $text
+ );
+
+ return $Inline;
+ }
+
+ protected function inlineCode($Excerpt)
+ {
+ $marker = $Excerpt['text'][0];
+
+ if (preg_match('/^(['.$marker.']++)[ ]*+(.+?)[ ]*+(?<!['.$marker.'])\1(?!'.$marker.')/s', $Excerpt['text'], $matches))
+ {
+ $text = $matches[2];
+ $text = preg_replace('/[ ]*+\n/', ' ', $text);
+
+ return array(
+ 'extent' => strlen($matches[0]),
+ 'element' => array(
+ 'name' => 'code',
+ 'text' => $text,
+ ),
+ );
+ }
+ }
+
+ protected function inlineEmailTag($Excerpt)
+ {
+ $hostnameLabel = '[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?';
+
+ $commonMarkEmail = '[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]++@'
+ . $hostnameLabel . '(?:\.' . $hostnameLabel . ')*';
+
+ if (strpos($Excerpt['text'], '>') !== false
+ and preg_match("/^<((mailto:)?$commonMarkEmail)>/i", $Excerpt['text'], $matches)
+ ){
+ $url = $matches[1];
+
+ if ( ! isset($matches[2]))
+ {
+ $url = "mailto:$url";
+ }
+
+ return array(
+ 'extent' => strlen($matches[0]),
+ 'element' => array(
+ 'name' => 'a',
+ 'text' => $matches[1],
+ 'attributes' => array(
+ 'href' => $url,
+ ),
+ ),
+ );
+ }
+ }
+
+ protected function inlineEmphasis($Excerpt)
+ {
+ if ( ! isset($Excerpt['text'][1]))
+ {
+ return;
+ }
+
+ $marker = $Excerpt['text'][0];
+
+ if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches))
+ {
+ $emphasis = 'strong';
+ }
+ elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches))
+ {
+ $emphasis = 'em';
+ }
+ else
+ {
+ return;
+ }
+
+ return array(
+ 'extent' => strlen($matches[0]),
+ 'element' => array(
+ 'name' => $emphasis,
+ 'handler' => array(
+ 'function' => 'lineElements',
+ 'argument' => $matches[1],
+ 'destination' => 'elements',
+ )
+ ),
+ );
+ }
+
+ protected function inlineEscapeSequence($Excerpt)
+ {
+ if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters))
+ {
+ return array(
+ 'element' => array('rawHtml' => $Excerpt['text'][1]),
+ 'extent' => 2,
+ );
+ }
+ }
+
+ protected function inlineImage($Excerpt)
+ {
+ if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[')
+ {
+ return;
+ }
+
+ $Excerpt['text']= substr($Excerpt['text'], 1);
+
+ $Link = $this->inlineLink($Excerpt);
+
+ if ($Link === null)
+ {
+ return;
+ }
+
+ $Inline = array(
+ 'extent' => $Link['extent'] + 1,
+ 'element' => array(
+ 'name' => 'img',
+ 'attributes' => array(
+ 'src' => $Link['element']['attributes']['href'],
+ 'alt' => $Link['element']['handler']['argument'],
+ ),
+ 'autobreak' => true,
+ ),
+ );
+
+ $Inline['element']['attributes'] += $Link['element']['attributes'];
+
+ unset($Inline['element']['attributes']['href']);
+
+ return $Inline;
+ }
+
+ protected function inlineLink($Excerpt)
+ {
+ $Element = array(
+ 'name' => 'a',
+ 'handler' => array(
+ 'function' => 'lineElements',
+ 'argument' => null,
+ 'destination' => 'elements',
+ ),
+ 'nonNestables' => array('Url', 'Link'),
+ 'attributes' => array(
+ 'href' => null,
+ 'title' => null,
+ ),
+ );
+
+ $extent = 0;
+
+ $remainder = $Excerpt['text'];
+
+ if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches))
+ {
+ $Element['handler']['argument'] = $matches[1];
+
+ $extent += strlen($matches[0]);
+
+ $remainder = substr($remainder, $extent);
+ }
+ else
+ {
+ return;
+ }
+
+ if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches))
+ {
+ $Element['attributes']['href'] = $matches[1];
+
+ if (isset($matches[2]))
+ {
+ $Element['attributes']['title'] = substr($matches[2], 1, - 1);
+ }
+
+ $extent += strlen($matches[0]);
+ }
+ else
+ {
+ if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches))
+ {
+ $definition = strlen($matches[1]) ? $matches[1] : $Element['handler']['argument'];
+ $definition = strtolower($definition);
+
+ $extent += strlen($matches[0]);
+ }
+ else
+ {
+ $definition = strtolower($Element['handler']['argument']);
+ }
+
+ if ( ! isset($this->DefinitionData['Reference'][$definition]))
+ {
+ return;
+ }
+
+ $Definition = $this->DefinitionData['Reference'][$definition];
+
+ $Element['attributes']['href'] = $Definition['url'];
+ $Element['attributes']['title'] = $Definition['title'];
+ }
+
+ return array(
+ 'extent' => $extent,
+ 'element' => $Element,
+ );
+ }
+
+ protected function inlineMarkup($Excerpt)
+ {
+ if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false)
+ {
+ return;
+ }
+
+ if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*+[ ]*+>/s', $Excerpt['text'], $matches))
+ {
+ return array(
+ 'element' => array('rawHtml' => $matches[0]),
+ 'extent' => strlen($matches[0]),
+ );
+ }
+
+ if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-?+[^-])*-->/s', $Excerpt['text'], $matches))
+ {
+ return array(
+ 'element' => array('rawHtml' => $matches[0]),
+ 'extent' => strlen($matches[0]),
+ );
+ }
+
+ if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*+(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+\/?>/s', $Excerpt['text'], $matches))
+ {
+ return array(
+ 'element' => array('rawHtml' => $matches[0]),
+ 'extent' => strlen($matches[0]),
+ );
+ }
+ }
+
+ protected function inlineSpecialCharacter($Excerpt)
+ {
+ if (substr($Excerpt['text'], 1, 1) !== ' ' and strpos($Excerpt['text'], ';') !== false
+ and preg_match('/^&(#?+[0-9a-zA-Z]++);/', $Excerpt['text'], $matches)
+ ) {
+ return array(
+ 'element' => array('rawHtml' => '&' . $matches[1] . ';'),
+ 'extent' => strlen($matches[0]),
+ );
+ }
+
+ return;
+ }
+
+ protected function inlineStrikethrough($Excerpt)
+ {
+ if ( ! isset($Excerpt['text'][1]))
+ {
+ return;
+ }
+
+ if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches))
+ {
+ return array(
+ 'extent' => strlen($matches[0]),
+ 'element' => array(
+ 'name' => 'del',
+ 'handler' => array(
+ 'function' => 'lineElements',
+ 'argument' => $matches[1],
+ 'destination' => 'elements',
+ )
+ ),
+ );
+ }
+ }
+
+ protected function inlineUrl($Excerpt)
+ {
+ if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/')
+ {
+ return;
+ }
+
+ if (strpos($Excerpt['context'], 'http') !== false
+ and preg_match('/\bhttps?+:[\/]{2}[^\s<]+\b\/*+/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)
+ ) {
+ $url = $matches[0][0];
+
+ $Inline = array(
+ 'extent' => strlen($matches[0][0]),
+ 'position' => $matches[0][1],
+ 'element' => array(
+ 'name' => 'a',
+ 'text' => $url,
+ 'attributes' => array(
+ 'href' => $url,
+ ),
+ ),
+ );
+
+ return $Inline;
+ }
+ }
+
+ protected function inlineUrlTag($Excerpt)
+ {
+ if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w++:\/{2}[^ >]++)>/i', $Excerpt['text'], $matches))
+ {
+ $url = $matches[1];
+
+ return array(
+ 'extent' => strlen($matches[0]),
+ 'element' => array(
+ 'name' => 'a',
+ 'text' => $url,
+ 'attributes' => array(
+ 'href' => $url,
+ ),
+ ),
+ );
+ }
+ }
+
+ # ~
+
+ protected function unmarkedText($text)
+ {
+ $Inline = $this->inlineText($text);
+ return $this->element($Inline['element']);
+ }
+
+ #
+ # Handlers
+ #
+
+ protected function handle(array $Element)
+ {
+ if (isset($Element['handler']))
+ {
+ if (!isset($Element['nonNestables']))
+ {
+ $Element['nonNestables'] = array();
+ }
+
+ if (is_string($Element['handler']))
+ {
+ $function = $Element['handler'];
+ $argument = $Element['text'];
+ unset($Element['text']);
+ $destination = 'rawHtml';
+ }
+ else
+ {
+ $function = $Element['handler']['function'];
+ $argument = $Element['handler']['argument'];
+ $destination = $Element['handler']['destination'];
+ }
+
+ $Element[$destination] = $this->{$function}($argument, $Element['nonNestables']);
+
+ if ($destination === 'handler')
+ {
+ $Element = $this->handle($Element);
+ }
+
+ unset($Element['handler']);
+ }
+
+ return $Element;
+ }
+
+ protected function handleElementRecursive(array $Element)
+ {
+ return $this->elementApplyRecursive(array($this, 'handle'), $Element);
+ }
+
+ protected function handleElementsRecursive(array $Elements)
+ {
+ return $this->elementsApplyRecursive(array($this, 'handle'), $Elements);
+ }
+
+ protected function elementApplyRecursive($closure, array $Element)
+ {
+ $Element = call_user_func($closure, $Element);
+
+ if (isset($Element['elements']))
+ {
+ $Element['elements'] = $this->elementsApplyRecursive($closure, $Element['elements']);
+ }
+ elseif (isset($Element['element']))
+ {
+ $Element['element'] = $this->elementApplyRecursive($closure, $Element['element']);
+ }
+
+ return $Element;
+ }
+
+ protected function elementApplyRecursiveDepthFirst($closure, array $Element)
+ {
+ if (isset($Element['elements']))
+ {
+ $Element['elements'] = $this->elementsApplyRecursiveDepthFirst($closure, $Element['elements']);
+ }
+ elseif (isset($Element['element']))
+ {
+ $Element['element'] = $this->elementsApplyRecursiveDepthFirst($closure, $Element['element']);
+ }
+
+ $Element = call_user_func($closure, $Element);
+
+ return $Element;
+ }
+
+ protected function elementsApplyRecursive($closure, array $Elements)
+ {
+ foreach ($Elements as &$Element)
+ {
+ $Element = $this->elementApplyRecursive($closure, $Element);
+ }
+
+ return $Elements;
+ }
+
+ protected function elementsApplyRecursiveDepthFirst($closure, array $Elements)
+ {
+ foreach ($Elements as &$Element)
+ {
+ $Element = $this->elementApplyRecursiveDepthFirst($closure, $Element);
+ }
+
+ return $Elements;
+ }
+
+ protected function element(array $Element)
+ {
+ if ($this->safeMode)
+ {
+ $Element = $this->sanitiseElement($Element);
+ }
+
+ # identity map if element has no handler
+ $Element = $this->handle($Element);
+
+ $hasName = isset($Element['name']);
+
+ $markup = '';
+
+ if ($hasName)
+ {
+ $markup .= '<' . $Element['name'];
+
+ if (isset($Element['attributes']))
+ {
+ foreach ($Element['attributes'] as $name => $value)
+ {
+ if ($value === null)
+ {
+ continue;
+ }
+
+ $markup .= " $name=\"".self::escape($value).'"';
+ }
+ }
+ }
+
+ $permitRawHtml = false;
+
+ if (isset($Element['text']))
+ {
+ $text = $Element['text'];
+ }
+ // very strongly consider an alternative if you're writing an
+ // extension
+ elseif (isset($Element['rawHtml']))
+ {
+ $text = $Element['rawHtml'];
+
+ $allowRawHtmlInSafeMode = isset($Element['allowRawHtmlInSafeMode']) && $Element['allowRawHtmlInSafeMode'];
+ $permitRawHtml = !$this->safeMode || $allowRawHtmlInSafeMode;
+ }
+
+ $hasContent = isset($text) || isset($Element['element']) || isset($Element['elements']);
+
+ if ($hasContent)
+ {
+ $markup .= $hasName ? '>' : '';
+
+ if (isset($Element['elements']))
+ {
+ $markup .= $this->elements($Element['elements']);
+ }
+ elseif (isset($Element['element']))
+ {
+ $markup .= $this->element($Element['element']);
+ }
+ else
+ {
+ if (!$permitRawHtml)
+ {
+ $markup .= self::escape($text, true);
+ }
+ else
+ {
+ $markup .= $text;
+ }
+ }
+
+ $markup .= $hasName ? '</' . $Element['name'] . '>' : '';
+ }
+ elseif ($hasName)
+ {
+ $markup .= ' />';
+ }
+
+ return $markup;
+ }
+
+ protected function elements(array $Elements)
+ {
+ $markup = '';
+
+ $autoBreak = true;
+
+ foreach ($Elements as $Element)
+ {
+ if (empty($Element))
+ {
+ continue;
+ }
+
+ $autoBreakNext = (isset($Element['autobreak'])
+ ? $Element['autobreak'] : isset($Element['name'])
+ );
+ // (autobreak === false) covers both sides of an element
+ $autoBreak = !$autoBreak ? $autoBreak : $autoBreakNext;
+
+ $markup .= ($autoBreak ? "\n" : '') . $this->element($Element);
+ $autoBreak = $autoBreakNext;
+ }
+
+ $markup .= $autoBreak ? "\n" : '';
+
+ return $markup;
+ }
+
+ # ~
+
+ protected function li($lines)
+ {
+ $Elements = $this->linesElements($lines);
+
+ if ( ! in_array('', $lines)
+ and isset($Elements[0]) and isset($Elements[0]['name'])
+ and $Elements[0]['name'] === 'p'
+ ) {
+ unset($Elements[0]['name']);
+ }
+
+ return $Elements;
+ }
+
+ #
+ # AST Convenience
+ #
+
+ /**
+ * Replace occurrences $regexp with $Elements in $text. Return an array of
+ * elements representing the replacement.
+ */
+ protected static function pregReplaceElements($regexp, $Elements, $text)
+ {
+ $newElements = array();
+
+ while (preg_match($regexp, $text, $matches, PREG_OFFSET_CAPTURE))
+ {
+ $offset = $matches[0][1];
+ $before = substr($text, 0, $offset);
+ $after = substr($text, $offset + strlen($matches[0][0]));
+
+ $newElements[] = array('text' => $before);
+
+ foreach ($Elements as $Element)
+ {
+ $newElements[] = $Element;
+ }
+
+ $text = $after;
+ }
+
+ $newElements[] = array('text' => $text);
+
+ return $newElements;
+ }
+
+ #
+ # Deprecated Methods
+ #
+
+ function parse($text)
+ {
+ $markup = $this->text($text);
+
+ return $markup;
+ }
+
+ protected function sanitiseElement(array $Element)
+ {
+ static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/';
+ static $safeUrlNameToAtt = array(
+ 'a' => 'href',
+ 'img' => 'src',
+ );
+
+ if ( ! isset($Element['name']))
+ {
+ unset($Element['attributes']);
+ return $Element;
+ }
+
+ if (isset($safeUrlNameToAtt[$Element['name']]))
+ {
+ $Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]);
+ }
+
+ if ( ! empty($Element['attributes']))
+ {
+ foreach ($Element['attributes'] as $att => $val)
+ {
+ # filter out badly parsed attribute
+ if ( ! preg_match($goodAttribute, $att))
+ {
+ unset($Element['attributes'][$att]);
+ }
+ # dump onevent attribute
+ elseif (self::striAtStart($att, 'on'))
+ {
+ unset($Element['attributes'][$att]);
+ }
+ }
+ }
+
+ return $Element;
+ }
+
+ protected function filterUnsafeUrlInAttribute(array $Element, $attribute)
+ {
+ foreach ($this->safeLinksWhitelist as $scheme)
+ {
+ if (self::striAtStart($Element['attributes'][$attribute], $scheme))
+ {
+ return $Element;
+ }
+ }
+
+ $Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]);
+
+ return $Element;
+ }
+
+ #
+ # Static Methods
+ #
+
+ protected static function escape($text, $allowQuotes = false)
+ {
+ return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8');
+ }
+
+ protected static function striAtStart($string, $needle)
+ {
+ $len = strlen($needle);
+
+ if ($len > strlen($string))
+ {
+ return false;
+ }
+ else
+ {
+ return strtolower(substr($string, 0, $len)) === strtolower($needle);
+ }
+ }
+
+ static function instance($name = 'default')
+ {
+ if (isset(self::$instances[$name]))
+ {
+ return self::$instances[$name];
+ }
+
+ $instance = new static();
+
+ self::$instances[$name] = $instance;
+
+ return $instance;
+ }
+
+ private static $instances = array();
+
+ #
+ # Fields
+ #
+
+ protected $DefinitionData;
+
+ #
+ # Read-Only
+
+ protected $specialCharacters = array(
+ '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', '~'
+ );
+
+ protected $StrongRegex = array(
+ '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*+[*])+?)[*]{2}(?![*])/s',
+ '_' => '/^__((?:\\\\_|[^_]|_[^_]*+_)+?)__(?!_)/us',
+ );
+
+ protected $EmRegex = array(
+ '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s',
+ '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us',
+ );
+
+ protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*+(?:\s*+=\s*+(?:[^"\'=<>`\s]+|"[^"]*+"|\'[^\']*+\'))?+';
+
+ protected $voidElements = array(
+ 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source',
+ );
+
+ protected $textLevelElements = array(
+ 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont',
+ 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing',
+ 'i', 'rp', 'del', 'code', 'strike', 'marquee',
+ 'q', 'rt', 'ins', 'font', 'strong',
+ 's', 'tt', 'kbd', 'mark',
+ 'u', 'xm', 'sub', 'nobr',
+ 'sup', 'ruby',
+ 'var', 'span',
+ 'wbr', 'time',
+ );
+}
diff --git a/blog/posts/building_a_cooler_body_2/index.md b/blog/posts/building_a_cooler_body_2/index.md
deleted file mode 100644
index 8f6fe6b..0000000
--- a/blog/posts/building_a_cooler_body_2/index.md
+++ /dev/null
@@ -1,3 +0,0 @@
-It has certainly been a very interesting year for my endocrine system.
-
-As of publishing, I started estrogen exactly one year ago, and the [blog post](../building_a_cooler_body/) about my Journey&trade; towards this also went up exactly one year ago. \ No newline at end of file
diff --git a/blog/posts/guide_sorcery_git/index.md b/blog/posts/guide_sorcery_git/index.md
deleted file mode 100644
index 4a46ca9..0000000
--- a/blog/posts/guide_sorcery_git/index.md
+++ /dev/null
@@ -1,183 +0,0 @@
-Recently, someone retooted [this blog post](https://char.lt/blog/2026/09/sorcery-repo-viewer/) onto my Bluesky feed. I found it compelling; the scrapers haven't become a problem for me yet, but I also don't use 99% of the features my Forgejo instance provides, and I thought the program the article was about seemed cool. Besides, my Forgejo instance is running on my old domain, so I'll be needing to migrate all my repos at some point in the next two years anyway, so I might as well have some fun with it and switch hosting solutions while I'm at it.
-
-Inconveniently for me, however, [Sorcery](https://git.t4t.associates/char/sorcery/) is certified Oomfware&trade; and doesn't have such luxuries as a pre-compiled binary to download or a professional install guide, so I guess if I want this sucker on my server I'm figuring that shit out myself. It's also designed for use with Nginx and not my current reverse proxy, Caddy, so I'll have to decipher the provided nginx config and port it over. I figured I may as well write all that down so you don't have to figure it out yourself.
-
-# Git server
-
-Sorcery is just a read-only frontend for your git repos, so we'll have to set up a git server to use it with. I'll just be setting up a basic ssh git server as described in the [official Git docs](https://git-scm.com/book/en/v2/Git-on-the-Server-Setting-Up-the-Server), but I'll copy the instructions over here for your convenience.
-
-First, add a user on your server for the git server and switch to it:
-
-```
-adduser git
-su git
-cd
-```
-
-If you have ssh pubkey authentication set up (which you should) now's the time to enable it for the git user as well. I just did this by copying the contents of my `.ssh/authorized_keys` file into the git user's one at `/home/git/.ssh/authorized_keys`.
-
-```
-mkdir .ssh && chmod 700 .ssh
-touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys
-exit
-nano ~/.ssh/authorized_keys
-<copy the contents>
-su git
-nano ~/.ssh/authorized_keys
-<paste, save and exit>
-```
-
-This is actually what I did.
-
-Test to make sure ssh login works, and if it does, the git server is now technically set up. You can create repositories anywhere on the server that the `git` user has read/write permissions by creating a directory for the repo (convention dictates that you call it `repoName.git` but you don't have to) and initializing a bare repository in there:
-
-```
-mkdir reponame.git
-cd reponame.git
-git init --bare
-```
-
-Now you should be able to add it as a remote with `git remote add origin git@your.domain:/absolute/path/to/repoName.git` on your machine, or if you're lazy like me and just put your repositories in a folder in the git user's home directory, with `git remote add origin git@your.domain:relativePathTo/repoName.git`.
-
-Sorcery expects a folder structure like this for your repositories:
-
-```
-reposFolder
-├─userFolder
-│ ├─repoName.git
-│ └─repoName2.git
-└─userFolder
-```
-
-Now on to the interesting part.
-
-# Installing the fucker from source
-
-Sorcery doesn't have a precompiled binary to use that I could find, so it has to be built from source. Due to the developer's choices, this will require the use of Nix. I'm installing and configuring it through the distro package manager on Ubuntu Server, so this part might be a little different for you if you're using something else.
-
-First, naturally, Nix needs to be installed and the source code cloned:
-
-```
-apt install -y nix
-git clone https://git.t4t.associates/char/sorcery
-cd sorcery
-```
-
-If we try to `nix build` now, Nix is gonna give us some errors, so let's fix those. First, it'll complain about a couple of "experimental features" not being enabled. Enable the relevant ones by appending the following to `/etc/nix/nix.conf`:
-
-```
-experimental-features = nix-command flakes
-```
-
-If you're in my situation, that file should look like this after:
-
-<p class="codetitle">/etc/nix/nix.conf</p>
-
-```
-# see https://nixos.org/manual/nix/stable/command-ref/conf-file
-
-sandbox = true
-experimental-features = nix-command flakes
-```
-
-Now it's probably gonna complain that you've been denied permission to get the status of some kind of daemon-socket. You can gain permission by adding yourself to the `nix-users` group, like so:
-
-```
-sudo usermod -a -G nix-users yourusername
-```
-
-Make sure to log out and back in after you do that.
-
-Okay, *now* we can run `nix build` in the git repo to get our binary:
-
-```
-nix build
-```
-
-It'll show up inside the cloned repo at `result/bin/sorceryd`. Now move it somewhere that's not that &mdash; the Sorcery README suggests moving it to `/usr/local/bin/` "or whatever". Installing it there will make some pre-provided things like the systemd unit work with fewer changes, so I recommend you do that.
-
-```
-mv result/bin/sorceryd /usr/local/bin/
-```
-
-If you put it somewhere else, replace mentions of `/usr/local/bin/` accordingly.
-
-# Reverse proxy configuration
-
-The dev provides an nginx config for Sorcery through a script included in the repo that generates one. It's pretty elaborate, so I'm gonna have to run the script and reverse engineer its output to make a Caddy config. If you're using Nginx, I'm guessing this next part will be relevant to you. If you're using Caddy, skip ahead to where I provide the working Caddy config I used.
-
-## Extracting the Nginx config
-
-The script in question is a Typescript file, and the dev recommends using Deno, so we're gonna have to install that first. Annoyingly, Deno doesn't publish to most distro package managers, so that'll look about like this:
-
-```
-curl -fsSL https://deno.land/install.sh | sh
-```
-
-Yucky, but fortunately after that it just works, assuming you told it to add itself to the PATH when it asked. Now run the script:
-
-```
-deno run sorcery.ngx.ts > sorcery.conf
-```
-
-If you're using Nginx, edit the newly generated `sorcery.conf` accordingly and do whatever it is you do with it.
-
-## Caddy config
-
-Wow, that was tough. Thanks to my hard work, you may now simply copy this into your Caddyfile and you're golden:
-
-```
-
-```
-
-# systemd configuration
-
-Sorcery's README provides a systemd unit and the environment file it expects. We'll put the environment file in place first &mdash; copy this to `/etc/sorcery/env` and edit accordingly:
-
-<p class="codetitle">/etc/sorcery/env</p>
-
-```
-SORCERY_REPOSITORIES=/absolute/path/to/reposFolder
-SORCERY_CACHE=/var/cache/sorcery
-SORCERY_SOCKET=/run/sorcery/sock
-SORCERY_INSTANCE_NAME=your.domain
-SORCERY_CLONE_URL_BASE=https://your.domain
-SORCERY_CONTROL_SOCKET=/run/sorcery/control
-```
-
-Now paste the following systemd unit to `/etc/systemd/system/sorceryd.service`:
-
-<p class="codetitle">/etc/systemd/system/sorceryd.service</p>
-
-```
-[Unit]
-Description=Sorcery Git forge
-After=network.target
-
-[Service]
-Type=simple
-User=git
-Group=git
-RuntimeDirectory=sorcery
-CacheDirectory=sorcery
-ConfigurationDirectory=sorcery
-EnvironmentFile=/etc/sorcery/env
-ExecStart=/usr/local/bin/sorceryd
-Restart=on-failure
-RestartSec=2
-UMask=0027
-NoNewPrivileges=true
-PrivateTmp=true
-ProtectSystem=strict
-ProtectHome=read-only
-
-[Install]
-WantedBy=multi-user.target
-```
-
-Mercifully, if you've followed this guide so far, you shouldn't need to change anything in there. Now you can start 'er up:
-
-```
-sudo systemctl daemon-reload
-sudo systemctl enable --now sorceryd.service
-``` \ No newline at end of file
diff --git a/blog/posts/guide_sorcery_git/index.php b/blog/posts/guide_sorcery_git/index.php
deleted file mode 100644
index 952e6d9..0000000
--- a/blog/posts/guide_sorcery_git/index.php
+++ /dev/null
@@ -1 +0,0 @@
-<?php include($_SERVER['DOCUMENT_ROOT'] . '/blog/post.php'); \ No newline at end of file
diff --git a/blog/posts/invaluable_contributions/bg.png b/blog/posts/invaluable_contributions/bg.png
new file mode 100644
index 0000000..c3f1f6d
--- /dev/null
+++ b/blog/posts/invaluable_contributions/bg.png
Binary files differ
diff --git a/blog/posts/invaluable_contributions/index.md b/blog/posts/invaluable_contributions/index.md
new file mode 100644
index 0000000..324cb82
--- /dev/null
+++ b/blog/posts/invaluable_contributions/index.md
@@ -0,0 +1,37 @@
+## Introduction
+
+Artificial Intelligence (AI) has emerged as a transformative force, revolutionizing various aspects of human life. Despite concerns and debates surrounding its ethical implications, it is essential to acknowledge the myriad ways in which AI tools contribute positively to humanity. This article explores the numerous benefits of AI, asserting that these technologies, when used responsibly, offer unparalleled advantages with minimal downsides.
+
+### 1. Efficiency and Productivity:
+
+One of the most significant advantages of AI tools is their ability to enhance efficiency and productivity across different industries. Automation powered by AI enables the swift execution of repetitive tasks, freeing up human resources to focus on more complex and creative endeavors. This leads to improved efficiency, reduced errors, and enhanced overall productivity.
+
+### 1. Healthcare Advancements:
+
+AI is making remarkable strides in the field of healthcare, revolutionizing diagnostics, treatment, and patient care. Machine learning algorithms can analyze vast amounts of medical data to detect patterns and predict disease outcomes. AI-powered medical imaging facilitates early detection of diseases like cancer, significantly improving prognosis and treatment outcomes.
+
+### 1. Education and Personalized Learning:
+
+AI has the potential to revolutionize education by enabling personalized learning experiences. Adaptive learning platforms can tailor educational content to individual student needs, ensuring a more effective and engaging learning process. Additionally, AI tools can automate administrative tasks, allowing educators to focus on delivering high-quality teaching.
+
+### 1. Environmental Sustainability:
+
+AI plays a crucial role in addressing environmental challenges by optimizing resource usage and promoting sustainable practices. Smart grids, powered by AI algorithms, enhance energy distribution efficiency, and predictive analytics help identify potential environmental risks. Autonomous vehicles and smart transportation systems contribute to reduced fuel consumption and emissions.
+
+### 1. Enhanced Customer Experiences:
+
+Businesses leverage AI tools to enhance customer experiences through chatbots, virtual assistants, and personalized recommendations. These technologies provide instant, round-the-clock customer support, improving customer satisfaction. AI-driven analytics also help companies understand customer behavior and preferences, enabling the delivery of more targeted and relevant services.
+
+### 1. Scientific Discovery and Research:
+
+AI accelerates scientific research by processing vast datasets, identifying patterns, and simulating complex scenarios. In fields such as genomics, drug discovery, and materials science, AI algorithms contribute to groundbreaking discoveries and advancements. This expedites the pace of innovation and the development of solutions to pressing global challenges.
+
+### 1. Social Impact and Accessibility:
+
+AI tools contribute to social impact initiatives by addressing issues related to accessibility and inclusion. Speech recognition technologies enable hands-free communication for individuals with disabilities, and AI-powered translation tools break down language barriers, fostering global communication and understanding.
+
+### Conclusion:
+
+While concerns about the ethical implications and potential downsides of AI exist, it is crucial to recognize the overwhelmingly positive impact these technologies have on humanity. The efficiency gains, healthcare advancements, educational innovations, environmental sustainability efforts, improved customer experiences, scientific discoveries, and enhanced social accessibility demonstrate the myriad ways AI contributes to a brighter and more promising future for humanity. Responsible development and deployment of AI will undoubtedly continue to shape a world where the benefits far outweigh the potential downsides.
+
+<p style="opacity: 0.8; font-style: italic; font-size: 0.9em;">This article was written with the assistance of ChatGPT.</p> \ No newline at end of file
diff --git a/blog/posts/building_a_cooler_body_2/index.php b/blog/posts/invaluable_contributions/index.php
index 952e6d9..952e6d9 100644
--- a/blog/posts/building_a_cooler_body_2/index.php
+++ b/blog/posts/invaluable_contributions/index.php
diff --git a/footer.php b/footer.php
index cc371ad..f91a942 100644
--- a/footer.php
+++ b/footer.php
@@ -5,7 +5,7 @@
<form class="footerform" action="/setfont.php" method="post" autocomplete="off">
<div>
<label for="font">Font Selector</label>
- <select id="font" name="font">
+ <select id="font" name="font" onchange="this.form.submit();">
<option <?php if($c=="b612mono"){echo("selected");}?> value="b612mono">B612 Mono</option>
<option <?php if($c=="b612"){echo("selected");}?> value="b612">B612</option>
<option <?php if($c=="opendyslexic"){echo("selected");}?> value="opendyslexic">OpenDyslexic</option>
@@ -19,7 +19,7 @@
<option <?php if($c=="browserdefault"){echo("selected");}?> value="browserdefault">Browser default</option>
</select>
</div>
- <input type="submit" value="Apply">
+ <noscript><input type="submit" value="Apply"></noscript>
</form>
<p>
<?php
@@ -43,8 +43,8 @@
echo("&copy;".date("Y")." ".$copyrice[array_rand($copyrice)]);
?> | <a href="https://git.bugwo.men/bugwomen.git/">source</a></p>
<div class="buttons">
- <img src="https://bugwo.men/etc/buttons/isopodhours.png" alt="isopod hours">
- <a target="_blank" href="https://deeptwisty.com/"><img src="https://bugwo.men/etc/buttons/deeptwisty_button.png" alt="deep twisty"></a>
+ <img src="https://bugwo.men/images/buttons/isopodhours.png" alt="isopod hours">
+ <a target="_blank" href="https://deeptwisty.com/"><img src="https://bugwo.men/images/buttons/deeptwisty_button.png" alt="deep twisty"></a>
<iframe src="https://bugwo.men/stuff/beat/frame.php?theme=pixel" style="width: 88px; height: 31px; border: none;" title="Current time in .beats: <?php echo '@'.date("B"); ?>"></iframe>
</div>
</footer> \ No newline at end of file
diff --git a/header.php b/header.php
index e25690a..1e8ed38 100644
--- a/header.php
+++ b/header.php
@@ -24,7 +24,7 @@ if(!preg_match('/(headless.*)/i', $_SERVER['HTTP_USER_AGENT'])) {
);
$seasonal = true;
break;
- case 10:
+ /*case 10:
$captions = array(
'Boo!',
'Happy Halloween!',
@@ -38,7 +38,7 @@ if(!preg_match('/(headless.*)/i', $_SERVER['HTTP_USER_AGENT'])) {
);
$seasonal = true;
break;
- /*case 12:
+ case 12:
$captions = array(
'hoe hoe hoe or some shit',
'Happy Holidays!',
@@ -148,6 +148,8 @@ if(!preg_match('/(headless.*)/i', $_SERVER['HTTP_USER_AGENT'])) {
'Bug women!',
'Cost streamlined!',
'would you rather have unlimited bacon and no more bugs, or bugs &ndash; unlimited bugs &ndash; and no bugs',
+ 'Continuously Integrated/Continuously Deployed!',
+ #'Fully Git-enabled!',
#'COUNTER',
'TUEADAY'
#'PLACEHIM',
@@ -197,7 +199,7 @@ function echolink($url, $name) {
</script>
<input type="checkbox" name="nav-checkbox-hack" id="nav-checkbox-hack" style="display: none;">
<div class="headerbar">
- <h1><?php echo($host); ?><sup>v4</sup></h1>
+ <h1><a href="/"><?php echo($host); ?><sup>v4</sup></a></h1>
<div>
<img src="https://bugwo.men/images/landing.webp" alt="bugwo.men v4" fetchpriority="high">
</div>
diff --git a/images/isopodgaming.png b/images/isopodgaming.png
new file mode 100644
index 0000000..ac0963a
--- /dev/null
+++ b/images/isopodgaming.png
Binary files differ
diff --git a/music/index.php b/music/index.php
index adc46cc..b92406f 100644
--- a/music/index.php
+++ b/music/index.php
@@ -4,57 +4,6 @@
<head>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/boilerplate.php'); ?>
<title>music | <?php echo($_SERVER['HTTP_HOST']);?></title>
- <style>
- #flex-container {
- display: flex;
- flex-wrap: wrap;
- filter: drop-shadow(3px 3px 6px black);
- }
- #flex-container a {
- --columncount: 2;
- position: relative;
- width: calc(100% / var(--columncount));
- aspect-ratio: 1;
- background-image: var(--img);
- background-size: cover;
- transition-duration: 0.5s;
- overflow: hidden;
- }
- #flex-container a:hover {
- z-index: 50;
- box-shadow: 0 0 12px 2px black;
- transform: scale(1.15);
- color: #df1955;
- }
- #flex-container a span {
- background-color: #000000cc;
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- height: 5.2rem;
- padding: 0 2rem;
- display: flex;
- align-items: center;
- transition-duration: 0.5s;
- box-sizing: border-box;
- }
- #flex-container a:hover span {
- bottom: -5.2rem;
- }
- @media only screen and (max-width: 43rem) {
- #flex-container a {
- --columncount: 1;
- }
- }
- @media only screen and (hover: none) {
- #flex-container a:hover {
- transform: initial;
- z-index: initial;
- box-shadow: initial;
- }
- }
- </style>
</head>
<body>
@@ -231,25 +180,25 @@
<p class="notice">What follows is the subset of this page's content that's still pending being redone.</p>
- <div id="flex-container">
- <a style="--img: url(covers/el_camino.jpg);" target="_blank" href="https://theblackkeys.com/?frontpage=true" ><span>The Black Keys - El Camino</span></a>
- <a style="--img: url(covers/unstoppable_force.jpg);" target="_blank" href="https://caliphate.bandcamp.com/album/unstoppable-force" ><span>CALIPHATE - Unstoppable Force</span></a>
- <a style="--img: url(covers/walks_of_lung.jpg);" target="_blank" href="https://patriciataxxon.bandcamp.com/album/walks-of-lung" ><span>Patricia Taxxon - Walks of Lung</span></a>
- <a style="--img: url(covers/two_house.jpg);" target="_blank" href="https://foodhouse.bandcamp.com/album/two-house" ><span>Food House - two house</span></a>
- <a style="--img: url(covers/american_automatic.jpg);" target="_blank" href="https://en.wikipedia.org/wiki/Kill_Memory_Crash" ><span>Kill Memory Crash - American Automatic</span></a>
- <a style="--img: url(covers/fucked_up_friends_3.jpg);" target="_blank" href="https://tobaxxo.bandcamp.com/album/fucked-up-friends-3" ><span>TOBACCO - Fucked Up Friends 3</span></a>
- <a style="--img: url(covers/synthicate.jpg);" target="_blank" href="https://newretrowave.bandcamp.com/album/synthicate" ><span>LAZERPUNK - Synthicate</span></a>
- <a style="--img: url(covers/peaks_and_valleys.jpg);" target="_blank" href="https://revolutionpeak.bandcamp.com/album/peaks-and-valleys" ><span>Revolution Peak - Peaks and Valleys</span></a>
- <a style="--img: url(covers/triangle_unicode.jpg);" target="_blank" href="https://wearemagonia.bandcamp.com/album/triangle-unicode-lp" ><span>We Are Magonia - Triangle Unicode</span></a>
- <a style="--img: url(covers/vast.jpg);" target="_blank" href="https://waterflame.bandcamp.com/album/vast" ><span>Waterflame - Vast</span></a>
- <a style="--img: url(covers/tortured_waters.jpg);" target="_blank" href="https://newretrowave.bandcamp.com/album/tortured-waters" ><span>DEADLIFE - Tortured Waters</span></a>
- <a style="--img: url(covers/spirit_phone.jpg);" target="_blank" href="http://www.neilcic.com/" ><span>Lemon Demon - Spirit Phone</span></a>
- <a style="--img: url(covers/millenialism.jpg);" target="_blank" href="https://music.businesscasual.biz/album/millennialism" ><span>NYSE - MILLENNIALISM</span></a>
- <a style="--img: url(covers/revolution_radio.jpg);" target="_blank" href="https://greenday.com/" ><span>Green Day - Revolution Radio</span></a>
- <a style="--img: url(covers/this_is_all_yours.jpg);" target="_blank" href="https://altjband.com/" ><span>Alt-J - This Is All Yours</span></a>
- <a style="--img: url(covers/the_last_ninja_2_c64_ost.jpg);" target="_blank" href="https://www.youtube-nocookie.com/embed/bjbN2RyZXHI" ><span>Matt Gray - The Last Ninja 2 (C64) OST</span></a>
- <a style="--img: url(covers/aeon_core.jpg);" target="_blank" href="https://perctrax.bandcamp.com/album/aeon-core" ><span>Scalameriya - Aeon Core</span></a>
- </div>
+ <ul id="flex-container">
+ <li><a style="--img: url(covers/el_camino.jpg);" target="_blank" href="https://theblackkeys.com/?frontpage=true" ><span>The Black Keys - El Camino</span></a></li>
+ <li><a style="--img: url(covers/unstoppable_force.jpg);" target="_blank" href="https://caliphate.bandcamp.com/album/unstoppable-force" ><span>CALIPHATE - Unstoppable Force</span></a></li>
+ <li><a style="--img: url(covers/walks_of_lung.jpg);" target="_blank" href="https://patriciataxxon.bandcamp.com/album/walks-of-lung" ><span>Patricia Taxxon - Walks of Lung</span></a></li>
+ <li><a style="--img: url(covers/two_house.jpg);" target="_blank" href="https://foodhouse.bandcamp.com/album/two-house" ><span>Food House - two house</span></a></li>
+ <li><a style="--img: url(covers/american_automatic.jpg);" target="_blank" href="https://en.wikipedia.org/wiki/Kill_Memory_Crash" ><span>Kill Memory Crash - American Automatic</span></a></li>
+ <li><a style="--img: url(covers/fucked_up_friends_3.jpg);" target="_blank" href="https://tobaxxo.bandcamp.com/album/fucked-up-friends-3" ><span>TOBACCO - Fucked Up Friends 3</span></a></li>
+ <li><a style="--img: url(covers/synthicate.jpg);" target="_blank" href="https://newretrowave.bandcamp.com/album/synthicate" ><span>LAZERPUNK - Synthicate</span></a></li>
+ <li><a style="--img: url(covers/peaks_and_valleys.jpg);" target="_blank" href="https://revolutionpeak.bandcamp.com/album/peaks-and-valleys" ><span>Revolution Peak - Peaks and Valleys</span></a></li>
+ <li><a style="--img: url(covers/triangle_unicode.jpg);" target="_blank" href="https://wearemagonia.bandcamp.com/album/triangle-unicode-lp" ><span>We Are Magonia - Triangle Unicode</span></a></li>
+ <li><a style="--img: url(covers/vast.jpg);" target="_blank" href="https://waterflame.bandcamp.com/album/vast" ><span>Waterflame - Vast</span></a></li>
+ <li><a style="--img: url(covers/tortured_waters.jpg);" target="_blank" href="https://newretrowave.bandcamp.com/album/tortured-waters" ><span>DEADLIFE - Tortured Waters</span></a></li>
+ <li><a style="--img: url(covers/spirit_phone.jpg);" target="_blank" href="http://www.neilcic.com/" ><span>Lemon Demon - Spirit Phone</span></a></li>
+ <li><a style="--img: url(covers/millenialism.jpg);" target="_blank" href="https://music.businesscasual.biz/album/millennialism" ><span>NYSE - MILLENNIALISM</span></a></li>
+ <li><a style="--img: url(covers/revolution_radio.jpg);" target="_blank" href="https://greenday.com/" ><span>Green Day - Revolution Radio</span></a></li>
+ <li><a style="--img: url(covers/this_is_all_yours.jpg);" target="_blank" href="https://altjband.com/" ><span>Alt-J - This Is All Yours</span></a></li>
+ <li><a style="--img: url(covers/the_last_ninja_2_c64_ost.jpg);" target="_blank" href="https://www.youtube-nocookie.com/embed/bjbN2RyZXHI" ><span>Matt Gray - The Last Ninja 2 (C64) OST</span></a></li>
+ <li><a style="--img: url(covers/aeon_core.jpg);" target="_blank" href="https://perctrax.bandcamp.com/album/aeon-core" ><span>Scalameriya - Aeon Core</span></a></li>
+ </ul>
</main>
<?php include($_SERVER['DOCUMENT_ROOT'] . '/footer.php');?>
diff --git a/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Bold.ttf b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Bold.ttf
new file mode 100644
index 0000000..80da7d0
--- /dev/null
+++ b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Bold.ttf
Binary files differ
diff --git a/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-BoldItalic.ttf b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-BoldItalic.ttf
new file mode 100644
index 0000000..d39bfaa
--- /dev/null
+++ b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-BoldItalic.ttf
Binary files differ
diff --git a/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Italic.ttf b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Italic.ttf
new file mode 100644
index 0000000..35f4fb7
--- /dev/null
+++ b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Italic.ttf
Binary files differ
diff --git a/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Regular.ttf b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Regular.ttf
new file mode 100644
index 0000000..f0edd19
--- /dev/null
+++ b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Regular.ttf
Binary files differ
diff --git a/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Bold.ttf b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Bold.ttf
new file mode 100644
index 0000000..8069fa6
--- /dev/null
+++ b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Bold.ttf
Binary files differ
diff --git a/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-BoldItalic.ttf b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-BoldItalic.ttf
new file mode 100644
index 0000000..44155b1
--- /dev/null
+++ b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-BoldItalic.ttf
Binary files differ
diff --git a/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Italic.ttf b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Italic.ttf
new file mode 100644
index 0000000..3541e33
--- /dev/null
+++ b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Italic.ttf
Binary files differ
diff --git a/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Regular.ttf b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Regular.ttf
new file mode 100644
index 0000000..157d62e
--- /dev/null
+++ b/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Regular.ttf
Binary files differ
diff --git a/stuff/fonts/Atkinson_Hyperlegible/OFL.txt b/stuff/fonts/Atkinson_Hyperlegible/OFL.txt
new file mode 100644
index 0000000..9d23fa3
--- /dev/null
+++ b/stuff/fonts/Atkinson_Hyperlegible/OFL.txt
@@ -0,0 +1,93 @@
+Copyright 2020 Braille Institute of America, Inc.
+
+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:
+https://openfontlicense.org
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/stuff/fonts/B612/B612-Bold.ttf b/stuff/fonts/B612/B612-Bold.ttf
new file mode 100644
index 0000000..9c12c10
--- /dev/null
+++ b/stuff/fonts/B612/B612-Bold.ttf
Binary files differ
diff --git a/stuff/fonts/B612/B612-BoldItalic.ttf b/stuff/fonts/B612/B612-BoldItalic.ttf
new file mode 100644
index 0000000..6007ef3
--- /dev/null
+++ b/stuff/fonts/B612/B612-BoldItalic.ttf
Binary files differ
diff --git a/stuff/fonts/B612/B612-Italic.ttf b/stuff/fonts/B612/B612-Italic.ttf
new file mode 100644
index 0000000..06e4437
--- /dev/null
+++ b/stuff/fonts/B612/B612-Italic.ttf
Binary files differ
diff --git a/stuff/fonts/B612/B612-Regular.ttf b/stuff/fonts/B612/B612-Regular.ttf
new file mode 100644
index 0000000..ab83ba3
--- /dev/null
+++ b/stuff/fonts/B612/B612-Regular.ttf
Binary files differ
diff --git a/stuff/fonts/B612/OFL.txt b/stuff/fonts/B612/OFL.txt
new file mode 100644
index 0000000..0b5d530
--- /dev/null
+++ b/stuff/fonts/B612/OFL.txt
@@ -0,0 +1,93 @@
+Copyright 2012 The B612 Project Authors (https://github.com/polarsys/b612)
+
+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:
+https://openfontlicense.org
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/stuff/fonts/B612_Mono/B612Mono-Bold.ttf b/stuff/fonts/B612_Mono/B612Mono-Bold.ttf
new file mode 100644
index 0000000..b282d8d
--- /dev/null
+++ b/stuff/fonts/B612_Mono/B612Mono-Bold.ttf
Binary files differ
diff --git a/stuff/fonts/B612_Mono/B612Mono-BoldItalic.ttf b/stuff/fonts/B612_Mono/B612Mono-BoldItalic.ttf
new file mode 100644
index 0000000..97b92cc
--- /dev/null
+++ b/stuff/fonts/B612_Mono/B612Mono-BoldItalic.ttf
Binary files differ
diff --git a/stuff/fonts/B612_Mono/B612Mono-Italic.ttf b/stuff/fonts/B612_Mono/B612Mono-Italic.ttf
new file mode 100644
index 0000000..c633e93
--- /dev/null
+++ b/stuff/fonts/B612_Mono/B612Mono-Italic.ttf
Binary files differ
diff --git a/stuff/fonts/B612_Mono/B612Mono-Regular.ttf b/stuff/fonts/B612_Mono/B612Mono-Regular.ttf
new file mode 100644
index 0000000..ed013f2
--- /dev/null
+++ b/stuff/fonts/B612_Mono/B612Mono-Regular.ttf
Binary files differ
diff --git a/stuff/fonts/B612_Mono/OFL.txt b/stuff/fonts/B612_Mono/OFL.txt
new file mode 100644
index 0000000..0b5d530
--- /dev/null
+++ b/stuff/fonts/B612_Mono/OFL.txt
@@ -0,0 +1,93 @@
+Copyright 2012 The B612 Project Authors (https://github.com/polarsys/b612)
+
+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:
+https://openfontlicense.org
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/stuff/fonts/DS-DIGI.ttf b/stuff/fonts/DS-DIGI.ttf
new file mode 100644
index 0000000..0925877
--- /dev/null
+++ b/stuff/fonts/DS-DIGI.ttf
Binary files differ
diff --git a/stuff/fonts/Google_Sans/GoogleSans-Bold.ttf b/stuff/fonts/Google_Sans/GoogleSans-Bold.ttf
new file mode 100644
index 0000000..fe51a05
--- /dev/null
+++ b/stuff/fonts/Google_Sans/GoogleSans-Bold.ttf
Binary files differ
diff --git a/stuff/fonts/Google_Sans/GoogleSans-BoldItalic.ttf b/stuff/fonts/Google_Sans/GoogleSans-BoldItalic.ttf
new file mode 100644
index 0000000..69f2274
--- /dev/null
+++ b/stuff/fonts/Google_Sans/GoogleSans-BoldItalic.ttf
Binary files differ
diff --git a/stuff/fonts/Google_Sans/GoogleSans-Italic.ttf b/stuff/fonts/Google_Sans/GoogleSans-Italic.ttf
new file mode 100644
index 0000000..205dbcc
--- /dev/null
+++ b/stuff/fonts/Google_Sans/GoogleSans-Italic.ttf
Binary files differ
diff --git a/stuff/fonts/Google_Sans/GoogleSans-Regular.ttf b/stuff/fonts/Google_Sans/GoogleSans-Regular.ttf
new file mode 100644
index 0000000..c732115
--- /dev/null
+++ b/stuff/fonts/Google_Sans/GoogleSans-Regular.ttf
Binary files differ
diff --git a/stuff/fonts/Google_Sans/GoogleSansCode-Bold.ttf b/stuff/fonts/Google_Sans/GoogleSansCode-Bold.ttf
new file mode 100644
index 0000000..b673c75
--- /dev/null
+++ b/stuff/fonts/Google_Sans/GoogleSansCode-Bold.ttf
Binary files differ
diff --git a/stuff/fonts/Google_Sans/GoogleSansCode-BoldItalic.ttf b/stuff/fonts/Google_Sans/GoogleSansCode-BoldItalic.ttf
new file mode 100644
index 0000000..fadb647
--- /dev/null
+++ b/stuff/fonts/Google_Sans/GoogleSansCode-BoldItalic.ttf
Binary files differ
diff --git a/stuff/fonts/Google_Sans/GoogleSansCode-Italic.ttf b/stuff/fonts/Google_Sans/GoogleSansCode-Italic.ttf
new file mode 100644
index 0000000..07aa7de
--- /dev/null
+++ b/stuff/fonts/Google_Sans/GoogleSansCode-Italic.ttf
Binary files differ
diff --git a/stuff/fonts/Google_Sans/GoogleSansCode-Regular.ttf b/stuff/fonts/Google_Sans/GoogleSansCode-Regular.ttf
new file mode 100644
index 0000000..8b34039
--- /dev/null
+++ b/stuff/fonts/Google_Sans/GoogleSansCode-Regular.ttf
Binary files differ
diff --git a/stuff/fonts/Google_Sans/OFL.txt b/stuff/fonts/Google_Sans/OFL.txt
new file mode 100644
index 0000000..5d6f71c
--- /dev/null
+++ b/stuff/fonts/Google_Sans/OFL.txt
@@ -0,0 +1,91 @@
+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:
+https://openfontlicense.org
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/stuff/fonts/Noto_Serif/NotoSansMono-Bold.ttf b/stuff/fonts/Noto_Serif/NotoSansMono-Bold.ttf
new file mode 100644
index 0000000..c56c765
--- /dev/null
+++ b/stuff/fonts/Noto_Serif/NotoSansMono-Bold.ttf
Binary files differ
diff --git a/stuff/fonts/Noto_Serif/NotoSansMono-Regular.ttf b/stuff/fonts/Noto_Serif/NotoSansMono-Regular.ttf
new file mode 100644
index 0000000..5470d50
--- /dev/null
+++ b/stuff/fonts/Noto_Serif/NotoSansMono-Regular.ttf
Binary files differ
diff --git a/stuff/fonts/Noto_Serif/NotoSerif-Bold.ttf b/stuff/fonts/Noto_Serif/NotoSerif-Bold.ttf
new file mode 100644
index 0000000..519d313
--- /dev/null
+++ b/stuff/fonts/Noto_Serif/NotoSerif-Bold.ttf
Binary files differ
diff --git a/stuff/fonts/Noto_Serif/NotoSerif-BoldItalic.ttf b/stuff/fonts/Noto_Serif/NotoSerif-BoldItalic.ttf
new file mode 100644
index 0000000..23ea70a
--- /dev/null
+++ b/stuff/fonts/Noto_Serif/NotoSerif-BoldItalic.ttf
Binary files differ
diff --git a/stuff/fonts/Noto_Serif/NotoSerif-Italic.ttf b/stuff/fonts/Noto_Serif/NotoSerif-Italic.ttf
new file mode 100644
index 0000000..c3ccb5f
--- /dev/null
+++ b/stuff/fonts/Noto_Serif/NotoSerif-Italic.ttf
Binary files differ
diff --git a/stuff/fonts/Noto_Serif/NotoSerif-Regular.ttf b/stuff/fonts/Noto_Serif/NotoSerif-Regular.ttf
new file mode 100644
index 0000000..1b13cd7
--- /dev/null
+++ b/stuff/fonts/Noto_Serif/NotoSerif-Regular.ttf
Binary files differ
diff --git a/stuff/fonts/Noto_Serif/OFL.txt b/stuff/fonts/Noto_Serif/OFL.txt
new file mode 100644
index 0000000..09f020b
--- /dev/null
+++ b/stuff/fonts/Noto_Serif/OFL.txt
@@ -0,0 +1,93 @@
+Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
+
+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:
+https://openfontlicense.org
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/stuff/fonts/OpenDyslexic/OpenDyslexic-Bold.otf b/stuff/fonts/OpenDyslexic/OpenDyslexic-Bold.otf
new file mode 100644
index 0000000..fc14a5a
--- /dev/null
+++ b/stuff/fonts/OpenDyslexic/OpenDyslexic-Bold.otf
Binary files differ
diff --git a/stuff/fonts/OpenDyslexic/OpenDyslexic-BoldItalic.otf b/stuff/fonts/OpenDyslexic/OpenDyslexic-BoldItalic.otf
new file mode 100644
index 0000000..99b4b1d
--- /dev/null
+++ b/stuff/fonts/OpenDyslexic/OpenDyslexic-BoldItalic.otf
Binary files differ
diff --git a/stuff/fonts/OpenDyslexic/OpenDyslexic-Italic.otf b/stuff/fonts/OpenDyslexic/OpenDyslexic-Italic.otf
new file mode 100644
index 0000000..8f53b29
--- /dev/null
+++ b/stuff/fonts/OpenDyslexic/OpenDyslexic-Italic.otf
Binary files differ
diff --git a/stuff/fonts/OpenDyslexic/OpenDyslexic-Regular.otf b/stuff/fonts/OpenDyslexic/OpenDyslexic-Regular.otf
new file mode 100644
index 0000000..039ceda
--- /dev/null
+++ b/stuff/fonts/OpenDyslexic/OpenDyslexic-Regular.otf
Binary files differ
diff --git a/stuff/fonts/OpenDyslexic/OpenDyslexicMono-Regular.otf b/stuff/fonts/OpenDyslexic/OpenDyslexicMono-Regular.otf
new file mode 100644
index 0000000..543d46b
--- /dev/null
+++ b/stuff/fonts/OpenDyslexic/OpenDyslexicMono-Regular.otf
Binary files differ
diff --git a/stuff/fonts/Ubuntu/Ubuntu-Bold.ttf b/stuff/fonts/Ubuntu/Ubuntu-Bold.ttf
new file mode 100644
index 0000000..c2293d5
--- /dev/null
+++ b/stuff/fonts/Ubuntu/Ubuntu-Bold.ttf
Binary files differ
diff --git a/stuff/fonts/Ubuntu/Ubuntu-BoldItalic.ttf b/stuff/fonts/Ubuntu/Ubuntu-BoldItalic.ttf
new file mode 100644
index 0000000..a3f4996
--- /dev/null
+++ b/stuff/fonts/Ubuntu/Ubuntu-BoldItalic.ttf
Binary files differ
diff --git a/stuff/fonts/Ubuntu/Ubuntu-Italic.ttf b/stuff/fonts/Ubuntu/Ubuntu-Italic.ttf
new file mode 100644
index 0000000..6bd39b0
--- /dev/null
+++ b/stuff/fonts/Ubuntu/Ubuntu-Italic.ttf
Binary files differ
diff --git a/stuff/fonts/Ubuntu/Ubuntu-Regular.ttf b/stuff/fonts/Ubuntu/Ubuntu-Regular.ttf
new file mode 100644
index 0000000..b5505e6
--- /dev/null
+++ b/stuff/fonts/Ubuntu/Ubuntu-Regular.ttf
Binary files differ
diff --git a/stuff/fonts/Ubuntu/UbuntuMono-Bold.ttf b/stuff/fonts/Ubuntu/UbuntuMono-Bold.ttf
new file mode 100644
index 0000000..01ad81b
--- /dev/null
+++ b/stuff/fonts/Ubuntu/UbuntuMono-Bold.ttf
Binary files differ
diff --git a/stuff/fonts/Ubuntu/UbuntuMono-BoldItalic.ttf b/stuff/fonts/Ubuntu/UbuntuMono-BoldItalic.ttf
new file mode 100644
index 0000000..731884e
--- /dev/null
+++ b/stuff/fonts/Ubuntu/UbuntuMono-BoldItalic.ttf
Binary files differ
diff --git a/stuff/fonts/Ubuntu/UbuntuMono-Italic.ttf b/stuff/fonts/Ubuntu/UbuntuMono-Italic.ttf
new file mode 100644
index 0000000..b89338d
--- /dev/null
+++ b/stuff/fonts/Ubuntu/UbuntuMono-Italic.ttf
Binary files differ
diff --git a/stuff/fonts/Ubuntu/UbuntuMono-Regular.ttf b/stuff/fonts/Ubuntu/UbuntuMono-Regular.ttf
new file mode 100644
index 0000000..4977028
--- /dev/null
+++ b/stuff/fonts/Ubuntu/UbuntuMono-Regular.ttf
Binary files differ
diff --git a/stuff/fonts/atkinsonhyperlegible.css b/stuff/fonts/atkinsonhyperlegible.css
new file mode 100644
index 0000000..972f456
--- /dev/null
+++ b/stuff/fonts/atkinsonhyperlegible.css
@@ -0,0 +1,54 @@
+@font-face {
+ font-family: atkinsonhyperlegible;
+ src: url(https://bugwo.men/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: atkinsonhyperlegible;
+ src: url(https://bugwo.men/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: atkinsonhyperlegible;
+ src: url(https://bugwo.men/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-Italic.ttf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: atkinsonhyperlegible;
+ src: url(https://bugwo.men/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegible-BoldItalic.ttf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: atkinsonhyperlegible_mono;
+ src: url(https://bugwo.men/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: atkinsonhyperlegible_mono;
+ src: url(https://bugwo.men/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: atkinsonhyperlegible_mono;
+ src: url(https://bugwo.men/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Italic.ttf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: atkinsonhyperlegible_mono;
+ src: url(https://bugwo.men/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-BoldItalic.ttf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+:root {
+ --bodyfont: atkinsonhyperlegible, sans-serif;
+ --monofont: atkinsonhyperlegible_mono, monospace;
+} \ No newline at end of file
diff --git a/stuff/fonts/atkinsonhyperlegiblemono.css b/stuff/fonts/atkinsonhyperlegiblemono.css
new file mode 100644
index 0000000..0814af9
--- /dev/null
+++ b/stuff/fonts/atkinsonhyperlegiblemono.css
@@ -0,0 +1,29 @@
+@font-face {
+ font-family: atkinsonhyperlegible_mono;
+ src: url(https://bugwo.men/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: atkinsonhyperlegible_mono;
+ src: url(https://bugwo.men/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: atkinsonhyperlegible_mono;
+ src: url(https://bugwo.men/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-Italic.ttf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: atkinsonhyperlegible_mono;
+ src: url(https://bugwo.men/stuff/fonts/Atkinson_Hyperlegible/AtkinsonHyperlegibleMono-BoldItalic.ttf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+:root {
+ --bodyfont: atkinsonhyperlegible_mono, monospace;
+ --monofont: atkinsonhyperlegible_mono, monospace;
+} \ No newline at end of file
diff --git a/stuff/fonts/b612.css b/stuff/fonts/b612.css
new file mode 100644
index 0000000..eefcb0f
--- /dev/null
+++ b/stuff/fonts/b612.css
@@ -0,0 +1,54 @@
+@font-face {
+ font-family: b612;
+ src: url(https://bugwo.men/stuff/fonts/B612/B612-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: b612;
+ src: url(https://bugwo.men/stuff/fonts/B612/B612-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: b612;
+ src: url(https://bugwo.men/stuff/fonts/B612/B612-Italic.ttf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: b612;
+ src: url(https://bugwo.men/stuff/fonts/B612/B612-BoldItalic.ttf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: b612_mono;
+ src: url(https://bugwo.men/stuff/fonts/B612_Mono/B612Mono-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: b612_mono;
+ src: url(https://bugwo.men/stuff/fonts/B612_Mono/B612Mono-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: b612_mono;
+ src: url(https://bugwo.men/stuff/fonts/B612_Mono/B612Mono-Italic.ttf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: b612_mono;
+ src: url(https://bugwo.men/stuff/fonts/B612_Mono/B612Mono-BoldItalic.ttf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+:root {
+ --bodyfont: b612, sans-serif;
+ --monofont: b612_mono, monospace;
+} \ No newline at end of file
diff --git a/stuff/fonts/b612mono.css b/stuff/fonts/b612mono.css
new file mode 100644
index 0000000..f015de5
--- /dev/null
+++ b/stuff/fonts/b612mono.css
@@ -0,0 +1,29 @@
+@font-face {
+ font-family: b612_mono;
+ src: url(https://bugwo.men/stuff/fonts/B612_Mono/B612Mono-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: b612_mono;
+ src: url(https://bugwo.men/stuff/fonts/B612_Mono/B612Mono-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: b612_mono;
+ src: url(https://bugwo.men/stuff/fonts/B612_Mono/B612Mono-Italic.ttf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: b612_mono;
+ src: url(https://bugwo.men/stuff/fonts/B612_Mono/B612Mono-BoldItalic.ttf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+:root {
+ --bodyfont: b612_mono, monospace;
+ --monofont: b612_mono, monospace;
+} \ No newline at end of file
diff --git a/stuff/fonts/browserdefault.css b/stuff/fonts/browserdefault.css
new file mode 100644
index 0000000..07038c8
--- /dev/null
+++ b/stuff/fonts/browserdefault.css
@@ -0,0 +1,9 @@
+/* :root {
+ --bodyfont: sans-serif;
+ --monofont: monospace;
+} */
+
+:root {
+ --bodyfont: unset;
+ --monofont: unset;
+} \ No newline at end of file
diff --git a/stuff/fonts/cafe.ttf b/stuff/fonts/cafe.ttf
new file mode 100644
index 0000000..e31d5fd
--- /dev/null
+++ b/stuff/fonts/cafe.ttf
Binary files differ
diff --git a/stuff/fonts/firsttimewriting.ttf b/stuff/fonts/firsttimewriting.ttf
new file mode 100644
index 0000000..180df00
--- /dev/null
+++ b/stuff/fonts/firsttimewriting.ttf
Binary files differ
diff --git a/stuff/fonts/googlesans.css b/stuff/fonts/googlesans.css
new file mode 100644
index 0000000..59b3785
--- /dev/null
+++ b/stuff/fonts/googlesans.css
@@ -0,0 +1,54 @@
+@font-face {
+ font-family: googlesans;
+ src: url(https://bugwo.men/stuff/fonts/Google_Sans/GoogleSans-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: googlesans;
+ src: url(https://bugwo.men/stuff/fonts/Google_Sans/GoogleSans-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: googlesans;
+ src: url(https://bugwo.men/stuff/fonts/Google_Sans/GoogleSans-Italic.ttf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: googlesans;
+ src: url(https://bugwo.men/stuff/fonts/Google_Sans/GoogleSans-BoldItalic.ttf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: googlesanscode;
+ src: url(https://bugwo.men/stuff/fonts/Google_Sans/GoogleSansCode-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: googlesanscode;
+ src: url(https://bugwo.men/stuff/fonts/Google_Sans/GoogleSansCode-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: googlesanscode;
+ src: url(https://bugwo.men/stuff/fonts/Google_Sans/GoogleSansCode-Italic.ttf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: googlesanscode;
+ src: url(https://bugwo.men/stuff/fonts/Google_Sans/GoogleSansCode-BoldItalic.ttf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+:root {
+ --bodyfont: googlesans, sans-serif;
+ --monofont: googlesanscode, monospace;
+} \ No newline at end of file
diff --git a/stuff/fonts/googlesanscode.css b/stuff/fonts/googlesanscode.css
new file mode 100644
index 0000000..5f701a8
--- /dev/null
+++ b/stuff/fonts/googlesanscode.css
@@ -0,0 +1,29 @@
+@font-face {
+ font-family: googlesanscode;
+ src: url(https://bugwo.men/stuff/fonts/Google_Sans/GoogleSansCode-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: googlesanscode;
+ src: url(https://bugwo.men/stuff/fonts/Google_Sans/GoogleSansCode-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: googlesanscode;
+ src: url(https://bugwo.men/stuff/fonts/Google_Sans/GoogleSansCode-Italic.ttf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: googlesanscode;
+ src: url(https://bugwo.men/stuff/fonts/Google_Sans/GoogleSansCode-BoldItalic.ttf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+:root {
+ --bodyfont: googlesanscode, sans-serif;
+ --monofont: googlesanscode, monospace;
+} \ No newline at end of file
diff --git a/stuff/fonts/notoserif.css b/stuff/fonts/notoserif.css
new file mode 100644
index 0000000..e1df357
--- /dev/null
+++ b/stuff/fonts/notoserif.css
@@ -0,0 +1,41 @@
+@font-face {
+ font-family: notoserif;
+ src: url(https://bugwo.men/stuff/fonts/Noto_Serif/NotoSerif-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: notoserif;
+ src: url(https://bugwo.men/stuff/fonts/Noto_Serif/NotoSerif-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: notoserif;
+ src: url(https://bugwo.men/stuff/fonts/Noto_Serif/NotoSerif-Italic.ttf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: notoserif;
+ src: url(https://bugwo.men/stuff/fonts/Noto_Serif/NotoSerif-BoldItalic.ttf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: notosansmono;
+ src: url(https://bugwo.men/stuff/fonts/Noto_Serif/NotoSansMono-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: notosansmono;
+ src: url(https://bugwo.men/stuff/fonts/Noto_Serif/NotoSansMono-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+
+:root {
+ --bodyfont: notoserif, serif;
+ --monofont: notosansmono, monospace;
+} \ No newline at end of file
diff --git a/stuff/fonts/opendyslexic.css b/stuff/fonts/opendyslexic.css
new file mode 100644
index 0000000..294b74c
--- /dev/null
+++ b/stuff/fonts/opendyslexic.css
@@ -0,0 +1,35 @@
+@font-face {
+ font-family: opendyslexic;
+ src: url(https://bugwo.men/stuff/fonts/OpenDyslexic/OpenDyslexic-Regular.otf);
+ font-display: swap;
+}
+@font-face {
+ font-family: opendyslexic;
+ src: url(https://bugwo.men/stuff/fonts/OpenDyslexic/OpenDyslexic-Bold.otf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: opendyslexic;
+ src: url(https://bugwo.men/stuff/fonts/OpenDyslexic/OpenDyslexic-Italic.otf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: opendyslexic;
+ src: url(https://bugwo.men/stuff/fonts/OpenDyslexic/OpenDyslexic-BoldItalic.otf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: opendyslexic_mono;
+ src: url(https://bugwo.men/stuff/fonts/OpenDyslexic/OpenDyslexicMono-Regular.otf);
+ font-display: swap;
+}
+
+:root {
+ --bodyfont: "opendyslexic", sans-serif;
+ --monofont: "opendyslexic_mono", monospace;
+} \ No newline at end of file
diff --git a/stuff/fonts/silkscreen.css b/stuff/fonts/silkscreen.css
new file mode 100644
index 0000000..636da3e
--- /dev/null
+++ b/stuff/fonts/silkscreen.css
@@ -0,0 +1,16 @@
+@font-face {
+ font-family: silkscreen;
+ src: url(https://bugwo.men/stuff/fonts/slkscr.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: silkscreen;
+ src: url(https://bugwo.men/stuff/fonts/slkscrb.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+
+:root {
+ --bodyfont: "silkscreen", sans-serif;
+ --monofont: "silkscreen", monospace;
+} \ No newline at end of file
diff --git a/stuff/fonts/slkscr.ttf b/stuff/fonts/slkscr.ttf
new file mode 100644
index 0000000..85a2037
--- /dev/null
+++ b/stuff/fonts/slkscr.ttf
Binary files differ
diff --git a/stuff/fonts/slkscrb.ttf b/stuff/fonts/slkscrb.ttf
new file mode 100644
index 0000000..2619b36
--- /dev/null
+++ b/stuff/fonts/slkscrb.ttf
Binary files differ
diff --git a/stuff/fonts/ubuntu.css b/stuff/fonts/ubuntu.css
new file mode 100644
index 0000000..0a67621
--- /dev/null
+++ b/stuff/fonts/ubuntu.css
@@ -0,0 +1,54 @@
+@font-face {
+ font-family: ubuntu;
+ src: url(https://bugwo.men/stuff/fonts/Ubuntu/Ubuntu-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: ubuntu;
+ src: url(https://bugwo.men/stuff/fonts/Ubuntu/Ubuntu-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: ubuntu;
+ src: url(https://bugwo.men/stuff/fonts/Ubuntu/Ubuntu-Italic.ttf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: ubuntu;
+ src: url(https://bugwo.men/stuff/fonts/Ubuntu/Ubuntu-BoldItalic.ttf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: ubuntu_mono;
+ src: url(https://bugwo.men/stuff/fonts/Ubuntu/UbuntuMono-Regular.ttf);
+ font-display: swap;
+}
+@font-face {
+ font-family: ubuntu_mono;
+ src: url(https://bugwo.men/stuff/fonts/Ubuntu/UbuntuMono-Bold.ttf);
+ font-weight: bold;
+ font-display: swap;
+}
+@font-face {
+ font-family: ubuntu_mono;
+ src: url(https://bugwo.men/stuff/fonts/Ubuntu/UbuntuMono-Italic.ttf);
+ font-style: italic;
+ font-display: swap;
+}
+@font-face {
+ font-family: ubuntu_mono;
+ src: url(https://bugwo.men/stuff/fonts/Ubuntu/UbuntuMono-BoldItalic.ttf);
+ font-weight: bold;
+ font-style: italic;
+ font-display: swap;
+}
+
+:root {
+ --bodyfont: "ubuntu", sans-serif;
+ --monofont: "ubuntu_mono", monospace;
+} \ No newline at end of file
diff --git a/stuff/webgarden/index.php b/stuff/webgarden/index.php
index c0aae52..9639fd8 100644
--- a/stuff/webgarden/index.php
+++ b/stuff/webgarden/index.php
@@ -252,8 +252,8 @@
<label for="mus"><a style="text-decoration: underline; cursor: pointer;">song</a></label>
<hr>
<iframe src="https://bugwo.men/stuff/beat/frame.php?theme=pixel" style="width: 84px; height: 27px;"></iframe>
- <img src="/etc/buttons/isopodhours.png" alt="isopod hours"/>
- <img src="/etc/buttons/trans.png" alt="transgender"/>
+ <img src="/images/buttons/isopodhours.png" alt="isopod hours"/>
+ <img src="/images/buttons/trans.png" alt="transgender"/>
</div>
<audio controls style="position: absolute; width: calc(100% - 0.4rem); top: 0.2rem; left: 0.2rem; z-index: 5;"><source src="music.mp3" type="audio/mp3"></audio>
</body>
diff --git a/style.css b/style.css
index e9741c6..750a712 100644
--- a/style.css
+++ b/style.css
@@ -84,11 +84,11 @@ body > p:last-child {
/* Links */
a {
- color: var(--accent1);
+ color: var(--linkcolor);
}
a:hover,
a:focus {
- color: var(--accent2);
+ color: var(--linkhover);
}
.backlink {
border-left: var(--stdpadding) solid var(--accent1);
@@ -112,6 +112,11 @@ header * {
pointer-events: auto;
}
+header h1 a {
+ color: var(--fg0);
+ text-decoration: none;
+}
+
.headerbar { /* This div represents the top header bar */
display: flex;
flex-direction: row;
diff --git a/uses/cumulonimbus/index.php b/uses/cumulonimbus/index.php
index 105f0b6..b75dd32 100644
--- a/uses/cumulonimbus/index.php
+++ b/uses/cumulonimbus/index.php
@@ -59,13 +59,6 @@
</section>
<section>
- <h4><a href="https://freshrss.org/">FreshRSS</a></h4>
- <p>I ended up with this because I elected to ditch Nextcloud in the process of migrating hosting providers, and this was the first RSS reader that I managed to get working on the new server. I swear, it's like the RSS 2.0 spec states that your self-hosted RSS reader has to have installation instructions that don't work.</p>
- <p>I've yet to find an RSS reader with a user experience I like, but this one is tolerable enough that I don't think "I should really find a replacement for this" every time I use it like I did when I was using Whatever Nextcloud Has&trade;, plus it supports a couple common APIs so I can replace the frontend if I decide I hate it.</p>
- <p>Speaking of which, I'm currently using a mobile app called Capy Reader to access this on my phone since the mobile web UI kind of sucks.</p>
- </section>
-
- <section>
<h4><a href="https://github.com/RSS-Bridge/rss-bridge">rss-bridge</a></h4>
<p>Extracts RSS feeds from a genuinely kind of shocking number of websites that don't otherwise have them. I make generous use of this. Feel free to use <a href="https://rss-bridge.bathynomus.xyz/">my instance</a> if you want.</p>
</section>
@@ -90,6 +83,12 @@
<h4><a href="https://zadzmo.org/code/nepenthes/">Nepenthes</a></h4>
<p>A tarpit for AI scrapers. Self-explanatory at this point.</p>
</section>
+
+ <section>
+ <h4><a href="https://craftycontrol.com/">Crafty Controller</a></h4>
+ <p>A convenient admin panel for my Minecraft server(s). It's easier than administrating the servers manually, which for something as trivial as a Minecraft server is saying something.</p>
+ <p>I used to run this on the beefier server in my <span class="house">house</span>, but when I was most recently called upon to spin up a minecraft server I was faced with the choice between finally setting up WireGuard again and just accepting the potentially slower performance of the cloud server, this is what I picked.</p>
+ </section>
</section>
</section>
</main>
diff --git a/uses/servy586/index.php b/uses/servy586/index.php
index 899752e..b0b39f6 100644
--- a/uses/servy586/index.php
+++ b/uses/servy586/index.php
@@ -115,7 +115,7 @@
<section>
<h4>OS - <a href="https://www.truenas.com/">TrueNAS Scale</a></h4>
- <p>I could probably recreate my elaborate configuration on like, baseline debian or something, but I don't want to. Between four ZFS pools, virtual machines, a slightly convoluted system of SMB shares, and various other services, the slick web GUI TrueNAS provides makes everything far more convenient. Its configuration export feature was also very handy when migrating to the new machine.</p>
+ <p>I could probably recreate my elaborate configuration on like, baseline debian or something, but I don't want to. Between four ZFS pools, virtual machines, a slightly convoluted system of file shares, and various other services, the slick web GUI TrueNAS provides makes everything far more convenient. Its configuration export feature was also very handy when migrating to the new machine.</p>
<p>It's got some idiosyncracies to it, but in general TrueNAS smooths out the experience of running this server enough that I'm doing a lot of things I probably couldn't be bothered to otherwise.</p>
</section>
@@ -140,6 +140,19 @@
</section>
<section>
+ <h4><a href="https://filebrowser.org/">Tailscale</a></h4>
+ <p>A "mesh VPN", whatever that means. In practice, Tailscale lets me connect to any of my devices from any other as though they're sharing a local LAN. You know, the thing VPNs are actually for. Half the stuff on this server is only worth running because Tailscale lets me access it away from my <span class="house">house</span> LAN, especially now that I'm routinely bringing a computer outside the house with me for school.</p>
+ </section>
+
+ <section>
+ <h4><a href="https://freshrss.org/">FreshRSS</a></h4>
+ <p>I ended up with this because I elected to ditch Nextcloud in the process of migrating hosting providers, and this was the first RSS reader that I managed to get working post cloud provider migration. I swear, it's like the RSS 2.0 spec states that your self-hosted RSS reader has to have installation instructions that don't work.</p>
+ <p>This used to be on the cloud server, but then a "turn your shit off NOW until you can update" level vuln was discovered in every PHP version released in the past 14 years and I could think of no undertaking more nightmarish than trying to manually set this thing up again. Fortunately, since the last time I deployed an RSS reader I had set up Tailscale on my TrueNAS box, so I could just put it there and both mitigate the vulnerability <em>and</em> offload my self-hosted RSS reader curse to the machines in one fell swoop. Nice!</p>
+ <p>I've yet to find an RSS reader with a user experience I like, but this one is tolerable enough that I don't think "I should really find a replacement for this" every time I use it like I did when I was using Whatever Nextcloud Has&trade;, plus it supports a couple common APIs so I can replace the frontend if I decide I hate it.</p>
+ <p>Speaking of which, I'm currently using a mobile app called Capy Reader to access this on my phone since the mobile web UI kind of sucks.</p>
+ </section>
+
+ <!--section>
<h4>OS - <a href="https://www.debian.org/">Debian Linux</a></h4>
<p>Wait, what? Didn't I just say I was running TrueNAS? I am, but I also have a virtual machine under TrueNAS for my game servers, and this is the OS I use for that. There's a learning curve here compared to Ubuntu Server, which I'm more used to, but at the end of the day Linux is Linux.</p>
</section>
@@ -152,7 +165,7 @@
<section>
<h4><a href="https://www.wireguard.com/">WireGuard</a></h4>
<p>I run a WireGuard client in the VM with a server on my VPS to make my game servers accessible from outside the <span class="house">house</span> without giving out my IP address, worrying about dynamic DNS, or trying to port forward on the solid lump of concentrated ISP malice that passes for my router. I had to write a couple configuration files by hand, god forbid, but otherwise this was much easier.</p>
- </section>
+ </section-->
</section>
</section>
</main>