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 @@ +
    +
    +

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

    + +
    + + {% if post.description|length %} +
    + {{ post.description|relurl(baseurl) }} + + + {% if post.inLanguage == 'hu' %}Tovább »{% else %}Continue »{% endif %} + + +
    + {% else %} +
    + {{ post.text|relurl(baseurl) }} +
    + {% endif %} + + +
    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 0000000..0fe1041 Binary files /dev/null and b/deploy/nasg/templates/watermark.png differ diff --git a/deploy/www/feed/atom.xml b/deploy/www/feed/atom.xml new file mode 100644 index 0000000..e06f1e4 --- /dev/null +++ b/deploy/www/feed/atom.xml @@ -0,0 +1,15 @@ + + + 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 0000000..2c894fe Binary files /dev/null and b/deploy/www/search.sqlite differ diff --git a/deploy/www/webhook.php b/deploy/www/webhook.php new file mode 100644 index 0000000..848162f --- /dev/null +++ b/deploy/www/webhook.php @@ -0,0 +1,56 @@ + 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)