From 5f9b0fc625689959bed1a15f005fb53a15c8f92d Mon Sep 17 00:00:00 2001 From: Melroy van den Berg Date: Tue, 9 Apr 2019 22:34:03 +0200 Subject: [PATCH] Add several bugs & improve readme --- README.md | 51 + deploy/content/home/index.md | 3 + deploy/nasg/templates/404.j2.php | 128 ++ deploy/nasg/templates/Category.j2.html | 56 + deploy/nasg/templates/Home.j2.html | 36 + deploy/nasg/templates/Micropub.j2.php | 114 ++ deploy/nasg/templates/Search.j2.php | 57 + deploy/nasg/templates/Singular.j2.html | 221 +++ deploy/nasg/templates/Singular.j2.txt | 8 + deploy/nasg/templates/WebImage.j2.html | 65 + deploy/nasg/templates/Webhook.j2.php | 56 + deploy/nasg/templates/base.j2.html | 199 +++ deploy/nasg/templates/konami.js | 18 + deploy/nasg/templates/meta-article.j2.html | 52 + deploy/nasg/templates/prism.css | 69 + deploy/nasg/templates/prism.js | 1742 ++++++++++++++++++++ deploy/nasg/templates/style-alt.css | 64 + deploy/nasg/templates/style-gallery.css | 34 + deploy/nasg/templates/style-print.css | 90 + deploy/nasg/templates/style.css | 358 ++++ deploy/nasg/templates/symbols.svg | 222 +++ deploy/nasg/templates/themeswitcher.js | 73 + deploy/nasg/templates/watermark.png | Bin 0 -> 41486 bytes deploy/www/feed/atom.xml | 15 + deploy/www/feed/index.json | 12 + deploy/www/feed/index.xml | 16 + deploy/www/gophermap | 3 + deploy/www/index.html | 1038 ++++++++++++ deploy/www/index.php | 122 ++ deploy/www/micropub.php | 114 ++ deploy/www/search.php | 1078 ++++++++++++ deploy/www/search.sqlite | Bin 0 -> 32768 bytes deploy/www/webhook.php | 56 + nasg.py | 19 +- pandoc.py | 15 +- 35 files changed, 6196 insertions(+), 8 deletions(-) create mode 100644 deploy/content/home/index.md create mode 100644 deploy/nasg/templates/404.j2.php create mode 100644 deploy/nasg/templates/Category.j2.html create mode 100644 deploy/nasg/templates/Home.j2.html create mode 100644 deploy/nasg/templates/Micropub.j2.php create mode 100644 deploy/nasg/templates/Search.j2.php create mode 100644 deploy/nasg/templates/Singular.j2.html create mode 100644 deploy/nasg/templates/Singular.j2.txt create mode 100644 deploy/nasg/templates/WebImage.j2.html create mode 100644 deploy/nasg/templates/Webhook.j2.php create mode 100644 deploy/nasg/templates/base.j2.html create mode 100644 deploy/nasg/templates/konami.js create mode 100644 deploy/nasg/templates/meta-article.j2.html create mode 100644 deploy/nasg/templates/prism.css create mode 100644 deploy/nasg/templates/prism.js create mode 100644 deploy/nasg/templates/style-alt.css create mode 100644 deploy/nasg/templates/style-gallery.css create mode 100644 deploy/nasg/templates/style-print.css create mode 100644 deploy/nasg/templates/style.css create mode 100644 deploy/nasg/templates/symbols.svg create mode 100644 deploy/nasg/templates/themeswitcher.js create mode 100644 deploy/nasg/templates/watermark.png create mode 100644 deploy/www/feed/atom.xml create mode 100644 deploy/www/feed/index.json create mode 100644 deploy/www/feed/index.xml create mode 100644 deploy/www/gophermap create mode 100644 deploy/www/index.html create mode 100644 deploy/www/index.php create mode 100644 deploy/www/micropub.php create mode 100644 deploy/www/search.php create mode 100644 deploy/www/search.sqlite create mode 100644 deploy/www/webhook.php diff --git a/README.md b/README.md index d55d097..ac6dadd 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,57 @@ How it works - fallback - 404 handler to do redirects/gones, gets populated with an array of both - micropub - a micropub endpoint that accepts micropub content and puts the incoming payload into a json file, nothing else +## Deploy + +### Requirements + +For Debian based distributions, install the packages: +* python3 +* python3-pip +* pandoc + +`sudo apt install python3 python3-pip pandoc` + +Install pipenv via pip: + +`sudo pip3 install pipenv` + +Install the pip dependency packages by using the Pipfile by running: + +`pipenv install` + +### Prepare + +Create a local base directory where your contents will be put into. Eg: + +`~/MyWebsite` + +Create the following directories within your base directory directory: `www`, `nasg/templates`, `content/home`. + +Copy the templates from the `templates` directory to the `~/MyWebsite/nasg/templates` directory. + +Create a new file within the root directory called `keys.py` with the following content: + +```python +webmentionio = { + 'domain': 'yourdomain.com', + 'token': 'token', + 'secret': 'secret' +} + +telegraph = { + 'token': 'token' +} + +zapier = { + 'zapier': 'secret' +} +``` + +Add an `index.md` file to the `~/MyWebsite/content/home` directory. + +Finally, change the [settings.py](settings.py) file, like the `base` path and `syncserver` etc. to your needs. + ## Functionalities based on file extensions/names - **entry_name/index.md**: main entry (YAML + Multimarkdown) diff --git a/deploy/content/home/index.md b/deploy/content/home/index.md new file mode 100644 index 0000000..15e5575 --- /dev/null +++ b/deploy/content/home/index.md @@ -0,0 +1,3 @@ +# Hello world + +This is a test diff --git a/deploy/nasg/templates/404.j2.php b/deploy/nasg/templates/404.j2.php new file mode 100644 index 0000000..e44b7d0 --- /dev/null +++ b/deploy/nasg/templates/404.j2.php @@ -0,0 +1,128 @@ + "{{ to }}", +{% endfor %} +); + +$redirects_re = array( + '^(?:sysadmin|it|linux-tech-coding|sysadmin-blog)\/?(page.*)?$' => 'category/article/', + '^(?:fotography|photoblog)\/?(page.*)?$' => '/category/photo/$1', + '^blog\/?(page.*)?$' => '/category/journal/', + '^blips\/?(page.*)?$' => '/category/note/$1', + '^r\/?(page.*)?$' => '/category/note/$1', + '^(?:linux-tech-coding|it|sysadmin-blog|sysadmin|fotography|blips|blog|photoblog|article|journal|photo|note|r)\/((?!page).*)' => '/$1', +); + +$gone = array( +{% for gone in gones %} + "{{ gone }}" => true, +{% endfor %} +); + +$gone_re = array( + '^cache\/.*$', + '^tag\/.*$', + '^comment\/.*$', + '^files\/.*$', + '^wp-content\/.*$', + '^broadcast\/wp-ffpc\.message$', +); + +function redirect_to($uri) { + header('HTTP/1.1 301 Moved Permanently'); + if (preg_match("/^https?/", $uri)) + $target = $uri; + else + $target = '{{ site.url }}/'. trim($uri, '/') . '/'; + header("Location: ". $target); + exit; +} + +function gone($uri) { + header('HTTP/1.1 410 Gone'); + die(' + + + + + Gone + + +

This content was deleted.

+
+

'.$uri.'

+ +'); +} + +function notfound($uri) { + header('HTTP/1.0 404 Not Found'); + die(' + + + + + Not found + + + +

This was not found.

+

Please search for it instead.

+

+

+ +
+

+
+

'.$uri.'

+ +'); +} + +function maybe_redirect($uri) { + if (file_exists("./$uri/index.html")) { + redirect_to($uri); + } +} + +$uri = filter_var($_SERVER['REQUEST_URI'], FILTER_SANITIZE_URL); +$uri = str_replace('../', '', $uri); +$uri = str_replace('/feed/', '', $uri); +$uri = str_replace('/atom/', '', $uri); +$uri = trim($uri, '/'); + +foreach ($gone_re as $pattern) { + if (preg_match(sprintf('/%s/', $pattern), $uri)) { + gone($uri); + } +} + +foreach ($redirects_re as $pattern => $target) { + $maybe = preg_match(sprintf('/%s/i', $pattern), $uri, $matches); + if ($maybe) { + $target = str_replace('$1', $matches[1], $target); + redirect_to($target); + } +} + +if (isset($gone[$uri])) { + gone($uri); +} +elseif (isset($redirects[$uri])) { + redirect_to($redirects[$uri]); +} +elseif (preg_match('/^\.well-known\/(host-meta|webfinger).*$/', $uri)) { + redirect_to("https://fed.brid.gy/{$uri}"); +} +elseif (strstr($uri, '_')) { + maybe_redirect(str_replace('_', '-', $uri)); +} +else { + notfound($uri); +} diff --git a/deploy/nasg/templates/Category.j2.html b/deploy/nasg/templates/Category.j2.html new file mode 100644 index 0000000..14de732 --- /dev/null +++ b/deploy/nasg/templates/Category.j2.html @@ -0,0 +1,56 @@ +{% extends "base.j2.html" %} +{% block lang %}{% endblock %} + +{% block title %}{{ category.title }}{% endblock %} +{% block meta %} + + + + +{% endblock %} + +{% block pagination %} +{% if category.paginated %} + +{% endif %} +{% endblock %} + +{% block content %} +
+ +{% set year = [0] %} +{% for post in posts %} + {% set _year = year.pop() %} + {% if not category.paginated and _year != post.copyrightYear %} + {% if not loop.first %} + + {% endif %} +
+

{{ post.copyrightYear }}

+ {% endif %} + {% set _ = year.append(post.copyrightYear)%} + {% include 'meta-article.j2.html' %} + {% if not category.paginated and loop.last %} +
+ {% endif %} +{% endfor %} +
+{% endblock %} diff --git a/deploy/nasg/templates/Home.j2.html b/deploy/nasg/templates/Home.j2.html new file mode 100644 index 0000000..f133c75 --- /dev/null +++ b/deploy/nasg/templates/Home.j2.html @@ -0,0 +1,36 @@ +{% extends "base.j2.html" %} + +{% block title %}{{ post.headline }} - {{ site.name }}{% endblock %} + +{% block meta %} + + + + {% for category, latest in elements %} + + + + {% endfor %} +{% endblock %} + +{% block content %} +
+ + + {% for category, post in posts %} +
+

in: + + + {{ category.name }} + +

+ {% include 'meta-article.j2.html' %} +
+{% endfor %} +
+{% endblock %} diff --git a/deploy/nasg/templates/Micropub.j2.php b/deploy/nasg/templates/Micropub.j2.php new file mode 100644 index 0000000..f96cf40 --- /dev/null +++ b/deploy/nasg/templates/Micropub.j2.php @@ -0,0 +1,114 @@ + array()))); + } + + if(isset($_GET['q']['syndicate-to'])) { + httpok(json_encode(array('syndicate-to' => array()))); + } + + badrequest('please POST a micropub request'); +} + +$raw = file_get_contents("php://input"); +print_r($raw); +try { + $decoded = json_decode($raw, true); +} catch (Exception $e) { + _syslog('failed to decode JSON, trying decoding form data'); + try { + parse_str($raw, $decoded); + } + catch (Exception $e) { + _syslog('failed to decoding form data as well'); + badrequest('invalid POST contents'); + } +} +print_r($decoded); + +$token = ''; +if ( isset($decoded['access_token']) ) { + $token = $decoded['access_token']; + unset($decoded['access_token']); +} +elseif ( isset($_SERVER['HTTP_AUTHORIZATION']) ) { + $token = trim(str_replace('Bearer', '', $_SERVER['HTTP_AUTHORIZATION'])); +} + +if (empty($token)) { + unauthorized('missing token'); +} + +$request = curl_init(); +curl_setopt($request, CURLOPT_URL, 'https://tokens.indieauth.com/token'); +curl_setopt($request, CURLOPT_HTTPHEADER, array( + 'Content-Type: application/x-www-form-urlencoded', + sprintf('Authorization: Bearer %s', $token) +)); +curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); +$response = curl_exec($request); +curl_close($request); +parse_str(urldecode($response), $verification); +if (! isset($verification['scope']) ) { + unauthorized('missing "scope"'); +} +if (! isset($verification['me']) ) { + unauthorized('missing "me"'); +} +if ( ! stristr($verification['me'], '{{ site.url }}') ) { + unauthorized('wrong domain'); +} +if ( ! stristr($verification['scope'], 'create') ) { + unauthorized('invalid scope'); +} + +$user = posix_getpwuid(posix_getuid()); +$now = time(); +$decoded['mtime'] = $now; +$fname = sprintf( + '%s/%s/%s.json', + $user['dir'], + '{{ paths.remotequeue }}', + microtime(true) +); + +file_put_contents($fname, json_encode($decoded, JSON_PRETTY_PRINT)); +accepted(); diff --git a/deploy/nasg/templates/Search.j2.php b/deploy/nasg/templates/Search.j2.php new file mode 100644 index 0000000..210ab62 --- /dev/null +++ b/deploy/nasg/templates/Search.j2.php @@ -0,0 +1,57 @@ +{% extends "base.j2.html" %} +{% block lang %}{% endblock %} +{% block title %}Search results for: {% endblock %} +{% block content %} + + +
+
+

Search results for:

+
+prepare(" + SELECT + url, category, title, snippet(data, '', '', '[...]', 5, 24) + FROM + data + WHERE + data MATCH :q + ORDER BY + category +"); +$sql->bindValue(':q', $q); +$results = $sql->execute(); + +printf("
"); +while ($row = $results->fetchArray(SQLITE3_ASSOC)) { + printf('
%s
%s
', relurl(baseurl, $row['url']), $row['title'], $row["snippet(data, '', '', '[...]', 5, 24)"]); + +} +printf("
"); +?> +
+{% endblock %} diff --git a/deploy/nasg/templates/Singular.j2.html b/deploy/nasg/templates/Singular.j2.html new file mode 100644 index 0000000..a34d1a4 --- /dev/null +++ b/deploy/nasg/templates/Singular.j2.html @@ -0,0 +1,221 @@ +{% extends "base.j2.html" %} + +{% block lang %} lang="{{ post.inLanguage }}" {% endblock %} + +{% block title %}{{ post.headline }} - {{ site.name }}{% endblock %} + +{% block meta %} + + + + + + + + + + + + + {% if post.image is iterable %} + + + + + {% else %} + + {% endif %} + + {% if post['@type'] == 'TechArticle' %} + + {% endif %} +{% endblock %} + +{% block prism %} + {% if post['@type'] == 'TechArticle' %} + + {% endif %} +{% endblock %} + +{% block cc %} +
  • + + + + + +
  • +{% endblock %} + +{% block content %} +
    +
    +
    +

    + {% if post.mentions %} + + + + + + RE: + + + {{ post.mentions.url }} + + + {% else %} + + {{ post.headline }} + + {% endif %} +

    + +

    + + {{ post.license | extractlicense }} + + by + + + {{ post.author.name }} + () + + at + + +
    + {{ post.url }} + +

    + +{% if post.subjectOf %} +

    + + Journey from + + to + , in + + {{ post.subjectOf.location.name }} + + + +

    +{% endif %} + +
    + + {% if post.review %} +
    + Review summary of: {{ post.review.name }} +

    + By + + + {{ post.author.name }} + in +

    +

    + + {{ post.review.reviewRating.ratingValue }} + out of + {{ post.review.reviewRating.bestRating }} + +

    +

    {{ post.review.text }}

    +
    + {% endif %} + + {% if post.description|length %} +
    + {{ post.description|relurl(baseurl) }} +
    + {% endif %} + +
    + {{ post.text|relurl(baseurl) }} +
    + + {% if 'WebPage' != post['@type'] %} + + + {% if post.comment|length %} +
    +

    Responses

    +
      + {% for comment in post.comment %} +
    1. + + {% if 'like-of' == comment.disambiguatingDescription %} + {% set icon = 'star' %} + {% elif 'bookmark-of' == comment.disambiguatingDescription %} + {% set icon = 'bookmark' %} + {% elif 'reply' == comment.disambiguatingDescription %} + {% set icon = 'reply' %} + {% else %} + {% set icon = 'link' %} + {% endif %} + + + + + from + + {% if comment.author.url %} + + {{ comment.author.name }} + + {% else %} + + {{ comment.author.name }} + + {% endif %} + + at + +
      + + {{ comment.url }} + + +
    2. + {% endfor %} +
    +
    + {% endif %} + + {% endif %} +
    +
    +{% endblock %} diff --git a/deploy/nasg/templates/Singular.j2.txt b/deploy/nasg/templates/Singular.j2.txt new file mode 100644 index 0000000..2326e17 --- /dev/null +++ b/deploy/nasg/templates/Singular.j2.txt @@ -0,0 +1,8 @@ +{{ post.headline|center(width=80) }} + +by {{ post.author.name }} <{{ post.author.email}}> +{{ post.datePublished|printdate }} + +{{ summary }} + +{{ content }} diff --git a/deploy/nasg/templates/WebImage.j2.html b/deploy/nasg/templates/WebImage.j2.html new file mode 100644 index 0000000..066cf36 --- /dev/null +++ b/deploy/nasg/templates/WebImage.j2.html @@ -0,0 +1,65 @@ +
    +{% if url != thumbnail.url %} + +{% endif %} + {{ headline }} +{% if url != thumbnail.url %} + +{% endif %} +
    + {{ caption }} +{% if creator is defined %} +{% macro exifvalue(key) %} + {% for data in exifData: %} + {% if key == data['name'] %} + {{ data['value'] }} + {% endif %} + {% endfor %} +{% endmacro %} +
    +
    Camera
    +
    + + + + {{ exifvalue('Model')|trim }} +
    +
    Aperture
    +
    + + + + f/{{ exifvalue('FNumber')|trim }} +
    +
    Shutter speed
    +
    + + + + {{ exifvalue('ExposureTime')|trim }} sec +
    +
    Focal length (as set)
    +
    + + + + {{ exifvalue('FocalLength')|trim }} +
    +
    Sensitivity
    +
    + + + + ISO {{ exifvalue('ISO')|trim }} +
    +
    Lens
    +
    + + + + {{ exifvalue('LensID')|trim }} +
    +
    +{% endif %} +
    +
    diff --git a/deploy/nasg/templates/Webhook.j2.php b/deploy/nasg/templates/Webhook.j2.php new file mode 100644 index 0000000..f2365d1 --- /dev/null +++ b/deploy/nasg/templates/Webhook.j2.php @@ -0,0 +1,56 @@ + + + + + {% block title %}{% endblock %} + + + + + + {% for key, value in meta.items() %} + + {% endfor %} + {% block meta %}{% endblock %} + + + + + + + +{% macro activemenu(name) %} +{% if (post is defined and post.name == name ) + or (post is defined and post.genre == name ) + or ( category is defined and category.name == name )%}class="active"{% endif %} +{% endmacro %} + +
    +
    + + +
    + + {% for action in site.potentialAction %} + {% if 'SearchAction' == action['@type'] %} +
    + + +
    + {% endif %} + {% endfor %} +
    +
    +
    + +{% block content %} +{% endblock %} + +{% block pagination %} +{% endblock %} + + + + + +{% include 'symbols.svg' %} + +{% block prism %} +{% endblock %} + + + diff --git a/deploy/nasg/templates/konami.js b/deploy/nasg/templates/konami.js new file mode 100644 index 0000000..39255e9 --- /dev/null +++ b/deploy/nasg/templates/konami.js @@ -0,0 +1,18 @@ +function kcl(cb) { + var input = ''; + var key = '38384040373937396665'; + document.addEventListener('keydown', function (e) { + input += ("" + e.keyCode); + if (input === key) { + return cb(); + } + if (!key.indexOf(input)) return; + input = ("" + e.keyCode); + }); +} + +kcl(function () { + var e = document.createElement('img'); + e.src = '/iddqd.gif'; + document.body.appendChild(e); +}) diff --git a/deploy/nasg/templates/meta-article.j2.html b/deploy/nasg/templates/meta-article.j2.html new file mode 100644 index 0000000..7092689 --- /dev/null +++ b/deploy/nasg/templates/meta-article.j2.html @@ -0,0 +1,52 @@ + diff --git a/deploy/nasg/templates/prism.css b/deploy/nasg/templates/prism.css new file mode 100644 index 0000000..eb7129d --- /dev/null +++ b/deploy/nasg/templates/prism.css @@ -0,0 +1,69 @@ +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #789; +} + +.token.punctuation { + color: #999; +} + +.namespace { +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #f05; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #7a0; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #a74; +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #09c; +} + +.token.function, +.token.class-name { + color: #D57; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} \ No newline at end of file diff --git a/deploy/nasg/templates/prism.js b/deploy/nasg/templates/prism.js new file mode 100644 index 0000000..4f84c6a --- /dev/null +++ b/deploy/nasg/templates/prism.js @@ -0,0 +1,1742 @@ +/* PrismJS 1.15.0 +https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript+c+csharp+bash+markup-templating+git+ini+java+json+markdown+makefile+nginx+perl+php+sql+python+yaml */ +var _self = (typeof window !== 'undefined') + ? window // if in browser + : ( + (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) + ? self // if in worker + : {} // if in node js + ); + +/** + * Prism: Lightweight, robust, elegant syntax highlighting + * MIT license http://www.opensource.org/licenses/mit-license.php/ + * @author Lea Verou http://lea.verou.me + */ + +var Prism = (function(){ + +// Private helper vars +var lang = /\blang(?:uage)?-([\w-]+)\b/i; +var uniqueId = 0; + +var _ = _self.Prism = { + manual: _self.Prism && _self.Prism.manual, + disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler, + util: { + encode: function (tokens) { + if (tokens instanceof Token) { + return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias); + } else if (_.util.type(tokens) === 'Array') { + return tokens.map(_.util.encode); + } else { + return tokens.replace(/&/g, '&').replace(/ text.length) { + // Something went terribly wrong, ABORT, ABORT! + return; + } + + if (str instanceof Token) { + continue; + } + + if (greedy && i != strarr.length - 1) { + pattern.lastIndex = pos; + var match = pattern.exec(text); + if (!match) { + break; + } + + var from = match.index + (lookbehind ? match[1].length : 0), + to = match.index + match[0].length, + k = i, + p = pos; + + for (var len = strarr.length; k < len && (p < to || (!strarr[k].type && !strarr[k - 1].greedy)); ++k) { + p += strarr[k].length; + // Move the index i to the element in strarr that is closest to from + if (from >= p) { + ++i; + pos = p; + } + } + + // If strarr[i] is a Token, then the match starts inside another Token, which is invalid + if (strarr[i] instanceof Token) { + continue; + } + + // Number of tokens to delete and replace with the new match + delNum = k - i; + str = text.slice(pos, p); + match.index -= pos; + } else { + pattern.lastIndex = 0; + + var match = pattern.exec(str), + delNum = 1; + } + + if (!match) { + if (oneshot) { + break; + } + + continue; + } + + if(lookbehind) { + lookbehindLength = match[1] ? match[1].length : 0; + } + + var from = match.index + lookbehindLength, + match = match[0].slice(lookbehindLength), + to = from + match.length, + before = str.slice(0, from), + after = str.slice(to); + + var args = [i, delNum]; + + if (before) { + ++i; + pos += before.length; + args.push(before); + } + + var wrapped = new Token(token, inside? _.tokenize(match, inside) : match, alias, match, greedy); + + args.push(wrapped); + + if (after) { + args.push(after); + } + + Array.prototype.splice.apply(strarr, args); + + if (delNum != 1) + _.matchGrammar(text, strarr, grammar, i, pos, true, token); + + if (oneshot) + break; + } + } + } + }, + + tokenize: function(text, grammar, language) { + var strarr = [text]; + + var rest = grammar.rest; + + if (rest) { + for (var token in rest) { + grammar[token] = rest[token]; + } + + delete grammar.rest; + } + + _.matchGrammar(text, strarr, grammar, 0, 0, false); + + return strarr; + }, + + hooks: { + all: {}, + + add: function (name, callback) { + var hooks = _.hooks.all; + + hooks[name] = hooks[name] || []; + + hooks[name].push(callback); + }, + + run: function (name, env) { + var callbacks = _.hooks.all[name]; + + if (!callbacks || !callbacks.length) { + return; + } + + for (var i=0, callback; callback = callbacks[i++];) { + callback(env); + } + } + } +}; + +var Token = _.Token = function(type, content, alias, matchedStr, greedy) { + this.type = type; + this.content = content; + this.alias = alias; + // Copy of the full string this token was created from + this.length = (matchedStr || "").length|0; + this.greedy = !!greedy; +}; + +Token.stringify = function(o, language, parent) { + if (typeof o == 'string') { + return o; + } + + if (_.util.type(o) === 'Array') { + return o.map(function(element) { + return Token.stringify(element, language, o); + }).join(''); + } + + var env = { + type: o.type, + content: Token.stringify(o.content, language, parent), + tag: 'span', + classes: ['token', o.type], + attributes: {}, + language: language, + parent: parent + }; + + if (o.alias) { + var aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias]; + Array.prototype.push.apply(env.classes, aliases); + } + + _.hooks.run('wrap', env); + + var attributes = Object.keys(env.attributes).map(function(name) { + return name + '="' + (env.attributes[name] || '').replace(/"/g, '"') + '"'; + }).join(' '); + + return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + (attributes ? ' ' + attributes : '') + '>' + env.content + ''; + +}; + +if (!_self.document) { + if (!_self.addEventListener) { + // in Node.js + return _self.Prism; + } + + if (!_.disableWorkerMessageHandler) { + // In worker + _self.addEventListener('message', function (evt) { + var message = JSON.parse(evt.data), + lang = message.language, + code = message.code, + immediateClose = message.immediateClose; + + _self.postMessage(_.highlight(code, _.languages[lang], lang)); + if (immediateClose) { + _self.close(); + } + }, false); + } + + return _self.Prism; +} + +//Get current script and highlight +var script = document.currentScript || [].slice.call(document.getElementsByTagName("script")).pop(); + +if (script) { + _.filename = script.src; + + if (!_.manual && !script.hasAttribute('data-manual')) { + if(document.readyState !== "loading") { + if (window.requestAnimationFrame) { + window.requestAnimationFrame(_.highlightAll); + } else { + window.setTimeout(_.highlightAll, 16); + } + } + else { + document.addEventListener('DOMContentLoaded', _.highlightAll); + } + } +} + +return _self.Prism; + +})(); + +if (typeof module !== 'undefined' && module.exports) { + module.exports = Prism; +} + +// hack for components to work correctly in node.js +if (typeof global !== 'undefined') { + global.Prism = Prism; +} +; +Prism.languages.markup = { + 'comment': //, + 'prolog': /<\?[\s\S]+?\?>/, + 'doctype': //i, + 'cdata': //i, + 'tag': { + pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i, + greedy: true, + inside: { + 'tag': { + pattern: /^<\/?[^\s>\/]+/i, + inside: { + 'punctuation': /^<\/?/, + 'namespace': /^[^\s>\/:]+:/ + } + }, + 'attr-value': { + pattern: /=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i, + inside: { + 'punctuation': [ + /^=/, + { + pattern: /(^|[^\\])["']/, + lookbehind: true + } + ] + } + }, + 'punctuation': /\/?>/, + 'attr-name': { + pattern: /[^\s>\/]+/, + inside: { + 'namespace': /^[^\s>\/:]+:/ + } + } + + } + }, + 'entity': /&#?[\da-z]{1,8};/i +}; + +Prism.languages.markup['tag'].inside['attr-value'].inside['entity'] = + Prism.languages.markup['entity']; + +// Plugin to make entity title show the real entity, idea by Roman Komarov +Prism.hooks.add('wrap', function(env) { + + if (env.type === 'entity') { + env.attributes['title'] = env.content.replace(/&/, '&'); + } +}); + +Prism.languages.xml = Prism.languages.markup; +Prism.languages.html = Prism.languages.markup; +Prism.languages.mathml = Prism.languages.markup; +Prism.languages.svg = Prism.languages.markup; + +Prism.languages.css = { + 'comment': /\/\*[\s\S]*?\*\//, + 'atrule': { + pattern: /@[\w-]+?.*?(?:;|(?=\s*\{))/i, + inside: { + 'rule': /@[\w-]+/ + // See rest below + } + }, + 'url': /url\((?:(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|.*?)\)/i, + 'selector': /[^{}\s][^{};]*?(?=\s*\{)/, + 'string': { + pattern: /("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, + greedy: true + }, + 'property': /[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i, + 'important': /\B!important\b/i, + 'function': /[-a-z0-9]+(?=\()/i, + 'punctuation': /[(){};:]/ +}; + +Prism.languages.css['atrule'].inside.rest = Prism.languages.css; + +if (Prism.languages.markup) { + Prism.languages.insertBefore('markup', 'tag', { + 'style': { + pattern: /()[\s\S]*?(?=<\/style>)/i, + lookbehind: true, + inside: Prism.languages.css, + alias: 'language-css', + greedy: true + } + }); + + Prism.languages.insertBefore('inside', 'attr-value', { + 'style-attr': { + pattern: /\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i, + inside: { + 'attr-name': { + pattern: /^\s*style/i, + inside: Prism.languages.markup.tag.inside + }, + 'punctuation': /^\s*=\s*['"]|['"]\s*$/, + 'attr-value': { + pattern: /.+/i, + inside: Prism.languages.css + } + }, + alias: 'language-css' + } + }, Prism.languages.markup.tag); +}; +Prism.languages.clike = { + 'comment': [ + { + pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, + lookbehind: true + }, + { + pattern: /(^|[^\\:])\/\/.*/, + lookbehind: true, + greedy: true + } + ], + 'string': { + pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, + greedy: true + }, + 'class-name': { + pattern: /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i, + lookbehind: true, + inside: { + punctuation: /[.\\]/ + } + }, + 'keyword': /\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/, + 'boolean': /\b(?:true|false)\b/, + 'function': /[a-z0-9_]+(?=\()/i, + 'number': /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i, + 'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/, + 'punctuation': /[{}[\];(),.:]/ +}; + +Prism.languages.javascript = Prism.languages.extend('clike', { + 'keyword': /\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/, + 'number': /\b(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/, + // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444) + 'function': /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/i, + 'operator': /-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/ +}); + +Prism.languages.insertBefore('javascript', 'keyword', { + 'regex': { + pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[[^\]\r\n]+]|\\.|[^/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})\]]))/, + lookbehind: true, + greedy: true + }, + // This must be declared before keyword because we use "function" inside the look-forward + 'function-variable': { + pattern: /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=\s*(?:function\b|(?:\([^()]*\)|[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/i, + alias: 'function' + }, + 'constant': /\b[A-Z][A-Z\d_]*\b/ +}); + +Prism.languages.insertBefore('javascript', 'string', { + 'template-string': { + pattern: /`(?:\\[\s\S]|\${[^}]+}|[^\\`])*`/, + greedy: true, + inside: { + 'interpolation': { + pattern: /\${[^}]+}/, + inside: { + 'interpolation-punctuation': { + pattern: /^\${|}$/, + alias: 'punctuation' + }, + rest: null // See below + } + }, + 'string': /[\s\S]+/ + } + } +}); +Prism.languages.javascript['template-string'].inside['interpolation'].inside.rest = Prism.languages.javascript; + +if (Prism.languages.markup) { + Prism.languages.insertBefore('markup', 'tag', { + 'script': { + pattern: /()[\s\S]*?(?=<\/script>)/i, + lookbehind: true, + inside: Prism.languages.javascript, + alias: 'language-javascript', + greedy: true + } + }); +} + +Prism.languages.js = Prism.languages.javascript; + +Prism.languages.c = Prism.languages.extend('clike', { + 'keyword': /\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/, + 'operator': /-[>-]?|\+\+?|!=?|<>?=?|==?|&&?|\|\|?|[~^%?*\/]/, + 'number': /(?:\b0x[\da-f]+|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?)[ful]*/i +}); + +Prism.languages.insertBefore('c', 'string', { + 'macro': { + // allow for multiline macro definitions + // spaces after the # character compile fine with gcc + pattern: /(^\s*)#\s*[a-z]+(?:[^\r\n\\]|\\(?:\r\n|[\s\S]))*/im, + lookbehind: true, + alias: 'property', + inside: { + // highlight the path of the include statement as a string + 'string': { + pattern: /(#\s*include\s*)(?:<.+?>|("|')(?:\\?.)+?\2)/, + lookbehind: true + }, + // highlight macro directives as keywords + 'directive': { + pattern: /(#\s*)\b(?:define|defined|elif|else|endif|error|ifdef|ifndef|if|import|include|line|pragma|undef|using)\b/, + lookbehind: true, + alias: 'keyword' + } + } + }, + // highlight predefined macros as constants + 'constant': /\b(?:__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\b/ +}); + +delete Prism.languages.c['class-name']; +delete Prism.languages.c['boolean']; + +Prism.languages.csharp = Prism.languages.extend('clike', { + 'keyword': /\b(?:abstract|add|alias|as|ascending|async|await|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|descending|do|double|dynamic|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|from|get|global|goto|group|if|implicit|in|int|interface|internal|into|is|join|let|lock|long|namespace|new|null|object|operator|orderby|out|override|params|partial|private|protected|public|readonly|ref|remove|return|sbyte|sealed|select|set|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|value|var|virtual|void|volatile|where|while|yield)\b/, + 'string': [ + { + pattern: /@("|')(?:\1\1|\\[\s\S]|(?!\1)[^\\])*\1/, + greedy: true + }, + { + pattern: /("|')(?:\\.|(?!\1)[^\\\r\n])*?\1/, + greedy: true + } + ], + 'class-name': [ + { + // (Foo bar, Bar baz) + pattern: /\b[A-Z]\w*(?:\.\w+)*\b(?=\s+\w+)/, + inside: { + punctuation: /\./ + } + }, + { + // [Foo] + pattern: /(\[)[A-Z]\w*(?:\.\w+)*\b/, + lookbehind: true, + inside: { + punctuation: /\./ + } + }, + { + // class Foo : Bar + pattern: /(\b(?:class|interface)\s+[A-Z]\w*(?:\.\w+)*\s*:\s*)[A-Z]\w*(?:\.\w+)*\b/, + lookbehind: true, + inside: { + punctuation: /\./ + } + }, + { + // class Foo + pattern: /((?:\b(?:class|interface|new)\s+)|(?:catch\s+\())[A-Z]\w*(?:\.\w+)*\b/, + lookbehind: true, + inside: { + punctuation: /\./ + } + } + ], + 'number': /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)f?/i +}); + +Prism.languages.insertBefore('csharp', 'class-name', { + 'generic-method': { + pattern: /\w+\s*<[^>\r\n]+?>\s*(?=\()/, + inside: { + function: /^\w+/, + 'class-name': { + pattern: /\b[A-Z]\w*(?:\.\w+)*\b/, + inside: { + punctuation: /\./ + } + }, + keyword: Prism.languages.csharp.keyword, + punctuation: /[<>(),.:]/ + } + }, + 'preprocessor': { + pattern: /(^\s*)#.*/m, + lookbehind: true, + alias: 'property', + inside: { + // highlight preprocessor directives as keywords + 'directive': { + pattern: /(\s*#)\b(?:define|elif|else|endif|endregion|error|if|line|pragma|region|undef|warning)\b/, + lookbehind: true, + alias: 'keyword' + } + } + } +}); + +Prism.languages.dotnet = Prism.languages.csharp; +(function(Prism) { + var insideString = { + variable: [ + // Arithmetic Environment + { + pattern: /\$?\(\([\s\S]+?\)\)/, + inside: { + // If there is a $ sign at the beginning highlight $(( and )) as variable + variable: [{ + pattern: /(^\$\(\([\s\S]+)\)\)/, + lookbehind: true + }, + /^\$\(\(/ + ], + number: /\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/, + // Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic + operator: /--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/, + // If there is no $ sign at the beginning highlight (( and )) as punctuation + punctuation: /\(\(?|\)\)?|,|;/ + } + }, + // Command Substitution + { + pattern: /\$\([^)]+\)|`[^`]+`/, + greedy: true, + inside: { + variable: /^\$\(|^`|\)$|`$/ + } + }, + /\$(?:[\w#?*!@]+|\{[^}]+\})/i + ] + }; + + Prism.languages.bash = { + 'shebang': { + pattern: /^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/, + alias: 'important' + }, + 'comment': { + pattern: /(^|[^"{\\])#.*/, + lookbehind: true + }, + 'string': [ + //Support for Here-Documents https://en.wikipedia.org/wiki/Here_document + { + pattern: /((?:^|[^<])<<\s*)["']?(\w+?)["']?\s*\r?\n(?:[\s\S])*?\r?\n\2/, + lookbehind: true, + greedy: true, + inside: insideString + }, + { + pattern: /(["'])(?:\\[\s\S]|\$\([^)]+\)|`[^`]+`|(?!\1)[^\\])*\1/, + greedy: true, + inside: insideString + } + ], + 'variable': insideString.variable, + // Originally based on http://ss64.com/bash/ + 'function': { + pattern: /(^|[\s;|&])(?:alias|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|npm|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)(?=$|[\s;|&])/, + lookbehind: true + }, + 'keyword': { + pattern: /(^|[\s;|&])(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|[\s;|&])/, + lookbehind: true + }, + 'boolean': { + pattern: /(^|[\s;|&])(?:true|false)(?=$|[\s;|&])/, + lookbehind: true + }, + 'operator': /&&?|\|\|?|==?|!=?|<<>|<=?|>=?|=~/, + 'punctuation': /\$?\(\(?|\)\)?|\.\.|[{}[\];]/ + }; + + var inside = insideString.variable[1].inside; + inside.string = Prism.languages.bash.string; + inside['function'] = Prism.languages.bash['function']; + inside.keyword = Prism.languages.bash.keyword; + inside['boolean'] = Prism.languages.bash['boolean']; + inside.operator = Prism.languages.bash.operator; + inside.punctuation = Prism.languages.bash.punctuation; + + Prism.languages.shell = Prism.languages.bash; +})(Prism); + +Prism.languages['markup-templating'] = {}; + +Object.defineProperties(Prism.languages['markup-templating'], { + buildPlaceholders: { + // Tokenize all inline templating expressions matching placeholderPattern + // If the replaceFilter function is provided, it will be called with every match. + // If it returns false, the match will not be replaced. + value: function (env, language, placeholderPattern, replaceFilter) { + if (env.language !== language) { + return; + } + + env.tokenStack = []; + + env.code = env.code.replace(placeholderPattern, function(match) { + if (typeof replaceFilter === 'function' && !replaceFilter(match)) { + return match; + } + var i = env.tokenStack.length; + // Check for existing strings + while (env.code.indexOf('___' + language.toUpperCase() + i + '___') !== -1) + ++i; + + // Create a sparse array + env.tokenStack[i] = match; + + return '___' + language.toUpperCase() + i + '___'; + }); + + // Switch the grammar to markup + env.grammar = Prism.languages.markup; + } + }, + tokenizePlaceholders: { + // Replace placeholders with proper tokens after tokenizing + value: function (env, language) { + if (env.language !== language || !env.tokenStack) { + return; + } + + // Switch the grammar back + env.grammar = Prism.languages[language]; + + var j = 0; + var keys = Object.keys(env.tokenStack); + var walkTokens = function (tokens) { + if (j >= keys.length) { + return; + } + for (var i = 0; i < tokens.length; i++) { + var token = tokens[i]; + if (typeof token === 'string' || (token.content && typeof token.content === 'string')) { + var k = keys[j]; + var t = env.tokenStack[k]; + var s = typeof token === 'string' ? token : token.content; + + var index = s.indexOf('___' + language.toUpperCase() + k + '___'); + if (index > -1) { + ++j; + var before = s.substring(0, index); + var middle = new Prism.Token(language, Prism.tokenize(t, env.grammar, language), 'language-' + language, t); + var after = s.substring(index + ('___' + language.toUpperCase() + k + '___').length); + var replacement; + if (before || after) { + replacement = [before, middle, after].filter(function (v) { return !!v; }); + walkTokens(replacement); + } else { + replacement = middle; + } + if (typeof token === 'string') { + Array.prototype.splice.apply(tokens, [i, 1].concat(replacement)); + } else { + token.content = replacement; + } + + if (j >= keys.length) { + break; + } + } + } else if (token.content && typeof token.content !== 'string') { + walkTokens(token.content); + } + } + }; + + walkTokens(env.tokens); + } + } +}); +Prism.languages.git = { + /* + * A simple one line comment like in a git status command + * For instance: + * $ git status + * # On branch infinite-scroll + * # Your branch and 'origin/sharedBranches/frontendTeam/infinite-scroll' have diverged, + * # and have 1 and 2 different commits each, respectively. + * nothing to commit (working directory clean) + */ + 'comment': /^#.*/m, + + /* + * Regexp to match the changed lines in a git diff output. Check the example below. + */ + 'deleted': /^[-–].*/m, + 'inserted': /^\+.*/m, + + /* + * a string (double and simple quote) + */ + 'string': /("|')(?:\\.|(?!\1)[^\\\r\n])*\1/m, + + /* + * a git command. It starts with a random prompt finishing by a $, then "git" then some other parameters + * For instance: + * $ git add file.txt + */ + 'command': { + pattern: /^.*\$ git .*$/m, + inside: { + /* + * A git command can contain a parameter starting by a single or a double dash followed by a string + * For instance: + * $ git diff --cached + * $ git log -p + */ + 'parameter': /\s--?\w+/m + } + }, + + /* + * Coordinates displayed in a git diff command + * For instance: + * $ git diff + * diff --git file.txt file.txt + * index 6214953..1d54a52 100644 + * --- file.txt + * +++ file.txt + * @@ -1 +1,2 @@ + * -Here's my tetx file + * +Here's my text file + * +And this is the second line + */ + 'coord': /^@@.*@@$/m, + + /* + * Match a "commit [SHA1]" line in a git log output. + * For instance: + * $ git log + * commit a11a14ef7e26f2ca62d4b35eac455ce636d0dc09 + * Author: lgiraudel + * Date: Mon Feb 17 11:18:34 2014 +0100 + * + * Add of a new line + */ + 'commit_sha1': /^commit \w{40}$/m +}; + +Prism.languages.ini= { + 'comment': /^[ \t]*;.*$/m, + 'selector': /^[ \t]*\[.*?\]/m, + 'constant': /^[ \t]*[^\s=]+?(?=[ \t]*=)/m, + 'attr-value': { + pattern: /=.*/, + inside: { + 'punctuation': /^[=]/ + } + } +}; +Prism.languages.java = Prism.languages.extend('clike', { + 'keyword': /\b(?:abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)\b/, + 'number': /\b0b[01]+\b|\b0x[\da-f]*\.?[\da-fp-]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?[df]?/i, + 'operator': { + pattern: /(^|[^.])(?:\+[+=]?|-[-=]?|!=?|<>?>?=?|==?|&[&=]?|\|[|=]?|\*=?|\/=?|%=?|\^=?|[?:~])/m, + lookbehind: true + } +}); + +Prism.languages.insertBefore('java','function', { + 'annotation': { + alias: 'punctuation', + pattern: /(^|[^.])@\w+/, + lookbehind: true + } +}); + +Prism.languages.insertBefore('java', 'class-name', { + 'generics': { + pattern: /<\s*\w+(?:\.\w+)?(?:\s*,\s*\w+(?:\.\w+)?)*>/i, + alias: 'function', + inside: { + keyword: Prism.languages.java.keyword, + punctuation: /[<>(),.:]/ + } + } +}); + +Prism.languages.json = { + 'property': /"(?:\\.|[^\\"\r\n])*"(?=\s*:)/i, + 'string': { + pattern: /"(?:\\.|[^\\"\r\n])*"(?!\s*:)/, + greedy: true + }, + 'number': /-?\d+\.?\d*([Ee][+-]?\d+)?/, + 'punctuation': /[{}[\],]/, + 'operator': /:/g, + 'boolean': /\b(?:true|false)\b/i, + 'null': /\bnull\b/i +}; + +Prism.languages.jsonp = Prism.languages.json; + +Prism.languages.markdown = Prism.languages.extend('markup', {}); +Prism.languages.insertBefore('markdown', 'prolog', { + 'blockquote': { + // > ... + pattern: /^>(?:[\t ]*>)*/m, + alias: 'punctuation' + }, + 'code': [ + { + // Prefixed by 4 spaces or 1 tab + pattern: /^(?: {4}|\t).+/m, + alias: 'keyword' + }, + { + // `code` + // ``code`` + pattern: /``.+?``|`[^`\n]+`/, + alias: 'keyword' + } + ], + 'title': [ + { + // title 1 + // ======= + + // title 2 + // ------- + pattern: /\w+.*(?:\r?\n|\r)(?:==+|--+)/, + alias: 'important', + inside: { + punctuation: /==+$|--+$/ + } + }, + { + // # title 1 + // ###### title 6 + pattern: /(^\s*)#+.+/m, + lookbehind: true, + alias: 'important', + inside: { + punctuation: /^#+|#+$/ + } + } + ], + 'hr': { + // *** + // --- + // * * * + // ----------- + pattern: /(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m, + lookbehind: true, + alias: 'punctuation' + }, + 'list': { + // * item + // + item + // - item + // 1. item + pattern: /(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m, + lookbehind: true, + alias: 'punctuation' + }, + 'url-reference': { + // [id]: http://example.com "Optional title" + // [id]: http://example.com 'Optional title' + // [id]: http://example.com (Optional title) + // [id]: "Optional title" + pattern: /!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/, + inside: { + 'variable': { + pattern: /^(!?\[)[^\]]+/, + lookbehind: true + }, + 'string': /(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/, + 'punctuation': /^[\[\]!:]|[<>]/ + }, + alias: 'url' + }, + 'bold': { + // **strong** + // __strong__ + + // Allow only one line break + pattern: /(^|[^\\])(\*\*|__)(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/, + lookbehind: true, + inside: { + 'punctuation': /^\*\*|^__|\*\*$|__$/ + } + }, + 'italic': { + // *em* + // _em_ + + // Allow only one line break + pattern: /(^|[^\\])([*_])(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/, + lookbehind: true, + inside: { + 'punctuation': /^[*_]|[*_]$/ + } + }, + 'url': { + // [example](http://example.com "Optional title") + // [example] [id] + pattern: /!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)| ?\[[^\]\n]*\])/, + inside: { + 'variable': { + pattern: /(!?\[)[^\]]+(?=\]$)/, + lookbehind: true + }, + 'string': { + pattern: /"(?:\\.|[^"\\])*"(?=\)$)/ + } + } + } +}); + +Prism.languages.markdown['bold'].inside['url'] = Prism.languages.markdown['url']; +Prism.languages.markdown['italic'].inside['url'] = Prism.languages.markdown['url']; +Prism.languages.markdown['bold'].inside['italic'] = Prism.languages.markdown['italic']; +Prism.languages.markdown['italic'].inside['bold'] = Prism.languages.markdown['bold']; +Prism.languages.makefile = { + 'comment': { + pattern: /(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/, + lookbehind: true + }, + 'string': { + pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, + greedy: true + }, + + // Built-in target names + 'builtin': /\.[A-Z][^:#=\s]+(?=\s*:(?!=))/, + + // Targets + 'symbol': { + pattern: /^[^:=\r\n]+(?=\s*:(?!=))/m, + inside: { + 'variable': /\$+(?:[^(){}:#=\s]+|(?=[({]))/ + } + }, + 'variable': /\$+(?:[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/, + + 'keyword': [ + // Directives + /-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/, + // Functions + { + pattern: /(\()(?:addsuffix|abspath|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:s|list)?)(?=[ \t])/, + lookbehind: true + } + ], + 'operator': /(?:::|[?:+!])?=|[|@]/, + 'punctuation': /[:;(){}]/ +}; +Prism.languages.nginx = Prism.languages.extend('clike', { + 'comment': { + pattern: /(^|[^"{\\])#.*/, + lookbehind: true + }, + 'keyword': /\b(?:CONTENT_|DOCUMENT_|GATEWAY_|HTTP_|HTTPS|if_not_empty|PATH_|QUERY_|REDIRECT_|REMOTE_|REQUEST_|SCGI|SCRIPT_|SERVER_|http|events|accept_mutex|accept_mutex_delay|access_log|add_after_body|add_before_body|add_header|addition_types|aio|alias|allow|ancient_browser|ancient_browser_value|auth|auth_basic|auth_basic_user_file|auth_http|auth_http_header|auth_http_timeout|autoindex|autoindex_exact_size|autoindex_localtime|break|charset|charset_map|charset_types|chunked_transfer_encoding|client_body_buffer_size|client_body_in_file_only|client_body_in_single_buffer|client_body_temp_path|client_body_timeout|client_header_buffer_size|client_header_timeout|client_max_body_size|connection_pool_size|create_full_put_path|daemon|dav_access|dav_methods|debug_connection|debug_points|default_type|deny|devpoll_changes|devpoll_events|directio|directio_alignment|disable_symlinks|empty_gif|env|epoll_events|error_log|error_page|expires|fastcgi_buffer_size|fastcgi_buffers|fastcgi_busy_buffers_size|fastcgi_cache|fastcgi_cache_bypass|fastcgi_cache_key|fastcgi_cache_lock|fastcgi_cache_lock_timeout|fastcgi_cache_methods|fastcgi_cache_min_uses|fastcgi_cache_path|fastcgi_cache_purge|fastcgi_cache_use_stale|fastcgi_cache_valid|fastcgi_connect_timeout|fastcgi_hide_header|fastcgi_ignore_client_abort|fastcgi_ignore_headers|fastcgi_index|fastcgi_intercept_errors|fastcgi_keep_conn|fastcgi_max_temp_file_size|fastcgi_next_upstream|fastcgi_no_cache|fastcgi_param|fastcgi_pass|fastcgi_pass_header|fastcgi_read_timeout|fastcgi_redirect_errors|fastcgi_send_timeout|fastcgi_split_path_info|fastcgi_store|fastcgi_store_access|fastcgi_temp_file_write_size|fastcgi_temp_path|flv|geo|geoip_city|geoip_country|google_perftools_profiles|gzip|gzip_buffers|gzip_comp_level|gzip_disable|gzip_http_version|gzip_min_length|gzip_proxied|gzip_static|gzip_types|gzip_vary|if|if_modified_since|ignore_invalid_headers|image_filter|image_filter_buffer|image_filter_jpeg_quality|image_filter_sharpen|image_filter_transparency|imap_capabilities|imap_client_buffer|include|index|internal|ip_hash|keepalive|keepalive_disable|keepalive_requests|keepalive_timeout|kqueue_changes|kqueue_events|large_client_header_buffers|limit_conn|limit_conn_log_level|limit_conn_zone|limit_except|limit_rate|limit_rate_after|limit_req|limit_req_log_level|limit_req_zone|limit_zone|lingering_close|lingering_time|lingering_timeout|listen|location|lock_file|log_format|log_format_combined|log_not_found|log_subrequest|map|map_hash_bucket_size|map_hash_max_size|master_process|max_ranges|memcached_buffer_size|memcached_connect_timeout|memcached_next_upstream|memcached_pass|memcached_read_timeout|memcached_send_timeout|merge_slashes|min_delete_depth|modern_browser|modern_browser_value|mp4|mp4_buffer_size|mp4_max_buffer_size|msie_padding|msie_refresh|multi_accept|open_file_cache|open_file_cache_errors|open_file_cache_min_uses|open_file_cache_valid|open_log_file_cache|optimize_server_names|override_charset|pcre_jit|perl|perl_modules|perl_require|perl_set|pid|pop3_auth|pop3_capabilities|port_in_redirect|post_action|postpone_output|protocol|proxy|proxy_buffer|proxy_buffer_size|proxy_buffering|proxy_buffers|proxy_busy_buffers_size|proxy_cache|proxy_cache_bypass|proxy_cache_key|proxy_cache_lock|proxy_cache_lock_timeout|proxy_cache_methods|proxy_cache_min_uses|proxy_cache_path|proxy_cache_use_stale|proxy_cache_valid|proxy_connect_timeout|proxy_cookie_domain|proxy_cookie_path|proxy_headers_hash_bucket_size|proxy_headers_hash_max_size|proxy_hide_header|proxy_http_version|proxy_ignore_client_abort|proxy_ignore_headers|proxy_intercept_errors|proxy_max_temp_file_size|proxy_method|proxy_next_upstream|proxy_no_cache|proxy_pass|proxy_pass_error_message|proxy_pass_header|proxy_pass_request_body|proxy_pass_request_headers|proxy_read_timeout|proxy_redirect|proxy_redirect_errors|proxy_send_lowat|proxy_send_timeout|proxy_set_body|proxy_set_header|proxy_ssl_session_reuse|proxy_store|proxy_store_access|proxy_temp_file_write_size|proxy_temp_path|proxy_timeout|proxy_upstream_fail_timeout|proxy_upstream_max_fails|random_index|read_ahead|real_ip_header|recursive_error_pages|request_pool_size|reset_timedout_connection|resolver|resolver_timeout|return|rewrite|root|rtsig_overflow_events|rtsig_overflow_test|rtsig_overflow_threshold|rtsig_signo|satisfy|satisfy_any|secure_link_secret|send_lowat|send_timeout|sendfile|sendfile_max_chunk|server|server_name|server_name_in_redirect|server_names_hash_bucket_size|server_names_hash_max_size|server_tokens|set|set_real_ip_from|smtp_auth|smtp_capabilities|so_keepalive|source_charset|split_clients|ssi|ssi_silent_errors|ssi_types|ssi_value_length|ssl|ssl_certificate|ssl_certificate_key|ssl_ciphers|ssl_client_certificate|ssl_crl|ssl_dhparam|ssl_engine|ssl_prefer_server_ciphers|ssl_protocols|ssl_session_cache|ssl_session_timeout|ssl_verify_client|ssl_verify_depth|starttls|stub_status|sub_filter|sub_filter_once|sub_filter_types|tcp_nodelay|tcp_nopush|timeout|timer_resolution|try_files|types|types_hash_bucket_size|types_hash_max_size|underscores_in_headers|uninitialized_variable_warn|upstream|use|user|userid|userid_domain|userid_expires|userid_name|userid_p3p|userid_path|userid_service|valid_referers|variables_hash_bucket_size|variables_hash_max_size|worker_connections|worker_cpu_affinity|worker_priority|worker_processes|worker_rlimit_core|worker_rlimit_nofile|worker_rlimit_sigpending|working_directory|xclient|xml_entities|xslt_entities|xslt_stylesheet|xslt_types)\b/i +}); + +Prism.languages.insertBefore('nginx', 'keyword', { + 'variable': /\$[a-z_]+/i +}); +Prism.languages.perl = { + 'comment': [ + { + // POD + pattern: /(^\s*)=\w+[\s\S]*?=cut.*/m, + lookbehind: true + }, + { + pattern: /(^|[^\\$])#.*/, + lookbehind: true + } + ], + // TODO Could be nice to handle Heredoc too. + 'string': [ + // q/.../ + { + pattern: /\b(?:q|qq|qx|qw)\s*([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/, + greedy: true + }, + + // q a...a + { + pattern: /\b(?:q|qq|qx|qw)\s+([a-zA-Z0-9])(?:(?!\1)[^\\]|\\[\s\S])*\1/, + greedy: true + }, + + // q(...) + { + pattern: /\b(?:q|qq|qx|qw)\s*\((?:[^()\\]|\\[\s\S])*\)/, + greedy: true + }, + + // q{...} + { + pattern: /\b(?:q|qq|qx|qw)\s*\{(?:[^{}\\]|\\[\s\S])*\}/, + greedy: true + }, + + // q[...] + { + pattern: /\b(?:q|qq|qx|qw)\s*\[(?:[^[\]\\]|\\[\s\S])*\]/, + greedy: true + }, + + // q<...> + { + pattern: /\b(?:q|qq|qx|qw)\s*<(?:[^<>\\]|\\[\s\S])*>/, + greedy: true + }, + + // "...", `...` + { + pattern: /("|`)(?:(?!\1)[^\\]|\\[\s\S])*\1/, + greedy: true + }, + + // '...' + // FIXME Multi-line single-quoted strings are not supported as they would break variables containing ' + { + pattern: /'(?:[^'\\\r\n]|\\.)*'/, + greedy: true + } + ], + 'regex': [ + // m/.../ + { + pattern: /\b(?:m|qr)\s*([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1[msixpodualngc]*/, + greedy: true + }, + + // m a...a + { + pattern: /\b(?:m|qr)\s+([a-zA-Z0-9])(?:(?!\1)[^\\]|\\[\s\S])*\1[msixpodualngc]*/, + greedy: true + }, + + // m(...) + { + pattern: /\b(?:m|qr)\s*\((?:[^()\\]|\\[\s\S])*\)[msixpodualngc]*/, + greedy: true + }, + + // m{...} + { + pattern: /\b(?:m|qr)\s*\{(?:[^{}\\]|\\[\s\S])*\}[msixpodualngc]*/, + greedy: true + }, + + // m[...] + { + pattern: /\b(?:m|qr)\s*\[(?:[^[\]\\]|\\[\s\S])*\][msixpodualngc]*/, + greedy: true + }, + + // m<...> + { + pattern: /\b(?:m|qr)\s*<(?:[^<>\\]|\\[\s\S])*>[msixpodualngc]*/, + greedy: true + }, + + // The lookbehinds prevent -s from breaking + // FIXME We don't handle change of separator like s(...)[...] + // s/.../.../ + { + pattern: /(^|[^-]\b)(?:s|tr|y)\s*([^a-zA-Z0-9\s{(\[<])(?:(?!\2)[^\\]|\\[\s\S])*\2(?:(?!\2)[^\\]|\\[\s\S])*\2[msixpodualngcer]*/, + lookbehind: true, + greedy: true + }, + + // s a...a...a + { + pattern: /(^|[^-]\b)(?:s|tr|y)\s+([a-zA-Z0-9])(?:(?!\2)[^\\]|\\[\s\S])*\2(?:(?!\2)[^\\]|\\[\s\S])*\2[msixpodualngcer]*/, + lookbehind: true, + greedy: true + }, + + // s(...)(...) + { + pattern: /(^|[^-]\b)(?:s|tr|y)\s*\((?:[^()\\]|\\[\s\S])*\)\s*\((?:[^()\\]|\\[\s\S])*\)[msixpodualngcer]*/, + lookbehind: true, + greedy: true + }, + + // s{...}{...} + { + pattern: /(^|[^-]\b)(?:s|tr|y)\s*\{(?:[^{}\\]|\\[\s\S])*\}\s*\{(?:[^{}\\]|\\[\s\S])*\}[msixpodualngcer]*/, + lookbehind: true, + greedy: true + }, + + // s[...][...] + { + pattern: /(^|[^-]\b)(?:s|tr|y)\s*\[(?:[^[\]\\]|\\[\s\S])*\]\s*\[(?:[^[\]\\]|\\[\s\S])*\][msixpodualngcer]*/, + lookbehind: true, + greedy: true + }, + + // s<...><...> + { + pattern: /(^|[^-]\b)(?:s|tr|y)\s*<(?:[^<>\\]|\\[\s\S])*>\s*<(?:[^<>\\]|\\[\s\S])*>[msixpodualngcer]*/, + lookbehind: true, + greedy: true + }, + + // /.../ + // The look-ahead tries to prevent two divisions on + // the same line from being highlighted as regex. + // This does not support multi-line regex. + { + pattern: /\/(?:[^\/\\\r\n]|\\.)*\/[msixpodualngc]*(?=\s*(?:$|[\r\n,.;})&|\-+*~<>!?^]|(lt|gt|le|ge|eq|ne|cmp|not|and|or|xor|x)\b))/, + greedy: true + } + ], + + // FIXME Not sure about the handling of ::, ', and # + 'variable': [ + // ${^POSTMATCH} + /[&*$@%]\{\^[A-Z]+\}/, + // $^V + /[&*$@%]\^[A-Z_]/, + // ${...} + /[&*$@%]#?(?=\{)/, + // $foo + /[&*$@%]#?(?:(?:::)*'?(?!\d)[\w$]+)+(?:::)*/i, + // $1 + /[&*$@%]\d+/, + // $_, @_, %! + // The negative lookahead prevents from breaking the %= operator + /(?!%=)[$@%][!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~]/ + ], + 'filehandle': { + // <>, , _ + pattern: /<(?![<=])\S*>|\b_\b/, + alias: 'symbol' + }, + 'vstring': { + // v1.2, 1.2.3 + pattern: /v\d+(?:\.\d+)*|\d+(?:\.\d+){2,}/, + alias: 'string' + }, + 'function': { + pattern: /sub [a-z0-9_]+/i, + inside: { + keyword: /sub/ + } + }, + 'keyword': /\b(?:any|break|continue|default|delete|die|do|else|elsif|eval|for|foreach|given|goto|if|last|local|my|next|our|package|print|redo|require|say|state|sub|switch|undef|unless|until|use|when|while)\b/, + 'number': /\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0b[01](?:_?[01])*|(?:\d(?:_?\d)*)?\.?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)\b/, + 'operator': /-[rwxoRWXOezsfdlpSbctugkTBMAC]\b|\+[+=]?|-[-=>]?|\*\*?=?|\/\/?=?|=[=~>]?|~[~=]?|\|\|?=?|&&?=?|<(?:=>?|<=?)?|>>?=?|![~=]?|[%^]=?|\.(?:=|\.\.?)?|[\\?]|\bx(?:=|\b)|\b(?:lt|gt|le|ge|eq|ne|cmp|not|and|or|xor)\b/, + 'punctuation': /[{}[\];(),:]/ +}; + +/** + * Original by Aaron Harun: http://aahacreative.com/2012/07/31/php-syntax-highlighting-prism/ + * Modified by Miles Johnson: http://milesj.me + * + * Supports the following: + * - Extends clike syntax + * - Support for PHP 5.3+ (namespaces, traits, generators, etc) + * - Smarter constant and function matching + * + * Adds the following new token classes: + * constant, delimiter, variable, function, package + */ +(function (Prism) { + Prism.languages.php = Prism.languages.extend('clike', { + 'keyword': /\b(?:and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/i, + 'constant': /\b[A-Z0-9_]{2,}\b/, + 'comment': { + pattern: /(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/, + lookbehind: true + } + }); + + Prism.languages.insertBefore('php', 'string', { + 'shell-comment': { + pattern: /(^|[^\\])#.*/, + lookbehind: true, + alias: 'comment' + } + }); + + Prism.languages.insertBefore('php', 'keyword', { + 'delimiter': { + pattern: /\?>|<\?(?:php|=)?/i, + alias: 'important' + }, + 'variable': /\$+(?:\w+\b|(?={))/i, + 'package': { + pattern: /(\\|namespace\s+|use\s+)[\w\\]+/, + lookbehind: true, + inside: { + punctuation: /\\/ + } + } + }); + + // Must be defined after the function pattern + Prism.languages.insertBefore('php', 'operator', { + 'property': { + pattern: /(->)[\w]+/, + lookbehind: true + } + }); + + Prism.languages.insertBefore('php', 'string', { + 'nowdoc-string': { + pattern: /<<<'([^']+)'(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\1;/, + greedy: true, + alias: 'string', + inside: { + 'delimiter': { + pattern: /^<<<'[^']+'|[a-z_]\w*;$/i, + alias: 'symbol', + inside: { + 'punctuation': /^<<<'?|[';]$/ + } + } + } + }, + 'heredoc-string': { + pattern: /<<<(?:"([^"]+)"(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\1;|([a-z_]\w*)(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\2;)/i, + greedy: true, + alias: 'string', + inside: { + 'delimiter': { + pattern: /^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i, + alias: 'symbol', + inside: { + 'punctuation': /^<<<"?|[";]$/ + } + }, + 'interpolation': null // See below + } + }, + 'single-quoted-string': { + pattern: /'(?:\\[\s\S]|[^\\'])*'/, + greedy: true, + alias: 'string' + }, + 'double-quoted-string': { + pattern: /"(?:\\[\s\S]|[^\\"])*"/, + greedy: true, + alias: 'string', + inside: { + 'interpolation': null // See below + } + } + }); + // The different types of PHP strings "replace" the C-like standard string + delete Prism.languages.php['string']; + + var string_interpolation = { + pattern: /{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[.+?]|->\w+)*)/, + lookbehind: true, + inside: { + rest: Prism.languages.php + } + }; + Prism.languages.php['heredoc-string'].inside['interpolation'] = string_interpolation; + Prism.languages.php['double-quoted-string'].inside['interpolation'] = string_interpolation; + + Prism.hooks.add('before-tokenize', function(env) { + if (!/(?:<\?php|<\?)/ig.test(env.code)) { + return; + } + + var phpPattern = /(?:<\?php|<\?)[\s\S]*?(?:\?>|$)/ig; + Prism.languages['markup-templating'].buildPlaceholders(env, 'php', phpPattern); + }); + + Prism.hooks.add('after-tokenize', function(env) { + Prism.languages['markup-templating'].tokenizePlaceholders(env, 'php'); + }); + +}(Prism)); +Prism.languages.sql= { + 'comment': { + pattern: /(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/, + lookbehind: true + }, + 'string' : { + pattern: /(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\])*\2/, + greedy: true, + lookbehind: true + }, + 'variable': /@[\w.$]+|@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/, + 'function': /\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i, // Should we highlight user defined functions too? + 'keyword': /\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:_INSERT|COL)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURNS?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i, + 'boolean': /\b(?:TRUE|FALSE|NULL)\b/i, + 'number': /\b0x[\da-f]+\b|\b\d+\.?\d*|\B\.\d+\b/i, + 'operator': /[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|IN|LIKE|NOT|OR|IS|DIV|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i, + 'punctuation': /[;[\]()`,.]/ +}; +Prism.languages.python = { + 'comment': { + pattern: /(^|[^\\])#.*/, + lookbehind: true + }, + 'triple-quoted-string': { + pattern: /("""|''')[\s\S]+?\1/, + greedy: true, + alias: 'string' + }, + 'string': { + pattern: /("|')(?:\\.|(?!\1)[^\\\r\n])*\1/, + greedy: true + }, + 'function': { + pattern: /((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g, + lookbehind: true + }, + 'class-name': { + pattern: /(\bclass\s+)\w+/i, + lookbehind: true + }, + 'keyword': /\b(?:as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|nonlocal|pass|print|raise|return|try|while|with|yield)\b/, + 'builtin':/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/, + 'boolean': /\b(?:True|False|None)\b/, + 'number': /(?:\b(?=\d)|\B(?=\.))(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i, + 'operator': /[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not)\b/, + 'punctuation': /[{}[\];(),.:]/ +}; + +Prism.languages.yaml = { + 'scalar': { + pattern: /([\-:]\s*(?:![^\s]+)?[ \t]*[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)[^\r\n]+(?:\2[^\r\n]+)*)/, + lookbehind: true, + alias: 'string' + }, + 'comment': /#.*/, + 'key': { + pattern: /(\s*(?:^|[:\-,[{\r\n?])[ \t]*(?:![^\s]+)?[ \t]*)[^\r\n{[\]},#\s]+?(?=\s*:\s)/, + lookbehind: true, + alias: 'atrule' + }, + 'directive': { + pattern: /(^[ \t]*)%.+/m, + lookbehind: true, + alias: 'important' + }, + 'datetime': { + pattern: /([:\-,[{]\s*(?:![^\s]+)?[ \t]*)(?:\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?)?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?)(?=[ \t]*(?:$|,|]|}))/m, + lookbehind: true, + alias: 'number' + }, + 'boolean': { + pattern: /([:\-,[{]\s*(?:![^\s]+)?[ \t]*)(?:true|false)[ \t]*(?=$|,|]|})/im, + lookbehind: true, + alias: 'important' + }, + 'null': { + pattern: /([:\-,[{]\s*(?:![^\s]+)?[ \t]*)(?:null|~)[ \t]*(?=$|,|]|})/im, + lookbehind: true, + alias: 'important' + }, + 'string': { + pattern: /([:\-,[{]\s*(?:![^\s]+)?[ \t]*)("|')(?:(?!\2)[^\\\r\n]|\\.)*\2(?=[ \t]*(?:$|,|]|}))/m, + lookbehind: true, + greedy: true + }, + 'number': { + pattern: /([:\-,[{]\s*(?:![^\s]+)?[ \t]*)[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+\.?\d*|\.?\d+)(?:e[+-]?\d+)?|\.inf|\.nan)[ \t]*(?=$|,|]|})/im, + lookbehind: true + }, + 'tag': /![^\s]+/, + 'important': /[&*][\w]+/, + 'punctuation': /---|[:[\]{}\-,|>?]|\.\.\./ +}; + diff --git a/deploy/nasg/templates/style-alt.css b/deploy/nasg/templates/style-alt.css new file mode 100644 index 0000000..4ee83a3 --- /dev/null +++ b/deploy/nasg/templates/style-alt.css @@ -0,0 +1,64 @@ +body { + color: #000; + background-color: #eee; +} + +a { + color: #3173b4; +} + +a:hover { + color: #014384; + border-bottom: 1px solid #014384; +} + +code, +pre { + color: #006400; +} + +button svg { + transform: rotate(180deg); + transition: all 0.2s; +} + +blockquote { + color: #555; +} + +td, th { + border: 1px solid #111; +} + +th, tr:nth-child(even) { + background-color: rgba(0, 0, 0, .1); +} + +pre > code::before { + color: #444; +} + +.footnotes hr::before { + color: #222; +} + +body > header, +body > footer{ + background-color: #333; + color: #ccc; +} + +body > header a, +body > footer a, +.theme input + label { + color: #71B3F4; +} + +input { + background-color: #222; +} + +body > footer a:hover { + color: #fff; + border-bottom: 1px solid #fff; +} \ No newline at end of file diff --git a/deploy/nasg/templates/style-gallery.css b/deploy/nasg/templates/style-gallery.css new file mode 100644 index 0000000..143f91e --- /dev/null +++ b/deploy/nasg/templates/style-gallery.css @@ -0,0 +1,34 @@ +main.photo { + display: flex; + flex-wrap: wrap; +} + +main.photo article { + max-width: 24em; + margin: 0.6em; + display: grid; + position: relative; +} + +main.photo article figure { + margin: 0; + padding: 0; +} + +main.photo article h2 { + margin: 0; + padding: 0.6em; + background: rgba(0,0,0,0.7); + position: absolute; + top: 50%; + left: 0; + right: 0; + text-align: center; + +} + +main.photo article figcaption, +main.photo article p, +main.photo article section { + display: none; +} \ No newline at end of file diff --git a/deploy/nasg/templates/style-print.css b/deploy/nasg/templates/style-print.css new file mode 100644 index 0000000..446452d --- /dev/null +++ b/deploy/nasg/templates/style-print.css @@ -0,0 +1,90 @@ + +* { + background-color: #fff !important; + color: #222; +} + +html, body { + font-size: 10pt !important; + font-family: Helvetica, sans-serif !important; +} + +@page { + margin: 0.6in 0.5in; +} + +.limit, +body > section { + max-width: 100% !important; + margin: 0 !important; +} + +h1, h2, h3, h4, h5, h6 { + page-break-after: avoid; +} + +h3, +a, +.footnotes a, +.h-feed .h-entry, +code, +pre { + border: none; +} + +p, li, blockquote, figure, .footnotes { + page-break-inside: avoid !important; +} + +a { + color: #000; +} + +td, th { + border: 1pt solid #666; +} + +.footnotes a { + display: block; + overflow: visible; + white-space: normal; + overflow:visible !important; + text-overflow:initial !important; +} + +.footnote-back { + display: none; +} + +body > header, +body > footer, +video, +audio, +.footnote-backref, +.footnote-back, +.encourage, +.noprint { + display:none !important; +} + +code, pre { + max-width: 96%; + page-break-inside: auto; + font-family: "Courier", "Courier New", monospace !important; +} + +pre { + border: 1pt dotted #666; + padding: 0.6em; +} + +.adaptimg { + max-height: 35vh; + max-width: 90vw; + outline: none; + border: 1px solid #000; +} + +.h-feed .h-entry { + page-break-after: always; +} diff --git a/deploy/nasg/templates/style.css b/deploy/nasg/templates/style.css new file mode 100644 index 0000000..34709a6 --- /dev/null +++ b/deploy/nasg/templates/style.css @@ -0,0 +1,358 @@ +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + font-family: "Courier", monospace; + margin: 0; + padding: 0; + line-height: 1.5em; +} + +body { + color: #eee; + background-color: #222; +} + +body > header, +body > footer { + background-color: #111; + text-align: center; + padding: 0.6em 0; +} + +body > main, +body > nav, +body > header > section, +body > footer > section { + max-width: 88ch; + margin: 0 auto; + padding: 0 1em; +} + +hr { + border: none; +} + +dt { + font-weight: bold; +} + +h1, h2, h3, h4, h5, h6, hr, +dt { + margin: 2em 0 0.6em 0; +} + +main p { + margin: 1em 0; +} + +h1 { + border-bottom: 4px double #999; + text-transform:uppercase; + text-align: center; + padding-bottom: 1em; +} + +article > footer > dl > dt, +h2 { + border-bottom: 1px solid #999; +} + +article > footer > dl > dt, +h3, +hr { + border-bottom: 1px dotted #999; +} + +h4 { + border-bottom: 1px dashed #999; +} + +svg { + transform: rotate(0deg); + fill: currentColor; + vertical-align:middle; +} + +body > svg { + display: none; +} + +a { + color: #f90; + text-decoration: none; + border-bottom: 1px solid transparent; +} + +a:hover { + color: #eee; + border-bottom: 1px solid #eee; +} + +sup { + vertical-align: unset; +} + +sup:before { + content: '['; +} + +sup:after { + content: ']'; +} + +input, button, label { + -webkit-appearance:none; +} + +nav > ul { + list-style-type: none; +} + +nav > ul > li { + display: inline-block; +} + +body > header form { + display: inline-block; + padding-left: 0.6em; + margin-top: 1em; +} + +body > header a { + font-weight: bold; + border-bottom: 3px solid transparent; + padding-bottom: 0.1em; +} + +body > header a:hover, +body > header a.active { + border-bottom: 3px solid #eee; + color: #eee; +} + +body > header a svg { + display: block; + margin: 0.1em auto; +} + +blockquote { + border-left: 3px solid #999; + margin: 2em 0 2em 1em; + padding: 0 0 0 1em; + color: #aaa; +} + +input { + width: 8em; + padding: 0 0.3em; + border: none; + background-color: #333; + color: #ccc; +} + +.hidden, .theme, +.theme input, input[type=submit] { + display: none; +} + +.theme input + label { + color: #f90; + cursor: pointer; + border-bottom: 3px solid transparent; + padding-bottom: 0.1em; +} + +.theme input:hover + label, +.theme input:checked + label { + border-bottom: 3px solid #eee; + color: #eee; +} + +body > footer { + margin-top: 2em; +} + +body > footer > section > * { + margin-bottom: 0.6em; +} + +body > footer .email span { + display: none; +} + +video, +figure img { + display: block; + max-height: 98vh; + max-width: 100%; + width:auto; + height:auto; + margin: 0 auto; + border: 1px solid #000; +} + +figure { + margin: 2em 0; +} + +figcaption { + margin-top: 1em; +} + +figcaption > dl { + margin-top: 1em; + color: #666; +} + +figcaption > dl * { + display: inline-block; +} + +figcaption > dl dt { + display: none; +} + +figcaption > dl dd { + margin: 0 0.3em; +} + +.vcard img { + height: 1em; +} + +code, pre { + color: #3c3; + border: 1px solid #666; + direction: ltr; + word-break: break-all; + word-wrap: break-word; + white-space: pre-wrap; + overflow:initial; +} + +pre { + padding: 0.6em; + position: relative; + margin: 1em 0; +} + +code { + padding: 0.05em 0.2em; +} + +pre > code { + border: none; +} + +pre > code::before { + content: attr(lang); + float: right; + color: #999; + border-left: 1px solid #666; + border-bottom: 1px solid #666; + padding: 0 0.3em; + margin: -0.6em -0.6em 0 0; +} + +table { + border-collapse: collapse; + width: 100%; +} + +td, th { + padding: 0.3em; + border: 1px solid #777; + text-align:left; +} + +th { + font-weight: bold; +} + +th, tr:nth-child(even) { + background-color: rgba(255, 255, 255, .1); +} + +main > header > p { + text-align: center; +} + +article > header { + border-bottom: 4px double #999; + margin-bottom: 2em; +} + +.h-feed article > header { + border: none; + margin: 0; +} + +main ul { + margin-left: 2em; +} + +main ol { + margin-left: 3em; +} + +li p { + margin: 0; +} + +.footnotes hr:before { + content: 'Links'; + color: #ccc; + font-weight: bold; +} + +.comments .u-url, +.footnotes a { + display: inline-block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + vertical-align: top; + max-width: 96%; +} + +.footnote-back { + margin: 0 0 0 0.6em; +} + +main > section > article { + padding-left: 1em; +} + +body > nav { + text-align: center; + margin-top: 2em; +} + +body > nav > ul > li { + margin: 0 0.6em; +} + +@media all and (min-width: 58em) { + body > header > section { + text-align: left; + display: flex; + justify-content:space-between; + } + + body > header a svg { + display: inline-block; + } + + body > header form { + margin-top: 0; + } +} + +body > img { + position: fixed; + bottom: 0; + right: 0; + width: 10em; + height: auto; +} \ No newline at end of file diff --git a/deploy/nasg/templates/symbols.svg b/deploy/nasg/templates/symbols.svg new file mode 100644 index 0000000..87b583f --- /dev/null +++ b/deploy/nasg/templates/symbols.svg @@ -0,0 +1,222 @@ + diff --git a/deploy/nasg/templates/themeswitcher.js b/deploy/nasg/templates/themeswitcher.js new file mode 100644 index 0000000..a105795 --- /dev/null +++ b/deploy/nasg/templates/themeswitcher.js @@ -0,0 +1,73 @@ +var DEFAULT_THEME = 'dark'; +var ALT_THEME = 'light'; +var STORAGE_KEY = 'theme'; +var colorscheme = document.getElementsByName('colorscheme'); + +function indicateTheme(mode) { + for(var i = colorscheme.length; i--; ) { + if(colorscheme[i].value == mode) { + colorscheme[i].checked = true; + } + } +} + +function applyTheme(mode) { + var st = document.getElementById('css_alt'); + if (mode == ALT_THEME) { + st.setAttribute('media', 'all'); + } + else { + st.setAttribute('media', 'speech'); + } +} + +function setTheme(e) { + var mode = e.target.value; + var mql = window.matchMedia('(prefers-color-scheme: ' + ALT_THEME + ')'); + /* user wants == mql match => remove storage */ + if ((mode == DEFAULT_THEME && !mql.matches) || (mode == ALT_THEME && mql.matches)) { + localStorage.removeItem(STORAGE_KEY); + } + else { + if(confirm("I\'ll need to store your choice in your browser, in a place called localStorage.\n\nAre you OK with this?")) { + localStorage.setItem(STORAGE_KEY, mode); + } + } + autoTheme(mql); +} + +function autoTheme(e) { + var mode = DEFAULT_THEME; + try { + var current = localStorage.getItem(STORAGE_KEY); + } catch(e) { + var current = DEFAULT_THEME; + } + if ( current != null) { + mode = current; + } + else if (e.matches) { + mode = ALT_THEME; + } + applyTheme(mode); + indicateTheme(mode); +} + +var mql = window.matchMedia('(prefers-color-scheme: ' + ALT_THEME + ')'); +autoTheme(mql); +mql.addListener(autoTheme); + +var test = 'ping'; +try { + localStorage.setItem(test, test); + localStorage.removeItem(test); + for(var i = colorscheme.length; i--; ) { + colorscheme[i].onclick = setTheme; + } + var themeforms = document.getElementsByClassName(STORAGE_KEY); + for(var i = themeforms.length; i--; ) { + themeforms[i].style.display = 'inline-block'; + } +} catch(e) { + console.log('localStorage is not available, manual theme switching is disabled'); +} diff --git a/deploy/nasg/templates/watermark.png b/deploy/nasg/templates/watermark.png new file mode 100644 index 0000000000000000000000000000000000000000..0fe10419bf3372b8a9ae32b5db0056cb60036f8c GIT binary patch literal 41486 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 + + https://petermolnar.net/feed/ + Peter Molnar + 1970-01-01T00:00:00+00:00 + + Peter Molnar + mail@petermolnar.net + + + + python-feedgen + https://petermolnar.net/favicon.png + Peter Molnar + diff --git a/deploy/www/feed/index.json b/deploy/www/feed/index.json new file mode 100644 index 0000000..a36a9c1 --- /dev/null +++ b/deploy/www/feed/index.json @@ -0,0 +1,12 @@ +{ + "version": "https://jsonfeed.org/version/1", + "title": "Peter Molnar", + "home_page_url": "https://petermolnar.net", + "feed_url": "https://petermolnar.net/index.json", + "author": { + "name": "Peter Molnar", + "url": "https://petermolnar.net/", + "avatar": "https://petermolnar.net/favicon.jpg" + }, + "items": [] +} \ No newline at end of file diff --git a/deploy/www/feed/index.xml b/deploy/www/feed/index.xml new file mode 100644 index 0000000..09b409b --- /dev/null +++ b/deploy/www/feed/index.xml @@ -0,0 +1,16 @@ + + + + Peter Molnar + https://petermolnar.net/feed/ + Peter Molnar + http://www.rssboard.org/rss-specification + python-feedgen + + https://petermolnar.net/favicon.png + Peter Molnar + https://petermolnar.net/feed/ + + Thu, 01 Jan 1970 00:00:00 +0000 + + diff --git a/deploy/www/gophermap b/deploy/www/gophermap new file mode 100644 index 0000000..8d36c2a --- /dev/null +++ b/deploy/www/gophermap @@ -0,0 +1,3 @@ +petermolnar.net's gopherhole - phlog, if you prefer + + diff --git a/deploy/www/index.html b/deploy/www/index.html new file mode 100644 index 0000000..18629c3 --- /dev/null +++ b/deploy/www/index.html @@ -0,0 +1,1038 @@ + + + + + 2019-04-09 20:28 - petermolnar.net + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    + +
    + + +
    +
    +
    +
    + +
    + + +
    + + + + + + + + + + \ No newline at end of file diff --git a/deploy/www/index.php b/deploy/www/index.php new file mode 100644 index 0000000..3cca64e --- /dev/null +++ b/deploy/www/index.php @@ -0,0 +1,122 @@ + 'category/article/', + '^(?:fotography|photoblog)\/?(page.*)?$' => '/category/photo/$1', + '^blog\/?(page.*)?$' => '/category/journal/', + '^blips\/?(page.*)?$' => '/category/note/$1', + '^r\/?(page.*)?$' => '/category/note/$1', + '^(?:linux-tech-coding|it|sysadmin-blog|sysadmin|fotography|blips|blog|photoblog|article|journal|photo|note|r)\/((?!page).*)' => '/$1', +); + +$gone = array( +); + +$gone_re = array( + '^cache\/.*$', + '^tag\/.*$', + '^comment\/.*$', + '^files\/.*$', + '^wp-content\/.*$', + '^broadcast\/wp-ffpc\.message$', +); + +function redirect_to($uri) { + header('HTTP/1.1 301 Moved Permanently'); + if (preg_match("/^https?/", $uri)) + $target = $uri; + else + $target = 'https://petermolnar.net/'. trim($uri, '/') . '/'; + header("Location: ". $target); + exit; +} + +function gone($uri) { + header('HTTP/1.1 410 Gone'); + die(' + + + + + Gone + + +

    This content was deleted.

    +
    +

    '.$uri.'

    + +'); +} + +function notfound($uri) { + header('HTTP/1.0 404 Not Found'); + die(' + + + + + Not found + + + +

    This was not found.

    +

    Please search for it instead.

    +

    +

    + +
    +

    +
    +

    '.$uri.'

    + +'); +} + +function maybe_redirect($uri) { + if (file_exists("./$uri/index.html")) { + redirect_to($uri); + } +} + +$uri = filter_var($_SERVER['REQUEST_URI'], FILTER_SANITIZE_URL); +$uri = str_replace('../', '', $uri); +$uri = str_replace('/feed/', '', $uri); +$uri = str_replace('/atom/', '', $uri); +$uri = trim($uri, '/'); + +foreach ($gone_re as $pattern) { + if (preg_match(sprintf('/%s/', $pattern), $uri)) { + gone($uri); + } +} + +foreach ($redirects_re as $pattern => $target) { + $maybe = preg_match(sprintf('/%s/i', $pattern), $uri, $matches); + if ($maybe) { + $target = str_replace('$1', $matches[1], $target); + redirect_to($target); + } +} + +if (isset($gone[$uri])) { + gone($uri); +} +elseif (isset($redirects[$uri])) { + redirect_to($redirects[$uri]); +} +elseif (preg_match('/^\.well-known\/(host-meta|webfinger).*$/', $uri)) { + redirect_to("https://fed.brid.gy/{$uri}"); +} +elseif (strstr($uri, '_')) { + maybe_redirect(str_replace('_', '-', $uri)); +} +else { + notfound($uri); +} \ No newline at end of file diff --git a/deploy/www/micropub.php b/deploy/www/micropub.php new file mode 100644 index 0000000..c24d24e --- /dev/null +++ b/deploy/www/micropub.php @@ -0,0 +1,114 @@ + array()))); + } + + if(isset($_GET['q']['syndicate-to'])) { + httpok(json_encode(array('syndicate-to' => array()))); + } + + badrequest('please POST a micropub request'); +} + +$raw = file_get_contents("php://input"); +print_r($raw); +try { + $decoded = json_decode($raw, true); +} catch (Exception $e) { + _syslog('failed to decode JSON, trying decoding form data'); + try { + parse_str($raw, $decoded); + } + catch (Exception $e) { + _syslog('failed to decoding form data as well'); + badrequest('invalid POST contents'); + } +} +print_r($decoded); + +$token = ''; +if ( isset($decoded['access_token']) ) { + $token = $decoded['access_token']; + unset($decoded['access_token']); +} +elseif ( isset($_SERVER['HTTP_AUTHORIZATION']) ) { + $token = trim(str_replace('Bearer', '', $_SERVER['HTTP_AUTHORIZATION'])); +} + +if (empty($token)) { + unauthorized('missing token'); +} + +$request = curl_init(); +curl_setopt($request, CURLOPT_URL, 'https://tokens.indieauth.com/token'); +curl_setopt($request, CURLOPT_HTTPHEADER, array( + 'Content-Type: application/x-www-form-urlencoded', + sprintf('Authorization: Bearer %s', $token) +)); +curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); +$response = curl_exec($request); +curl_close($request); +parse_str(urldecode($response), $verification); +if (! isset($verification['scope']) ) { + unauthorized('missing "scope"'); +} +if (! isset($verification['me']) ) { + unauthorized('missing "me"'); +} +if ( ! stristr($verification['me'], 'https://petermolnar.net') ) { + unauthorized('wrong domain'); +} +if ( ! stristr($verification['scope'], 'create') ) { + unauthorized('invalid scope'); +} + +$user = posix_getpwuid(posix_getuid()); +$now = time(); +$decoded['mtime'] = $now; +$fname = sprintf( + '%s/%s/%s.json', + $user['dir'], + 'queue', + microtime(true) +); + +file_put_contents($fname, json_encode($decoded, JSON_PRETTY_PRINT)); +accepted(); \ No newline at end of file diff --git a/deploy/www/search.php b/deploy/www/search.php new file mode 100644 index 0000000..bc3a5cc --- /dev/null +++ b/deploy/www/search.php @@ -0,0 +1,1078 @@ + + + + + Search results for: <?php echo($_GET['q']); ?> + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    + +
    + + +
    +
    +
    +
    + + + +
    +
    +

    Search results for:

    +
    +prepare(" + SELECT + url, category, title, snippet(data, '', '', '[...]', 5, 24) + FROM + data + WHERE + data MATCH :q + ORDER BY + category +"); +$sql->bindValue(':q', $q); +$results = $sql->execute(); + +printf("
    "); +while ($row = $results->fetchArray(SQLITE3_ASSOC)) { + printf('
    %s
    %s
    ', relurl(baseurl, $row['url']), $row['title'], $row["snippet(data, '', '', '[...]', 5, 24)"]); + +} +printf("
    "); +?> +
    + + + + + + + + + + \ No newline at end of file diff --git a/deploy/www/search.sqlite b/deploy/www/search.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..2c894feeda7662952eceae976d2d7f4d5a49d1ee GIT binary patch literal 32768 zcmeI&K}#D!6u|M_YFx3#dXZ2lI3ThKgrZds9)!jcB-GkA#)9o3tl3c(H`#VGitQ~z zPd)b1d%r-xOTSQeXE!mLq!$V1@Lx#sW@erD<~OS_n8Ww`o|57;2%C-)8^)qxn#M~Z z48zDoui5C;y=J0dI&H-LW*T=t)8?&@jPd;0pKSJrVLkq9Ec{+Dvp?s5Woz?mQIiV+ z1Q0*~0R#|0009KTTtyUNHNrS}xVfqE_17FAKZZZ|6N% zR1Rw8y>eB&t5)8Ws>kAW`M4-99sfd#-Tk+_h0_@;x4LR}p4?3C2937&ElHHd){qqG zke!c$QHkPtl02R5X)Cv~VqS0GBx=hu*9((+b(k5FCb`MZ`|?uy-Q^TL_o^317@?}4 z_(9{m*XK*;Qnu@|<=z<>>`#X6N<#MmZ;o*Bjbdex!Hw z+Pq2E2wEyir?aK;)R1K9(0_N-ZmeB|zFib{W4)=orqtn!mXk&s%2R&Qx!G`(JPX3F z`j)Nk?1k%(rj=V-n*IK?S7BUPTF{3|wRTk6PoL&^KpY)b4)(;UYH#M}#GNZDrZ~{4 z3mfc?iyZ9L1rK(2iytzQXbujv0;L}b>F$jF>AstW*4{ThVi_tpm#yd*Yv*$iDjD8d zeL)}IN50+vj}bE 0: + return self[self.sortedkeys[0]].published.timestamp + else: + return 0 @property def rssfeedfpath(self): @@ -1759,7 +1762,10 @@ class Category(dict): [self[k].dt for k in self.sortedkeys[start:end]], reverse=True ) - return s[0] + if len(s) > 0: + return s[0] # Timestamp in seconds since epoch + else: + return 0 @property def ctmplvars(self): @@ -2071,10 +2077,11 @@ class Sitemap(dict): return os.path.join(settings.paths.get('build'), 'sitemap.txt') async def render(self): - if self.mtime >= sorted(self.values())[-1]: - return - with open(self.renderfile, 'wt') as f: - f.write("\n".join(sorted(self.keys()))) + if len(self) > 0: + if self.mtime >= sorted(self.values())[-1]: + return + with open(self.renderfile, 'wt') as f: + f.write("\n".join(sorted(self.keys()))) class WebmentionIO(object): diff --git a/pandoc.py b/pandoc.py index 03ba130..aa86f40 100644 --- a/pandoc.py +++ b/pandoc.py @@ -57,15 +57,26 @@ class Pandoc(str): conv_from, '+'.join(self.in_options) ) - + + is_pandoc_version2 = False + try: + version = subprocess.check_output(['pandoc', '-v']) + if version.startswith(b'pandoc 2'): + is_pandoc_version2 = True + except OSError: + print("Error: pandoc is not installed!") + cmd = [ 'pandoc', '-o-', conv_to, conv_from, - '--quiet', '--no-highlight' ] + if is_pandoc_version2: + # Only pandoc v2 and higher support quiet param + cmd.append('--quiet') + if self.columns: cmd.append(self.columns)