├── dist └── .gitkeep ├── custom-page.hbs ├── README.md ├── .gitignore ├── src ├── fonts │ ├── jetbrains-mono.woff2 │ ├── protogroteskweb-bold.woff2 │ ├── protogroteskweb-light.woff2 │ ├── protogroteskweb-regular.woff2 │ └── protogroteskweb-extralight.woff2 ├── less │ ├── components │ │ ├── _highlight.less │ │ ├── _listing.less │ │ ├── _navigation.less │ │ ├── _avatar.less │ │ ├── _404.less │ │ ├── _fonts.less │ │ ├── _loadAnimation.less │ │ ├── _darkMode.less │ │ ├── _gradient.less │ │ ├── _post.less │ │ └── _comments.less │ ├── style.less │ └── lib │ │ └── prism.less └── js │ ├── components │ ├── external-links.js │ ├── og-images.js │ ├── newsletter.js │ ├── comment-count.js │ ├── koeing-gallery.js │ ├── blogcast-whitelabel.js │ ├── darkMode.js │ └── feature-image.js │ ├── index.js │ └── lib │ ├── svgBlob.js │ ├── noise.js │ └── prism.js ├── partials ├── navigation.hbs ├── footer.hbs └── header.hbs ├── .github ├── FUNDING.yml └── workflows │ ├── main.yml │ └── release.yml ├── custom-fiction.hbs ├── page.hbs ├── default.hbs ├── webpack.mix.js ├── base.hbs ├── error-401.hbs ├── tag.hbs ├── error-404.hbs ├── package.json ├── newsletter.hbs ├── home.hbs ├── tailwind.config.js ├── index.hbs ├── post.hbs └── amp.hbs /dist/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /custom-page.hbs: -------------------------------------------------------------------------------- 1 | {{!< page}} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Miguel Piedrafita's website -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist/*.zip 3 | assets/ -------------------------------------------------------------------------------- /src/fonts/jetbrains-mono.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m1guelpf/website-theme/HEAD/src/fonts/jetbrains-mono.woff2 -------------------------------------------------------------------------------- /src/fonts/protogroteskweb-bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m1guelpf/website-theme/HEAD/src/fonts/protogroteskweb-bold.woff2 -------------------------------------------------------------------------------- /src/fonts/protogroteskweb-light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m1guelpf/website-theme/HEAD/src/fonts/protogroteskweb-light.woff2 -------------------------------------------------------------------------------- /src/fonts/protogroteskweb-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m1guelpf/website-theme/HEAD/src/fonts/protogroteskweb-regular.woff2 -------------------------------------------------------------------------------- /src/fonts/protogroteskweb-extralight.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m1guelpf/website-theme/HEAD/src/fonts/protogroteskweb-extralight.woff2 -------------------------------------------------------------------------------- /partials/navigation.hbs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: m1guelpf 4 | patreon: m1guelpiedrafita 5 | custom: https://miguelpiedrafita.com/patreon 6 | -------------------------------------------------------------------------------- /src/less/components/_highlight.less: -------------------------------------------------------------------------------- 1 | .highlight { 2 | @apply .bg-inherit .text-sepia-900 .font-medium .px-1 .rounded; 3 | 4 | background-color: #fbf9c9; 5 | 6 | transition: background-color 1s ease-in, color 1s ease-in; 7 | } 8 | 9 | body[data-dark] .highlight { 10 | background-color: #4e4b06; 11 | } -------------------------------------------------------------------------------- /src/js/components/external-links.js: -------------------------------------------------------------------------------- 1 | const isInternal = new RegExp(location.host) 2 | const isMailto = /^mailto:.*/ 3 | 4 | Array.from(document.getElementsByTagName('a')).filter(link => { 5 | return ! isInternal.test(link.href) && ! isMailto.test(link.href) 6 | }).forEach(link => { 7 | link.target = '_blank' 8 | link.rel = 'noopener' 9 | }) -------------------------------------------------------------------------------- /src/js/components/og-images.js: -------------------------------------------------------------------------------- 1 | if (document.body.classList.contains('post-template')) { 2 | const url = `https://og.m1guelpf.me${(new URL(document.location.href)).pathname}` 3 | 4 | document.querySelector('meta[property="og:image"]').setAttribute('content', url) 5 | document.querySelector('meta[name="twitter:image"]').setAttribute('content', url) 6 | } -------------------------------------------------------------------------------- /src/less/components/_listing.less: -------------------------------------------------------------------------------- 1 | [data-article-listing] { 2 | h2 { 3 | @apply .mb-1 .text-lg; 4 | } 5 | 6 | p { 7 | @apply .font-medium .text-base .mb-10; 8 | } 9 | 10 | a { 11 | @apply .border-b-2 .border-transparent; 12 | 13 | &:hover { 14 | @apply .text-gradient .border-gradient; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /custom-fiction.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | 3 | {{> header }} 4 | 5 | {{#post}} 6 |
7 |

{{ title }}

8 |

{{ date format="DD/MM/YY" }}

9 |
10 |
11 | {{content}} 12 |
13 | {{/post}} -------------------------------------------------------------------------------- /src/less/components/_navigation.less: -------------------------------------------------------------------------------- 1 | .navigation { 2 | @apply text-sm text-sepia-300 text-center; 3 | 4 | a { 5 | @apply mr-2; 6 | 7 | transition: color 1s ease-in; 8 | 9 | &:hover { 10 | @apply text-gradient border-gradient border-b-2; 11 | } 12 | } 13 | } 14 | 15 | @screen md { 16 | .navigation a { 17 | @apply mr-0 ml-2; 18 | } 19 | } -------------------------------------------------------------------------------- /src/less/components/_avatar.less: -------------------------------------------------------------------------------- 1 | .avatar { 2 | figcaption { 3 | top: .5rem; 4 | left: 3.8rem; 5 | transform: translate3d(0, 25%, 0) rotate(4deg); 6 | transition: all .3s ease; 7 | transition-delay: .1s; 8 | } 9 | 10 | img { 11 | transform: rotate(-8deg) scale(1); 12 | transition: all .25s ease; 13 | } 14 | 15 | &:hover { 16 | figcaption { 17 | opacity: 1; 18 | transform: translate3d(0, 0, 0) rotate(0deg); 19 | } 20 | 21 | img { 22 | transform: rotate(0deg) scale(1.2); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /page.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | 3 |
4 | {{> header }} 5 | {{#post}} 6 |
7 |

{{ title }}

8 |
9 |
10 | {{ content }} 11 |
12 | {{/post}} 13 |
-------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Theme 2 | 3 | on: 4 | push: 5 | paths: 6 | - '**.hbs' 7 | - 'src/**' 8 | - 'package.json' 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v1 17 | 18 | - name: Build assets 19 | uses: elstudio/actions-js-build/build@v2 20 | with: 21 | args: run prod 22 | 23 | - name: Deploy Ghost Theme 24 | uses: TryGhost/action-deploy-theme@v1.2.0 25 | with: 26 | api-url: ${{ secrets.GHOST_ADMIN_API_URL }} 27 | api-key: ${{ secrets.GHOST_ADMIN_API_KEY }} 28 | exclude: node_modules/* 29 | -------------------------------------------------------------------------------- /default.hbs: -------------------------------------------------------------------------------- 1 | {{!< base}} 2 | 3 |
4 | {{{body}}} 5 | 6 |
7 | {{> footer }} 8 |
9 | 10 |
11 |
12 | 18 |
-------------------------------------------------------------------------------- /src/less/style.less: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | /* purgecss start ignore */ 6 | @import "components/_fonts"; 7 | @import "components/_darkMode"; 8 | @import "components/_loadAnimation"; 9 | @import "components/_navigation"; 10 | @import "components/_post"; 11 | @import "components/_comments"; 12 | @import "components/_listing"; 13 | @import "components/_404"; 14 | @import "components/_avatar"; 15 | /* purgecss end ignore */ 16 | 17 | 18 | 19 | @import "components/_gradient"; 20 | 21 | 22 | 23 | .box-decoration-break-clone { 24 | box-decoration-break: clone; 25 | } 26 | 27 | /* purgecss start ignore */ 28 | @import "components/_highlight"; 29 | /* purgecss end ignore */ -------------------------------------------------------------------------------- /src/less/components/_404.less: -------------------------------------------------------------------------------- 1 | .animate-squiggly { 2 | animation: squiggly-anim 0.34s linear infinite; 3 | } 4 | 5 | @keyframes squiggly-anim { 6 | 0% { 7 | -webkit-filter: url("#squiggly-0"); 8 | filter: url("#squiggly-0"); 9 | } 10 | 11 | 25% { 12 | -webkit-filter: url("#squiggly-1"); 13 | filter: url("#squiggly-1"); 14 | } 15 | 16 | 50% { 17 | -webkit-filter: url("#squiggly-2"); 18 | filter: url("#squiggly-2"); 19 | } 20 | 21 | 75% { 22 | -webkit-filter: url("#squiggly-3"); 23 | filter: url("#squiggly-3"); 24 | } 25 | 26 | 100% { 27 | -webkit-filter: url("#squiggly-4"); 28 | filter: url("#squiggly-4"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Add theme artifact to release 2 | 3 | on: [release] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | 13 | - name: Build assets 14 | uses: elstudio/actions-js-build/build@v2 15 | with: 16 | args: run prod 17 | 18 | - name: Create artifact 19 | uses: TheDoctor0/zip-release@v0.2.0 20 | with: 21 | filename: 'mp-theme.zip' 22 | exclusions: '*.git* /*node_modules/* .editorconfig' 23 | 24 | - name: Upload to Release 25 | uses: JasonEtco/upload-to-release@v0.1.0 26 | with: 27 | args: mp-theme.zip application/zip 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | -------------------------------------------------------------------------------- /src/js/components/newsletter.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | window.newsletter = () => ({ 4 | subscribed: false, 5 | email: null, 6 | init() { 7 | this.subscribed = localStorage.getItem('subscribedToNewsletter') == 'true' 8 | }, 9 | submitForm() { 10 | axios.post('https://newsletter.m1guelpf.me/api/subscribe/8d2265d5-111d-41b2-b170-11d4aff0dca7', { 11 | email: this.email, 12 | }).then(() => this.subscriptionSucceeded()).catch(error => { 13 | if (error.response && error.response.data.code == 'already_subscribed') return this.subscriptionSucceeded() 14 | 15 | alert(error.response.data.message) 16 | }) 17 | }, 18 | subscriptionSucceeded() { 19 | this.subscribed = true 20 | 21 | fathom('trackGoal', 'Z8TWLFZX', 0); 22 | 23 | localStorage.setItem('subscribedToNewsletter', true); 24 | }, 25 | }) 26 | -------------------------------------------------------------------------------- /partials/footer.hbs: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /partials/header.hbs: -------------------------------------------------------------------------------- 1 |
2 | 15 |
-------------------------------------------------------------------------------- /src/js/components/comment-count.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | if (document.querySelector('[data-comment-count]')) { 4 | const paths = {} 5 | 6 | document.querySelectorAll('[data-comment-count]').forEach(el => { 7 | paths[el.getAttribute('data-comments-for')] = el 8 | }) 9 | 10 | axios.post('https://comments.m1guelpf.me/api/comment/count', { 11 | domain: parent.location.host, 12 | paths: Object.keys(paths) 13 | }, { 14 | headers: { 15 | 'Content-type': 'application/x-www-form-urlencoded' 16 | } 17 | }).then(response => { 18 | Object.entries(response.data.commentCounts).forEach(result => { 19 | paths[result[0]].innerHTML = `— ${result[1] + 1} ${result[1] == 0 ? 'comment':'comments'}` 20 | }) 21 | }).catch(error => { 22 | console.log("[commento] error: " + error.message) 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /src/js/index.js: -------------------------------------------------------------------------------- 1 | import 'alpinejs'; 2 | import 'instant.page'; 3 | 4 | import './lib/prism'; 5 | import './components/darkMode'; 6 | import './components/feature-image'; 7 | import './components/koeing-gallery'; 8 | import './components/blogcast-whitelabel'; 9 | import './components/external-links'; 10 | import './components/newsletter'; 11 | import './components/comment-count'; 12 | import './components/og-images'; 13 | 14 | Array.from(document.getElementsByTagName('a')).forEach(link => { 15 | link.addEventListener('transitionrun', () => { 16 | if (isHovered(link)) { 17 | link.style.transition = 'none' 18 | } 19 | }); 20 | 21 | link.addEventListener('mouseout', () => { 22 | setTimeout(() => { 23 | link.style.transition = null 24 | }, 1000) 25 | }); 26 | }) 27 | 28 | function isHovered(el) { 29 | return (el.parentElement.querySelector(':hover') === el); 30 | } -------------------------------------------------------------------------------- /src/js/components/koeing-gallery.js: -------------------------------------------------------------------------------- 1 | import mediumZoom from 'medium-zoom' 2 | 3 | var images = document.querySelectorAll('.kg-gallery-image img'); 4 | 5 | images.forEach(image => { 6 | var container = image.closest('.kg-gallery-image'); 7 | 8 | var width = image.attributes.width.value; 9 | var height = image.attributes.height.value; 10 | var ratio = width / height; 11 | 12 | container.style.flex = ratio + ' 1 0%'; 13 | }) 14 | 15 | if (document.querySelector('.post-template')) { 16 | window.addEventListener('load', () => { 17 | const zoomImages = [ 18 | ...document.querySelectorAll('article .kg-image-card img:not(.no-zoomable)'), 19 | ...document.querySelectorAll('article .kg-gallery-image img:not(.no-zoomable)') 20 | ] 21 | 22 | mediumZoom(zoomImages, { 23 | margin: 24, 24 | background: 'var(--sepia-500)' 25 | }); 26 | }, false); 27 | } 28 | -------------------------------------------------------------------------------- /src/less/components/_fonts.less: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-display: swap; 3 | font-weight: 700; 4 | font-family: "Protogrotesk"; 5 | src: url("/assets/fonts/protogroteskweb-bold.woff2") format('woff2'); 6 | } 7 | 8 | @font-face { 9 | font-display: swap; 10 | font-weight: 100; 11 | font-family: "Protogrotesk"; 12 | src: url("/assets/fonts/protogroteskweb-extralight.woff2") format('woff2'); 13 | } 14 | 15 | @font-face { 16 | font-display: swap; 17 | font-weight: 300; 18 | font-family: "Protogrotesk"; 19 | src: url("/assets/fonts/protogroteskweb-light.woff2") format('woff2'); 20 | } 21 | 22 | @font-face { 23 | font-display: swap; 24 | font-weight: 400; 25 | font-family: "Protogrotesk"; 26 | src: url("/assets/fonts/protogroteskweb-regular.woff2") format('woff2'); 27 | } 28 | @font-face { 29 | font-display: swap; 30 | font-weight: 400; 31 | font-family: "Jetbrains Mono"; 32 | src: local('Jetbrains Mono'), url("/assets/fonts/jetbrains-mono.woff2") format('woff2'); 33 | } -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-mix'); 2 | 3 | require('mix-tailwindcss'); 4 | 5 | Mix.manifest.refresh = _ => void 0 6 | 7 | /* 8 | |-------------------------------------------------------------------------- 9 | | Mix Asset Management 10 | |-------------------------------------------------------------------------- 11 | | 12 | | Mix provides a clean, fluent API for defining some Webpack build steps 13 | | for your Laravel application. By default, we are compiling the Sass 14 | | file for your application, as well as bundling up your JS files. 15 | | 16 | */ 17 | 18 | mix 19 | .less('src/less/style.less', 'assets/css') 20 | .copy('src/fonts/*', 'assets/fonts') 21 | .options({ 22 | postCss: [ 23 | require('tailwindcss'), 24 | require('autoprefixer'), 25 | ] 26 | }) 27 | .webpackConfig({ 28 | output: { 29 | publicPath: '/assets/', 30 | chunkFilename: 'js/[name].js?[chunkhash]', 31 | }, 32 | }) 33 | .js('src/js/index.js', 'assets/js') 34 | .setPublicPath('assets/'); -------------------------------------------------------------------------------- /src/less/components/_loadAnimation.less: -------------------------------------------------------------------------------- 1 | @keyframes fadeInUp { 2 | 0% { 3 | opacity: 0; 4 | transform: translateY(24px); 5 | } 6 | 7 | 100% { 8 | opacity: 1; 9 | transform: translateY(0); 10 | } 11 | } 12 | 13 | .animation { 14 | animation-duration: 1s; 15 | animation-fill-mode: both; 16 | } 17 | 18 | .animation-fadeInUp { 19 | animation-name: fadeInUp; 20 | } 21 | 22 | .animation-delay-2 { 23 | animation-delay: .2s; 24 | } 25 | 26 | .animation-delay-4 { 27 | animation-delay: .4s; 28 | } 29 | 30 | .animation-hello { 31 | animation: hello 5s ease-in-out 1s; 32 | } 33 | 34 | @keyframes hello { 35 | 5% { 36 | transform: rotate(20deg) 37 | } 38 | 39 | 8% { 40 | transform: rotate(-15deg) 41 | } 42 | 43 | 11% { 44 | transform: rotate(10deg) 45 | } 46 | 47 | 14% { 48 | transform: rotate(-10deg) 49 | } 50 | 51 | 17% { 52 | transform: rotate(5deg) 53 | } 54 | 55 | 20% { 56 | transform: rotate(-5deg) 57 | } 58 | 59 | 23% { 60 | transform: rotate(0deg) 61 | } 62 | } -------------------------------------------------------------------------------- /base.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{meta_title}} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {{ghost_head}} 19 | 20 | 21 | 22 | 23 | {{{body}}} 24 | 25 | {{!-- --}} 26 | 27 | {{{block "scripts"}}} 28 | 29 | {{ghost_foot}} 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/js/components/blogcast-whitelabel.js: -------------------------------------------------------------------------------- 1 | const playerContainer = document.querySelector('[data-blogcast-player]') 2 | const playerFallback = document.querySelector('[data-blogcast-error]') 3 | const playBtn = document.getElementById('playAudioBtn') 4 | const pauseBtn = document.getElementById('pauseAudioBtn') 5 | const blogcastPlayer = document.getElementById('blogcastPlayer') 6 | 7 | if (playerContainer && playerFallback && blogcastPlayer) { 8 | blogcastPlayer.addEventListener('loadeddata', () => { 9 | playerFallback.style.display = 'none' 10 | playerContainer.style.display = null 11 | }) 12 | } 13 | 14 | if (playBtn && pauseBtn && blogcastPlayer) { 15 | playBtn.addEventListener('click', () => { 16 | blogcastPlayer.play() 17 | playBtn.style.display = 'none' 18 | pauseBtn.style.display = null 19 | }) 20 | pauseBtn.addEventListener('click', () => { 21 | blogcastPlayer.pause() 22 | playBtn.style.display = null 23 | pauseBtn.style.display = 'none' 24 | }) 25 | 26 | blogcastPlayer.addEventListener('ended', () => { 27 | blogcastPlayer.currentTime = 0; 28 | playBtn.style.display = null 29 | pauseBtn.style.display = 'none' 30 | }) 31 | } -------------------------------------------------------------------------------- /src/js/components/darkMode.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('load', () => { 2 | document.body.classList.remove('preload') 3 | }); 4 | (function () { 5 | window.__onThemeChange = function () {}; 6 | 7 | function setTheme(newTheme) { 8 | window.__theme = newTheme; 9 | preferredTheme = newTheme; 10 | 11 | newTheme == 'dark' ? document.body.setAttribute('data-dark', true) : document.body.removeAttribute('data-dark') 12 | 13 | window.__onThemeChange(newTheme); 14 | } 15 | 16 | var preferredTheme; 17 | 18 | try { 19 | preferredTheme = localStorage.getItem('theme'); 20 | } catch (err) {} 21 | 22 | window.__setPreferredTheme = function (newTheme) { 23 | setTheme(newTheme); 24 | 25 | try { 26 | localStorage.setItem('theme', newTheme); 27 | } catch (err) {} 28 | } 29 | 30 | var darkQuery = window.matchMedia('(prefers-color-scheme: dark)'); 31 | 32 | darkQuery.addListener(function (e) { 33 | window.__setPreferredTheme(e.matches ? 'dark' : 'light') 34 | }); 35 | 36 | setTheme(preferredTheme || (darkQuery.matches ? 'dark' : 'light')); 37 | })(); 38 | 39 | document.getElementById('themeToggle').onclick = () => { 40 | window.__setPreferredTheme( 41 | window.__theme == 'light' ? 'dark' : 'light' 42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /src/js/components/feature-image.js: -------------------------------------------------------------------------------- 1 | import './../lib/svgBlob' 2 | 3 | (() => { 4 | 5 | new SvgBlob('#blobbed', { 6 | speedFactor: .5, 7 | animateOnHover: false, 8 | animateWhenVisible: true, 9 | }) 10 | 11 | setTimeout(() => { 12 | Array.from(document.querySelectorAll("article pre[class*='language-']")).forEach(el => { 13 | const codeEl = el.querySelector('code') 14 | 15 | if (codeEl.innerHTML.indexOf("\n") === codeEl.innerHTML.length - 1) { 16 | return; 17 | } 18 | 19 | el.classList.add('code-blob') 20 | }) 21 | new SvgBlob(".code-blob", { 22 | speedFactor: .5, 23 | animateOnHover: false, 24 | animateWhenVisible: false, 25 | hideOnMobile: true, 26 | }) 27 | }, 1000) 28 | 29 | if (document.querySelector('.tag-internal-blobify-images')) { 30 | Array.from(document.querySelectorAll('.kg-image-card')).forEach(el => { 31 | const wrapper = document.createElement('div') 32 | wrapper.classList.add('kg-image-blob') 33 | el.prepend(wrapper) 34 | wrapper.appendChild(el.querySelector('img')) 35 | }) 36 | 37 | new SvgBlob('.kg-image-blob', { 38 | speedFactor: .5, 39 | animateOnHover: true, 40 | animateWhenVisible: false, 41 | }) 42 | } 43 | })() -------------------------------------------------------------------------------- /error-401.hbs: -------------------------------------------------------------------------------- 1 | {{!< base}} 2 | 3 |
4 |
5 |

– 401 –

6 |

HOW DARE YOU

7 |

How dare you try and invade my privacy like this ಠ╭╮ಠ

8 | ← Go home 9 |
10 |
11 | -------------------------------------------------------------------------------- /tag.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | 3 | {{#tag}} 4 |
5 | {{> header }} 6 | 7 |
8 |

#{{name}}

9 |

{{ description }}

10 |
11 | {{/tag}} 12 |
13 | {{#foreach posts}} 14 |
15 |
16 |

17 | {{title}} 18 | {{#if featured}} 19 | 20 | 21 | 22 | 23 | {{/if}} 24 |

25 |
26 |
27 |

{{excerpt}}

28 |
29 | 32 |
33 | {{/foreach}} 34 |
35 |
-------------------------------------------------------------------------------- /error-404.hbs: -------------------------------------------------------------------------------- 1 | {{!< base}} 2 | 3 |
4 |
5 |

– 404 –

6 |

W H Y

7 |

Why do you do this to me, you got my hopes up to serve you a page but as always you request the impossible :(

8 | ← Go home 9 |
10 |
11 | -------------------------------------------------------------------------------- /src/less/components/_darkMode.less: -------------------------------------------------------------------------------- 1 | :root { 2 | --brand: #f2709c; 3 | 4 | --sepia-500: #f5f5f0; 5 | --sepia-900: #3c371e; 6 | --sepia-300: #3c371e99; 7 | --sepia-100: #3c371e4d; 8 | 9 | --blue-500: #1e64c8; 10 | --yellow-300: #e8d87e; 11 | --orange-400: #ff8a00; 12 | 13 | --white: #ffffff; 14 | --black: #000000; 15 | 16 | --featured-theme-1: #22D2A0; 17 | --featured-theme-2: #E1CC13; 18 | --featured-theme-3: #FD9065; 19 | --featured-theme-4: #55CAE7; 20 | } 21 | 22 | [data-dark] { 23 | --sepia-500: #181a1b; 24 | --sepia-900: #e8e6e3; 25 | --sepia-300: #d5d2cc99; 26 | --sepia-100: #d5d2cc4d; 27 | 28 | --blue-500: #65a9e8; 29 | 30 | --white: #3c371e; 31 | --black: #e8e6e3; 32 | } 33 | 34 | * { 35 | transition: border-color 1s ease-in; 36 | } 37 | 38 | body { 39 | transition: color 1s ease-in, background-color 1s ease-in; 40 | } 41 | 42 | h1, .text-sepia-300, .text-sepia-100, .text-blue-500, .text-transition { 43 | transition: color 1s ease-in; 44 | 45 | & a { 46 | transition: color 1s ease-in, border-color 1s ease-in; 47 | } 48 | } 49 | 50 | .border-transition, a { 51 | transition: border-color 1s ease-in; 52 | 53 | &.text-transition { 54 | transition: color 1s ease-in, border-color 1s ease-in; 55 | } 56 | } 57 | 58 | .border-width-transition { 59 | transition: border-width 1s ease-in; 60 | } 61 | 62 | .bg-white, .bg-blue-500, .background-transition { 63 | transition: background-color 1s ease-in; 64 | 65 | &.border-width-transition { 66 | transition: background-color 1s ease-in, border-width 1s ease-in; 67 | } 68 | } 69 | 70 | .text-transition { 71 | transition: color 1s ease-in; 72 | } 73 | 74 | .height-transition { 75 | transition: height 1s ease-in; 76 | } 77 | 78 | .opacity-transition { 79 | transition: opacity 1s ease-in; 80 | 81 | &.height-transition { 82 | transition: opacity 1s ease-in, transform 1s ease-in; 83 | } 84 | } 85 | 86 | 87 | .preload * { 88 | transition: none !important; 89 | } -------------------------------------------------------------------------------- /src/less/components/_gradient.less: -------------------------------------------------------------------------------- 1 | @variants hover, group-hover { 2 | .bg-gradient { 3 | background: linear-gradient(to right, rgb(242, 112, 156), rgb(255, 148, 114)); 4 | } 5 | 6 | .border-gradient { 7 | border-image: linear-gradient(to right, rgb(242, 112, 156), rgb(255, 148, 114)) 100% ~'1 / 1 / 0'stretch; 8 | } 9 | 10 | .text-gradient { 11 | background: linear-gradient(to right, rgb(242, 112, 156), rgb(255, 148, 114)); 12 | -webkit-background-clip: text; 13 | -webkit-text-fill-color: transparent; 14 | } 15 | .text-gradient-none { 16 | -webkit-background-clip: inherit; 17 | -webkit-text-fill-color: inherit; 18 | } 19 | } 20 | 21 | .bg-gradient-featured { 22 | @apply relative; 23 | z-index: 1; 24 | 25 | > div { 26 | transition: border-color 0.3s ease-in-out, color 0.3s ease-in-out; 27 | } 28 | 29 | &:first-of-type { 30 | background-image: radial-gradient(theme('colors.featured-theme-1') 35%, transparent 35%); 31 | 32 | > div { 33 | border-color: theme('colors.featured-theme-1'); 34 | } 35 | } 36 | &:nth-of-type(2) { 37 | background-image: radial-gradient(theme('colors.featured-theme-2') 35%, transparent 35%); 38 | 39 | > div { 40 | border-color: theme('colors.featured-theme-2'); 41 | } 42 | } 43 | &:nth-of-type(3) { 44 | background-image: radial-gradient(theme('colors.featured-theme-3') 35%, transparent 35%); 45 | 46 | > div { 47 | border-color: theme('colors.featured-theme-3'); 48 | } 49 | } 50 | &:nth-of-type(4) { 51 | background-image: radial-gradient(theme('colors.featured-theme-4') 35%, transparent 35%); 52 | 53 | > div { 54 | border-color: theme('colors.featured-theme-4'); 55 | } 56 | } 57 | &::before { 58 | @apply absolute inset-0 opacity-0 bg-2; 59 | content: ""; 60 | z-index: -1; 61 | transition: opacity 0.3s ease-in-out; 62 | 63 | background-image: radial-gradient(rgb(242, 112, 156) 35%, transparent 35%); 64 | } 65 | &:hover { 66 | &::before { 67 | @apply opacity-100; 68 | } 69 | > div { 70 | border-color: rgb(242, 112, 156); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mp-theme", 3 | "description": "Ghost theme for miguelpiedrafita.com", 4 | "keywords": [ 5 | "ghost-theme" 6 | ], 7 | "version": "0.0.1", 8 | "engines": { 9 | "ghost-api": "v2" 10 | }, 11 | "license": "MIT", 12 | "author": { 13 | "name": "Miguel Piedrafita", 14 | "email": "soy@miguelpiedrafita.com" 15 | }, 16 | "config": { 17 | "posts_per_page": 9999, 18 | "image_sizes": { 19 | "xxs": { 20 | "width": 30 21 | }, 22 | "xs": { 23 | "width": 100 24 | }, 25 | "s": { 26 | "width": 300 27 | }, 28 | "m": { 29 | "width": 600 30 | }, 31 | "l": { 32 | "width": 1000 33 | }, 34 | "xl": { 35 | "width": 2000 36 | } 37 | } 38 | }, 39 | "scripts": { 40 | "dev": "npm run development", 41 | "test": "gscan .", 42 | "zip": "zip -r dist/mp-theme.zip assets partials *.hbs package.json", 43 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 44 | "watch": "npm run development -- --watch", 45 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 46 | "prod": "npm run production", 47 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 48 | }, 49 | "devDependencies": { 50 | "autoprefixer": "^9.5.1", 51 | "cross-env": "^5.2.0", 52 | "gscan": "^2.6.1", 53 | "laravel-mix": "^4.0.16", 54 | "less": "^3.9.0", 55 | "less-loader": "^5.0.0", 56 | "mix-tailwindcss": "^1.1.0", 57 | "tailwindcss": "^1.0", 58 | "vue-template-compiler": "^2.6.10" 59 | }, 60 | "dependencies": { 61 | "@babel/plugin-syntax-dynamic-import": "^7.2.0", 62 | "@tailwindcss/custom-forms": "^0.1.4", 63 | "alpinejs": "^2.3.3", 64 | "axios": "^0.19.0", 65 | "codemirror": "^5.47.0", 66 | "instant.page": "^1.2.2", 67 | "lazysizes": "^5.1.0", 68 | "medium-zoom": "^1.0.4", 69 | "resize-detector": "^0.2.0" 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /newsletter.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | 3 |
4 | {{> header }} 5 |
6 |

Join my newsletter

7 |
8 |
9 |

I send an email every saturday with project updates, article drafts & general thoughts. I'll never spam you or share your information with anyone.[1]

10 |
11 |
12 | 13 | 14 |
15 | 18 |
19 | 20 |
21 | 22 |
23 |
    24 |
  1. 25 |

    Ideally everyone should, but sadly this isn't always the case. I believe privacy is a fundamental human right and the lack of it is one of the worst problems in today's society, and I promise you I'd never sell or trade your information.

    26 |
  2. 27 |
28 |
29 |
30 | 31 |
-------------------------------------------------------------------------------- /home.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | 3 |
4 | {{> header }} 5 |
6 |

👋 Hi! I'm an 18-year-old maker who enjoys creating fun stuff.

7 |
8 |
9 |

I'm currently dedicating most of my time to building Sitesauce, a one-click solution to create static sites from any dynamically-generated website (like WordPress or Ghost sites) and keep them updated when content changes.

10 | 11 |

Before that, I built and sold Blogcast, a service that uses state of the art text-to-speech technology to automate article narration. I also built and sold UnMarkDocs, an service to generate beautiful documentation pages with super-powerered markdown.

12 | 13 |

I've also started and worked on many other projects that unfortunately never saw the light of day, like Snaptier or Maker Army. You can see a complete list of all my current and past projects here.

14 | 15 |

I enjoy to contributing to open source on GitHub where I've helped over 500 projects, and mantaining an online coding community for teenagers I founded. I also love to learn new things, and especially enjoy researching about philosophy, psychology and other subjects while studying the International Baccalaureate.

16 | 17 |

If you've reached this point, you probably want to learn more about my projects or read my articles. You can also follow me on Twitter, where I actively share what I'm working on, or subscribe to my newsletter to get regular updates on my projects.

18 |
19 |
20 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | const defaultTheme = require('tailwindcss/defaultTheme') 2 | 3 | module.exports = { 4 | purge: ['./**/*.hbs'], 5 | theme: { 6 | extend: { 7 | colors: { 8 | 'inherit': 'inherit', 9 | 'none': 'none', 10 | 'brand': 'var(--brand)', 11 | 'yellow-300': 'var(--yellow-300)', 12 | 'orange-400': 'var(--orange-400)', 13 | 'sepia-500': 'var(--sepia-500)', 14 | 'sepia-900': 'var(--sepia-900)', 15 | 'sepia-300': 'var(--sepia-300)', 16 | 'sepia-100': 'var(--sepia-100)', 17 | 'blue-500': 'var(--blue-500)', 18 | 'white': 'var(--white)', 19 | 'black': 'var(--black)', 20 | 'featured-theme-1': '#22D2A0', 21 | 'featured-theme-2': '#E1CC13', 22 | 'featured-theme-3': '#FD9065', 23 | 'featured-theme-4': '#55CAE7', 24 | }, 25 | fontFamily: { 26 | 'sans-no-emoji': defaultTheme.fontFamily.sans.filter(font => !font.includes('Emoji')), 27 | 'main': ['Protogrotesk', ...defaultTheme.fontFamily.sans], 28 | 'mono': ['"Jetbrains Mono"', '"Operator Mono Lig"', '"Operator Mono"', '"Fira Code"', '"Source Sans Pro"', ...defaultTheme.fontFamily.mono] 29 | }, 30 | letterSpacing: { 31 | px: '.1px' 32 | }, 33 | padding: { 34 | '.2': '0.125rem', 35 | 'header': 'calc(theme("padding.48") + theme("padding.4"))' 36 | }, 37 | margin: { 38 | '.2': '0.125rem' 39 | }, 40 | fontSize: { 41 | '5vw': '5vw', 42 | '8vw': '8vw', 43 | }, 44 | fill: theme => { 45 | return theme('colors') 46 | }, 47 | stroke: theme => { 48 | return theme('colors') 49 | }, 50 | borderRadius: { 51 | 'huge': '200px' 52 | }, 53 | minHeight: { 54 | 'auto': 'auto', 55 | }, 56 | maxHeight: { 57 | 'sm': '16rem' 58 | }, 59 | maxWidth: { 60 | 'screen': '100vw' 61 | }, 62 | width: theme => { 63 | return theme('maxWidth') 64 | }, 65 | lineHeight: { 66 | '6': '1.5rem' 67 | }, 68 | backgroundSize: { 69 | 2: '0.25rem 0.25rem', 70 | }, 71 | }, 72 | }, 73 | variants: ['responsive', 'group-hover', 'focus-within', 'hover', 'focus', 'active', 'dark',], 74 | plugins: [ 75 | require('@tailwindcss/custom-forms'), 76 | function({ addVariant, e }) { 77 | addVariant('dark', ({ container, separator }) => { 78 | container.walkRules(rule => { 79 | rule.selector = `[data-dark] .${e(`dark${separator}${rule.selector.slice(1)}`)}` 80 | }) 81 | }) 82 | } 83 | ], 84 | } 85 | -------------------------------------------------------------------------------- /index.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | 3 |
4 | {{> header }} 5 |
6 | {{#is "page"}} 7 |

Articles

8 |

I like to write about things that have helped me and about things I think can help others. The ones with a bookmark icon next to them are my favourites.

9 | {{else}} 10 |

Ficción

11 | {{/is}} 12 |
13 |
14 | {{#get "posts" limit="4" filter="featured:true"}} 15 | 28 | {{/get}} 29 | {{#foreach posts}} 30 |
31 |
32 | 33 | {{#if featured}} 34 | 35 | {{/if}} 36 | {{ date format="MMM \\'YY" }} — {{ reading_time }} 37 | 38 |

39 | {{title}} 40 |

41 |
42 |
43 | {{/foreach}} 44 |
45 |
-------------------------------------------------------------------------------- /src/less/lib/prism.less: -------------------------------------------------------------------------------- 1 | code[class*='language-'], 2 | pre[class*='language-'] { 3 | color: #ffffff; 4 | @apply .font-mono; 5 | direction: ltr; 6 | text-align: left; 7 | white-space: pre; 8 | word-spacing: normal; 9 | word-break: normal; 10 | line-height: 1.5; 11 | 12 | -moz-tab-size: 4; 13 | -o-tab-size: 4; 14 | tab-size: 4; 15 | 16 | -webkit-hyphens: none; 17 | -moz-hyphens: none; 18 | -ms-hyphens: none; 19 | hyphens: none; 20 | } 21 | 22 | pre[class*='language-']::-moz-selection, 23 | pre[class*='language-'] ::-moz-selection, 24 | code[class*='language-']::-moz-selection, 25 | code[class*='language-'] ::-moz-selection { 26 | color: inherit; 27 | background: #A599E9; 28 | } 29 | 30 | pre[class*='language-']::selection, 31 | pre[class*='language-'] ::selection, 32 | code[class*='language-']::selection, 33 | code[class*='language-'] ::selection { 34 | color: inherit; 35 | background: #A599E9; 36 | } 37 | 38 | /* Code blocks */ 39 | pre[class*='language-'] { 40 | padding: 2em; 41 | margin: 0.5em 0; 42 | overflow: auto; 43 | } 44 | 45 | :not(pre)>code[class*='language-'], 46 | pre[class*='language-'] { 47 | background: #1E1E3F; 48 | } 49 | 50 | /* Inline code */ 51 | :not(pre)>code[class*='language-'] { 52 | padding: 0.1em; 53 | border-radius: 0.3em; 54 | } 55 | 56 | .token.comment, 57 | .token.prolog, 58 | .token.cdata { 59 | color: #B362FF; 60 | } 61 | 62 | .token.delimiter, 63 | .token.keyword, 64 | .token.selector, 65 | .token.important, 66 | .token.atrule { 67 | color: #FF9D00; 68 | } 69 | 70 | .token.operator, 71 | .token.attr-name { 72 | color: rgb(255, 180, 84); 73 | } 74 | 75 | .token.punctuation { 76 | color: #FFFFFF; 77 | } 78 | 79 | .token.boolean { 80 | color: rgb(255, 98, 140); 81 | } 82 | 83 | .token.tag, 84 | .token.tag .punctuation, 85 | .token.doctype, 86 | .token.builtin { 87 | color: rgb(255, 157, 0); 88 | } 89 | 90 | .token.entity, 91 | .token.number, 92 | .token.symbol { 93 | color: #6897bb; 94 | } 95 | 96 | .token.property, 97 | .token.constant, 98 | .token.variable { 99 | color: #FF628C; 100 | } 101 | 102 | .token.string, 103 | .token.char { 104 | color: #A5FF90; 105 | } 106 | 107 | .token.attr-value, 108 | .token.attr-value .punctuation { 109 | color: #a5c261; 110 | } 111 | 112 | .token.attr-value .punctuation:first-child { 113 | color: #a9b7c6; 114 | } 115 | 116 | .token.url { 117 | color: #287bde; 118 | text-decoration: underline; 119 | } 120 | 121 | .token.function { 122 | color: rgb(250, 208, 0); 123 | } 124 | 125 | .token.regex { 126 | background: #364135; 127 | } 128 | 129 | .token.bold { 130 | font-weight: bold; 131 | } 132 | 133 | .token.italic { 134 | font-style: italic; 135 | } 136 | 137 | .token.inserted { 138 | color: #00FF00; 139 | } 140 | 141 | .token.deleted { 142 | color: #FF000D; 143 | } 144 | 145 | /*code.language-css .token.punctuation { 146 | color: #cc7832; 147 | }*/ 148 | 149 | code.language-css .token.property, 150 | code.language-css .token.property+.token.punctuation { 151 | color: #a9b7c6; 152 | } 153 | 154 | code.language-css .token.id { 155 | color: #ffc66d; 156 | } 157 | 158 | code.language-css .token.selector>.token.class, 159 | code.language-css .token.selector>.token.attribute, 160 | code.language-css .token.selector>.token.pseudo-class, 161 | code.language-css .token.selector>.token.pseudo-element { 162 | color: #ffc66d; 163 | } 164 | 165 | .token.class-name { 166 | color: #FB94FF; 167 | } 168 | -------------------------------------------------------------------------------- /post.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | 3 | {{> header }} 4 | {{#post}} 5 |
6 |
7 |

{{ title }}

8 | {{ date format="MMMM DD, YYYY" }} — {{ reading_time }} 9 |
10 |
11 |
12 |
13 | {{content}} 14 |
15 |
16 |
17 |
18 |

Enjoyed the article? Consider sharing it on Twitter so others can enjoy it too :)

19 | 25 |
26 |
27 |
28 |

Receive project updates, article drafts & thoughts on your inbox every saturday.

29 | Subscribe 30 |
31 |
32 | 33 |
34 | 35 |
36 | {{#next_post in="primary_author" }} 37 | 38 |
next article
39 | 40 |
{{ title }}
41 |
42 | {{/next_post}} 43 | 44 | {{#prev_post in="primary_author"}} 45 | 46 |
previous article
47 | 48 |
{{ title }}
49 |
50 | {{/prev_post}} 51 |
52 | 53 | 54 | {{/post}} 55 | -------------------------------------------------------------------------------- /src/less/components/_post.less: -------------------------------------------------------------------------------- 1 | #article, .article { 2 | @apply .font-main .leading-relaxed; 3 | 4 | h1 { 5 | @apply .text-4xl .my-6; 6 | } 7 | 8 | h2 { 9 | @apply .text-3xl .my-6; 10 | } 11 | 12 | h3 { 13 | @apply .text-2xl .my-6; 14 | } 15 | 16 | p { 17 | @apply .font-light .text-xl .my-6 .text-justify; 18 | } 19 | 20 | a:not([data-ignore-link-styling]) { 21 | @apply .border-b-2 .border-sepia-900; 22 | 23 | &:hover { 24 | @apply .text-gradient .border-gradient; 25 | } 26 | } 27 | 28 | ul, ol { 29 | @apply .ml-4 .list-outside .text-xl; 30 | 31 | li { 32 | @apply .ml-2 .my-2; 33 | } 34 | } 35 | 36 | ul { 37 | @apply .list-disc; 38 | } 39 | 40 | ol { 41 | @apply .list-decimal; 42 | } 43 | 44 | blockquote { 45 | @apply .italic .border-l-4 .border-sepia-900 .pl-2 .text-xl; 46 | } 47 | 48 | strong { 49 | @apply .font-bold; 50 | } 51 | 52 | .footnote-ref { 53 | @apply .ml-1; 54 | 55 | a { 56 | @apply .border-0 .text-sm; 57 | } 58 | } 59 | 60 | hr.footnotes-sep { 61 | @apply .border-b-2 .border-sepia-900 .my-8 .mx-10; 62 | } 63 | 64 | section.footnotes ol { 65 | @apply .text-base .mx-10; 66 | 67 | li { 68 | p { 69 | @apply .text-base; 70 | } 71 | 72 | a.footnote-backref { 73 | @apply .font-sans-no-emoji .border-0; 74 | } 75 | } 76 | } 77 | 78 | table { 79 | @apply .w-full .font-mono .text-xs; 80 | border-collapse: separate; 81 | border-spacing: .125rem; 82 | 83 | thead th { 84 | @apply .border-b .border-black .text-left; 85 | } 86 | 87 | td, th { 88 | @apply .py-1 .px-2; 89 | } 90 | 91 | tbody tr { 92 | &:hover { 93 | @apply .bg-white; 94 | } 95 | } 96 | } 97 | 98 | code a:not([data-ignore-link-styling]) { 99 | border-color: currentColor; 100 | } 101 | 102 | pre { 103 | @apply .my-4 .rounded-lg; 104 | } 105 | 106 | :not(pre) > code { 107 | @apply bg-sepia-100 text-sm leading-6 inline-block rounded px-1 whitespace-no-wrap text-sepia-900 font-normal align-baseline; 108 | 109 | transition: background-color 1s ease-in, color 1s ease-in; 110 | } 111 | 112 | :not(pre) { 113 | overflow-wrap: break-word; 114 | } 115 | 116 | figure { 117 | @apply .m-0; 118 | } 119 | 120 | figcaption { 121 | @apply .text-center .p-2 .text-sepia-100; 122 | 123 | a { 124 | @apply .border-sepia-100; 125 | } 126 | } 127 | 128 | img { 129 | @apply .max-w-full .rounded-lg .z-10 .block; 130 | } 131 | 132 | .kg-width-wide img { 133 | max-width: 85vw; 134 | } 135 | 136 | .kg-width-full img { 137 | @apply .max-w-screen .w-screen .rounded-none; 138 | } 139 | 140 | .kg-gallery-container { 141 | @apply .flex .flex-col .mx-auto .my-6 .max-w-5xl; 142 | } 143 | 144 | .kg-gallery-row { 145 | @apply .flex .flex-row .justify-center; 146 | } 147 | 148 | .kg-gallery-image img { 149 | @apply .block .m-0 .w-full .h-full; 150 | } 151 | 152 | .kg-gallery-row:not(:first-of-type) { 153 | margin: 0.75em 0 0 0; 154 | } 155 | 156 | .kg-gallery-image:not(:first-of-type) { 157 | margin: 0 0 0 0.75em; 158 | } 159 | 160 | .kg-card { 161 | @apply .flex .flex-col .items-center .w-full; 162 | } 163 | 164 | .kg-image-blob, 165 | .code-blob { 166 | @apply .relative; 167 | } 168 | } 169 | 170 | .twitter-btn { 171 | @apply .rounded .inline-flex .items-center .text-white .p-2; 172 | background-color: #1a95e0; 173 | color: white; 174 | 175 | &:hover { 176 | background-color: #0c7abf; 177 | } 178 | 179 | svg { 180 | @apply .w-4 .h-4 .mr-1; 181 | } 182 | } 183 | 184 | .patreon-btn { 185 | @apply .mt-4 .flex .items-center .justify-center .rounded .py-2 .px-4 .w-full .max-w-xs .mx-auto; 186 | background-color: rgb(249, 104, 84); 187 | border-color: rgb(249, 104, 84); 188 | color: white; 189 | 190 | svg { 191 | @apply .w-4 .h-4 .mr-2; 192 | } 193 | 194 | p { 195 | @apply .uppercase .font-semibold; 196 | @apply .m-0 !important; 197 | color: white; 198 | } 199 | } 200 | 201 | @import "../lib/prism"; -------------------------------------------------------------------------------- /src/less/components/_comments.less: -------------------------------------------------------------------------------- 1 | .commento-root { 2 | @apply mt-10 max-w-3xl mx-auto bg-white shadow px-4 pt-4 rounded-lg overflow-x-auto !important; 3 | transition: background-color 1s ease-in; 4 | 5 | * { 6 | transition: color 1s ease-in; 7 | } 8 | 9 | &.commento-root-min-height { 10 | min-height: 335px !important; 11 | } 12 | 13 | .commento-blurred { 14 | filter: blur(3px); 15 | pointer-events: none; 16 | @apply .opacity-100 .pointer-events-none !important; 17 | } 18 | 19 | .commento-main-area { 20 | transition: none !important; 21 | } 22 | 23 | .commento-login-box { 24 | @apply .rounded-lg .bg-white .shadow-lg .w-full !important; 25 | transition: background-color 1s ease-in !important; 26 | 27 | .commento-oauth-buttons { 28 | .commento-button { 29 | @apply .text-white .shadow !important; 30 | } 31 | .commento-github-button { 32 | @apply .bg-black !important; 33 | transition: background-color 1s ease-in, color 1s ease-in; 34 | } 35 | } 36 | 37 | .commento-login-box-hr { 38 | @apply .bg-sepia-100 !important; 39 | } 40 | 41 | .commento-login-box-subtitle { 42 | @apply .text-sepia-900 !important; 43 | } 44 | 45 | .commento-login-link { 46 | @apply .border-b-2 .border-blue-500 .border-solid .text-blue-500 .font-semibold !important; 47 | transition: color 1s ease-in, border-color 1s ease-in; 48 | 49 | &:hover { 50 | @apply .border-gradient .text-gradient; 51 | } 52 | } 53 | 54 | .commento-email { 55 | @apply .bg-white .rounded-lg .shadow-md .overflow-hidden .flex .items-center .items-stretch .justify-between !important; 56 | transition: background-color 1s ease-in; 57 | 58 | .commento-input { 59 | @apply .h-full .flex-1 .rounded-none !important; 60 | } 61 | 62 | .commento-email-button { 63 | @apply .text-blue-500 !important; 64 | 65 | &:hover { 66 | @apply .bg-gradient .text-white !important; 67 | } 68 | } 69 | } 70 | } 71 | 72 | .commento-login { 73 | @apply .flex .items-center .justify-between .w-auto .mb-4 !important; 74 | 75 | &:before { 76 | content: "Comments"; 77 | 78 | @apply .text-left .text-xl .font-medium .text-sepia-900; 79 | } 80 | 81 | } 82 | .commento-login .commento-login-text, 83 | .commento-logged-container .commento-logout { 84 | @apply .mr-0 .h-auto .text-sepia-900 .font-bold !important; 85 | 86 | &:hover { 87 | @apply .text-gradient; 88 | } 89 | } 90 | 91 | .commento-error-box { 92 | @apply .bg-red-500 .text-white .h-auto .py-2 .mb-4 !important; 93 | } 94 | 95 | .commento-logged-container { 96 | @apply .static .h-auto .flex .items-center .justify-between !important; 97 | 98 | .commento-logged-in-as { 99 | @apply .static .flex .items-center !important; 100 | .commento-name { 101 | @apply .static .text-sepia-900 !important; 102 | } 103 | } 104 | 105 | .commento-logout { 106 | @apply .static .w-full .text-right !important; 107 | } 108 | } 109 | 110 | .commento-mod-tools { 111 | &:before { 112 | @apply .text-blue-500 !important; 113 | transition: color 1s ease-in; 114 | } 115 | 116 | #commento-mod-tools-lock-button { 117 | @apply .text-sepia-300 !important; 118 | } 119 | } 120 | 121 | .commento-round-check { 122 | input:checked+label:before { 123 | @apply .bg-blue-500 .border-blue-500 !important; 124 | transition: background-color 1s ease-in, border-color 1s ease-in; 125 | } 126 | 127 | label { 128 | @apply .text-sepia-300 !important; 129 | } 130 | } 131 | 132 | 133 | .commento-textarea-container textarea { 134 | @apply .bg-sepia-500 .rounded-lg !important; 135 | transition: background-color 1s ease-in; 136 | 137 | &:focus { 138 | @apply .shadow-outline; 139 | } 140 | } 141 | 142 | .commento-markdown-help, 143 | .commento-body { 144 | @apply .mb-4 !important; 145 | 146 | * { 147 | @apply .text-sepia-900 !important; 148 | transition: color 1s ease-in; 149 | } 150 | 151 | tr { 152 | @apply .pl-2 !important; 153 | } 154 | 155 | a { 156 | @apply .border-b-2 .border-sepia-900 .text-sepia-900 !important; 157 | transition: color 1s ease-in, border-color 1s ease-in; 158 | 159 | &:hover { 160 | @apply .text-gradient .border-gradient !important; 161 | } 162 | } 163 | 164 | blockquote { 165 | @apply .italic .border-l-4 .pl-2 .m-0 !important; 166 | } 167 | } 168 | 169 | .commento-submit-button { 170 | @apply .text-white .bg-blue-500 .border-0 .rounded-lg !important; 171 | transition: background-color 1s ease-in, color 1s ease-in; 172 | 173 | &:hover { 174 | @apply .bg-gradient !important; 175 | } 176 | } 177 | 178 | .commento-markdown-button { 179 | @apply .text-sepia-900 .m-0 !important; 180 | font-size: 0 !important; 181 | 182 | &:before { 183 | @apply .font-bold .mr-1; 184 | font-size: initial !important; 185 | content: "M↓"; 186 | } 187 | 188 | &:after { 189 | @apply .text-sm .normal-case !important; 190 | content: "Markdown"; 191 | } 192 | 193 | b { 194 | @apply .hidden !important; 195 | } 196 | } 197 | 198 | .commento-markdown-help { 199 | @apply .w-full .border-sepia-300 !important; 200 | } 201 | 202 | .commento-card { 203 | @apply .border-t-0 .pt-0 !important; 204 | 205 | .commento-option- { 206 | &collapse { 207 | @apply .hidden !important; 208 | } 209 | 210 | &remove { 211 | @apply .bg-red-500 !important; 212 | } 213 | 214 | &unsticky { 215 | @apply .bg-orange-400 !important; 216 | } 217 | } 218 | 219 | .commento-name { 220 | @apply .text-sepia-900 !important; 221 | } 222 | 223 | .commento-score, 224 | .commento-timeago { 225 | @apply .text-sepia-300 !important; 226 | } 227 | } 228 | 229 | .commento-footer { 230 | @apply hidden; 231 | } 232 | } -------------------------------------------------------------------------------- /amp.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{!-- Document Settings --}} 5 | 6 | 7 | {{!-- Page Meta --}} 8 | {{meta_title}} 9 | 10 | {{!-- Mobile Meta --}} 11 | 12 | 13 | 14 | {{amp_ghost_head}} 15 | 16 | {{!-- Styles'n'Scripts --}} 17 | 18 | 19 | 20 | {{!-- The AMP boilerplate --}} 21 | 22 | 23 | 24 | {{amp_components}} 25 | 26 | 27 | 28 | 29 | {{#post}} 30 |
31 | 34 |
35 | 36 |
37 |
38 | 39 |
40 |

{{title}}

41 | 45 |
46 | {{#if feature_image}} 47 |
48 | 49 |
50 | {{/if}} 51 |
52 | 53 | {{amp_content}} 54 | 55 |
56 | 57 |
58 |
59 | {{/post}} 60 | 63 | 64 | -------------------------------------------------------------------------------- /src/js/lib/svgBlob.js: -------------------------------------------------------------------------------- 1 | import noise from './noise' 2 | import { addListener } from 'resize-detector' 3 | 4 | (global => { 5 | class SvgBlob { 6 | constructor(elements, options) { 7 | this.defaults = { 8 | clipPadding: 20, 9 | minPointsDistance: 80, 10 | speedFactor: 1, 11 | animateOnHover: true, 12 | animateWhenVisible: false, 13 | hideOnMobile: false, 14 | round: true, 15 | resize: true, 16 | resizeTimeout: 100, 17 | debug: false 18 | } 19 | 20 | this.init(elements, options) 21 | } 22 | init(elements, options) { 23 | this.options = extend({}, this.defaults, options) 24 | var nodes = is.str(elements) ? document.querySelectorAll(elements) : elements 25 | this.elements = [] 26 | for (var index = 0; index < nodes.length; index++) { 27 | var node = nodes[index] 28 | this.elements.push(this.initElement(node)) 29 | this.updatePath(index, 0) 30 | if (this.options.animateOnHover) { 31 | node.addEventListener('mouseenter', this.resumeAnimation.bind(this, index)) 32 | node.addEventListener('mouseleave', this.pauseAnimation.bind(this, index)) 33 | } 34 | if (this.options.animateWhenVisible) { 35 | var interIndex = index, 36 | observer = new IntersectionObserver(entries => { 37 | entries.forEach(entry => { 38 | entry.isIntersecting ? this.resumeAnimation(interIndex) : this.pauseAnimation(interIndex) 39 | }) 40 | }, { 41 | rootMargin: "0px", 42 | threshold: 0.1 43 | }); 44 | observer.observe(node); 45 | } 46 | if (this.options.resize) { 47 | function resize(index) { 48 | var element = this.elements[index] 49 | if (element.resizeTimer) { 50 | clearTimeout(element.resizeTimer) 51 | } 52 | element.resizeTimer = setTimeout(this.resizeElement.bind(this, index), this.options.resizeTimeout) 53 | } 54 | addListener(node, resize.bind(this, index)) 55 | } 56 | } 57 | } 58 | initElement(node) { 59 | var width = node.offsetWidth 60 | var height = node.offsetHeight 61 | var points = this.getPoints(width, height, this.options) 62 | var svg = document.createElementNS(_svgNS, 'svg') 63 | svg.setAttribute('viewBox', '0 0 ' + width + ' ' + height + '') 64 | var path = document.createElementNS(_svgNS, 'path') 65 | path.setAttribute('class', 'svg-blob__path') 66 | if (this.options.debug) { 67 | svg.setAttribute('class', 'svg-blob__svg --debug') 68 | svg.appendChild(path) 69 | } else { 70 | svg.setAttribute('class', `absolute left-0 top-0 w-full h-full pointer-events-none ${this.options.hideOnMobile ? 'hidden md:block':''}`) 71 | var defs = document.createElementNS(_svgNS, 'defs') 72 | svg.appendChild(defs) 73 | var clipPath = document.createElementNS(_svgNS, 'clipPath') 74 | var clipPathId = 'svg-blob__clip--' + uuidv4() + '' 75 | clipPath.setAttribute('id', clipPathId) 76 | defs.appendChild(clipPath) 77 | node.style.clipPath = 'url(#' + clipPathId + ')' 78 | clipPath.appendChild(path) 79 | } 80 | node.insertBefore(svg, node.firstChild) 81 | 82 | return { 83 | node: node, 84 | points: points, 85 | svg: svg, 86 | path: path, 87 | time: randomInRange(0, 10000), 88 | raf: { 89 | id: 0, 90 | timeDiff: 0, 91 | paused: true 92 | } 93 | } 94 | } 95 | getPoints(width, height) { 96 | var clipPadding = this.options.clipPadding 97 | var sides = [{ 98 | name: 'top', 99 | points: this.generatePoints(width) 100 | }, { 101 | name: 'right', 102 | points: this.generatePoints(height) 103 | }, { 104 | name: 'bottom', 105 | points: this.generatePoints(width) 106 | }, { 107 | name: 'left', 108 | points: this.generatePoints(height) 109 | }] 110 | var points = [] 111 | sides.forEach(function (side) { 112 | var horizontal = side.name === 'top' || side.name === 'bottom' 113 | var topOrRight = side.name === 'top' || side.name === 'right' 114 | var topOrLeft = side.name === 'top' || side.name === 'left' 115 | var value, valueRange, randRange 116 | side.points.forEach(function (point) { 117 | value = topOrRight ? point : (horizontal ? width : height) - point 118 | valueRange = topOrRight ? [value - clipPadding, value] : [value, value + clipPadding] 119 | randRange = topOrLeft ? [0, clipPadding] : [-clipPadding, 0] 120 | if (side.name === 'right') { 121 | randRange[0] += width 122 | randRange[1] += width 123 | } else if (side.name === 'bottom') { 124 | randRange[0] += height 125 | randRange[1] += height 126 | } 127 | points.push({ 128 | xRange: horizontal ? valueRange : randRange, 129 | yRange: horizontal ? randRange : valueRange 130 | }) 131 | }) 132 | }) 133 | return points 134 | } 135 | generatePoints(len) { 136 | var minPointsDistance = this.options.minPointsDistance 137 | var points = [] 138 | var lines = [{ 139 | x: 0, 140 | w: len 141 | }] 142 | 143 | function splitLine() { 144 | if (lines.length) { 145 | var line = lines.shift() 146 | if (line.w > minPointsDistance * 2) { 147 | var line1Size = randomInRange(minPointsDistance, line.w - minPointsDistance) 148 | var line1 = extend({}, line, { 149 | w: line1Size 150 | }) 151 | var line2 = extend({}, line, { 152 | x: line.x + line1Size, 153 | w: line.w - line1Size 154 | }) 155 | lines.push(line1, line2) 156 | } else { 157 | points.push(line) 158 | splitLine() 159 | } 160 | } else { 161 | points = points.sort(function (a, b) { 162 | return a.x - b.x 163 | }).map(function (line) { 164 | return line.x 165 | }) 166 | points.shift() 167 | points.push(len) 168 | } 169 | } 170 | while (lines.length) { 171 | splitLine() 172 | } 173 | return points 174 | } 175 | updatePath(index, timeDiff) { 176 | var speedFactor = this.options.speedFactor 177 | var element = this.elements[index] 178 | var time = element.time + timeDiff 179 | element.points.forEach(function (point, pointIndex) { 180 | var noiseX = (noise.simplex2(pointIndex * 2, time * 0.0005 * speedFactor) + 1) / 2 181 | var noiseY = (noise.simplex2(pointIndex * 2 + 1, time * 0.0005 * speedFactor) + 1) / 2 182 | var xMin = point.xRange[0] 183 | var xMax = point.xRange[1] 184 | var yMin = point.yRange[0] 185 | var yMax = point.yRange[1] 186 | point.x = noiseX * (xMax - xMin) + xMin 187 | point.y = noiseY * (yMax - yMin) + yMin 188 | }) 189 | element.path.setAttribute('d', this.buildPath(element.points)) 190 | } 191 | buildPath(points) { 192 | var d = 'M ' + points[0].x + ' ' + points[0].y + '' 193 | var i, p0, p1, len = points.length 194 | for (i = 0; i <= len; i++) { 195 | p0 = points[i >= len ? i - len : i] 196 | p1 = points[i + 1 >= len ? i + 1 - len : i + 1] 197 | if (this.options.round) { 198 | d += ' Q ' + p0.x + ' ' + p0.y + ' ' + (p0.x + p1.x) * 0.5 + ' ' + (p0.y + p1.y) * 0.5 + '' 199 | } else { 200 | d += ' L ' + p0.x + ' ' + p0.y + '' 201 | } 202 | } 203 | return d 204 | } 205 | resumeAnimation(index) { 206 | var raf = this.elements[index].raf 207 | if (raf.paused) { 208 | var time0 = performance.now() 209 | var time1, timeDiff 210 | var self = this 211 | 212 | function render() { 213 | time1 = performance.now() 214 | timeDiff = time1 - time0 215 | self.updatePath(index, timeDiff) 216 | raf.timeDiff = timeDiff 217 | raf.id = requestAnimationFrame(render) 218 | } 219 | raf.paused = false 220 | raf.timeDiff = 0 221 | raf.id = requestAnimationFrame(render) 222 | } 223 | } 224 | pauseAnimation(index) { 225 | var element = this.elements[index] 226 | var raf = element.raf 227 | if (!raf.paused) { 228 | cancelAnimationFrame(raf.id) 229 | element.time += raf.timeDiff 230 | raf.paused = true 231 | } 232 | } 233 | resizeElement(index) { 234 | var element = this.elements[index] 235 | this.pauseAnimation(index) 236 | var width = element.node.offsetWidth 237 | var height = element.node.offsetHeight 238 | element.points = this.getPoints(width, height) 239 | element.svg.setAttribute('viewBox', '0 0 ' + width + ' ' + height + '') 240 | element.time = randomInRange(0, 10000) 241 | element.raf = { 242 | id: 0, 243 | timeDiff: 0 244 | } 245 | this.updatePath(index, 0) 246 | } 247 | } 248 | var _svgNS = 'http://www.w3.org/2000/svg' 249 | var is = { 250 | arr: function arr(a) { 251 | return Array.isArray(a) 252 | }, 253 | str: function str(a) { 254 | return typeof a === 'string' 255 | }, 256 | fnc: function fnc(a) { 257 | return typeof a === 'function' 258 | }, 259 | und: function und(a) { 260 | return typeof a === 'undefined' 261 | } 262 | } 263 | 264 | function uuidv4() { 265 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 266 | var r = Math.random() * 16 | 0, 267 | v = c == 'x' ? r : (r & 0x3 | 0x8) 268 | return v.toString(16) 269 | }) 270 | } 271 | 272 | function extendSingle(target, source) { 273 | for (var key in source) { 274 | target[key] = is.arr(source[key]) ? source[key].slice(0) : source[key] 275 | } 276 | return target 277 | } 278 | 279 | function extend(target, source) { 280 | if (!target) target = {} 281 | for (var i = 1; i < arguments.length; i++) { 282 | extendSingle(target, arguments[i]) 283 | } 284 | return target 285 | } 286 | 287 | function randomInRange(min, max) { 288 | return Math.floor(Math.random() * (max - min + 1)) + min 289 | } 290 | 291 | global.SvgBlob = SvgBlob 292 | })(window) -------------------------------------------------------------------------------- /src/js/lib/noise.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A speed-improved perlin and simplex noise algorithms for 2D. 3 | * 4 | * Based on example code by Stefan Gustavson (stegu@itn.liu.se). 5 | * Optimisations by Peter Eastman (peastman@drizzle.stanford.edu). 6 | * Better rank ordering method by Stefan Gustavson in 2012. 7 | * Converted to Javascript by Joseph Gentle. 8 | * 9 | * Version 2012-03-09 10 | * 11 | * This code was placed in the public domain by its original author, 12 | * Stefan Gustavson. You may use it as you see fit, but 13 | * attribution is appreciated. 14 | * 15 | */ 16 | 17 | var module = {}; 18 | 19 | class Grad { 20 | constructor(x, y, z) { 21 | this.x = x; 22 | this.y = y; 23 | this.z = z; 24 | } 25 | dot2(x, y) { 26 | return this.x * x + this.y * y; 27 | } 28 | dot3(x, y, z) { 29 | return this.x * x + this.y * y + this.z * z; 30 | } 31 | } 32 | 33 | 34 | 35 | var grad3 = [new Grad(1, 1, 0), new Grad(-1, 1, 0), new Grad(1, -1, 0), new Grad(-1, -1, 0), 36 | new Grad(1, 0, 1), new Grad(-1, 0, 1), new Grad(1, 0, -1), new Grad(-1, 0, -1), 37 | new Grad(0, 1, 1), new Grad(0, -1, 1), new Grad(0, 1, -1), new Grad(0, -1, -1) 38 | ]; 39 | 40 | var p = [151, 160, 137, 91, 90, 15, 41 | 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 42 | 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 43 | 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 44 | 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 45 | 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 46 | 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 47 | 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 48 | 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 49 | 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 50 | 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 51 | 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 52 | 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 53 | ]; 54 | // To remove the need for index wrapping, double the permutation table length 55 | var perm = new Array(512); 56 | var gradP = new Array(512); 57 | 58 | // This isn't a very good seeding function, but it works ok. It supports 2^16 59 | // different seed values. Write something better if you need more seeds. 60 | module.seed = function (seed) { 61 | if (seed > 0 && seed < 1) { 62 | // Scale the seed out 63 | seed *= 65536; 64 | } 65 | 66 | seed = Math.floor(seed); 67 | if (seed < 256) { 68 | seed |= seed << 8; 69 | } 70 | 71 | for (var i = 0; i < 256; i++) { 72 | var v; 73 | if (i & 1) { 74 | v = p[i] ^ (seed & 255); 75 | } else { 76 | v = p[i] ^ ((seed >> 8) & 255); 77 | } 78 | 79 | perm[i] = perm[i + 256] = v; 80 | gradP[i] = gradP[i + 256] = grad3[v % 12]; 81 | } 82 | }; 83 | 84 | module.seed(0); 85 | 86 | /* 87 | for(var i=0; i<256; i++) { 88 | perm[i] = perm[i + 256] = p[i]; 89 | gradP[i] = gradP[i + 256] = grad3[perm[i] % 12]; 90 | }*/ 91 | 92 | // Skewing and unskewing factors for 2, 3, and 4 dimensions 93 | var F2 = 0.5 * (Math.sqrt(3) - 1); 94 | var G2 = (3 - Math.sqrt(3)) / 6; 95 | 96 | var F3 = 1 / 3; 97 | var G3 = 1 / 6; 98 | 99 | // 2D simplex noise 100 | module.simplex2 = function (xin, yin) { 101 | var n0, n1, n2; // Noise contributions from the three corners 102 | // Skew the input space to determine which simplex cell we're in 103 | var s = (xin + yin) * F2; // Hairy factor for 2D 104 | var i = Math.floor(xin + s); 105 | var j = Math.floor(yin + s); 106 | var t = (i + j) * G2; 107 | var x0 = xin - i + t; // The x,y distances from the cell origin, unskewed. 108 | var y0 = yin - j + t; 109 | // For the 2D case, the simplex shape is an equilateral triangle. 110 | // Determine which simplex we are in. 111 | var i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords 112 | if (x0 > y0) { // lower triangle, XY order: (0,0)->(1,0)->(1,1) 113 | i1 = 1; 114 | j1 = 0; 115 | } else { // upper triangle, YX order: (0,0)->(0,1)->(1,1) 116 | i1 = 0; 117 | j1 = 1; 118 | } 119 | // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and 120 | // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where 121 | // c = (3-sqrt(3))/6 122 | var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords 123 | var y1 = y0 - j1 + G2; 124 | var x2 = x0 - 1 + 2 * G2; // Offsets for last corner in (x,y) unskewed coords 125 | var y2 = y0 - 1 + 2 * G2; 126 | // Work out the hashed gradient indices of the three simplex corners 127 | i &= 255; 128 | j &= 255; 129 | var gi0 = gradP[i + perm[j]]; 130 | var gi1 = gradP[i + i1 + perm[j + j1]]; 131 | var gi2 = gradP[i + 1 + perm[j + 1]]; 132 | // Calculate the contribution from the three corners 133 | var t0 = 0.5 - x0 * x0 - y0 * y0; 134 | if (t0 < 0) { 135 | n0 = 0; 136 | } else { 137 | t0 *= t0; 138 | n0 = t0 * t0 * gi0.dot2(x0, y0); // (x,y) of grad3 used for 2D gradient 139 | } 140 | var t1 = 0.5 - x1 * x1 - y1 * y1; 141 | if (t1 < 0) { 142 | n1 = 0; 143 | } else { 144 | t1 *= t1; 145 | n1 = t1 * t1 * gi1.dot2(x1, y1); 146 | } 147 | var t2 = 0.5 - x2 * x2 - y2 * y2; 148 | if (t2 < 0) { 149 | n2 = 0; 150 | } else { 151 | t2 *= t2; 152 | n2 = t2 * t2 * gi2.dot2(x2, y2); 153 | } 154 | // Add contributions from each corner to get the final noise value. 155 | // The result is scaled to return values in the interval [-1,1]. 156 | return 70 * (n0 + n1 + n2); 157 | }; 158 | 159 | // 3D simplex noise 160 | module.simplex3 = function (xin, yin, zin) { 161 | var n0, n1, n2, n3; // Noise contributions from the four corners 162 | 163 | // Skew the input space to determine which simplex cell we're in 164 | var s = (xin + yin + zin) * F3; // Hairy factor for 2D 165 | var i = Math.floor(xin + s); 166 | var j = Math.floor(yin + s); 167 | var k = Math.floor(zin + s); 168 | 169 | var t = (i + j + k) * G3; 170 | var x0 = xin - i + t; // The x,y distances from the cell origin, unskewed. 171 | var y0 = yin - j + t; 172 | var z0 = zin - k + t; 173 | 174 | // For the 3D case, the simplex shape is a slightly irregular tetrahedron. 175 | // Determine which simplex we are in. 176 | var i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords 177 | var i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords 178 | if (x0 >= y0) { 179 | if (y0 >= z0) { 180 | i1 = 1; 181 | j1 = 0; 182 | k1 = 0; 183 | i2 = 1; 184 | j2 = 1; 185 | k2 = 0; 186 | } else if (x0 >= z0) { 187 | i1 = 1; 188 | j1 = 0; 189 | k1 = 0; 190 | i2 = 1; 191 | j2 = 0; 192 | k2 = 1; 193 | } else { 194 | i1 = 0; 195 | j1 = 0; 196 | k1 = 1; 197 | i2 = 1; 198 | j2 = 0; 199 | k2 = 1; 200 | } 201 | } else { 202 | if (y0 < z0) { 203 | i1 = 0; 204 | j1 = 0; 205 | k1 = 1; 206 | i2 = 0; 207 | j2 = 1; 208 | k2 = 1; 209 | } else if (x0 < z0) { 210 | i1 = 0; 211 | j1 = 1; 212 | k1 = 0; 213 | i2 = 0; 214 | j2 = 1; 215 | k2 = 1; 216 | } else { 217 | i1 = 0; 218 | j1 = 1; 219 | k1 = 0; 220 | i2 = 1; 221 | j2 = 1; 222 | k2 = 0; 223 | } 224 | } 225 | // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), 226 | // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and 227 | // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where 228 | // c = 1/6. 229 | var x1 = x0 - i1 + G3; // Offsets for second corner 230 | var y1 = y0 - j1 + G3; 231 | var z1 = z0 - k1 + G3; 232 | 233 | var x2 = x0 - i2 + 2 * G3; // Offsets for third corner 234 | var y2 = y0 - j2 + 2 * G3; 235 | var z2 = z0 - k2 + 2 * G3; 236 | 237 | var x3 = x0 - 1 + 3 * G3; // Offsets for fourth corner 238 | var y3 = y0 - 1 + 3 * G3; 239 | var z3 = z0 - 1 + 3 * G3; 240 | 241 | // Work out the hashed gradient indices of the four simplex corners 242 | i &= 255; 243 | j &= 255; 244 | k &= 255; 245 | var gi0 = gradP[i + perm[j + perm[k]]]; 246 | var gi1 = gradP[i + i1 + perm[j + j1 + perm[k + k1]]]; 247 | var gi2 = gradP[i + i2 + perm[j + j2 + perm[k + k2]]]; 248 | var gi3 = gradP[i + 1 + perm[j + 1 + perm[k + 1]]]; 249 | 250 | // Calculate the contribution from the four corners 251 | var t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0; 252 | if (t0 < 0) { 253 | n0 = 0; 254 | } else { 255 | t0 *= t0; 256 | n0 = t0 * t0 * gi0.dot3(x0, y0, z0); // (x,y) of grad3 used for 2D gradient 257 | } 258 | var t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1; 259 | if (t1 < 0) { 260 | n1 = 0; 261 | } else { 262 | t1 *= t1; 263 | n1 = t1 * t1 * gi1.dot3(x1, y1, z1); 264 | } 265 | var t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2; 266 | if (t2 < 0) { 267 | n2 = 0; 268 | } else { 269 | t2 *= t2; 270 | n2 = t2 * t2 * gi2.dot3(x2, y2, z2); 271 | } 272 | var t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3; 273 | if (t3 < 0) { 274 | n3 = 0; 275 | } else { 276 | t3 *= t3; 277 | n3 = t3 * t3 * gi3.dot3(x3, y3, z3); 278 | } 279 | // Add contributions from each corner to get the final noise value. 280 | // The result is scaled to return values in the interval [-1,1]. 281 | return 32 * (n0 + n1 + n2 + n3); 282 | 283 | }; 284 | 285 | // ##### Perlin noise stuff 286 | 287 | function fade(t) { 288 | return t * t * t * (t * (t * 6 - 15) + 10); 289 | } 290 | 291 | function lerp(a, b, t) { 292 | return (1 - t) * a + t * b; 293 | } 294 | 295 | // 2D Perlin Noise 296 | module.perlin2 = function (x, y) { 297 | // Find unit grid cell containing point 298 | var X = Math.floor(x), 299 | Y = Math.floor(y); 300 | // Get relative xy coordinates of point within that cell 301 | x = x - X; 302 | y = y - Y; 303 | // Wrap the integer cells at 255 (smaller integer period can be introduced here) 304 | X = X & 255; 305 | Y = Y & 255; 306 | 307 | // Calculate noise contributions from each of the four corners 308 | var n00 = gradP[X + perm[Y]].dot2(x, y); 309 | var n01 = gradP[X + perm[Y + 1]].dot2(x, y - 1); 310 | var n10 = gradP[X + 1 + perm[Y]].dot2(x - 1, y); 311 | var n11 = gradP[X + 1 + perm[Y + 1]].dot2(x - 1, y - 1); 312 | 313 | // Compute the fade curve value for x 314 | var u = fade(x); 315 | 316 | // Interpolate the four results 317 | return lerp( 318 | lerp(n00, n10, u), 319 | lerp(n01, n11, u), 320 | fade(y)); 321 | }; 322 | 323 | // 3D Perlin Noise 324 | module.perlin3 = function (x, y, z) { 325 | // Find unit grid cell containing point 326 | var X = Math.floor(x), 327 | Y = Math.floor(y), 328 | Z = Math.floor(z); 329 | // Get relative xyz coordinates of point within that cell 330 | x = x - X; 331 | y = y - Y; 332 | z = z - Z; 333 | // Wrap the integer cells at 255 (smaller integer period can be introduced here) 334 | X = X & 255; 335 | Y = Y & 255; 336 | Z = Z & 255; 337 | 338 | // Calculate noise contributions from each of the eight corners 339 | var n000 = gradP[X + perm[Y + perm[Z]]].dot3(x, y, z); 340 | var n001 = gradP[X + perm[Y + perm[Z + 1]]].dot3(x, y, z - 1); 341 | var n010 = gradP[X + perm[Y + 1 + perm[Z]]].dot3(x, y - 1, z); 342 | var n011 = gradP[X + perm[Y + 1 + perm[Z + 1]]].dot3(x, y - 1, z - 1); 343 | var n100 = gradP[X + 1 + perm[Y + perm[Z]]].dot3(x - 1, y, z); 344 | var n101 = gradP[X + 1 + perm[Y + perm[Z + 1]]].dot3(x - 1, y, z - 1); 345 | var n110 = gradP[X + 1 + perm[Y + 1 + perm[Z]]].dot3(x - 1, y - 1, z); 346 | var n111 = gradP[X + 1 + perm[Y + 1 + perm[Z + 1]]].dot3(x - 1, y - 1, z - 1); 347 | 348 | // Compute the fade curve value for x, y, z 349 | var u = fade(x); 350 | var v = fade(y); 351 | var w = fade(z); 352 | 353 | // Interpolate 354 | return lerp( 355 | lerp( 356 | lerp(n000, n100, u), 357 | lerp(n001, n101, u), w), 358 | lerp( 359 | lerp(n010, n110, u), 360 | lerp(n011, n111, u), w), 361 | v); 362 | }; 363 | 364 | export default module; -------------------------------------------------------------------------------- /src/js/lib/prism.js: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.15.0 2 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+ruby+css-extras+diff+markup-templating+graphql+less+handlebars+json+markdown+php+php-extras+sql+python+yaml&plugins=autolinker */ 3 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-([\w-]+)\b/i,t=0,n=_self.Prism={manual:_self.Prism&&_self.Prism.manual,disableWorkerMessageHandler:_self.Prism&&_self.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof a?new a(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&").replace(/e.length)return;if(!(S instanceof l)){if(f&&k!=t.length-1){if(p.lastIndex=T,!(P=p.exec(e)))break;for(var y=P.index+(m?P[1].length:0),I=P.index+P[0].length,A=k,N=T,O=t.length;O>A&&(I>N||!t[A].type&&!t[A-1].greedy);++A)N+=t[A].length,y>=N&&(++k,T=N);if(t[k]instanceof l)continue;R=A-k,S=e.slice(T,N),P.index-=T}else{p.lastIndex=0;var P=p.exec(S),R=1}if(P){m&&(h=P[1]?P[1].length:0);I=(y=P.index+h)+(P=P[0].slice(h)).length;var w=S.slice(0,y),L=S.slice(I),v=[k,R];w&&(++k,T+=w.length,v.push(w));var C=new l(u,c?n.tokenize(P,c):P,b,P,f);if(v.push(C),L&&v.push(L),Array.prototype.splice.apply(t,v),1!=R&&n.matchGrammar(e,t,a,k,T,!0,u),s)break}else if(s)break}}}}},tokenize:function(e,t){var a=[e],r=t.rest;if(r){for(var i in r)t[i]=r[i];delete t.rest}return n.matchGrammar(e,a,t,0,0,!1),a},hooks:{all:{},add:function(e,t){var a=n.hooks.all;a[e]=a[e]||[],a[e].push(t)},run:function(e,t){var a=n.hooks.all[e];if(a&&a.length)for(var r,i=0;r=a[i++];)r(t)}}},a=n.Token=function(e,t,n,a,r){this.type=e,this.content=t,this.alias=n,this.length=0|(a||"").length,this.greedy=!!r};if(a.stringify=function(e,t,r){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return a.stringify(n,t,e)}).join("");var i={type:e.type,content:a.stringify(e.content,t,r),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:r};if(e.alias){var s="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(i.classes,s)}n.hooks.run("wrap",i);var o=Object.keys(i.attributes).map(function(e){return e+'="'+(i.attributes[e]||"").replace(/"/g,""")+'"'}).join(" ");return"<"+i.tag+' class="'+i.classes.join(" ")+'"'+(o?" "+o:"")+">"+i.content+""},!_self.document)return _self.addEventListener?(n.disableWorkerMessageHandler||_self.addEventListener("message",function(e){var t=JSON.parse(e.data),a=t.language,r=t.code,i=t.immediateClose;_self.postMessage(n.highlight(r,n.languages[a],a)),i&&_self.close()},!1),_self.Prism):_self.Prism;var r=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return r&&(n.filename=r.src,n.manual||r.hasAttribute("data-manual")||("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(n.highlightAll):window.setTimeout(n.highlightAll,16):document.addEventListener("DOMContentLoaded",n.highlightAll))),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(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:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/(^|[^\\])["']/,lookbehind:!0}]}},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,Prism.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.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-]+/}},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:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.languages.css,Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/()[\s\S]*?(?=<\/style>)/i,lookbehind:!0,inside:Prism.languages.css,alias:"language-css",greedy:!0}}),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:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,lookbehind:!0,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:/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/},Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},/\b(?:as|async|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|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]+)n?|\d+n|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,function:/[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\(|\.(?:apply|bind|call)\()/,operator:/-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[[^\]\r\n]+]|\\.|[^\/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})\]]))/,lookbehind:!0,greedy:!0},"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:!0,inside:{interpolation:{pattern:/\${[^}]+}/,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/()[\s\S]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript",greedy:!0}}),Prism.languages.js=Prism.languages.javascript,function(e){var t={variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\([^)]+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},/\$(?:[\w#?*!@]+|\{[^}]+\})/i]};e.languages.bash={shebang:{pattern:/^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,alias:"important"},comment:{pattern:/(^|[^"{\\])#.*/,lookbehind:!0},string:[{pattern:/((?:^|[^<])<<\s*)["']?(\w+?)["']?\s*\r?\n(?:[\s\S])*?\r?\n\2/,lookbehind:!0,greedy:!0,inside:t},{pattern:/(["'])(?:\\[\s\S]|\$\([^)]+\)|`[^`]+`|(?!\1)[^\\])*\1/,greedy:!0,inside:t}],variable:t.variable,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:!0},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:!0},boolean:{pattern:/(^|[\s;|&])(?:true|false)(?=$|[\s;|&])/,lookbehind:!0},operator:/&&?|\|\|?|==?|!=?|<<>|<=?|>=?|=~/,punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];]/};var n=t.variable[1].inside;n.string=e.languages.bash.string,n.function=e.languages.bash.function,n.keyword=e.languages.bash.keyword,n.boolean=e.languages.bash.boolean,n.operator=e.languages.bash.operator,n.punctuation=e.languages.bash.punctuation,e.languages.shell=e.languages.bash}(Prism),function(e){e.languages.ruby=e.languages.extend("clike",{comment:[/#.*/,{pattern:/^=begin(?:\r?\n|\r)(?:.*(?:\r?\n|\r))*?=end/m,greedy:!0}],keyword:/\b(?:alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|protected|private|public|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/});var t={pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:e.languages.ruby}};e.languages.insertBefore("ruby","keyword",{regex:[{pattern:/%r([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1[gim]{0,3}/,greedy:!0,inside:{interpolation:t}},{pattern:/%r\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/,greedy:!0,inside:{interpolation:t}},{pattern:/%r\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/,greedy:!0,inside:{interpolation:t}},{pattern:/%r\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/,greedy:!0,inside:{interpolation:t}},{pattern:/%r<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/,greedy:!0,inside:{interpolation:t}},{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\\\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0}],variable:/[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,symbol:{pattern:/(^|[^:]):[a-zA-Z_]\w*(?:[?!]|\b)/,lookbehind:!0}}),e.languages.insertBefore("ruby","number",{builtin:/\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|Fixnum|Float|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,constant:/\b[A-Z]\w*(?:[?!]|\b)/}),e.languages.ruby.string=[{pattern:/%[qQiIwWxs]?([^a-zA-Z0-9\s{(\[<])(?:(?!\1)[^\\]|\\[\s\S])*\1/,greedy:!0,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?\((?:[^()\\]|\\[\s\S])*\)/,greedy:!0,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/,greedy:!0,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?\[(?:[^\[\]\\]|\\[\s\S])*\]/,greedy:!0,inside:{interpolation:t}},{pattern:/%[qQiIwWxs]?<(?:[^<>\\]|\\[\s\S])*>/,greedy:!0,inside:{interpolation:t}},{pattern:/("|')(?:#\{[^}]+\}|\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0,inside:{interpolation:t}}]}(Prism),Prism.languages.css.selector={pattern:/[^{}\s][^{}]*(?=\s*\{)/,inside:{"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+(?:\(.*\))?/,class:/\.[-:.\w]+/,id:/#[-:.\w]+/,attribute:/\[[^\]]+\]/}},Prism.languages.insertBefore("css","function",{hexcode:/#[\da-f]{3,8}/i,entity:/\\[\da-f]{1,8}/i,number:/[\d%.]+/}),Prism.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d+.*$/m],deleted:/^[-<].*$/m,inserted:/^[+>].*$/m,diff:{pattern:/^!(?!!).+$/m,alias:"important"}},Prism.languages["markup-templating"]={},Object.defineProperties(Prism.languages["markup-templating"],{buildPlaceholders:{value:function(e,t,n,a){e.language===t&&(e.tokenStack=[],e.code=e.code.replace(n,function(n){if("function"==typeof a&&!a(n))return n;for(var r=e.tokenStack.length;-1!==e.code.indexOf("___"+t.toUpperCase()+r+"___");)++r;return e.tokenStack[r]=n,"___"+t.toUpperCase()+r+"___"}),e.grammar=Prism.languages.markup)}},tokenizePlaceholders:{value:function(e,t){if(e.language===t&&e.tokenStack){e.grammar=Prism.languages[t];var n=0,a=Object.keys(e.tokenStack),r=function(i){if(!(n>=a.length))for(var s=0;s-1){++n;var p,c=d.substring(0,g),m=new Prism.Token(t,Prism.tokenize(u,e.grammar,t),"language-"+t,u),f=d.substring(g+("___"+t.toUpperCase()+l+"___").length);if(c||f?(p=[c,m,f].filter(function(e){return!!e}),r(p)):p=m,"string"==typeof o?Array.prototype.splice.apply(i,[s,1].concat(p)):o.content=p,n>=a.length)break}}else o.content&&"string"!=typeof o.content&&r(o.content)}};r(e.tokens)}}}}),Prism.languages.graphql={comment:/#.*/,string:{pattern:/"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:true|false)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":/[a-z_]\w*(?=\s*:)/i,keyword:[{pattern:/(fragment\s+(?!on)[a-z_]\w*\s+|\.{3}\s*)on\b/,lookbehind:!0},/\b(?:query|fragment|mutation)\b/],operator:/!|=|\.{3}/,punctuation:/[!(){}\[\]:=,]/},Prism.languages.less=Prism.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-]+?(?:\([^{}]+\)|[^(){};])*?(?=\s*\{)/i,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\([^{}]*\)|[^{};@])*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/i,punctuation:/[{}();:,]/,operator:/[+\-*\/]/}),Prism.languages.insertBefore("less","punctuation",{function:Prism.languages.less.function}),Prism.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-]+.*?(?=[(;])/,lookbehind:!0,alias:"function"}}),function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/i,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:true|false)\b/,block:{pattern:/^(\s*~?\s*)[#\/]\S+?(?=\s*~?\s*$|\s)/i,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)}),e.hooks.add("after-tokenize",function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")})}(Prism),Prism.languages.json={comment:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,property:{pattern:/"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,greedy:!0},string:{pattern:/"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,greedy:!0},number:/-?\d+\.?\d*(e[+-]?\d+)?/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:true|false)\b/,null:/\bnull\b/},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:[{pattern:/^(?: {4}|\t).+/m,alias:"keyword"},{pattern:/``.+?``|`[^`\n]+`/,alias:"keyword"}],title:[{pattern:/\w+.*(?:\r?\n|\r)(?:==+|--+)/,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#+.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:/(^|[^\\])(\*\*|__)(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^\*\*|^__|\*\*$|__$/}},italic:{pattern:/(^|[^\\])([*_])(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^[*_]|[*_]$/}},url:{pattern:/!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)| ?\[[^\]\n]*\])/,inside:{variable:{pattern:/(!?\[)[^\]]+(?=\]$)/,lookbehind:!0},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,function(e){e.languages.php=e.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:!0}}),e.languages.insertBefore("php","string",{"shell-comment":{pattern:/(^|[^\\])#.*/,lookbehind:!0,alias:"comment"}}),e.languages.insertBefore("php","keyword",{delimiter:{pattern:/\?>|<\?(?:php|=)?/i,alias:"important"},variable:/\$+(?:\w+\b|(?={))/i,package:{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/,lookbehind:!0,inside:{punctuation:/\\/}}}),e.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/,lookbehind:!0}});var t={pattern:/{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[.+?]|->\w+)*)/,lookbehind:!0,inside:{rest:e.languages.php}};e.languages.insertBefore("php","string",{"nowdoc-string":{pattern:/<<<'([^']+)'(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\1;/,greedy:!0,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:!0,alias:"string",inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:t}},"single-quoted-string":{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0,alias:"string"},"double-quoted-string":{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,alias:"string",inside:{interpolation:t}}}),delete e.languages.php.string,e.hooks.add("before-tokenize",function(t){if(/(?:<\?php|<\?)/gi.test(t.code)){e.languages["markup-templating"].buildPlaceholders(t,"php",/(?:<\?php|<\?)[\s\S]*?(?:\?>|$)/gi)}}),e.hooks.add("after-tokenize",function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"php")})}(Prism),Prism.languages.insertBefore("php","variable",{this:/\$this\b/,global:/\$(?:_(?:SERVER|GET|POST|FILES|REQUEST|SESSION|ENV|COOKIE)|GLOBALS|HTTP_RAW_POST_DATA|argc|argv|php_errormsg|http_response_header)\b/,scope:{pattern:/\b[\w\\]+::/,inside:{keyword:/static|self|parent/,punctuation:/::|\\/}}}),Prism.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,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:!0},"triple-quoted-string":{pattern:/("""|''')[\s\S]+?\1/,greedy:!0,alias:"string"},string:{pattern:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},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:!0,alias:"string"},comment:/#.*/,key:{pattern:/(\s*(?:^|[:\-,[{\r\n?])[ \t]*(?:![^\s]+)?[ \t]*)[^\r\n{[\]},#\s]+?(?=\s*:\s)/,lookbehind:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,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:!0,alias:"number"},boolean:{pattern:/([:\-,[{]\s*(?:![^\s]+)?[ \t]*)(?:true|false)[ \t]*(?=$|,|]|})/im,lookbehind:!0,alias:"important"},null:{pattern:/([:\-,[{]\s*(?:![^\s]+)?[ \t]*)(?:null|~)[ \t]*(?=$|,|]|})/im,lookbehind:!0,alias:"important"},string:{pattern:/([:\-,[{]\s*(?:![^\s]+)?[ \t]*)("|')(?:(?!\2)[^\\\r\n]|\\.)*\2(?=[ \t]*(?:$|,|]|}|\s*#))/m,lookbehind:!0,greedy:!0},number:{pattern:/([:\-,[{]\s*(?:![^\s]+)?[ \t]*)[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+\.?\d*|\.?\d+)(?:e[+-]?\d+)?|\.inf|\.nan)[ \t]*(?=$|,|]|})/im,lookbehind:!0},tag:/![^\s]+/,important:/[&*][\w]+/,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},function(){if(("undefined"==typeof self||self.Prism)&&("undefined"==typeof global||global.Prism)){var e=/\b([a-z]{3,7}:\/\/|tel:)[\w\-+%~\/.:=&]+(?:\?[\w\-+%~\/.:#=?&!$'()*,;]*)?(?:#[\w\-+%~\/.:#=?&!$'()*,;]*)?/,t=/\b\S+@[\w.]+[a-z]{2}/,n=/\[([^\]]+)]\(([^)]+)\)/,a=["comment","url","attr-value","string"];Prism.plugins.autolinker={processGrammar:function(r){r&&!r["url-link"]&&(Prism.languages.DFS(r,function(r,i,s){a.indexOf(s)>-1&&"Array"!==Prism.util.type(i)&&(i.pattern||(i=this[r]={pattern:i}),i.inside=i.inside||{},"comment"==s&&(i.inside["md-link"]=n),"attr-value"==s?Prism.languages.insertBefore("inside","punctuation",{"url-link":e},i):i.inside["url-link"]=e,i.inside["email-link"]=t)}),r["url-link"]=e,r["email-link"]=t)}},Prism.hooks.add("before-highlight",function(e){Prism.plugins.autolinker.processGrammar(e.grammar)}),Prism.hooks.add("wrap",function(e){if(/-link$/.test(e.type)){e.tag="a",e.attributes.target="_blank noopener";var t=e.content;if("email-link"==e.type&&0!=t.indexOf("mailto:"))t="mailto:"+t;else if("md-link"==e.type){var a=e.content.match(n);t=a[2],e.content=a[1]}e.attributes.href=t}try{e.content=decodeURIComponent(e.content)}catch(e){}})}}(); --------------------------------------------------------------------------------