From 958a68292191d8a4c9024ca2f1f658135ab6f704 Mon Sep 17 00:00:00 2001 From: Minteck Date: Thu, 21 Apr 2022 14:37:44 +0200 Subject: WIP projects page --- .DS_Store | Bin 6148 -> 6148 bytes .idea/.name | 1 + .idea/icon.svg | 29 + about/index.php | 2 +- assets/.DS_Store | Bin 0 -> 6148 bytes assets/css/main.css | 24 + assets/favicon/android-chrome-192x192.png | Bin 0 -> 23701 bytes assets/favicon/android-chrome-512x512.png | Bin 0 -> 72513 bytes assets/favicon/apple-touch-icon.png | Bin 0 -> 17620 bytes assets/favicon/browserconfig.xml | 9 + assets/favicon/favicon-16x16.png | Bin 0 -> 4749 bytes assets/favicon/favicon-32x32.png | Bin 0 -> 5703 bytes assets/favicon/favicon-48x48.png | Bin 0 -> 7211 bytes assets/favicon/favicon-64x64.png | Bin 0 -> 8642 bytes assets/favicon/favicon.ico | Bin 0 -> 32038 bytes assets/favicon/manifest.json | 19 + assets/favicon/mstile-150x150.png | Bin 0 -> 14865 bytes assets/favicon/safari-pinned-tab.svg | 45 + assets/img/.DS_Store | Bin 0 -> 6148 bytes assets/img/icon.png | Bin 0 -> 143689 bytes assets/img/icon.svg | 409 +++++++ assets/img/letters/#.png | Bin 0 -> 1373 bytes assets/img/letters/.DS_Store | Bin 0 -> 6148 bytes assets/img/letters/0.png | Bin 0 -> 1781 bytes assets/img/letters/1.png | Bin 0 -> 864 bytes assets/img/letters/2.png | Bin 0 -> 1550 bytes assets/img/letters/3.png | Bin 0 -> 1872 bytes assets/img/letters/4.png | Bin 0 -> 1260 bytes assets/img/letters/5.png | Bin 0 -> 1616 bytes assets/img/letters/6.png | Bin 0 -> 1945 bytes assets/img/letters/7.png | Bin 0 -> 1185 bytes assets/img/letters/8.png | Bin 0 -> 2115 bytes assets/img/letters/9.png | Bin 0 -> 1932 bytes assets/img/letters/a.png | Bin 0 -> 1827 bytes assets/img/letters/b.png | Bin 0 -> 1616 bytes assets/img/letters/c.png | Bin 0 -> 1842 bytes assets/img/letters/d.png | Bin 0 -> 1533 bytes assets/img/letters/e.png | Bin 0 -> 650 bytes assets/img/letters/f.png | Bin 0 -> 639 bytes assets/img/letters/g.png | Bin 0 -> 1835 bytes assets/img/letters/h.png | Bin 0 -> 649 bytes assets/img/letters/i.png | Bin 0 -> 587 bytes assets/img/letters/j.png | Bin 0 -> 1110 bytes assets/img/letters/k.png | Bin 0 -> 1682 bytes assets/img/letters/l.png | Bin 0 -> 618 bytes assets/img/letters/m.png | Bin 0 -> 1986 bytes assets/img/letters/n.png | Bin 0 -> 1504 bytes assets/img/letters/o.png | Bin 0 -> 2047 bytes assets/img/letters/p.png | Bin 0 -> 1279 bytes assets/img/letters/q.png | Bin 0 -> 2172 bytes assets/img/letters/r.png | Bin 0 -> 1589 bytes assets/img/letters/s.png | Bin 0 -> 1980 bytes assets/img/letters/script.sh | 6 + assets/img/letters/t.png | Bin 0 -> 606 bytes assets/img/letters/u.png | Bin 0 -> 1174 bytes assets/img/letters/v.png | Bin 0 -> 1801 bytes assets/img/letters/w.png | Bin 0 -> 2589 bytes assets/img/letters/x.png | Bin 0 -> 1878 bytes assets/img/letters/y.png | Bin 0 -> 1431 bytes assets/img/letters/z.png | Bin 0 -> 1230 bytes faq/index.php | 29 - includes/Parsedown.php | 1712 +++++++++++++++++++++++++++++ includes/fetcher/index.js | 132 ++- includes/fetcher/projects.json | 624 +++-------- includes/functions.php | 49 +- includes/header.php | 10 + includes/navigation.php | 3 - index.php | 8 +- projects/index.php | 20 +- services/index.php | 2 +- social/index.php | 2 +- 71 files changed, 2563 insertions(+), 572 deletions(-) create mode 100644 .idea/.name create mode 100644 .idea/icon.svg create mode 100644 assets/.DS_Store create mode 100755 assets/favicon/android-chrome-192x192.png create mode 100755 assets/favicon/android-chrome-512x512.png create mode 100755 assets/favicon/apple-touch-icon.png create mode 100755 assets/favicon/browserconfig.xml create mode 100755 assets/favicon/favicon-16x16.png create mode 100755 assets/favicon/favicon-32x32.png create mode 100644 assets/favicon/favicon-48x48.png create mode 100644 assets/favicon/favicon-64x64.png create mode 100755 assets/favicon/favicon.ico create mode 100755 assets/favicon/manifest.json create mode 100755 assets/favicon/mstile-150x150.png create mode 100644 assets/favicon/safari-pinned-tab.svg create mode 100644 assets/img/.DS_Store create mode 100644 assets/img/icon.png create mode 100644 assets/img/icon.svg create mode 100644 assets/img/letters/#.png create mode 100644 assets/img/letters/.DS_Store create mode 100644 assets/img/letters/0.png create mode 100644 assets/img/letters/1.png create mode 100644 assets/img/letters/2.png create mode 100644 assets/img/letters/3.png create mode 100644 assets/img/letters/4.png create mode 100644 assets/img/letters/5.png create mode 100644 assets/img/letters/6.png create mode 100644 assets/img/letters/7.png create mode 100644 assets/img/letters/8.png create mode 100644 assets/img/letters/9.png create mode 100644 assets/img/letters/a.png create mode 100644 assets/img/letters/b.png create mode 100644 assets/img/letters/c.png create mode 100644 assets/img/letters/d.png create mode 100644 assets/img/letters/e.png create mode 100644 assets/img/letters/f.png create mode 100644 assets/img/letters/g.png create mode 100644 assets/img/letters/h.png create mode 100644 assets/img/letters/i.png create mode 100644 assets/img/letters/j.png create mode 100644 assets/img/letters/k.png create mode 100644 assets/img/letters/l.png create mode 100644 assets/img/letters/m.png create mode 100644 assets/img/letters/n.png create mode 100644 assets/img/letters/o.png create mode 100644 assets/img/letters/p.png create mode 100644 assets/img/letters/q.png create mode 100644 assets/img/letters/r.png create mode 100644 assets/img/letters/s.png create mode 100755 assets/img/letters/script.sh create mode 100644 assets/img/letters/t.png create mode 100644 assets/img/letters/u.png create mode 100644 assets/img/letters/v.png create mode 100644 assets/img/letters/w.png create mode 100644 assets/img/letters/x.png create mode 100644 assets/img/letters/y.png create mode 100644 assets/img/letters/z.png delete mode 100644 faq/index.php create mode 100644 includes/Parsedown.php diff --git a/.DS_Store b/.DS_Store index 4902e9e..9460f41 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..fdb1220 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Ember - Website v10 \ No newline at end of file diff --git a/.idea/icon.svg b/.idea/icon.svg new file mode 100644 index 0000000..5c39c8a --- /dev/null +++ b/.idea/icon.svg @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/about/index.php b/about/index.php index ab47009..b491734 100644 --- a/about/index.php +++ b/about/index.php @@ -1,4 +1,4 @@ - +
diff --git a/assets/.DS_Store b/assets/.DS_Store new file mode 100644 index 0000000..cda87bd Binary files /dev/null and b/assets/.DS_Store differ diff --git a/assets/css/main.css b/assets/css/main.css index 2fb8f55..7658373 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -43,4 +43,28 @@ nav.navbar { .faq-separator { background-color: gray; margin: 1rem -20px; +} + +.stylized-card { + background: rgba(0, 0, 0, .5) !important; + text-align: center; +} + +.stylized-card-icon { + width: 64px; + height: 64px; + margin-bottom: 5px; + border-radius: 10px; + background: rgba(255, 255, 255, .1); +} + +.col-lg-4 { + padding-top: calc(var(--bs-gutter-x) * .5); + padding-bottom: calc(var(--bs-gutter-x) * .5); +} + +.memberview-icon { + width: 48px; + height: 48px; + vertical-align: middle; } \ No newline at end of file diff --git a/assets/favicon/android-chrome-192x192.png b/assets/favicon/android-chrome-192x192.png new file mode 100755 index 0000000..f5dbc6b Binary files /dev/null and b/assets/favicon/android-chrome-192x192.png differ diff --git a/assets/favicon/android-chrome-512x512.png b/assets/favicon/android-chrome-512x512.png new file mode 100755 index 0000000..a3bf4bd Binary files /dev/null and b/assets/favicon/android-chrome-512x512.png differ diff --git a/assets/favicon/apple-touch-icon.png b/assets/favicon/apple-touch-icon.png new file mode 100755 index 0000000..6342fda Binary files /dev/null and b/assets/favicon/apple-touch-icon.png differ diff --git a/assets/favicon/browserconfig.xml b/assets/favicon/browserconfig.xml new file mode 100755 index 0000000..021d23d --- /dev/null +++ b/assets/favicon/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #a56510 + + + diff --git a/assets/favicon/favicon-16x16.png b/assets/favicon/favicon-16x16.png new file mode 100755 index 0000000..aa0bb47 Binary files /dev/null and b/assets/favicon/favicon-16x16.png differ diff --git a/assets/favicon/favicon-32x32.png b/assets/favicon/favicon-32x32.png new file mode 100755 index 0000000..7d11a19 Binary files /dev/null and b/assets/favicon/favicon-32x32.png differ diff --git a/assets/favicon/favicon-48x48.png b/assets/favicon/favicon-48x48.png new file mode 100644 index 0000000..e97141b Binary files /dev/null and b/assets/favicon/favicon-48x48.png differ diff --git a/assets/favicon/favicon-64x64.png b/assets/favicon/favicon-64x64.png new file mode 100644 index 0000000..dc00769 Binary files /dev/null and b/assets/favicon/favicon-64x64.png differ diff --git a/assets/favicon/favicon.ico b/assets/favicon/favicon.ico new file mode 100755 index 0000000..f68855a Binary files /dev/null and b/assets/favicon/favicon.ico differ diff --git a/assets/favicon/manifest.json b/assets/favicon/manifest.json new file mode 100755 index 0000000..8e6ca9c --- /dev/null +++ b/assets/favicon/manifest.json @@ -0,0 +1,19 @@ +{ + "name": "Minteck", + "short_name": "Minteck", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#a56510", + "background_color": "#a56510", + "display": "standalone" +} diff --git a/assets/favicon/mstile-150x150.png b/assets/favicon/mstile-150x150.png new file mode 100755 index 0000000..6952d8e Binary files /dev/null and b/assets/favicon/mstile-150x150.png differ diff --git a/assets/favicon/safari-pinned-tab.svg b/assets/favicon/safari-pinned-tab.svg new file mode 100644 index 0000000..c8cc783 --- /dev/null +++ b/assets/favicon/safari-pinned-tab.svg @@ -0,0 +1,45 @@ + + + + + + + + + + diff --git a/assets/img/.DS_Store b/assets/img/.DS_Store new file mode 100644 index 0000000..f47b144 Binary files /dev/null and b/assets/img/.DS_Store differ diff --git a/assets/img/icon.png b/assets/img/icon.png new file mode 100644 index 0000000..1a915be Binary files /dev/null and b/assets/img/icon.png differ diff --git a/assets/img/icon.svg b/assets/img/icon.svg new file mode 100644 index 0000000..9dbfeaf --- /dev/null +++ b/assets/img/icon.svg @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/img/letters/#.png b/assets/img/letters/#.png new file mode 100644 index 0000000..27a3f52 Binary files /dev/null and b/assets/img/letters/#.png differ diff --git a/assets/img/letters/.DS_Store b/assets/img/letters/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/assets/img/letters/.DS_Store differ diff --git a/assets/img/letters/0.png b/assets/img/letters/0.png new file mode 100644 index 0000000..8bc761f Binary files /dev/null and b/assets/img/letters/0.png differ diff --git a/assets/img/letters/1.png b/assets/img/letters/1.png new file mode 100644 index 0000000..7135d14 Binary files /dev/null and b/assets/img/letters/1.png differ diff --git a/assets/img/letters/2.png b/assets/img/letters/2.png new file mode 100644 index 0000000..d236f23 Binary files /dev/null and b/assets/img/letters/2.png differ diff --git a/assets/img/letters/3.png b/assets/img/letters/3.png new file mode 100644 index 0000000..4c036fd Binary files /dev/null and b/assets/img/letters/3.png differ diff --git a/assets/img/letters/4.png b/assets/img/letters/4.png new file mode 100644 index 0000000..f37d034 Binary files /dev/null and b/assets/img/letters/4.png differ diff --git a/assets/img/letters/5.png b/assets/img/letters/5.png new file mode 100644 index 0000000..232bf7d Binary files /dev/null and b/assets/img/letters/5.png differ diff --git a/assets/img/letters/6.png b/assets/img/letters/6.png new file mode 100644 index 0000000..d5e4f5d Binary files /dev/null and b/assets/img/letters/6.png differ diff --git a/assets/img/letters/7.png b/assets/img/letters/7.png new file mode 100644 index 0000000..dcd1023 Binary files /dev/null and b/assets/img/letters/7.png differ diff --git a/assets/img/letters/8.png b/assets/img/letters/8.png new file mode 100644 index 0000000..1996089 Binary files /dev/null and b/assets/img/letters/8.png differ diff --git a/assets/img/letters/9.png b/assets/img/letters/9.png new file mode 100644 index 0000000..0237c92 Binary files /dev/null and b/assets/img/letters/9.png differ diff --git a/assets/img/letters/a.png b/assets/img/letters/a.png new file mode 100644 index 0000000..0f6794f Binary files /dev/null and b/assets/img/letters/a.png differ diff --git a/assets/img/letters/b.png b/assets/img/letters/b.png new file mode 100644 index 0000000..664dc9e Binary files /dev/null and b/assets/img/letters/b.png differ diff --git a/assets/img/letters/c.png b/assets/img/letters/c.png new file mode 100644 index 0000000..231f60f Binary files /dev/null and b/assets/img/letters/c.png differ diff --git a/assets/img/letters/d.png b/assets/img/letters/d.png new file mode 100644 index 0000000..5993268 Binary files /dev/null and b/assets/img/letters/d.png differ diff --git a/assets/img/letters/e.png b/assets/img/letters/e.png new file mode 100644 index 0000000..4c1d13b Binary files /dev/null and b/assets/img/letters/e.png differ diff --git a/assets/img/letters/f.png b/assets/img/letters/f.png new file mode 100644 index 0000000..825d5ef Binary files /dev/null and b/assets/img/letters/f.png differ diff --git a/assets/img/letters/g.png b/assets/img/letters/g.png new file mode 100644 index 0000000..8beaae1 Binary files /dev/null and b/assets/img/letters/g.png differ diff --git a/assets/img/letters/h.png b/assets/img/letters/h.png new file mode 100644 index 0000000..fd5c053 Binary files /dev/null and b/assets/img/letters/h.png differ diff --git a/assets/img/letters/i.png b/assets/img/letters/i.png new file mode 100644 index 0000000..fb10ab7 Binary files /dev/null and b/assets/img/letters/i.png differ diff --git a/assets/img/letters/j.png b/assets/img/letters/j.png new file mode 100644 index 0000000..29aaa12 Binary files /dev/null and b/assets/img/letters/j.png differ diff --git a/assets/img/letters/k.png b/assets/img/letters/k.png new file mode 100644 index 0000000..52d7dcb Binary files /dev/null and b/assets/img/letters/k.png differ diff --git a/assets/img/letters/l.png b/assets/img/letters/l.png new file mode 100644 index 0000000..80b63df Binary files /dev/null and b/assets/img/letters/l.png differ diff --git a/assets/img/letters/m.png b/assets/img/letters/m.png new file mode 100644 index 0000000..86f8404 Binary files /dev/null and b/assets/img/letters/m.png differ diff --git a/assets/img/letters/n.png b/assets/img/letters/n.png new file mode 100644 index 0000000..5913c20 Binary files /dev/null and b/assets/img/letters/n.png differ diff --git a/assets/img/letters/o.png b/assets/img/letters/o.png new file mode 100644 index 0000000..fb40d35 Binary files /dev/null and b/assets/img/letters/o.png differ diff --git a/assets/img/letters/p.png b/assets/img/letters/p.png new file mode 100644 index 0000000..d39850c Binary files /dev/null and b/assets/img/letters/p.png differ diff --git a/assets/img/letters/q.png b/assets/img/letters/q.png new file mode 100644 index 0000000..d39194e Binary files /dev/null and b/assets/img/letters/q.png differ diff --git a/assets/img/letters/r.png b/assets/img/letters/r.png new file mode 100644 index 0000000..88f1dda Binary files /dev/null and b/assets/img/letters/r.png differ diff --git a/assets/img/letters/s.png b/assets/img/letters/s.png new file mode 100644 index 0000000..9f258c3 Binary files /dev/null and b/assets/img/letters/s.png differ diff --git a/assets/img/letters/script.sh b/assets/img/letters/script.sh new file mode 100755 index 0000000..19e43e0 --- /dev/null +++ b/assets/img/letters/script.sh @@ -0,0 +1,6 @@ +letters=( a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9 0 \# ) +for i in "${letters[@]}" +do + l=$(echo $i | tr '[:lower:]' '[:upper:]') + convert -background transparent -fill white -font Roboto -size 150x150 -gravity center caption:$l $i.png +done diff --git a/assets/img/letters/t.png b/assets/img/letters/t.png new file mode 100644 index 0000000..2a9940f Binary files /dev/null and b/assets/img/letters/t.png differ diff --git a/assets/img/letters/u.png b/assets/img/letters/u.png new file mode 100644 index 0000000..9ac3206 Binary files /dev/null and b/assets/img/letters/u.png differ diff --git a/assets/img/letters/v.png b/assets/img/letters/v.png new file mode 100644 index 0000000..3f47765 Binary files /dev/null and b/assets/img/letters/v.png differ diff --git a/assets/img/letters/w.png b/assets/img/letters/w.png new file mode 100644 index 0000000..166303a Binary files /dev/null and b/assets/img/letters/w.png differ diff --git a/assets/img/letters/x.png b/assets/img/letters/x.png new file mode 100644 index 0000000..977e2c9 Binary files /dev/null and b/assets/img/letters/x.png differ diff --git a/assets/img/letters/y.png b/assets/img/letters/y.png new file mode 100644 index 0000000..f3c5f84 Binary files /dev/null and b/assets/img/letters/y.png differ diff --git a/assets/img/letters/z.png b/assets/img/letters/z.png new file mode 100644 index 0000000..d5dd9be Binary files /dev/null and b/assets/img/letters/z.png differ diff --git a/faq/index.php b/faq/index.php deleted file mode 100644 index c1338e7..0000000 --- a/faq/index.php +++ /dev/null @@ -1,29 +0,0 @@ - - - -
-
-

Frequently Asked Questions

-
-
-
- Do you provide free hosting? -
-

- Yes. When I create a website for you, free hosting and maintenance is included for as long as your website is being developed and as long as possible. However, if your website receives a lot of traffic, it is recommended that you move to proper hosting. -

-
-
-
-
- Can you create for someone else? -
-

- Yes, although this only applies to people I know and trust; and may be limited depending on my motivation and free time. If we are friends, feel free to ask if you want a website. -

-
-
-
-
- - \ No newline at end of file diff --git a/includes/Parsedown.php b/includes/Parsedown.php new file mode 100644 index 0000000..1d80e42 --- /dev/null +++ b/includes/Parsedown.php @@ -0,0 +1,1712 @@ +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 + $markup = $this->lines($lines); + + # trim line breaks + $markup = trim($markup, "\n"); + + return $markup; + } + + # + # 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; + + protected $safeLinksWhitelist = array( + 'http://', + 'https://', + 'ftp://', + 'ftps://', + 'mailto:', + '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) + { + $CurrentBlock = null; + + foreach ($lines as $line) + { + if (chop($line) === '') + { + if (isset($CurrentBlock)) + { + $CurrentBlock['interrupted'] = true; + } + + continue; + } + + if (strpos($line, "\t") !== false) + { + $parts = explode("\t", $line); + + $line = $parts[0]; + + unset($parts[0]); + + foreach ($parts as $part) + { + $shortage = 4 - mb_strlen($line, 'utf-8') % 4; + + $line .= str_repeat(' ', $shortage); + $line .= $part; + } + } + + $indent = 0; + + while (isset($line[$indent]) and $line[$indent] === ' ') + { + $indent ++; + } + + $text = $indent > 0 ? substr($line, $indent) : $line; + + # ~ + + $Line = array('body' => $line, 'indent' => $indent, 'text' => $text); + + # ~ + + if (isset($CurrentBlock['continuable'])) + { + $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); + + if (isset($Block)) + { + $CurrentBlock = $Block; + + continue; + } + else + { + if ($this->isBlockCompletable($CurrentBlock['type'])) + { + $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($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'])) + { + $Blocks []= $CurrentBlock; + + $Block['identified'] = true; + } + + if ($this->isBlockContinuable($blockType)) + { + $Block['continuable'] = true; + } + + $CurrentBlock = $Block; + + continue 2; + } + } + + # ~ + + if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted'])) + { + $CurrentBlock['element']['text'] .= "\n".$text; + } + else + { + $Blocks []= $CurrentBlock; + + $CurrentBlock = $this->paragraph($Line); + + $CurrentBlock['identified'] = true; + } + } + + # ~ + + if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) + { + $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); + } + + # ~ + + $Blocks []= $CurrentBlock; + + unset($Blocks[0]); + + # ~ + + $markup = ''; + + foreach ($Blocks as $Block) + { + if (isset($Block['hidden'])) + { + continue; + } + + $markup .= "\n"; + $markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']); + } + + $markup .= "\n"; + + # ~ + + return $markup; + } + + 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 ! isset($Block['type']) and ! isset($Block['interrupted'])) + { + return void; + } + + if ($Line['indent'] >= 4) + { + $text = substr($Line['body'], 4); + + $Block = array( + 'element' => array( + 'name' => 'pre', + 'handler' => 'element', + 'text' => array( + 'name' => 'code', + 'text' => $text, + ), + ), + ); + + return $Block; + } + } + + protected function blockCodeContinue($Line, $Block) + { + if ($Line['indent'] >= 4) + { + if (isset($Block['interrupted'])) + { + $Block['element']['text']['text'] .= "\n"; + + unset($Block['interrupted']); + } + + $Block['element']['text']['text'] .= "\n"; + + $text = substr($Line['body'], 4); + + $Block['element']['text']['text'] .= $text; + + return $Block; + } + } + + protected function blockCodeComplete($Block) + { + $text = $Block['element']['text']['text']; + + $Block['element']['text']['text'] = $text; + + return $Block; + } + + # + # Comment + + protected function blockComment($Line) + { + if ($this->markupEscaped or $this->safeMode) + { + return; + } + + if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!') + { + $Block = array( + 'markup' => $Line['body'], + ); + + if (preg_match('/-->$/', $Line['text'])) + { + $Block['closed'] = true; + } + + return $Block; + } + } + + protected function blockCommentContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + $Block['markup'] .= "\n" . $Line['body']; + + if (preg_match('/-->$/', $Line['text'])) + { + $Block['closed'] = true; + } + + return $Block; + } + + # + # Fenced Code + + protected function blockFencedCode($Line) + { + if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([^`]+)?[ ]*$/', $Line['text'], $matches)) + { + $Element = array( + 'name' => 'code', + 'text' => '', + ); + + if (isset($matches[1])) + { + /** + * 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($matches[1], 0, strcspn($matches[1], " \t\n\f\r")); + + $class = 'language-'.$language; + + $Element['attributes'] = array( + 'class' => $class, + ); + } + + $Block = array( + 'char' => $Line['text'][0], + 'element' => array( + 'name' => 'pre', + 'handler' => 'element', + 'text' => $Element, + ), + ); + + return $Block; + } + } + + protected function blockFencedCodeContinue($Line, $Block) + { + if (isset($Block['complete'])) + { + return; + } + + if (isset($Block['interrupted'])) + { + $Block['element']['text']['text'] .= "\n"; + + unset($Block['interrupted']); + } + + if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text'])) + { + $Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1); + + $Block['complete'] = true; + + return $Block; + } + + $Block['element']['text']['text'] .= "\n".$Line['body']; + + return $Block; + } + + protected function blockFencedCodeComplete($Block) + { + $text = $Block['element']['text']['text']; + + $Block['element']['text']['text'] = $text; + + return $Block; + } + + # + # Header + + protected function blockHeader($Line) + { + if (isset($Line['text'][1])) + { + $level = 1; + + while (isset($Line['text'][$level]) and $Line['text'][$level] === '#') + { + $level ++; + } + + if ($level > 6) + { + return; + } + + $text = trim($Line['text'], '# '); + + $Block = array( + 'element' => array( + 'name' => 'h' . min(6, $level), + 'text' => $text, + 'handler' => 'line', + ), + ); + + return $Block; + } + } + + # + # List + + protected function blockList($Line) + { + list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]'); + + if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches)) + { + $Block = array( + 'indent' => $Line['indent'], + 'pattern' => $pattern, + 'element' => array( + 'name' => $name, + 'handler' => 'elements', + ), + ); + + if($name === 'ol') + { + $listStart = stristr($matches[0], '.', true); + + if($listStart !== '1') + { + $Block['element']['attributes'] = array('start' => $listStart); + } + } + + $Block['li'] = array( + 'name' => 'li', + 'handler' => 'li', + 'text' => array( + $matches[2], + ), + ); + + $Block['element']['text'] []= & $Block['li']; + + return $Block; + } + } + + protected function blockListContinue($Line, array $Block) + { + if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches)) + { + if (isset($Block['interrupted'])) + { + $Block['li']['text'] []= ''; + + $Block['loose'] = true; + + unset($Block['interrupted']); + } + + unset($Block['li']); + + $text = isset($matches[1]) ? $matches[1] : ''; + + $Block['li'] = array( + 'name' => 'li', + 'handler' => 'li', + 'text' => array( + $text, + ), + ); + + $Block['element']['text'] []= & $Block['li']; + + return $Block; + } + + if ($Line['text'][0] === '[' and $this->blockReference($Line)) + { + return $Block; + } + + if ( ! isset($Block['interrupted'])) + { + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + $Block['li']['text'] []= $text; + + return $Block; + } + + if ($Line['indent'] > 0) + { + $Block['li']['text'] []= ''; + + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + $Block['li']['text'] []= $text; + + unset($Block['interrupted']); + + return $Block; + } + } + + protected function blockListComplete(array $Block) + { + if (isset($Block['loose'])) + { + foreach ($Block['element']['text'] as &$li) + { + if (end($li['text']) !== '') + { + $li['text'] []= ''; + } + } + } + + return $Block; + } + + # + # Quote + + protected function blockQuote($Line) + { + if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) + { + $Block = array( + 'element' => array( + 'name' => 'blockquote', + 'handler' => 'lines', + 'text' => (array) $matches[1], + ), + ); + + return $Block; + } + } + + protected function blockQuoteContinue($Line, array $Block) + { + if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) + { + if (isset($Block['interrupted'])) + { + $Block['element']['text'] []= ''; + + unset($Block['interrupted']); + } + + $Block['element']['text'] []= $matches[1]; + + return $Block; + } + + if ( ! isset($Block['interrupted'])) + { + $Block['element']['text'] []= $Line['text']; + + return $Block; + } + } + + # + # Rule + + protected function blockRule($Line) + { + if (preg_match('/^(['.$Line['text'][0].'])([ ]*\1){2,}[ ]*$/', $Line['text'])) + { + $Block = array( + 'element' => array( + 'name' => 'hr' + ), + ); + + return $Block; + } + } + + # + # Setext + + protected function blockSetextHeader($Line, array $Block = null) + { + if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) + { + return; + } + + if (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[\w-]*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches)) + { + $element = strtolower($matches[1]); + + if (in_array($element, $this->textLevelElements)) + { + return; + } + + $Block = array( + 'name' => $matches[1], + 'depth' => 0, + 'markup' => $Line['text'], + ); + + $length = strlen($matches[0]); + + $remainder = substr($Line['text'], $length); + + if (trim($remainder) === '') + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + $Block['closed'] = true; + + $Block['void'] = true; + } + } + else + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + return; + } + + if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder)) + { + $Block['closed'] = true; + } + } + + return $Block; + } + } + + protected function blockMarkupContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open + { + $Block['depth'] ++; + } + + if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'])) # close + { + if ($Block['depth'] > 0) + { + $Block['depth'] --; + } + else + { + $Block['closed'] = true; + } + } + + if (isset($Block['interrupted'])) + { + $Block['markup'] .= "\n"; + + unset($Block['interrupted']); + } + + $Block['markup'] .= "\n".$Line['body']; + + return $Block; + } + + # + # Reference + + protected function blockReference($Line) + { + if (preg_match('/^\[(.+?)]:[ ]*?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches)) + { + $id = strtolower($matches[1]); + + $Data = array( + 'url' => $matches[2], + 'title' => null, + ); + + if (isset($matches[3])) + { + $Data['title'] = $matches[3]; + } + + $this->DefinitionData['Reference'][$id] = $Data; + + $Block = array( + 'hidden' => true, + ); + + return $Block; + } + } + + # + # Table + + protected function blockTable($Line, array $Block = null) + { + if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) + { + return; + } + + if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '') + { + $alignments = array(); + + $divider = $Line['text']; + + $divider = trim($divider); + $divider = trim($divider, '|'); + + $dividerCells = explode('|', $divider); + + foreach ($dividerCells as $dividerCell) + { + $dividerCell = trim($dividerCell); + + if ($dividerCell === '') + { + continue; + } + + $alignment = null; + + if ($dividerCell[0] === ':') + { + $alignment = 'left'; + } + + if (substr($dividerCell, - 1) === ':') + { + $alignment = $alignment === 'left' ? 'center' : 'right'; + } + + $alignments []= $alignment; + } + + # ~ + + $HeaderElements = array(); + + $header = $Block['element']['text']; + + $header = trim($header); + $header = trim($header, '|'); + + $headerCells = explode('|', $header); + + foreach ($headerCells as $index => $headerCell) + { + $headerCell = trim($headerCell); + + $HeaderElement = array( + 'name' => 'th', + 'text' => $headerCell, + 'handler' => 'line', + ); + + 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', + 'handler' => 'elements', + ), + ); + + $Block['element']['text'] []= array( + 'name' => 'thead', + 'handler' => 'elements', + ); + + $Block['element']['text'] []= array( + 'name' => 'tbody', + 'handler' => 'elements', + 'text' => array(), + ); + + $Block['element']['text'][0]['text'] []= array( + 'name' => 'tr', + 'handler' => 'elements', + 'text' => $HeaderElements, + ); + + return $Block; + } + } + + protected function blockTableContinue($Line, array $Block) + { + if (isset($Block['interrupted'])) + { + return; + } + + if ($Line['text'][0] === '|' or strpos($Line['text'], '|')) + { + $Elements = array(); + + $row = $Line['text']; + + $row = trim($row); + $row = trim($row, '|'); + + preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches); + + foreach ($matches[0] as $index => $cell) + { + $cell = trim($cell); + + $Element = array( + 'name' => 'td', + 'handler' => 'line', + 'text' => $cell, + ); + + if (isset($Block['alignments'][$index])) + { + $Element['attributes'] = array( + 'style' => 'text-align: '.$Block['alignments'][$index].';', + ); + } + + $Elements []= $Element; + } + + $Element = array( + 'name' => 'tr', + 'handler' => 'elements', + 'text' => $Elements, + ); + + $Block['element']['text'][1]['text'] []= $Element; + + return $Block; + } + } + + # + # ~ + # + + protected function paragraph($Line) + { + $Block = array( + 'element' => array( + 'name' => 'p', + 'text' => $Line['text'], + 'handler' => 'line', + ), + ); + + return $Block; + } + + # + # Inline Elements + # + + protected $InlineTypes = array( + '"' => array('SpecialCharacter'), + '!' => array('Image'), + '&' => array('SpecialCharacter'), + '*' => array('Emphasis'), + ':' => array('Url'), + '<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'), + '>' => array('SpecialCharacter'), + '[' => array('Link'), + '_' => array('Emphasis'), + '`' => array('Code'), + '~' => array('Strikethrough'), + '\\' => array('EscapeSequence'), + ); + + # ~ + + protected $inlineMarkerList = '!"*_&[:<>`~\\'; + + # + # ~ + # + + public function line($text, $nonNestables=array()) + { + $markup = ''; + + # $excerpt is based on the first occurrence of a marker + + while ($excerpt = strpbrk($text, $this->inlineMarkerList)) + { + $marker = $excerpt[0]; + + $markerPosition = strpos($text, $marker); + + $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 ( ! empty($nonNestables) and in_array($inlineType, $nonNestables)) + { + 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 + + foreach ($nonNestables as $non_nestable) + { + $Inline['element']['nonNestables'][] = $non_nestable; + } + + # the text that comes before the inline + $unmarkedText = substr($text, 0, $Inline['position']); + + # compile the unmarked text + $markup .= $this->unmarkedText($unmarkedText); + + # compile the inline + $markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']); + + # 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); + + $markup .= $this->unmarkedText($unmarkedText); + + $text = substr($text, $markerPosition + 1); + } + + $markup .= $this->unmarkedText($text); + + return $markup; + } + + # + # ~ + # + + protected function inlineCode($Excerpt) + { + $marker = $Excerpt['text'][0]; + + if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(? strlen($matches[0]), + 'element' => array( + 'name' => 'code', + 'text' => $text, + ), + ); + } + } + + protected function inlineEmailTag($Excerpt) + { + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/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' => 'line', + 'text' => $matches[1], + ), + ); + } + + protected function inlineEscapeSequence($Excerpt) + { + if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) + { + return array( + 'markup' => $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']['text'], + ), + ), + ); + + $Inline['element']['attributes'] += $Link['element']['attributes']; + + unset($Inline['element']['attributes']['href']); + + return $Inline; + } + + protected function inlineLink($Excerpt) + { + $Element = array( + 'name' => 'a', + 'handler' => 'line', + 'nonNestables' => array('Url', 'Link'), + 'text' => null, + 'attributes' => array( + 'href' => null, + 'title' => null, + ), + ); + + $extent = 0; + + $remainder = $Excerpt['text']; + + if (preg_match('/\[((?:[^][]++|(?R))*+)]/', $remainder, $matches)) + { + $Element['text'] = $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['text']; + $definition = strtolower($definition); + + $extent += strlen($matches[0]); + } + else + { + $definition = strtolower($Element['text']); + } + + 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( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + } + + protected function inlineSpecialCharacter($Excerpt) + { + if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text'])) + { + return array( + 'markup' => '&', + 'extent' => 1, + ); + } + + $SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot'); + + if (isset($SpecialCharacter[$Excerpt['text'][0]])) + { + return array( + 'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';', + 'extent' => 1, + ); + } + } + + 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', + 'text' => $matches[1], + 'handler' => 'line', + ), + ); + } + } + + protected function inlineUrl($Excerpt) + { + if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') + { + return; + } + + if (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) + { + if ($this->breaksEnabled) + { + $text = preg_replace('/[ ]*\n/', "
\n", $text); + } + else + { + $text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/', "
\n", $text); + $text = str_replace(" \n", "\n", $text); + } + + return $text; + } + + # + # Handlers + # + + protected function element(array $Element) + { + if ($this->safeMode) + { + $Element = $this->sanitiseElement($Element); + } + + $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; + } + + if (isset($text)) + { + $markup .= '>'; + + if (!isset($Element['nonNestables'])) + { + $Element['nonNestables'] = array(); + } + + if (isset($Element['handler'])) + { + $markup .= $this->{$Element['handler']}($text, $Element['nonNestables']); + } + elseif (!$permitRawHtml) + { + $markup .= self::escape($text, true); + } + else + { + $markup .= $text; + } + + $markup .= ''; + } + else + { + $markup .= ' />'; + } + + return $markup; + } + + protected function elements(array $Elements) + { + $markup = ''; + + foreach ($Elements as $Element) + { + $markup .= "\n" . $this->element($Element); + } + + $markup .= "\n"; + + return $markup; + } + + # ~ + + protected function li($lines) + { + $markup = $this->lines($lines); + + $trimmedMarkup = trim($markup); + + if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '

') + { + $markup = $trimmedMarkup; + $markup = substr($markup, 3); + + $position = strpos($markup, "

"); + + $markup = substr_replace($markup, '', $position, 4); + } + + return $markup; + } + + # + # 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($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 string $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?'; + + protected array $voidElements = array( + 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', + ); + + protected array $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/includes/fetcher/index.js b/includes/fetcher/index.js index 0f3dcac..0b36111 100644 --- a/includes/fetcher/index.js +++ b/includes/fetcher/index.js @@ -12,9 +12,9 @@ let gitlabProjectsRaw; if (smallestId > 0) { - gitlabProjectsRaw = (await axios.get(`https://gitlab.minteck.org/api/v4/projects?order_by=id&archived=false&simple=true&id_before=${smallestId}`)).data; + gitlabProjectsRaw = (await axios.get(`https://gitlab.minteck.org/api/v4/users/minteck/projects?order_by=id&archived=false&simple=true&id_before=${smallestId}`)).data; } else { - gitlabProjectsRaw = (await axios.get(`https://gitlab.minteck.org/api/v4/projects?order_by=id&archived=false&simple=true`)).data; + gitlabProjectsRaw = (await axios.get(`https://gitlab.minteck.org/api/v4/users/minteck/projects?order_by=id&archived=false&simple=true`)).data; } for (let project of gitlabProjectsRaw) { gitlabProjects.push({ @@ -25,7 +25,9 @@ issues: null, vcs: project.http_url_to_repo, web: project.web_url, - showcase: project.topics.includes("Showcase") + icon: project.avatar_url, + showcase: project.topics.includes("Showcase"), + date: project.last_activity_at }) smallestId = project.id; } @@ -35,37 +37,84 @@ } console.log("Fetching projects... YouTrack"); - const youtrackProjectsRaw = (await axios.get(`https://youtrack.minteck.org/api/admin/projects?fields=id,name,shortName,description`)).data; let youtrackProjects = []; - - for (let project of youtrackProjectsRaw) { - youtrackProjects.push({ - gitlab_id: null, - youtrack_id: project.id, - name: project.name, - description: project.description, - issues: project.shortName, - vcs: null, - web: null, - showcase: false - }) - } - - console.log("Merging data...") + let unusedBase = []; + let unusedYoutrackProjects = []; let projects = {}; let projectsPlusYoutrack = {}; - for (let project of youtrackProjects) { - nameCompareYoutrack = project.name.toLowerCase().replace(/[^a-z]+/gm, ""); - descCompareYoutrack = project.description.toLowerCase().replace(/[^a-z]+/gm, ""); - for (let gprj of gitlabProjects) { - nameCompareGitlab = gprj.name.toLowerCase().replace(/[^a-z]+/gm, ""); - descCompareGitlab = gprj.description.toLowerCase().replace(/[^a-z]+/gm, ""); + try { + const youtrackProjectsRaw = (await axios.get(`https://youtrack.minteck.org/api/admin/projects?fields=id,name,shortName,description`)).data; + for (let project of youtrackProjectsRaw) { + youtrackProjects.push({ + gitlab_id: null, + youtrack_id: project.id, + name: project.name, + description: project.description, + issues: project.shortName, + vcs: null, + web: null, + icon: null, + showcase: false, + date: null + }) + } + + console.log("Merging data...") + for (let project of youtrackProjects) { + nameCompareYoutrack = project.name.toLowerCase().replace(/[^a-z]+/gm, ""); + descCompareYoutrack = project.description.toLowerCase().replace(/[^a-z]+/gm, ""); + + for (let gprj of gitlabProjects) { + nameCompareGitlab = gprj.name.toLowerCase().replace(/[^a-z]+/gm, ""); + descCompareGitlab = gprj.description.toLowerCase().replace(/[^a-z]+/gm, ""); - if (nameCompareGitlab === nameCompareYoutrack || descCompareGitlab === descCompareYoutrack) { - gprj.youtrack_id = project.youtrack_id; + if (nameCompareGitlab === nameCompareYoutrack || descCompareGitlab === descCompareYoutrack) { + gprj.youtrack_id = project.youtrack_id; + gprj.issues = "https://youtrack.minteck.org/issues/" + project.youtrack_id; + } + + if (gprj.youtrack_id === null) { + id = crypto.createHash('sha1').update(gprj.gitlab_id.toString() + "null").digest('hex'); + } else { + id = crypto.createHash('sha1').update(gprj.gitlab_id.toString() + gprj.youtrack_id.toString()).digest('hex'); + projectsPlusYoutrack[id] = gprj; + } + projects[id] = gprj; } + } + const knownYoutrackIds = Object.keys(projectsPlusYoutrack).map((i) => { return projectsPlusYoutrack[i].youtrack_id; }); + for (let project of youtrackProjectsRaw) { + if (!knownYoutrackIds.includes(project.id)) { + project.name_compare = project.name.toLowerCase().replace(/[^a-z]+/gm, ""); + project.description_compare = project.description.toLowerCase().replace(/[^a-z]+/gm, ""); + unusedYoutrackProjects.push(project); + } + } + + for (let project of gitlabProjects) { + project.name_compare = project.name.toLowerCase().replace(/[^a-z]+/gm, ""); + project.description_compare = project.description.toLowerCase().replace(/[^a-z]+/gm, ""); + unusedBase.push(project); + } + + projects = Object.keys(projects).map((i) => { + return { + id: i, + ...projects[i] + } + }) + projects.sort((a, b) => (new Date(b.date) - new Date(a.date))); + + fs.writeFileSync("projects.json", JSON.stringify(projects, null, 4)); + fs.writeFileSync("unused-live.json", JSON.stringify(unusedYoutrackProjects, null, 4)); + fs.writeFileSync("unused-base.json", JSON.stringify(unusedBase, null, 4)); + console.log("Done merging, found " + Object.keys(projects).length + " projects (" + Object.keys(projectsPlusYoutrack).length + " on YouTrack, " + unusedYoutrackProjects.length + " unused)"); + } catch (e) { + console.log("Failed to fetch YouTrack projects (" + e.message + ")"); + + for (let gprj of gitlabProjects) { if (gprj.youtrack_id === null) { id = crypto.createHash('sha1').update(gprj.gitlab_id.toString() + "null").digest('hex'); } else { @@ -74,27 +123,16 @@ } projects[id] = gprj; } - } - const knownYoutrackIds = Object.keys(projectsPlusYoutrack).map((i) => { return projectsPlusYoutrack[i].youtrack_id; }); - let unusedYoutrackProjects = []; - for (let project of youtrackProjectsRaw) { - if (!knownYoutrackIds.includes(project.id)) { - project.name_compare = project.name.toLowerCase().replace(/[^a-z]+/gm, ""); - project.description_compare = project.description.toLowerCase().replace(/[^a-z]+/gm, ""); - unusedYoutrackProjects.push(project); - } - } + projects = Object.keys(projects).map((i) => { + return { + id: i, + ...projects[i] + } + }) + projects.sort((a, b) => (new Date(b.date) - new Date(a.date))); - let unusedBase = []; - for (let project of gitlabProjects) { - project.name_compare = project.name.toLowerCase().replace(/[^a-z]+/gm, ""); - project.description_compare = project.description.toLowerCase().replace(/[^a-z]+/gm, ""); - unusedBase.push(project); + fs.writeFileSync("projects.json", JSON.stringify(projects, null, 4)); + console.log("Done fetching, found " + Object.keys(projects).length + " projects"); } - - fs.writeFileSync("projects.json", JSON.stringify(projects, false, 4)); - fs.writeFileSync("unused-live.json", JSON.stringify(unusedYoutrackProjects, false, 4)); - fs.writeFileSync("unused-base.json", JSON.stringify(unusedBase, false, 4)); - console.log("Done merging, found " + Object.keys(projects).length + " projects (" + Object.keys(projectsPlusYoutrack).length + " on YouTrack, " + unusedYoutrackProjects.length + " unused)"); })() \ No newline at end of file diff --git a/includes/fetcher/projects.json b/includes/fetcher/projects.json index 081b099..373200a 100644 --- a/includes/fetcher/projects.json +++ b/includes/fetcher/projects.json @@ -1,209 +1,19 @@ -{ - "980aaf996775f99f3ccac3c010eeb9982470ce53": { - "gitlab_id": 73, - "youtrack_id": "0-52", - "name": "WebX - Website v10", - "description": "Yet another modern website for me", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/webx.git", - "web": "http://gitlab.minteck.org/minteck/webx", - "showcase": false, - "name_compare": "webxwebsitev", - "description_compare": "yetanothermodernwebsiteforme" - }, - "1b10549feef5a95c59f9a09f11eff72f380c9049": { - "gitlab_id": 72, - "youtrack_id": "0-51", - "name": "AutoDocs", - "description": "Publishing documentation for your projects is sometimes hard, AutoDocs got you covered!", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/autodocs.git", - "web": "http://gitlab.minteck.org/minteck/autodocs", - "showcase": false, - "name_compare": "autodocs", - "description_compare": "publishingdocumentationforyourprojectsissometimeshardautodocsgotyoucovered" - }, - "a2702e2f2bcf561027ccf0eb85708f0460db3ebc": { - "gitlab_id": 71, - "youtrack_id": null, - "name": "Familine Planning", - "description": "Plan, manage and sort events", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/familine-planning.git", - "web": "http://gitlab.minteck.org/minteck/familine-planning", - "showcase": false, - "name_compare": "familineplanning", - "description_compare": "planmanageandsortevents" - }, - "179b3939dcdf48591a9faae3ff7e5aece2bb0034": { - "gitlab_id": 70, - "youtrack_id": null, - "name": "Familine Session Manager", - "description": "Authentication session management system for Familine", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/familine-session.git", - "web": "http://gitlab.minteck.org/minteck/familine-session", - "showcase": false, - "name_compare": "familinesessionmanager", - "description_compare": "authenticationsessionmanagementsystemforfamiline" - }, - "b8380a76e7f90112398d58d72fe88184696982c4": { - "gitlab_id": 69, - "youtrack_id": null, - "name": "Familine Media", - "description": "Family media center", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/familine-media.git", - "web": "http://gitlab.minteck.org/minteck/familine-media", - "showcase": false, - "name_compare": "familinemedia", - "description_compare": "familymediacenter" - }, - "6039ddda5676adfcc1ea25ba5fc8438f37904151": { - "gitlab_id": 68, - "youtrack_id": null, - "name": "Familine Public Introduction", - "description": "Publicly accessible homepage for Familine", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/familine-intro.git", - "web": "http://gitlab.minteck.org/minteck/familine-intro", - "showcase": false, - "name_compare": "familinepublicintroduction", - "description_compare": "publiclyaccessiblehomepageforfamiline" - }, - "30c6eeba4139ca4d5330f6a54d535111443d2a84": { - "gitlab_id": 67, +[ + { + "id": "e8ed872c86e59f4bf70fb023695a714a6973d11d", + "gitlab_id": 25, "youtrack_id": null, - "name": "Familine CDN", - "description": "Content delivery network and static assets for Familine", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/familine-cdn.git", - "web": "http://gitlab.minteck.org/minteck/familine-cdn", - "showcase": false, - "name_compare": "familinecdn", - "description_compare": "contentdeliverynetworkandstaticassetsforfamiline" - }, - "fa344572018fda9017ac256070f4ad6610cad084": { - "gitlab_id": 66, - "youtrack_id": "0-11", - "name": "Snowjail", - "description": "Sandboxing technology for Twilight Package Manager packages", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/snowjail.git", - "web": "http://gitlab.minteck.org/minteck/snowjail", - "showcase": false, - "name_compare": "snowjail", - "description_compare": "sandboxingtechnologyfortwilightpackagemanagerpackages" - }, - "b33700d38f096fc476edcfbb84b0d475639a9adf": { - "gitlab_id": 65, - "youtrack_id": "0-12", - "name": "Voicer", - "description": "An open-source offline-first voice assistant", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/voicer.git", - "web": "http://gitlab.minteck.org/minteck/voicer", - "showcase": false, - "name_compare": "voicer", - "description_compare": "anopensourceofflinefirstvoiceassistant" - }, - "63c80d908c7b3d056d5ebf9b83034381eef5ddd4": { - "gitlab_id": 62, - "youtrack_id": "0-13", - "name": "Website for the Cloudburst System", - "description": "A website made in collaboration and for [Cloudburst](https://github.com/CloudburstSys). https://cloudburst-system.test.minteck.net.eu.org/ Future readers: this is not a commission, please don't ask me to create a website for you", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/cloudsdale.git", - "web": "http://gitlab.minteck.org/minteck/cloudsdale", - "showcase": false, - "name_compare": "websiteforthecloudburstsystem", - "description_compare": "awebsitemadeincollaborationandforcloudbursthttpsgithubcomcloudburstsyshttpscloudburstsystemtestminteckneteuorgfuturereadersthisisnotacommissionpleasedontaskmetocreateawebsiteforyou" - }, - "a8169ad64935e63ee65c1b38d4b625a315f7a0be": { - "gitlab_id": 61, - "youtrack_id": "0-10", - "name": "r-Place archive", - "description": "An archive viewer for r/place (Reddit's April Fools 2022)", + "name": "Neutron", + "description": "A simple, lightweight and easy PHP content management system", "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/placearchive.git", - "web": "http://gitlab.minteck.org/minteck/placearchive", + "vcs": "http://gitlab.minteck.org/minteck/neutron.git", + "web": "http://gitlab.minteck.org/minteck/neutron", + "icon": "http://gitlab.minteck.org/uploads/-/system/project/avatar/25/5-6b0fab376f30ad8eea6bc3e8fa15de6f.png", "showcase": true, - "name_compare": "rplacearchive", - "description_compare": "anarchiveviewerforrplaceredditsaprilfools" - }, - "7adce3f27d6625c6867fcb46756dc520a58a2e70": { - "gitlab_id": 60, - "youtrack_id": "0-3", - "name": "Argon", - "description": "Frontend and Web client for the Argon Music Platform", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/argon.git", - "web": "http://gitlab.minteck.org/minteck/argon", - "showcase": false, - "name_compare": "argon", - "description_compare": "frontendandwebclientfortheargonmusicplatform" - }, - "1cf12f94d06a8807a63151ae38ed6b76820a4f72": { - "gitlab_id": 59, - "youtrack_id": "0-4", - "name": "Argon 3pAD", - "description": "3rd-party analytics data federation daemon for the Argon Music Platform", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/argon-3pad.git", - "web": "http://gitlab.minteck.org/minteck/argon-3pad", - "showcase": false, - "name_compare": "argonpad", - "description_compare": "rdpartyanalyticsdatafederationdaemonfortheargonmusicplatform" - }, - "54d9cb53bb467dfe3b0552c5e72cfb638f29299b": { - "gitlab_id": 58, - "youtrack_id": "0-2", - "name": "Alicorn Operating System", - "description": "The next-generation operating system using Web technologies", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/alicorn.git", - "web": "http://gitlab.minteck.org/minteck/alicorn", - "showcase": false, - "name_compare": "alicornoperatingsystem", - "description_compare": "thenextgenerationoperatingsystemusingwebtechnologies" + "date": "2022-04-20T14:48:41.736Z" }, - "bf78ae1ff90298f79d212242dd33183cb770fadf": { - "gitlab_id": 57, - "youtrack_id": "0-15", - "name": "Argon Transcoding Engine", - "description": "An automated transcoding engine for the Argon Music Platform, using ffmpeg as a backend", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/argon-transcode.git", - "web": "http://gitlab.minteck.org/minteck/argon-transcode", - "showcase": false, - "name_compare": "argontranscodingengine", - "description_compare": "anautomatedtranscodingenginefortheargonmusicplatformusingffmpegasabackend" - }, - "6471f1f106be87f080990c7eea042c81ac78dee8": { - "gitlab_id": 55, - "youtrack_id": null, - "name": "twilight-setup", - "description": "", - "issues": null, - "vcs": "http://gitlab.minteck.org/twipkg-bin/twilight-setup.git", - "web": "http://gitlab.minteck.org/twipkg-bin/twilight-setup", - "showcase": false, - "name_compare": "twilightsetup", - "description_compare": "" - }, - "aabeadbcd02bcf622394c945562d4d4537e61c10": { - "gitlab_id": 54, - "youtrack_id": "0-44", - "name": "Twilight Setup Utility", - "description": "A self-extracting online installer/repairer/uninstaller for the [Twilight Package Manager](/minteck/twilight)", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/twilight-setup.git", - "web": "http://gitlab.minteck.org/minteck/twilight-setup", - "showcase": false, - "name_compare": "twilightsetuputility", - "description_compare": "aselfextractingonlineinstallerrepaireruninstallerforthetwilightpackagemanagermintecktwilight" - }, - "52c292243fe696711ae37e155b011733eb2e6d0a": { + { + "id": "52c292243fe696711ae37e155b011733eb2e6d0a", "gitlab_id": 50, "youtrack_id": null, "name": "Twilight", @@ -211,107 +21,51 @@ "issues": null, "vcs": "http://gitlab.minteck.org/minteck/twilight.git", "web": "http://gitlab.minteck.org/minteck/twilight", + "icon": null, "showcase": false, - "name_compare": "twilight", - "description_compare": "agitbasedpackagemanagermadeformintecksinfrastructurenotforproductionseereadmemintecktwilightblobtrunkreadmemdfordetails" + "date": "2022-04-17T15:37:40.719Z" }, - "3345c862bdf8957517e4ce4fc72ba6587d34bc64": { - "gitlab_id": 46, - "youtrack_id": "0-19", - "name": "Cobalt", - "description": "A powerful, extensible and developer-friendly Markdown-based content management system", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/cobalt.git", - "web": "http://gitlab.minteck.org/minteck/cobalt", - "showcase": false, - "name_compare": "cobalt", - "description_compare": "apowerfulextensibleanddeveloperfriendlymarkdownbasedcontentmanagementsystem" - }, - "2a7293fcaee5b5edfdd442f35144977eb9a4f266": { - "gitlab_id": 44, - "youtrack_id": "0-40", - "name": "Ponyfind", - "description": "A pony Discord bot, made by an Equestrian.", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/ponyfind.git", - "web": "http://gitlab.minteck.org/minteck/ponyfind", - "showcase": true, - "name_compare": "ponyfind", - "description_compare": "aponydiscordbotmadebyanequestrian" - }, - "834d30d1fa3e5e08ad4a7556d6edfec903d12ccf": { - "gitlab_id": 43, - "youtrack_id": "0-39", - "name": "pony.minteck.org", - "description": "Ponies! 🦄", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/pony.git", - "web": "http://gitlab.minteck.org/minteck/pony", - "showcase": false, - "name_compare": "ponyminteckorg", - "description_compare": "ponies" - }, - "f5f92ad74f4dc911b6f8dde9404f0123a5322784": { - "gitlab_id": 38, + { + "id": "980aaf996775f99f3ccac3c010eeb9982470ce53", + "gitlab_id": 73, "youtrack_id": null, - "name": "Familine Desktop", - "description": "A desktop app for Familine", + "name": "Ember - Website v10", + "description": "Yet another modern website for me, but this time it's actually good | Now live on [staging.minteck.org](https://staging.minteck.org)", "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/desktop.git", - "web": "http://gitlab.minteck.org/minteck/desktop", + "vcs": "http://gitlab.minteck.org/minteck/ember.git", + "web": "http://gitlab.minteck.org/minteck/ember", + "icon": "http://gitlab.minteck.org/uploads/-/system/project/avatar/73/Ember__22we_could_keep_working_together_22_S6E5_copy_2.png", "showcase": false, - "name_compare": "familinedesktop", - "description_compare": "adesktopappforfamiline" + "date": "2022-04-16T15:35:40.241Z" }, - "f22d052294fa1896a776076c9fec6614f463a6d9": { + { + "id": "f22d052294fa1896a776076c9fec6614f463a6d9", "gitlab_id": 35, - "youtrack_id": "0-30", + "youtrack_id": null, "name": "Foxperson", "description": "A new game made using Godot 3.", "issues": null, "vcs": "http://gitlab.minteck.org/minteck/foxperson.git", "web": "http://gitlab.minteck.org/minteck/foxperson", + "icon": "http://gitlab.minteck.org/uploads/-/system/project/avatar/35/icon.png", "showcase": false, - "name_compare": "foxperson", - "description_compare": "anewgamemadeusinggodot" + "date": "2022-04-15T15:06:31.707Z" }, - "e8ed872c86e59f4bf70fb023695a714a6973d11d": { - "gitlab_id": 25, - "youtrack_id": "0-1", - "name": "Neutron", - "description": "A simple, lightweight and easy PHP content management system — JetBrains Request ID: 11042022/9185466", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/neutron.git", - "web": "http://gitlab.minteck.org/minteck/neutron", - "showcase": true, - "name_compare": "neutron", - "description_compare": "asimplelightweightandeasyphpcontentmanagementsystemjetbrainsrequestid" - }, - "f3f83c9c2dab262308e04c6424de960b3f8fa259": { + { + "id": "f3f83c9c2dab262308e04c6424de960b3f8fa259", "gitlab_id": 22, - "youtrack_id": "0-41", + "youtrack_id": null, "name": "Rainbow - Website v9", - "description": "A new dynamic and blazing fast Web server for Minteck, default `htdocs` includes [staging.minteck.org](https://staging.minteck.org)", + "description": "A new dynamic and blazing fast Web server for Minteck, default `htdocs` includes [minteck.org](https://minteck.org)", "issues": null, "vcs": "http://gitlab.minteck.org/minteck/rainbow.git", "web": "http://gitlab.minteck.org/minteck/rainbow", + "icon": "http://gitlab.minteck.org/uploads/-/system/project/avatar/22/icon.png", "showcase": false, - "name_compare": "rainbowwebsitev", - "description_compare": "anewdynamicandblazingfastwebserverforminteckdefaulthtdocsincludesstagingminteckorghttpsstagingminteckorg" + "date": "2022-04-14T14:08:13.616Z" }, - "de0c2e523b1680eeabbf388fed48e0ac73d86f8e": { - "gitlab_id": 15, - "youtrack_id": null, - "name": "Familine Share", - "description": "(French) Share files with the entire world right from Familine and safely", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/share.git", - "web": "http://gitlab.minteck.org/minteck/share", - "showcase": false, - "name_compare": "familineshare", - "description_compare": "frenchsharefileswiththeentireworldrightfromfamilineandsafely" - }, - "58fed8a4724d0c41eebc6dfc1617930d7f773f61": { + { + "id": "58fed8a4724d0c41eebc6dfc1617930d7f773f61", "gitlab_id": 12, "youtrack_id": null, "name": "Me", @@ -319,260 +73,164 @@ "issues": null, "vcs": "http://gitlab.minteck.org/minteck/minteck.git", "web": "http://gitlab.minteck.org/minteck/minteck", + "icon": null, "showcase": false, - "name_compare": "me", - "description_compare": "someofmystuff" + "date": "2022-04-13T17:13:01.625Z" }, - "1f88f38480fa8008aa31d91ce15c870b65da2257": { - "gitlab_id": 11, - "youtrack_id": null, - "name": "Familine Movies", - "description": "(French) Share movie productions from your family with your family; easy and simple to use.", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/movies.git", - "web": "http://gitlab.minteck.org/minteck/movies", - "showcase": false, - "name_compare": "familinemovies", - "description_compare": "frenchsharemovieproductionsfromyourfamilywithyourfamilyeasyandsimpletouse" - }, - "f378984db5bb0f340a6e0150128acd67b8aed5ba": { - "gitlab_id": 9, + { + "id": "2a7293fcaee5b5edfdd442f35144977eb9a4f266", + "gitlab_id": 44, "youtrack_id": null, - "name": "Familine Help", - "description": "(French) General help center to get help and tips about all Familine services.", + "name": "Ponyfind", + "description": "A pony Discord bot, made by an Equestrian.", "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/help.git", - "web": "http://gitlab.minteck.org/minteck/help", - "showcase": false, - "name_compare": "familinehelp", - "description_compare": "frenchgeneralhelpcentertogethelpandtipsaboutallfamilineservices" + "vcs": "http://gitlab.minteck.org/minteck/ponyfind.git", + "web": "http://gitlab.minteck.org/minteck/ponyfind", + "icon": "http://gitlab.minteck.org/uploads/-/system/project/avatar/44/vlcsnap-2022-01-08-22h16m17s487.png", + "showcase": true, + "date": "2022-04-13T17:12:51.739Z" }, - "8267dde1cad2da4c8641ed08d88cd846bb2ffccf": { - "gitlab_id": 7, + { + "id": "bf78ae1ff90298f79d212242dd33183cb770fadf", + "gitlab_id": 57, "youtrack_id": null, - "name": "Familine Genealogy", - "description": "View GEDCOM files in a shiny cool Web interface.", + "name": "Argon Transcoding Engine", + "description": "An automated transcoding engine for the Argon Music Platform, using ffmpeg as a backend", "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/genealogy.git", - "web": "http://gitlab.minteck.org/minteck/genealogy", + "vcs": "http://gitlab.minteck.org/minteck/argon-transcode.git", + "web": "http://gitlab.minteck.org/minteck/argon-transcode", + "icon": null, "showcase": false, - "name_compare": "familinegenealogy", - "description_compare": "viewgedcomfilesinashinycoolwebinterface" + "date": "2022-04-13T17:12:42.388Z" }, - "c03ff9948d214d8d35959266521f6640ac330686": { - "gitlab_id": 6, + { + "id": "63c80d908c7b3d056d5ebf9b83034381eef5ddd4", + "gitlab_id": 62, "youtrack_id": null, - "name": "Familine Core", - "description": "(French) Core files making Familine actually work.", + "name": "Website for the Cloudburst System", + "description": "A website made in collaboration and for [Cloudburst](https://github.com/CloudburstSys). https://conep.one/ Future readers: this is not a commission, please don't ask me to create a website for you", "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/core.git", - "web": "http://gitlab.minteck.org/minteck/core", + "vcs": "http://gitlab.minteck.org/minteck/cloudsdale.git", + "web": "http://gitlab.minteck.org/minteck/cloudsdale", + "icon": "http://gitlab.minteck.org/uploads/-/system/project/avatar/62/android-chrome-512x512.png", "showcase": false, - "name_compare": "familinecore", - "description_compare": "frenchcorefilesmakingfamilineactuallywork" + "date": "2022-04-13T17:12:37.329Z" }, - "68b82313efe7ebb0088b3adc1790fac41ae9598c": { - "gitlab_id": 2, + { + "id": "b33700d38f096fc476edcfbb84b0d475639a9adf", + "gitlab_id": 65, "youtrack_id": null, - "name": "WolfEye Backend", - "description": "WolfEye's API and backend processing code", - "issues": null, - "vcs": "http://gitlab.minteck.org/jae/wolfeye-api.git", - "web": "http://gitlab.minteck.org/jae/wolfeye-api", - "showcase": false, - "name_compare": "wolfeyebackend", - "description_compare": "wolfeyesapiandbackendprocessingcode" - }, - "f884c41416235588a43e31bd28ea89bcbed28e87": { - "gitlab_id": 60, - "youtrack_id": "0-3", - "name": "Argon", - "description": "Frontend and Web client for the Argon Music Platform", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/argon.git", - "web": "http://gitlab.minteck.org/minteck/argon", - "showcase": false, - "name_compare": "argon", - "description_compare": "frontendandwebclientfortheargonmusicplatform" - }, - "1aa018e88d06be0c8f3aa0d8caaa70d7c17a2fb8": { - "gitlab_id": 59, - "youtrack_id": "0-4", - "name": "Argon 3pAD", - "description": "3rd-party analytics data federation daemon for the Argon Music Platform", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/argon-3pad.git", - "web": "http://gitlab.minteck.org/minteck/argon-3pad", - "showcase": false, - "name_compare": "argonpad", - "description_compare": "rdpartyanalyticsdatafederationdaemonfortheargonmusicplatform" - }, - "1149c45380143aae738bf71c0bf599c2c621d962": { - "gitlab_id": 57, - "youtrack_id": "0-15", - "name": "Argon Transcoding Engine", - "description": "An automated transcoding engine for the Argon Music Platform, using ffmpeg as a backend", + "name": "Voicer", + "description": "An open-source offline-first voice assistant", "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/argon-transcode.git", - "web": "http://gitlab.minteck.org/minteck/argon-transcode", + "vcs": "http://gitlab.minteck.org/minteck/voicer.git", + "web": "http://gitlab.minteck.org/minteck/voicer", + "icon": null, "showcase": false, - "name_compare": "argontranscodingengine", - "description_compare": "anautomatedtranscodingenginefortheargonmusicplatformusingffmpegasabackend" + "date": "2022-04-13T17:12:35.143Z" }, - "cb1a6f17454740b360a469470efe8d74e66f18df": { + { + "id": "1b10549feef5a95c59f9a09f11eff72f380c9049", "gitlab_id": 72, - "youtrack_id": "0-51", + "youtrack_id": null, "name": "AutoDocs", "description": "Publishing documentation for your projects is sometimes hard, AutoDocs got you covered!", "issues": null, "vcs": "http://gitlab.minteck.org/minteck/autodocs.git", "web": "http://gitlab.minteck.org/minteck/autodocs", + "icon": null, "showcase": false, - "name_compare": "autodocs", - "description_compare": "publishingdocumentationforyourprojectsissometimeshardautodocsgotyoucovered" + "date": "2022-04-13T17:12:26.656Z" }, - "bd3a87a69db21ed761f1f3a6ed60b11a0205b173": { - "gitlab_id": 46, - "youtrack_id": "0-19", - "name": "Cobalt", - "description": "A powerful, extensible and developer-friendly Markdown-based content management system", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/cobalt.git", - "web": "http://gitlab.minteck.org/minteck/cobalt", - "showcase": false, - "name_compare": "cobalt", - "description_compare": "apowerfulextensibleanddeveloperfriendlymarkdownbasedcontentmanagementsystem" - }, - "5130f04d775705f9228157e0e04efffd2f308f90": { - "gitlab_id": 35, - "youtrack_id": "0-30", - "name": "Foxperson", - "description": "A new game made using Godot 3.", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/foxperson.git", - "web": "http://gitlab.minteck.org/minteck/foxperson", - "showcase": false, - "name_compare": "foxperson", - "description_compare": "anewgamemadeusinggodot" - }, - "50ccf062ed15056cc37a12ed2aff3f922712b56b": { - "gitlab_id": 25, - "youtrack_id": "0-1", - "name": "Neutron", - "description": "A simple, lightweight and easy PHP content management system — JetBrains Request ID: 11042022/9185466", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/neutron.git", - "web": "http://gitlab.minteck.org/minteck/neutron", - "showcase": true, - "name_compare": "neutron", - "description_compare": "asimplelightweightandeasyphpcontentmanagementsystemjetbrainsrequestid" - }, - "a86ecc4a9b6ada137b3aed7cfadfd9f00ca6ebcf": { - "gitlab_id": 43, - "youtrack_id": "0-39", - "name": "pony.minteck.org", - "description": "Ponies! 🦄", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/pony.git", - "web": "http://gitlab.minteck.org/minteck/pony", - "showcase": false, - "name_compare": "ponyminteckorg", - "description_compare": "ponies" - }, - "2d14c68f00f86b7477520fafdfce54da9e6614db": { - "gitlab_id": 44, - "youtrack_id": "0-40", - "name": "Ponyfind", - "description": "A pony Discord bot, made by an Equestrian.", - "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/ponyfind.git", - "web": "http://gitlab.minteck.org/minteck/ponyfind", - "showcase": true, - "name_compare": "ponyfind", - "description_compare": "aponydiscordbotmadebyanequestrian" - }, - "6b5e94ee9ecb841221410185fe42e31000032c50": { + { + "id": "a8169ad64935e63ee65c1b38d4b625a315f7a0be", "gitlab_id": 61, - "youtrack_id": "0-10", + "youtrack_id": null, "name": "r-Place archive", "description": "An archive viewer for r/place (Reddit's April Fools 2022)", "issues": null, "vcs": "http://gitlab.minteck.org/minteck/placearchive.git", "web": "http://gitlab.minteck.org/minteck/placearchive", + "icon": "http://gitlab.minteck.org/uploads/-/system/project/avatar/61/logo.png", "showcase": true, - "name_compare": "rplacearchive", - "description_compare": "anarchiveviewerforrplaceredditsaprilfools" + "date": "2022-04-13T14:33:17.289Z" }, - "f742b3fbcfa54dc144098930971b156d57426e94": { - "gitlab_id": 22, - "youtrack_id": "0-41", - "name": "Rainbow - Website v9", - "description": "A new dynamic and blazing fast Web server for Minteck, default `htdocs` includes [staging.minteck.org](https://staging.minteck.org)", + { + "id": "7adce3f27d6625c6867fcb46756dc520a58a2e70", + "gitlab_id": 60, + "youtrack_id": null, + "name": "Argon", + "description": "Frontend and Web client for the Argon Music Platform", "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/rainbow.git", - "web": "http://gitlab.minteck.org/minteck/rainbow", + "vcs": "http://gitlab.minteck.org/minteck/argon.git", + "web": "http://gitlab.minteck.org/minteck/argon", + "icon": null, "showcase": false, - "name_compare": "rainbowwebsitev", - "description_compare": "anewdynamicandblazingfastwebserverforminteckdefaulthtdocsincludesstagingminteckorghttpsstagingminteckorg" + "date": "2022-04-12T11:37:10.147Z" }, - "25638a6855b4502ae04fe092ee26f62f08df45f0": { + { + "id": "fa344572018fda9017ac256070f4ad6610cad084", "gitlab_id": 66, - "youtrack_id": "0-11", + "youtrack_id": null, "name": "Snowjail", "description": "Sandboxing technology for Twilight Package Manager packages", "issues": null, "vcs": "http://gitlab.minteck.org/minteck/snowjail.git", "web": "http://gitlab.minteck.org/minteck/snowjail", + "icon": null, "showcase": false, - "name_compare": "snowjail", - "description_compare": "sandboxingtechnologyfortwilightpackagemanagerpackages" + "date": "2022-04-09T16:38:58.915Z" }, - "118c4e7f568d30340f0cd63fa921bab7f5dd71d2": { - "gitlab_id": 54, - "youtrack_id": "0-44", - "name": "Twilight Setup Utility", - "description": "A self-extracting online installer/repairer/uninstaller for the [Twilight Package Manager](/minteck/twilight)", + { + "id": "6d7e1ed7601aec219fc7eaac56c55a0fb138184a", + "gitlab_id": 58, + "youtrack_id": null, + "name": "Alicorn Operating System", + "description": "The next-generation operating system using Web technologies", "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/twilight-setup.git", - "web": "http://gitlab.minteck.org/minteck/twilight-setup", + "vcs": "http://gitlab.minteck.org/minteck/alicorn.git", + "web": "http://gitlab.minteck.org/minteck/alicorn", + "icon": null, "showcase": false, - "name_compare": "twilightsetuputility", - "description_compare": "aselfextractingonlineinstallerrepaireruninstallerforthetwilightpackagemanagermintecktwilight" + "date": "2022-04-08T20:01:08.451Z" }, - "6546bc8f3da6d606b1a99953e3a664dd5e0bee75": { - "gitlab_id": 65, - "youtrack_id": "0-12", - "name": "Voicer", - "description": "An open-source offline-first voice assistant", + { + "id": "1cf12f94d06a8807a63151ae38ed6b76820a4f72", + "gitlab_id": 59, + "youtrack_id": null, + "name": "Argon 3pAD", + "description": "3rd-party analytics data federation daemon for the Argon Music Platform", "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/voicer.git", - "web": "http://gitlab.minteck.org/minteck/voicer", + "vcs": "http://gitlab.minteck.org/minteck/argon-3pad.git", + "web": "http://gitlab.minteck.org/minteck/argon-3pad", + "icon": null, "showcase": false, - "name_compare": "voicer", - "description_compare": "anopensourceofflinefirstvoiceassistant" + "date": "2022-04-08T12:10:24.064Z" }, - "cf8c67740a78e7328b870797a9b32cdf5f04e3d2": { - "gitlab_id": 62, - "youtrack_id": "0-13", - "name": "Website for the Cloudburst System", - "description": "A website made in collaboration and for [Cloudburst](https://github.com/CloudburstSys). https://cloudburst-system.test.minteck.net.eu.org/ Future readers: this is not a commission, please don't ask me to create a website for you", + { + "id": "3345c862bdf8957517e4ce4fc72ba6587d34bc64", + "gitlab_id": 46, + "youtrack_id": null, + "name": "Cobalt", + "description": "A powerful, extensible and developer-friendly Markdown-based content management system", "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/cloudsdale.git", - "web": "http://gitlab.minteck.org/minteck/cloudsdale", + "vcs": "http://gitlab.minteck.org/minteck/cobalt.git", + "web": "http://gitlab.minteck.org/minteck/cobalt", + "icon": null, "showcase": false, - "name_compare": "websiteforthecloudburstsystem", - "description_compare": "awebsitemadeincollaborationandforcloudbursthttpsgithubcomcloudburstsyshttpscloudburstsystemtestminteckneteuorgfuturereadersthisisnotacommissionpleasedontaskmetocreateawebsiteforyou" + "date": "2022-04-08T12:02:51.617Z" }, - "8508e56751f4ad1d7f6b5fd5dae2e282eea8a865": { - "gitlab_id": 73, - "youtrack_id": "0-52", - "name": "WebX - Website v10", - "description": "Yet another modern website for me", + { + "id": "834d30d1fa3e5e08ad4a7556d6edfec903d12ccf", + "gitlab_id": 43, + "youtrack_id": null, + "name": "pony.minteck.org", + "description": "Ponies! 🦄", "issues": null, - "vcs": "http://gitlab.minteck.org/minteck/webx.git", - "web": "http://gitlab.minteck.org/minteck/webx", + "vcs": "http://gitlab.minteck.org/minteck/pony.git", + "web": "http://gitlab.minteck.org/minteck/pony", + "icon": "http://gitlab.minteck.org/uploads/-/system/project/avatar/43/icon.png", "showcase": false, - "name_compare": "webxwebsitev", - "description_compare": "yetanothermodernwebsiteforme" + "date": "2022-04-03T08:15:08.565Z" } -} \ No newline at end of file +] \ No newline at end of file diff --git a/includes/functions.php b/includes/functions.php index defa152..38dda54 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -1,6 +1,6 @@ = 0) { + return $tense = 'just now'; + } elseif ($difference > 0) { + $tense = 'ago'; + } else { + $tense = 'later'; + } + + for ($j = 0; $difference >= $lengths[$j] && $j < count($lengths)-1; $j++) { + $difference /= $lengths[$j]; + } + + $difference = round($difference); + + $period = $periods[$j] . ($difference >1 ? 's' :''); + return "{$difference} {$period} {$tense} "; +} + +require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/Parsedown.php"; +global $Parsedown; +$Parsedown = new Parsedown(); \ No newline at end of file diff --git a/includes/header.php b/includes/header.php index 099267a..09257fe 100644 --- a/includes/header.php +++ b/includes/header.php @@ -16,5 +16,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/includes/navigation.php b/includes/navigation.php index b670067..2d0fabf 100644 --- a/includes/navigation.php +++ b/includes/navigation.php @@ -21,9 +21,6 @@ - diff --git a/index.php b/index.php index 44bb82e..e982712 100644 --- a/index.php +++ b/index.php @@ -1,8 +1,12 @@ - +
- +
+ +
+
+

Minteck

Your typical keyboard-addicted pony

diff --git a/projects/index.php b/projects/index.php index 9c5010f..e693deb 100644 --- a/projects/index.php +++ b/projects/index.php @@ -1,10 +1,26 @@ - +

Projects

- Coming soon +
+ +
+ +
+
+
+ style="background: hsla(, 100%, 50%, 0.1) !important;" src="" alt=""> +

+

line(trim($project["description"])))) ?>

+ " target="_blank" class="btn btn-outline-light">View Project +
Updated
+
+
+
+ +
\ No newline at end of file diff --git a/services/index.php b/services/index.php index 92da22b..103245a 100644 --- a/services/index.php +++ b/services/index.php @@ -1,4 +1,4 @@ - +
diff --git a/social/index.php b/social/index.php index 7cdc88e..47f045b 100644 --- a/social/index.php +++ b/social/index.php @@ -1,4 +1,4 @@ - +
-- cgit