Compare commits

...

No commits in common. 'da33a8c38b5ff937c61fc194ae6c7e019a577b68' and '603f7f861ebb33966899971dc390e87f3239eb23' have entirely different histories.

15
.gitignore vendored

@ -1,7 +1,10 @@
# zola trash
zola
public
static/processed_images
# os trash
*.log
.cache
.DS_Store
src/.temp
node_modules
dist
.env
.env.*
.vitepress/cache
.vitepress/dist

@ -0,0 +1,72 @@
import { defineConfig } from 'vitepress'
import { defineConfigWithTheme } from 'vitepress'
import type { ThemeConfig } from './theme/Config'
export default defineConfigWithTheme<ThemeConfig>({
title: "k0r.386",
description: "Norman Köhrings Homepage",
lang: 'en',
head: [
['link', { rel: 'icon', href: '/favicon.png' }],
['link', { rel: 'alternate', href: 'https://k0r.in' }],
['link', { rel: 'alternate', href: 'https://koehr.in' }],
['link', { rel: 'alternate', href: 'https://koehr.ing' }],
['link', { rel: 'canonical', href: 'https://koehr.ing' }],
['meta', { content: "The personal page and weblog of Norman Köhring", name: "description" }],
['meta', { content: "Norman Köhring", name: "author" }],
['meta', { content: "the codeartist — programmer and engineer based in Berlin", name: "DC.title" }],
['meta', { content: "52.4595, 13.5335", name: "ICBM" }],
['meta', { content: "52.4595; 13.5335", name: "geo.position" }],
['meta', { content: "DE-BE", name: "geo.region" }],
['meta', { content: "Berlin", name: "geo.plac,ename" }],
['meta', { content: "width=device-width,initial-scale=1.0", name: "viewport" }],
],
themeConfig: {
commands: [{
command: 'about',
aliases: ['info'],
help: 'Who is Norman Köhring?',
message: 'Norman Köhring is a programmer, hacker and open source enthusiast based in Berlin. He is the Principal Frontend Engineer at Code Gaia, where he is a proud part of revolutionizing carbon emission reporting.',
uris: [{
label: 'Berlin', uri: 'https://www.openstreetmap.org/#map=12/52.4595/13.5335'
}, {
label: 'CodeGaia', uri: 'https://codegaia.io/'
}, {
label: 'Hacker?', uri: 'https://en.wikipedia.org/wiki/Hacker'
}]
}, {
command: 'contact',
aliases: ['email', 'homepage', 'www'],
help: 'How to contact Norman Köhring?',
message: [
'# other servers',
'email - n@koehr.in OR norman.koehring@mailbox.org',
'mastodon - mstdn.io/@koehr',
'twitter - twitter.com/koehr_in',
'github - github.com/nkoehring',
'instagram - instagram.com/coffee_n_code',
'500px - 500px.com/koehr',
'# my server',
'sourcecode - git.k0r.in/ (forgejo)',
'fediverse - m.k0r.in/@n (misskey)',
].join('\n'),
uris: [{
label: 'email', uri: 'mailto:n@koehr.in'
}, {
label: 'mastodon', uri: 'https://mstdn.io/@koehr'
}, {
label: 'twitter', uri: 'https://twitter.com/koehr_in'
}, {
label: 'github', uri: 'https://github.com/nkoehring'
}, {
label: 'instagram', uri: 'https://instagram.com/coffee_n_code'
}, {
label: '500px', uri: 'https://500px.com/koehr'
}, {
label: 'sourcecode', uri: 'https://git.k0r.in/'
}, {
label: 'fediverse', uri: 'https://m.k0r.in/@n'
}]
}],
}
})

@ -0,0 +1,16 @@
export type Uri = {
label: string
uri: string
}
export type SimpleCommand = {
command: string,
aliases?: string[],
help?: string,
message: string,
uris: Uri[],
}
export interface ThemeConfig {
commands: SimpleCommand[]
}

@ -0,0 +1,69 @@
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import { useData } from 'vitepress'
import useTerminal from './useTerminal'
import titleArt from './titles'
const { site, page, frontmatter } = useData()
const enhancedReadability = ref(false)
const title = computed(() => {
const titleKey = frontmatter.value.title
const title = titleArt[titleKey] || titleArt['not_found']
return title.join('\n')
})
const content = computed(() => frontmatter.value.content ?? ['this page does not exist'])
const commands = computed(() => site.value.themeConfig.commands)
const prompt = '\n$> '
const lines = ref(title.value + '\n\n' + content.value.join('\n') + '\n' + prompt)
const textArea = ref<HTMLTextAreaElement | null>(null)
const footer = ref([])
onMounted(() => {
if (textArea.value === null) {
console.error('textarea is missing')
return
}
const { addText, addLine, clear, footerLinks } = useTerminal(textArea.value, commands.value)
watch(frontmatter, () => {
addText(title.value + '\n', false)
addLine(content.value.join('\n'))
}, { immediate: true })
watch(footerLinks, () => {
footer.value = footerLinks.value
}, { immediate: true })
})
</script>
<template>
<div id="screen" :class="{ 'enhanced-readability': enhancedReadability }">
<div id="wrap">
<div id="interlace" />
<div id="scanline" />
<div id="inner">
<textarea ref="textArea"
spellcheck="false"
autocorrect="false"
autocapitalize="false"
autocomplete="false"
autofocus
></textarea>
<footer>
<a v-for="({ uri, label}) in footer"
:href="uri"
target="_blank"
rel="noopener"
>
{{ label }}
</a>
</footer>
</div>
</div>
</div>
</template>

@ -0,0 +1,15 @@
// https://vitepress.dev/guide/custom-theme
import Layout from './Layout.vue'
import type { Theme } from 'vitepress'
import '@fontsource/vt323'
import './reset.css'
import './style.css'
export default {
Layout,
enhanceApp({ app, router, siteData }) {
// ...
}
} satisfies Theme

@ -0,0 +1,114 @@
/***
The new CSS reset - version 1.11.2 (last updated 15.11.2023)
GitHub page: https://github.com/elad2412/the-new-css-reset
***/
/*
Remove all the styles of the "User-Agent-Stylesheet", except for the 'display' property
- The "symbol *" part is to solve Firefox SVG sprite bug
- The "html" element is excluded, otherwise a bug in Chrome breaks the CSS hyphens property (https://github.com/elad2412/the-new-css-reset/issues/36)
*/
*:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) {
all: unset;
display: revert;
}
/* Preferred box-sizing value */
*,
*::before,
*::after {
box-sizing: border-box;
}
/* Fix mobile Safari increase font-size on landscape mode */
html {
-moz-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
}
/* Reapply the pointer cursor for anchor tags */
a,
button {
cursor: revert;
}
/* Remove list styles (bullets/numbers) */
ol,
ul,
menu,
summary {
list-style: none;
}
/* For images to not be able to exceed their container */
img {
max-inline-size: 100%;
max-block-size: 100%;
}
/* removes spacing between cells in tables */
table {
border-collapse: collapse;
}
/* Safari - solving issue when using user-select:none on the <body> text input doesn't working */
input,
textarea {
-webkit-user-select: auto;
}
/* revert the 'white-space' property for textarea elements on Safari */
textarea {
white-space: revert;
}
/* minimum style to allow to style meter element */
meter {
-webkit-appearance: revert;
appearance: revert;
}
/* preformatted text - use only for this feature */
:where(pre) {
all: revert;
box-sizing: border-box;
}
/* reset default text opacity of input placeholder */
::placeholder {
color: unset;
}
/* fix the feature of 'hidden' attribute.
display:revert; revert to element instead of attribute */
:where([hidden]) {
display: none;
}
/* revert for bug in Chromium browsers
- fix for the content editable attribute will work properly.
- webkit-user-select: auto; added for Safari in case of using user-select:none on wrapper element*/
:where([contenteditable]:not([contenteditable="false"])) {
-moz-user-modify: read-write;
-webkit-user-modify: read-write;
overflow-wrap: break-word;
-webkit-line-break: after-white-space;
-webkit-user-select: auto;
}
/* apply back the draggable feature - exist only in Chromium and Safari */
:where([draggable="true"]) {
-webkit-user-drag: element;
}
/* Revert Modal native behavior */
:where(dialog:modal) {
all: revert;
box-sizing: border-box;
}
/* Remove details summary webkit styles */
::-webkit-details-marker {
display: none;
}

@ -0,0 +1,162 @@
:root {
--black: #000;
--white: #FFF;
--red: #800;
--cyan: #AFE;
--violet: #C4C;
--green: #0C5;
--blue: #00A;
--yellow: #EE7;
--orange: #D85;
--brown: #640;
--light-red: #F77;
--light-green: #AF6;
--light-blue: #08F;
--grey-1: #333;
--grey-2: #777;
--grey-3: #BBB;
--crt-frame: #BFBCAD;
}
@keyframes scanline {
0% {
top: 0;
}
30% {
top: 100%;
}
100% {
top: 100%;
}
}
@media (prefers-color-scheme: light) {
body {
background: var(--cyan);
color: var(--blue);
}
}
@media (max-width: 1280px) {
#app {
width: 90vw;
height: 90vh;
}
}
body {
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-family: VT323, monospace;
font-size: 24px;
background: var(--black);
}
#app {
position: relative;
z-index: 10;
background: var(--crt-frame);
width: 1280px;
height: 900px;
max-width: 1280px;
max-height: 1024px;
box-shadow: inset 0.25em 0.25em 2px rgba(255, 255, 255, 0.4), inset -0.25em -0.25em 2px rgba(0, 0, 0, 0.4);
user-select: none;
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
perspective: 1000;
color: var(--cyan);
text-shadow: 0 0 2px yellow;
}
#screen.enhanced-readability {
text-shadow: none;
}
#screen {
width: calc(100% - 2.4em);
height: calc(100% - 2.4em);
overflow: hidden;
margin: 1.2em;
z-index: 20;
box-shadow: 0 0 1px 3px #0A0A0AB2;
background: var(--blue);
}
#app,
#screen {
border-radius: 1em;
}
#wrap {
position: relative;
height: 100%;
padding: 1.5em;
background: radial-gradient(ellipse at center, #FFF2 0%, #0003 100%);
}
#interlace {
position: absolute;
right: 0;
top: 0;
bottom: 0;
left: 0;
background: linear-gradient(#888 50%, #000 0);
background-repeat: repeat-y;
background-size: 100% 4px;
opacity: .1;
z-index: 21;
pointer-events: none;
}
#scanline {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1em;
background: linear-gradient(180deg, transparent 0, #EEE 50%, navy 0, transparent);
opacity: .1;
animation: scanline 6s linear infinite;
pointer-events: none;
}
#inner {
height: 100%;
background: #0003;
border-radius: .5em;
overflow-y: auto;
}
#inner::selection {
color: var(--blue);
background: var(--cyan);
}
#inner>textarea {
width: 100%;
height: calc(100% - 1.5em);
padding: 0 1em;
scroll-behavior: smooth;
}
#inner>footer {
display: flex;
flex-flow: row nowrap;
height: 1.5em;
line-height: 1.5em;
overflow-x: auto;
}
#inner>footer>a {
padding: 0 1em;
margin-right: 1em;
background: var(--cyan);
color: var(--blue);
}

@ -0,0 +1,29 @@
export default {
welcome: [
" ________ __ ",
"| | | |.-----.| |.----.-----.--------.-----.",
"| | | || -__|| || __| _ | | -__|",
"|________||_____||__||____|_____|__|__|__|_____|",
],
aboutMe: [
" _______ __ __ _______ ",
"| _ | |--.-----.--.--.| |_ | | |.-----.",
"| | _ | _ | | || _| | || -__|",
"|___|___|_____|_____|_____||____| |__|_|__||_____|",
],
resume: [
" ______ ",
"| __ \.-----.-----.--.--.--------.-----.",
"| <| -__|__ --| | | | -__|",
"|___|__||_____|_____|_____|__|__|__|_____|",
],
not_found: [
" _____ ______ _____ ",
"| | || | | | ",
"|__ | -- |__ |",
" |__||______| |__| ",
]
}

@ -0,0 +1,171 @@
import { ref } from 'vue'
import type { SimpleCommand, Uri } from './Config'
import { useRouter } from 'vitepress'
export default function useTerminal(inputEl: HTMLTextAreaElement, commands: SimpleCommand[]) {
const prompt = '\n$> '
const footerLinks = ref([])
const router = useRouter()
console.log('router', router)
function moveCursorToEnd() {
const pos = inputEl.value.length
// allow text selection
if (inputEl.selectionStart !== inputEl.selectionEnd) {
console.debug('allowing text selection', inputEl.selectionStart, inputEl.selectionEnd)
return
}
inputEl.setSelectionRange(pos, pos)
}
function setFocus() {
inputEl.focus()
}
function addText(text: string, addPrompt=true) {
const line = addPrompt ? text + prompt : text
inputEl.value = inputEl.value + line
inputEl.scrollTop = inputEl.scrollTopMax
}
function addLine(line: string) {
addText('\n'+line)
}
function clear() {
footerLinks.value = []
inputEl.value = ''
addText('')
}
type SYS_OUT = 'NOT_FOUND' | 'USAGE' | 'INFO' | '404'
const SHELL = 'k0rSH'
const INFO = 'k0rSH v0.1: the k0r SHell, fiddled together by k0r -- https://k0r.in'
const PAD = 16
const USAGE = [
...commands.map(cmd => {
const command = `${(cmd.command+':').padEnd(PAD)}`
const help = `${cmd.help ?? 'no helptext provided'}`
const aliases = cmd.aliases ? ` (aliases: ${cmd.aliases?.join(', ')})` : ''
return `${command}${help}${aliases}`
}),
`${'help:'.padEnd(PAD)}This help text. (aliases: usage)`,
`${'version:'.padEnd(PAD)}Print version information.`,
`${'clear:'.padEnd(PAD)}Clear the screen.`,
].join('\n')
function systemOutput(output: SYS_OUT, arg = '') {
switch (output) {
case 'NOT_FOUND':
console.debug('command not found')
addLine(`${SHELL}: ${arg}: command not found...`)
break
case 'USAGE':
console.log('help is underway')
addLine(`${SHELL} - available commands:\n\n${USAGE}`)
break
case 'INFO':
console.log('explaining myself')
addLine(`${SHELL}: ${INFO}`)
break
case '404':
console.log('page not found', arg)
addLine(`${SHELL}: ${arg}: this page does not exist`)
break
}
}
function cursorAtPrompt() {
return inputEl.value.endsWith(prompt)
}
function setFooter(uris: Uri[]) {
footerLinks.value = uris
}
/// returns current command written in the command line
/// in the format: [command, arg1, arg2, ..., argN]
function getCurrentCommand() {
const value = inputEl.value
const start = value.lastIndexOf(prompt) + prompt.length
const end = value.length
return value.slice(start, end).trim().split(' ')
}
function execUserCommand(cmd: string) {
const userCommand = commands.find(c => {
const commandMatch = c.command === cmd
const aliasesMatch = c.aliases.includes(cmd)
return commandMatch || aliasesMatch
})
if (!userCommand) return systemOutput('NOT_FOUND', cmd)
addLine(userCommand.message)
setFooter(userCommand.uris)
}
function listPages() {
addLine('TODO: list pages')
}
async function openPage(page: string) {
await router.go(page)
}
function handleCurrentCommand() {
const [cmd, ...args] = getCurrentCommand()
if (!cmd) {
addText('')
return
}
switch (cmd) {
case 'help':
case 'usage':
systemOutput('USAGE')
break
case 'version':
systemOutput('INFO')
break
case 'clear':
clear()
break
case 'ls':
case 'list':
listPages()
break
case 'go':
case 'open':
addText('\n', false)
if (!args.length) addText('USAGE: go page_name')
else router.go(args[0])
break
default:
execUserCommand(cmd)
}
}
function handleInput(ev) {
switch (ev.key) {
case 'Enter':
handleCurrentCommand()
ev.preventDefault()
break
case 'Backspace':
if (cursorAtPrompt()) ev.preventDefault()
break
}
}
inputEl.addEventListener('focus', () => moveCursorToEnd())
inputEl.addEventListener('blur', () => inputEl.focus())
inputEl.addEventListener('click', () => moveCursorToEnd())
inputEl.addEventListener('keydown', handleInput)
return { addText, addLine, setFocus, clear, footerLinks }
}

@ -1,10 +1,25 @@
pipeline:
ntfy:
image: codeberg.org/l-x/woodpecker-ntfy
settings:
url: https://ntfy.sh/k0r
title: build finished
click: https://ci.k0r.in
icon: https://woodpecker-ci.org/img/logo.svg
tags: robot,${CI_BUILD_EVENT},${CI_REPO_NAME}
message: >
📝 Commit by ${CI_COMMIT_AUTHOR} on ${CI_COMMIT_BRANCH}:
${CI_COMMIT_MESSAGE}
build:
image: jauderho/zola:latest
image: node:20-alpine
commands:
- zola check
- npm install
- npm run docs:build
- chmod -R a+rw /mnt
- zola build -o /mnt/dist --force
- rm -fr /mnt/dist
- cp -R .vitepress/dist /mnt/dist
volumes:
- /home/n/CI/k0r_in:/mnt/
- /home/n/CI/koehr_ing:/mnt/

@ -0,0 +1,6 @@
---
title: 'not_found'
content: [
'This page does not exist.',
]
---

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 José Lopes
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -1,11 +0,0 @@
# k0r.386
![k0r.386 screenshot](https://git.k0r.in/n/k0r.386/raw/branch/main/screenshot.png)
## [k0r.in](https://k0r.in/)
## Theme
The Zola theme is heavily inspired and partially based on [ZOLA.386](https://github.com/lopes/zola.386).
The font used is FixedSys300 from [fixedsys-css](https://github.com/javanile/fixedsys-css), which was modified and optimized via the [FontSquirrel WebFont Generator](https://www.fontsquirrel.com/tools/webfont-generator).

@ -1,80 +0,0 @@
base_url = "https://ng.k0r.in"
compile_sass = true
build_search_index = false
generate_rss = true
highlight_code = true
# theme = "k0r.386"
default_language = "en"
title = "k0r"
description = "programmer and engineer based in Berlin"
taxonomies = [
{name="categories", rss=true},
{name="tags", rss=true},
]
[markdown]
# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola
highlight_code = true
[extra]
author = "Norman Köhring"
year = "2023"
keywords = "homepage, personal, programming, webdev, retro, hacking"
theme_color = "#190084"
menu_items = [
{path="", name="Home"},
{path="categories", name="Categories"},
{path="tags", name="Tags"},
{path="about", name="About"},
]
sidebars = [
{title="Main Menu", internal=true, items=[
{path="/", name="Home"},
{path="/cv", name="CV / Résumé"},
{path="/til", name="Today I Learned"},
{path="/articles", name="Articles"},
{path="/log", name="Microblog"},
{path="/slides", name="Slides"},
]},
{title="Selfhosted", internal=false, items=[
{path="https://m.k0r.in/@n", name="Fediverse/Mastodon"},
{path="https://git.k0r.in", name="Code"},
{path="https://ci.k0r.in", name="CI"},
{path="https://koehr.pw", name="Passwords"},
{path="https://url.k0r.in", name="Bookmarks"},
{path="https://srx.k0r.in", name="Search"},
]},
{title="Elsewhere", internal=false, items=[
{path="https://mstdn.io/@koehr", name="Fediverse/Mastodon"},
{path="https://twitter.com/koehr_in", name="Twitter"},
{path="https://github.com/nkoehring", name="Github"},
{path="https://sr.ht/~koehr", name="Sourcehut"},
{path="https://instagram.com/coffee_n_code", name="Instagram"},
{path="https://500px.com/koehr", name="Photography"},
{path="mailto:n[at]koehr.in", name="Mail"},
]}
]
### THIRD PARTY
# google_analytics = "UA-012345-67"
# disqus = "disqus-user"
### SOCIAL MEDIA
image = "https://raw.githubusercontent.com/lopes/zola.386/master/screenshot.png"
twitter_user = "koehr_in"
linkedin_user = "nkoehring"
github_user = "nkoehring"
# gitlab_user = ""
### I18N WORDS
label_tags = "Tags"
label_tag = "Tag"
label_categories = "Categories"
label_category = "Category"
label_author = "Author"
label_date = "Date"
label_taxonomy = "Taxonomy"
label_reading = "Reading time"
label_read_more = "Read more"

@ -1,11 +0,0 @@
+++
title = "k0r"
description = "programmer and engineer based in Berlin"
template = "home.html"
sort_by = "weight"
[taxonomies]
categories = ["home"]
tags = []
+++

@ -1,6 +0,0 @@
+++
paginate_by = 20
sort_by = "date"
sort_direction = "decending"
insert_anchor_links = "none"
+++

@ -1,6 +0,0 @@
+++
paginate_by = 20
sort_by = "date"
sort_direction = "decending"
insert_anchor_links = "none"
+++

@ -1,6 +0,0 @@
+++
paginate_by = 20
sort_by = "date"
sort_direction = "decending"
insert_anchor_links = "none"
+++

@ -0,0 +1,9 @@
---
title: 'resume'
content: [
'This is my CV',
'stuff',
'foo',
'bar',
]
---

@ -0,0 +1,16 @@
---
title: 'welcome'
content: [
'This is the homepage of Norman Köhring,',
'a programmer, OpenSource enthusiast and hacker based in Berlin, Germany.',
'',
'I call myself a code artist because programming can and should be seen as a creative process. Therefore code is art. I love to craft pieces of art with code that are beautiful and elegant in their simplicity, readability and architecture.',
'',
'Type "help" to see a list of available commands.',
'Some commands might update the footer with useful links.'
]
---
Some testcontent for testing.
It is a *paragraph*!

@ -1,12 +0,0 @@
# based on:
# https://www.getzola.org/documentation/deployment/netlify/
[build]
publish = "public"
command = "zola build"
[build.environment]
ZOLA_VERSION = "0.14.0"
[context.deploy-preview]
command = "zola build --base-url $DEPLOY_PRIME_URL"

@ -0,0 +1,14 @@
{
"scripts": {
"docs:dev": "vitepress dev",
"docs:build": "vitepress build",
"docs:preview": "vitepress preview"
},
"devDependencies": {
"vitepress": "1.0.0-rc.31",
"vue": "^3.3.10"
},
"dependencies": {
"@fontsource/vt323": "^5.0.8"
}
}

File diff suppressed because it is too large Load Diff

@ -1,170 +0,0 @@
// fixing font path
@font-face {
font-family: 'Fixed';
font-style: normal;
font-weight: normal;
src: local(''), url('./fonts/fixedsys.woff') format('woff');
}
:root {
font: 20px / 1.1 'Fixed';
background-color: #190084;
color: #BBB;
}
body {
visibility: shown;
margin: 0;
padding: 0;
}
body>nav {
background-color: #BBB;
color: #000;
}
body>nav>.container {
display: flex;
}
body>nav h1 {
margin: 0 1rem;
color: inherit;
}
body>nav a {
color: inherit;
display: inline-block;
padding: 0 .5em;
}
body>nav ul {
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
body>nav li {
display: inline-block;
}
.container {
margin: auto;
max-width: 980px;
}
body>main>header {
padding: 1rem 1rem;
margin: 1rem 0 1rem;
background: #0AA;
}
body>main>header>h1 {
color: #000;
}
h1 {
font-size: 1rem;
color: #FFF;
font-weight: 300;
margin: 0;
}
h1>small {
font-size: 1rem;
color: #DDD;
}
a {
color: #fefe54;
text-decoration: none;
}
.flex-col {
display: flex;
flex-flow: column nowrap;
}
.flex-row {
display: flex;
flex-flow: row nowrap;
}
.gap {
gap: 2rem;
}
.w-1\/4 {
flex: auto;
width: 25%;
}
.w-2\/4 {
flex: auto;
width: 50%;
}
.w-3\/4 {
flex: auto;
width: 75%;
}
.w-4\/4 {
flex: auto;
width: 100%;
}
.box {
border: 2px solid black;
box-shadow: 0 0 0 5px, 11px 13px 0 4px black;
}
.bg-error {
background-color: #B00;
}
.text-white {
color: white;
}
nav {
background: #BBB;
margin: 0 0 2rem;
}
nav>header {
background: black;
color: #BBB;
margin: .5rem .5rem 0;
padding: 0 .5rem;
}
nav>menu {
list-style: none;
margin: 0;
padding: 0;
color: black;
margin: 0 .5rem .5rem;
}
nav>menu>li>a {
display: inline-block;
width: calc(100% - 1rem);
padding: 0 .5rem;
}
nav li:hover,
nav li.active {
background-color: #000;
color: #BBB;
}
nav li>a {
color: black;
}
nav li:hover>a,
nav li.active>a {
color: #BBB;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

@ -1,41 +0,0 @@
{
"name": "App",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

@ -1,111 +0,0 @@
self._386 = self._386 || {};
$(function(){
var character = { height: 20, width: 12.4 };
function scrollLock() {
var last = 0;
$(window).bind('scroll', function(e) {
var func, off = $(window).scrollTop();
console.log(off, last, off < last ? "up" : "down");
// this determines whether the user is intending to go up or down.
func = off < last ? "floor" : "ceil";
// make sure we don't run this from ourselves
if(off % character.height === 0) {
return;
}
last = off;
window.scrollTo(
0,
Math[func](off / character.height) * character.height
);
});
}
function loading() {
if(_386.fastLoad) {
document.body.style.visibility='visible';
return;
}
var
onePass = _386.onePass,
speedFactor = 1 / (_386.speedFactor || 1) * 165000;
wrap = document.createElement('div'),
bar = wrap.appendChild(document.createElement('div')),
cursor = document.createElement('div'),
// If the user specified that the visibility is hidden, then we
// start at the first pass ... otherwise we just do the
// cursor fly-by
pass = ($(document.body).css('visibility') == 'visible') ? 1 : 0,
height = $(window).height(),
width = $(window).width(),
// this makes the loading of the screen proportional to the real-estate of the window.
// it helps keep the cool sequence there while not making it waste too much time.
rounds = (height * width / speedFactor),
column = width, row = height - character.height;
wrap.id = "wrap386";
bar.id = "bar386";
cursor.id = "cursor386";
cursor.innerHTML = bar.innerHTML = '&#9604;';
// only inject the wrap if the pass is 0
if(pass === 0) {
document.body.appendChild(wrap);
document.body.style.visibility='visible';
} else {
document.body.appendChild(cursor);
rounds /= 2;
character.height *= 4;
}
var ival = setInterval(function(){
for(var m = 0; m < rounds; m++) {
column -= character.width;
if(column <= 0) {
column = width;
row -= character.height;
}
if(row <= 0) {
pass++;
row = height - character.height;
if(pass == 2) {
document.body.removeChild(cursor);
clearInterval(ival);
} else {
wrap.parentNode.removeChild(wrap);
if(onePass) {
clearInterval(ival);
} else {
document.body.appendChild(cursor);
rounds /= 2;
character.height *= 4;
}
}
}
if(pass === 0) {
bar.style.width = column + "px";
wrap.style.height = row + "px";
} else {
cursor.style.right = column + "px";
cursor.style.bottom = row + "px";
}
}
}, 1);
}
loading();
});

@ -1,117 +0,0 @@
/* ==========================================================
* bootstrap-affix.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#affix
* ==========================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================== */
!function ($) {
"use strict"; // jshint ;_;
/* AFFIX CLASS DEFINITION
* ====================== */
var Affix = function (element, options) {
this.options = $.extend({}, $.fn.affix.defaults, options)
this.$window = $(window)
.on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
.on('click.affix.data-api', $.proxy(function () { setTimeout($.proxy(this.checkPosition, this), 1) }, this))
this.$element = $(element)
this.checkPosition()
}
Affix.prototype.checkPosition = function () {
if (!this.$element.is(':visible')) return
var scrollHeight = $(document).height()
, scrollTop = this.$window.scrollTop()
, position = this.$element.offset()
, offset = this.options.offset
, offsetBottom = offset.bottom
, offsetTop = offset.top
, reset = 'affix affix-top affix-bottom'
, affix
if (typeof offset != 'object') offsetBottom = offsetTop = offset
if (typeof offsetTop == 'function') offsetTop = offset.top()
if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?
false : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?
'bottom' : offsetTop != null && scrollTop <= offsetTop ?
'top' : false
if (this.affixed === affix) return
this.affixed = affix
this.unpin = affix == 'bottom' ? position.top - scrollTop : null
this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))
}
/* AFFIX PLUGIN DEFINITION
* ======================= */
var old = $.fn.affix
$.fn.affix = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('affix')
, options = typeof option == 'object' && option
if (!data) $this.data('affix', (data = new Affix(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.affix.Constructor = Affix
$.fn.affix.defaults = {
offset: 0
}
/* AFFIX NO CONFLICT
* ================= */
$.fn.affix.noConflict = function () {
$.fn.affix = old
return this
}
/* AFFIX DATA-API
* ============== */
$(window).on('load', function () {
$('[data-spy="affix"]').each(function () {
var $spy = $(this)
, data = $spy.data()
data.offset = data.offset || {}
data.offsetBottom && (data.offset.bottom = data.offsetBottom)
data.offsetTop && (data.offset.top = data.offsetTop)
$spy.affix(data)
})
})
}(window.jQuery);

@ -1,99 +0,0 @@
/* ==========================================================
* bootstrap-alert.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#alerts
* ==========================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================== */
!function ($) {
"use strict"; // jshint ;_;
/* ALERT CLASS DEFINITION
* ====================== */
var dismiss = '[data-dismiss="alert"]'
, Alert = function (el) {
$(el).on('click', dismiss, this.close)
}
Alert.prototype.close = function (e) {
var $this = $(this)
, selector = $this.attr('data-target')
, $parent
if (!selector) {
selector = $this.attr('href')
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
}
$parent = $(selector)
e && e.preventDefault()
$parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
$parent.trigger(e = $.Event('close'))
if (e.isDefaultPrevented()) return
$parent.removeClass('in')
function removeElement() {
$parent
.trigger('closed')
.remove()
}
$.support.transition && $parent.hasClass('fade') ?
$parent.on($.support.transition.end, removeElement) :
removeElement()
}
/* ALERT PLUGIN DEFINITION
* ======================= */
var old = $.fn.alert
$.fn.alert = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('alert')
if (!data) $this.data('alert', (data = new Alert(this)))
if (typeof option == 'string') data[option].call($this)
})
}
$.fn.alert.Constructor = Alert
/* ALERT NO CONFLICT
* ================= */
$.fn.alert.noConflict = function () {
$.fn.alert = old
return this
}
/* ALERT DATA-API
* ============== */
$(document).on('click.alert.data-api', dismiss, Alert.prototype.close)
}(window.jQuery);

@ -1,105 +0,0 @@
/* ============================================================
* bootstrap-button.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#buttons
* ============================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============================================================ */
!function ($) {
"use strict"; // jshint ;_;
/* BUTTON PUBLIC CLASS DEFINITION
* ============================== */
var Button = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, $.fn.button.defaults, options)
}
Button.prototype.setState = function (state) {
var d = 'disabled'
, $el = this.$element
, data = $el.data()
, val = $el.is('input') ? 'val' : 'html'
state = state + 'Text'
data.resetText || $el.data('resetText', $el[val]())
$el[val](data[state] || this.options[state])
// push to event loop to allow forms to submit
setTimeout(function () {
state == 'loadingText' ?
$el.addClass(d).attr(d, d) :
$el.removeClass(d).removeAttr(d)
}, 0)
}
Button.prototype.toggle = function () {
var $parent = this.$element.closest('[data-toggle="buttons-radio"]')
$parent && $parent
.find('.active')
.removeClass('active')
this.$element.toggleClass('active')
}
/* BUTTON PLUGIN DEFINITION
* ======================== */
var old = $.fn.button
$.fn.button = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('button')
, options = typeof option == 'object' && option
if (!data) $this.data('button', (data = new Button(this, options)))
if (option == 'toggle') data.toggle()
else if (option) data.setState(option)
})
}
$.fn.button.defaults = {
loadingText: 'loading...'
}
$.fn.button.Constructor = Button
/* BUTTON NO CONFLICT
* ================== */
$.fn.button.noConflict = function () {
$.fn.button = old
return this
}
/* BUTTON DATA-API
* =============== */
$(document).on('click.button.data-api', '[data-toggle^=button]', function (e) {
var $btn = $(e.target)
if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
$btn.button('toggle')
})
}(window.jQuery);

@ -1,207 +0,0 @@
/* ==========================================================
* bootstrap-carousel.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#carousel
* ==========================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================== */
!function ($) {
"use strict"; // jshint ;_;
/* CAROUSEL CLASS DEFINITION
* ========================= */
var Carousel = function (element, options) {
this.$element = $(element)
this.$indicators = this.$element.find('.carousel-indicators')
this.options = options
this.options.pause == 'hover' && this.$element
.on('mouseenter', $.proxy(this.pause, this))
.on('mouseleave', $.proxy(this.cycle, this))
}
Carousel.prototype = {
cycle: function (e) {
if (!e) this.paused = false
if (this.interval) clearInterval(this.interval);
this.options.interval
&& !this.paused
&& (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
return this
}
, getActiveIndex: function () {
this.$active = this.$element.find('.item.active')
this.$items = this.$active.parent().children()
return this.$items.index(this.$active)
}
, to: function (pos) {
var activeIndex = this.getActiveIndex()
, that = this
if (pos > (this.$items.length - 1) || pos < 0) return
if (this.sliding) {
return this.$element.one('slid', function () {
that.to(pos)
})
}
if (activeIndex == pos) {
return this.pause().cycle()
}
return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
}
, pause: function (e) {
if (!e) this.paused = true
if (this.$element.find('.next, .prev').length && $.support.transition.end) {
this.$element.trigger($.support.transition.end)
this.cycle(true)
}
clearInterval(this.interval)
this.interval = null
return this
}
, next: function () {
if (this.sliding) return
return this.slide('next')
}
, prev: function () {
if (this.sliding) return
return this.slide('prev')
}
, slide: function (type, next) {
var $active = this.$element.find('.item.active')
, $next = next || $active[type]()
, isCycling = this.interval
, direction = type == 'next' ? 'left' : 'right'
, fallback = type == 'next' ? 'first' : 'last'
, that = this
, e
this.sliding = true
isCycling && this.pause()
$next = $next.length ? $next : this.$element.find('.item')[fallback]()
e = $.Event('slide', {
relatedTarget: $next[0]
, direction: direction
})
if ($next.hasClass('active')) return
if (this.$indicators.length) {
this.$indicators.find('.active').removeClass('active')
this.$element.one('slid', function () {
var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
$nextIndicator && $nextIndicator.addClass('active')
})
}
if ($.support.transition && this.$element.hasClass('slide')) {
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
$next.addClass(type)
$next[0].offsetWidth // force reflow
$active.addClass(direction)
$next.addClass(direction)
this.$element.one($.support.transition.end, function () {
$next.removeClass([type, direction].join(' ')).addClass('active')
$active.removeClass(['active', direction].join(' '))
that.sliding = false
setTimeout(function () { that.$element.trigger('slid') }, 0)
})
} else {
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
$active.removeClass('active')
$next.addClass('active')
this.sliding = false
this.$element.trigger('slid')
}
isCycling && this.cycle()
return this
}
}
/* CAROUSEL PLUGIN DEFINITION
* ========================== */
var old = $.fn.carousel
$.fn.carousel = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('carousel')
, options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
, action = typeof option == 'string' ? option : options.slide
if (!data) $this.data('carousel', (data = new Carousel(this, options)))
if (typeof option == 'number') data.to(option)
else if (action) data[action]()
else if (options.interval) data.pause().cycle()
})
}
$.fn.carousel.defaults = {
interval: 5000
, pause: 'hover'
}
$.fn.carousel.Constructor = Carousel
/* CAROUSEL NO CONFLICT
* ==================== */
$.fn.carousel.noConflict = function () {
$.fn.carousel = old
return this
}
/* CAROUSEL DATA-API
* ================= */
$(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
var $this = $(this), href
, $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
, options = $.extend({}, $target.data(), $this.data())
, slideIndex
$target.carousel(options)
if (slideIndex = $this.attr('data-slide-to')) {
$target.data('carousel').pause().to(slideIndex).cycle()
}
e.preventDefault()
})
}(window.jQuery);

@ -1,167 +0,0 @@
/* =============================================================
* bootstrap-collapse.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#collapse
* =============================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============================================================ */
!function ($) {
"use strict"; // jshint ;_;
/* COLLAPSE PUBLIC CLASS DEFINITION
* ================================ */
var Collapse = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, $.fn.collapse.defaults, options)
if (this.options.parent) {
this.$parent = $(this.options.parent)
}
this.options.toggle && this.toggle()
}
Collapse.prototype = {
constructor: Collapse
, dimension: function () {
var hasWidth = this.$element.hasClass('width')
return hasWidth ? 'width' : 'height'
}
, show: function () {
var dimension
, scroll
, actives
, hasData
if (this.transitioning || this.$element.hasClass('in')) return
dimension = this.dimension()
scroll = $.camelCase(['scroll', dimension].join('-'))
actives = this.$parent && this.$parent.find('> .accordion-group > .in')
if (actives && actives.length) {
hasData = actives.data('collapse')
if (hasData && hasData.transitioning) return
actives.collapse('hide')
hasData || actives.data('collapse', null)
}
this.$element[dimension](0)
this.transition('addClass', $.Event('show'), 'shown')
$.support.transition && this.$element[dimension](this.$element[0][scroll])
}
, hide: function () {
var dimension
if (this.transitioning || !this.$element.hasClass('in')) return
dimension = this.dimension()
this.reset(this.$element[dimension]())
this.transition('removeClass', $.Event('hide'), 'hidden')
this.$element[dimension](0)
}
, reset: function (size) {
var dimension = this.dimension()
this.$element
.removeClass('collapse')
[dimension](size || 'auto')
[0].offsetWidth
this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
return this
}
, transition: function (method, startEvent, completeEvent) {
var that = this
, complete = function () {
if (startEvent.type == 'show') that.reset()
that.transitioning = 0
that.$element.trigger(completeEvent)
}
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
this.transitioning = 1
this.$element[method]('in')
$.support.transition && this.$element.hasClass('collapse') ?
this.$element.one($.support.transition.end, complete) :
complete()
}
, toggle: function () {
this[this.$element.hasClass('in') ? 'hide' : 'show']()
}
}
/* COLLAPSE PLUGIN DEFINITION
* ========================== */
var old = $.fn.collapse
$.fn.collapse = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('collapse')
, options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option)
if (!data) $this.data('collapse', (data = new Collapse(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.collapse.defaults = {
toggle: true
}
$.fn.collapse.Constructor = Collapse
/* COLLAPSE NO CONFLICT
* ==================== */
$.fn.collapse.noConflict = function () {
$.fn.collapse = old
return this
}
/* COLLAPSE DATA-API
* ================= */
$(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {
var $this = $(this), href
, target = $this.attr('data-target')
|| e.preventDefault()
|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
, option = $(target).data('collapse') ? 'toggle' : $this.data()
$this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
$(target).collapse(option)
})
}(window.jQuery);

@ -1,165 +0,0 @@
/* ============================================================
* bootstrap-dropdown.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#dropdowns
* ============================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============================================================ */
!function ($) {
"use strict"; // jshint ;_;
/* DROPDOWN CLASS DEFINITION
* ========================= */
var toggle = '[data-toggle=dropdown]'
, Dropdown = function (element) {
var $el = $(element).on('click.dropdown.data-api', this.toggle)
$('html').on('click.dropdown.data-api', function () {
$el.parent().removeClass('open')
})
}
Dropdown.prototype = {
constructor: Dropdown
, toggle: function (e) {
var $this = $(this)
, $parent
, isActive
if ($this.is('.disabled, :disabled')) return
$parent = getParent($this)
isActive = $parent.hasClass('open')
clearMenus()
if (!isActive) {
$parent.toggleClass('open')
}
$this.focus()
return false
}
, keydown: function (e) {
var $this
, $items
, $active
, $parent
, isActive
, index
if (!/(38|40|27)/.test(e.keyCode)) return
$this = $(this)
e.preventDefault()
e.stopPropagation()
if ($this.is('.disabled, :disabled')) return
$parent = getParent($this)
isActive = $parent.hasClass('open')
if (!isActive || (isActive && e.keyCode == 27)) {
if (e.which == 27) $parent.find(toggle).focus()
return $this.click()
}
$items = $('[role=menu] li:not(.divider):visible a', $parent)
if (!$items.length) return
index = $items.index($items.filter(':focus'))
if (e.keyCode == 38 && index > 0) index-- // up
if (e.keyCode == 40 && index < $items.length - 1) index++ // down
if (!~index) index = 0
$items
.eq(index)
.focus()
}
}
function clearMenus() {
$(toggle).each(function () {
getParent($(this)).removeClass('open')
})
}
function getParent($this) {
var selector = $this.attr('data-target')
, $parent
if (!selector) {
selector = $this.attr('href')
selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
}
$parent = selector && $(selector)
if (!$parent || !$parent.length) $parent = $this.parent()
return $parent
}
/* DROPDOWN PLUGIN DEFINITION
* ========================== */
var old = $.fn.dropdown
$.fn.dropdown = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('dropdown')
if (!data) $this.data('dropdown', (data = new Dropdown(this)))
if (typeof option == 'string') data[option].call($this)
})
}
$.fn.dropdown.Constructor = Dropdown
/* DROPDOWN NO CONFLICT
* ==================== */
$.fn.dropdown.noConflict = function () {
$.fn.dropdown = old
return this
}
/* APPLY TO STANDARD DROPDOWN ELEMENTS
* =================================== */
$(document)
.on('click.dropdown.data-api', clearMenus)
.on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
.on('click.dropdown-menu', function (e) { e.stopPropagation() })
.on('click.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
.on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
}(window.jQuery);

@ -1,247 +0,0 @@
/* =========================================================
* bootstrap-modal.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#modals
* =========================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================= */
!function ($) {
"use strict"; // jshint ;_;
/* MODAL CLASS DEFINITION
* ====================== */
var Modal = function (element, options) {
this.options = options
this.$element = $(element)
.delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
this.options.remote && this.$element.find('.modal-body').load(this.options.remote)
}
Modal.prototype = {
constructor: Modal
, toggle: function () {
return this[!this.isShown ? 'show' : 'hide']()
}
, show: function () {
var that = this
, e = $.Event('show')
this.$element.trigger(e)
if (this.isShown || e.isDefaultPrevented()) return
this.isShown = true
this.escape()
this.backdrop(function () {
var transition = $.support.transition && that.$element.hasClass('fade')
if (!that.$element.parent().length) {
that.$element.appendTo(document.body) //don't move modals dom position
}
that.$element.show()
if (transition) {
that.$element[0].offsetWidth // force reflow
}
that.$element
.addClass('in')
.attr('aria-hidden', false)
that.enforceFocus()
transition ?
that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) :
that.$element.focus().trigger('shown')
})
}
, hide: function (e) {
e && e.preventDefault()
var that = this
e = $.Event('hide')
this.$element.trigger(e)
if (!this.isShown || e.isDefaultPrevented()) return
this.isShown = false
this.escape()
$(document).off('focusin.modal')
this.$element
.removeClass('in')
.attr('aria-hidden', true)
$.support.transition && this.$element.hasClass('fade') ?
this.hideWithTransition() :
this.hideModal()
}
, enforceFocus: function () {
var that = this
$(document).on('focusin.modal', function (e) {
if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
that.$element.focus()
}
})
}
, escape: function () {
var that = this
if (this.isShown && this.options.keyboard) {
this.$element.on('keyup.dismiss.modal', function ( e ) {
e.which == 27 && that.hide()
})
} else if (!this.isShown) {
this.$element.off('keyup.dismiss.modal')
}
}
, hideWithTransition: function () {
var that = this
, timeout = setTimeout(function () {
that.$element.off($.support.transition.end)
that.hideModal()
}, 500)
this.$element.one($.support.transition.end, function () {
clearTimeout(timeout)
that.hideModal()
})
}
, hideModal: function () {
var that = this
this.$element.hide()
this.backdrop(function () {
that.removeBackdrop()
that.$element.trigger('hidden')
})
}
, removeBackdrop: function () {
this.$backdrop && this.$backdrop.remove()
this.$backdrop = null
}
, backdrop: function (callback) {
var that = this
, animate = this.$element.hasClass('fade') ? 'fade' : ''
if (this.isShown && this.options.backdrop) {
var doAnimate = $.support.transition && animate
this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
.appendTo(document.body)
this.$backdrop.click(
this.options.backdrop == 'static' ?
$.proxy(this.$element[0].focus, this.$element[0])
: $.proxy(this.hide, this)
)
if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
this.$backdrop.addClass('in')
if (!callback) return
doAnimate ?
this.$backdrop.one($.support.transition.end, callback) :
callback()
} else if (!this.isShown && this.$backdrop) {
this.$backdrop.removeClass('in')
$.support.transition && this.$element.hasClass('fade')?
this.$backdrop.one($.support.transition.end, callback) :
callback()
} else if (callback) {
callback()
}
}
}
/* MODAL PLUGIN DEFINITION
* ======================= */
var old = $.fn.modal
$.fn.modal = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('modal')
, options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
if (!data) $this.data('modal', (data = new Modal(this, options)))
if (typeof option == 'string') data[option]()
else if (options.show) data.show()
})
}
$.fn.modal.defaults = {
backdrop: true
, keyboard: true
, show: true
}
$.fn.modal.Constructor = Modal
/* MODAL NO CONFLICT
* ================= */
$.fn.modal.noConflict = function () {
$.fn.modal = old
return this
}
/* MODAL DATA-API
* ============== */
$(document).on('click.modal.data-api', '[data-toggle="modal"]', function (e) {
var $this = $(this)
, href = $this.attr('href')
, $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
, option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data())
e.preventDefault()
$target
.modal(option)
.one('hide', function () {
$this.focus()
})
})
}(window.jQuery);

@ -1,114 +0,0 @@
/* ===========================================================
* bootstrap-popover.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#popovers
* ===========================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =========================================================== */
!function ($) {
"use strict"; // jshint ;_;
/* POPOVER PUBLIC CLASS DEFINITION
* =============================== */
var Popover = function (element, options) {
this.init('popover', element, options)
}
/* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
========================================== */
Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
constructor: Popover
, setContent: function () {
var $tip = this.tip()
, title = this.getTitle()
, content = this.getContent()
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
$tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)
$tip.removeClass('fade top bottom left right in')
}
, hasContent: function () {
return this.getTitle() || this.getContent()
}
, getContent: function () {
var content
, $e = this.$element
, o = this.options
content = (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
|| $e.attr('data-content')
return content
}
, tip: function () {
if (!this.$tip) {
this.$tip = $(this.options.template)
}
return this.$tip
}
, destroy: function () {
this.hide().$element.off('.' + this.type).removeData(this.type)
}
})
/* POPOVER PLUGIN DEFINITION
* ======================= */
var old = $.fn.popover
$.fn.popover = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('popover')
, options = typeof option == 'object' && option
if (!data) $this.data('popover', (data = new Popover(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.popover.Constructor = Popover
$.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
placement: 'right'
, trigger: 'click'
, content: ''
, template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
})
/* POPOVER NO CONFLICT
* =================== */
$.fn.popover.noConflict = function () {
$.fn.popover = old
return this
}
}(window.jQuery);

@ -1,162 +0,0 @@
/* =============================================================
* bootstrap-scrollspy.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#scrollspy
* =============================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============================================================== */
!function ($) {
"use strict"; // jshint ;_;
/* SCROLLSPY CLASS DEFINITION
* ========================== */
function ScrollSpy(element, options) {
var process = $.proxy(this.process, this)
, $element = $(element).is('body') ? $(window) : $(element)
, href
this.options = $.extend({}, $.fn.scrollspy.defaults, options)
this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)
this.selector = (this.options.target
|| ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
|| '') + ' .nav li > a'
this.$body = $('body')
this.refresh()
this.process()
}
ScrollSpy.prototype = {
constructor: ScrollSpy
, refresh: function () {
var self = this
, $targets
this.offsets = $([])
this.targets = $([])
$targets = this.$body
.find(this.selector)
.map(function () {
var $el = $(this)
, href = $el.data('target') || $el.attr('href')
, $href = /^#\w/.test(href) && $(href)
return ( $href
&& $href.length
&& [[ $href.position().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]] ) || null
})
.sort(function (a, b) { return a[0] - b[0] })
.each(function () {
self.offsets.push(this[0])
self.targets.push(this[1])
})
}
, process: function () {
var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
, scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
, maxScroll = scrollHeight - this.$scrollElement.height()
, offsets = this.offsets
, targets = this.targets
, activeTarget = this.activeTarget
, i
if (scrollTop >= maxScroll) {
return activeTarget != (i = targets.last()[0])
&& this.activate ( i )
}
for (i = offsets.length; i--;) {
activeTarget != targets[i]
&& scrollTop >= offsets[i]
&& (!offsets[i + 1] || scrollTop <= offsets[i + 1])
&& this.activate( targets[i] )
}
}
, activate: function (target) {
var active
, selector
this.activeTarget = target
$(this.selector)
.parent('.active')
.removeClass('active')
selector = this.selector
+ '[data-target="' + target + '"],'
+ this.selector + '[href="' + target + '"]'
active = $(selector)
.parent('li')
.addClass('active')
if (active.parent('.dropdown-menu').length) {
active = active.closest('li.dropdown').addClass('active')
}
active.trigger('activate')
}
}
/* SCROLLSPY PLUGIN DEFINITION
* =========================== */
var old = $.fn.scrollspy
$.fn.scrollspy = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('scrollspy')
, options = typeof option == 'object' && option
if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.scrollspy.Constructor = ScrollSpy
$.fn.scrollspy.defaults = {
offset: 10
}
/* SCROLLSPY NO CONFLICT
* ===================== */
$.fn.scrollspy.noConflict = function () {
$.fn.scrollspy = old
return this
}
/* SCROLLSPY DATA-API
* ================== */
$(window).on('load', function () {
$('[data-spy="scroll"]').each(function () {
var $spy = $(this)
$spy.scrollspy($spy.data())
})
})
}(window.jQuery);

@ -1,144 +0,0 @@
/* ========================================================
* bootstrap-tab.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#tabs
* ========================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ======================================================== */
!function ($) {
"use strict"; // jshint ;_;
/* TAB CLASS DEFINITION
* ==================== */
var Tab = function (element) {
this.element = $(element)
}
Tab.prototype = {
constructor: Tab
, show: function () {
var $this = this.element
, $ul = $this.closest('ul:not(.dropdown-menu)')
, selector = $this.attr('data-target')
, previous
, $target
, e
if (!selector) {
selector = $this.attr('href')
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
}
if ( $this.parent('li').hasClass('active') ) return
previous = $ul.find('.active:last a')[0]
e = $.Event('show', {
relatedTarget: previous
})
$this.trigger(e)
if (e.isDefaultPrevented()) return
$target = $(selector)
this.activate($this.parent('li'), $ul)
this.activate($target, $target.parent(), function () {
$this.trigger({
type: 'shown'
, relatedTarget: previous
})
})
}
, activate: function ( element, container, callback) {
var $active = container.find('> .active')
, transition = callback
&& $.support.transition
&& $active.hasClass('fade')
function next() {
$active
.removeClass('active')
.find('> .dropdown-menu > .active')
.removeClass('active')
element.addClass('active')
if (transition) {
element[0].offsetWidth // reflow for transition
element.addClass('in')
} else {
element.removeClass('fade')
}
if ( element.parent('.dropdown-menu') ) {
element.closest('li.dropdown').addClass('active')
}
callback && callback()
}
transition ?
$active.one($.support.transition.end, next) :
next()
$active.removeClass('in')
}
}
/* TAB PLUGIN DEFINITION
* ===================== */
var old = $.fn.tab
$.fn.tab = function ( option ) {
return this.each(function () {
var $this = $(this)
, data = $this.data('tab')
if (!data) $this.data('tab', (data = new Tab(this)))
if (typeof option == 'string') data[option]()
})
}
$.fn.tab.Constructor = Tab
/* TAB NO CONFLICT
* =============== */
$.fn.tab.noConflict = function () {
$.fn.tab = old
return this
}
/* TAB DATA-API
* ============ */
$(document).on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
e.preventDefault()
$(this).tab('show')
})
}(window.jQuery);

@ -1,361 +0,0 @@
/* ===========================================================
* bootstrap-tooltip.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#tooltips
* Inspired by the original jQuery.tipsy by Jason Frame
* ===========================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================== */
!function ($) {
"use strict"; // jshint ;_;
/* TOOLTIP PUBLIC CLASS DEFINITION
* =============================== */
var Tooltip = function (element, options) {
this.init('tooltip', element, options)
}
Tooltip.prototype = {
constructor: Tooltip
, init: function (type, element, options) {
var eventIn
, eventOut
, triggers
, trigger
, i
this.type = type
this.$element = $(element)
this.options = this.getOptions(options)
this.enabled = true
triggers = this.options.trigger.split(' ')
for (i = triggers.length; i--;) {
trigger = triggers[i]
if (trigger == 'click') {
this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
} else if (trigger != 'manual') {
eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
}
}
this.options.selector ?
(this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
this.fixTitle()
}
, getOptions: function (options) {
options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)
if (options.delay && typeof options.delay == 'number') {
options.delay = {
show: options.delay
, hide: options.delay
}
}
return options
}
, enter: function (e) {
var defaults = $.fn[this.type].defaults
, options = {}
, self
this._options && $.each(this._options, function (key, value) {
if (defaults[key] != value) options[key] = value
}, this)
self = $(e.currentTarget)[this.type](options).data(this.type)
if (!self.options.delay || !self.options.delay.show) return self.show()
clearTimeout(this.timeout)
self.hoverState = 'in'
this.timeout = setTimeout(function() {
if (self.hoverState == 'in') self.show()
}, self.options.delay.show)
}
, leave: function (e) {
var self = $(e.currentTarget)[this.type](this._options).data(this.type)
if (this.timeout) clearTimeout(this.timeout)
if (!self.options.delay || !self.options.delay.hide) return self.hide()
self.hoverState = 'out'
this.timeout = setTimeout(function() {
if (self.hoverState == 'out') self.hide()
}, self.options.delay.hide)
}
, show: function () {
var $tip
, pos
, actualWidth
, actualHeight
, placement
, tp
, e = $.Event('show')
if (this.hasContent() && this.enabled) {
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
$tip = this.tip()
this.setContent()
if (this.options.animation) {
$tip.addClass('fade')
}
placement = typeof this.options.placement == 'function' ?
this.options.placement.call(this, $tip[0], this.$element[0]) :
this.options.placement
$tip
.detach()
.css({ top: 0, left: 0, display: 'block' })
this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
pos = this.getPosition()
actualWidth = $tip[0].offsetWidth
actualHeight = $tip[0].offsetHeight
switch (placement) {
case 'bottom':
tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
break
case 'top':
tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
break
case 'left':
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
break
case 'right':
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
break
}
this.applyPlacement(tp, placement)
this.$element.trigger('shown')
}
}
, applyPlacement: function(offset, placement){
var $tip = this.tip()
, width = $tip[0].offsetWidth
, height = $tip[0].offsetHeight
, actualWidth
, actualHeight
, delta
, replace
$tip
.offset(offset)
.addClass(placement)
.addClass('in')
actualWidth = $tip[0].offsetWidth
actualHeight = $tip[0].offsetHeight
if (placement == 'top' && actualHeight != height) {
offset.top = offset.top + height - actualHeight
replace = true
}
if (placement == 'bottom' || placement == 'top') {
delta = 0
if (offset.left < 0){
delta = offset.left * -2
offset.left = 0
$tip.offset(offset)
actualWidth = $tip[0].offsetWidth
actualHeight = $tip[0].offsetHeight
}
this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
} else {
this.replaceArrow(actualHeight - height, actualHeight, 'top')
}
if (replace) $tip.offset(offset)
}
, replaceArrow: function(delta, dimension, position){
this
.arrow()
.css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
}
, setContent: function () {
var $tip = this.tip()
, title = this.getTitle()
$tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
$tip.removeClass('fade in top bottom left right')
}
, hide: function () {
var that = this
, $tip = this.tip()
, e = $.Event('hide')
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
$tip.removeClass('in')
function removeWithAnimation() {
var timeout = setTimeout(function () {
$tip.off($.support.transition.end).detach()
}, 500)
$tip.one($.support.transition.end, function () {
clearTimeout(timeout)
$tip.detach()
})
}
$.support.transition && this.$tip.hasClass('fade') ?
removeWithAnimation() :
$tip.detach()
this.$element.trigger('hidden')
return this
}
, fixTitle: function () {
var $e = this.$element
if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
$e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
}
}
, hasContent: function () {
return this.getTitle()
}
, getPosition: function () {
var el = this.$element[0]
return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
width: el.offsetWidth
, height: el.offsetHeight
}, this.$element.offset())
}
, getTitle: function () {
var title
, $e = this.$element
, o = this.options
title = $e.attr('data-original-title')
|| (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
return title
}
, tip: function () {
return this.$tip = this.$tip || $(this.options.template)
}
, arrow: function(){
return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
}
, validate: function () {
if (!this.$element[0].parentNode) {
this.hide()
this.$element = null
this.options = null
}
}
, enable: function () {
this.enabled = true
}
, disable: function () {
this.enabled = false
}
, toggleEnabled: function () {
this.enabled = !this.enabled
}
, toggle: function (e) {
var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
self.tip().hasClass('in') ? self.hide() : self.show()
}
, destroy: function () {
this.hide().$element.off('.' + this.type).removeData(this.type)
}
}
/* TOOLTIP PLUGIN DEFINITION
* ========================= */
var old = $.fn.tooltip
$.fn.tooltip = function ( option ) {
return this.each(function () {
var $this = $(this)
, data = $this.data('tooltip')
, options = typeof option == 'object' && option
if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.tooltip.Constructor = Tooltip
$.fn.tooltip.defaults = {
animation: true
, placement: 'top'
, selector: false
, template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
, trigger: 'hover focus'
, title: ''
, delay: 0
, html: false
, container: false
}
/* TOOLTIP NO CONFLICT
* =================== */
$.fn.tooltip.noConflict = function () {
$.fn.tooltip = old
return this
}
}(window.jQuery);

@ -1,60 +0,0 @@
/* ===================================================
* bootstrap-transition.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#transitions
* ===================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================== */
!function ($) {
"use strict"; // jshint ;_;
/* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
* ======================================================= */
$(function () {
$.support.transition = (function () {
var transitionEnd = (function () {
var el = document.createElement('bootstrap')
, transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd'
, 'MozTransition' : 'transitionend'
, 'OTransition' : 'oTransitionEnd otransitionend'
, 'transition' : 'transitionend'
}
, name
for (name in transEndEventNames){
if (el.style[name] !== undefined) {
return transEndEventNames[name]
}
}
}())
return transitionEnd && {
end: transitionEnd
}
})()
})
}(window.jQuery);

@ -1,335 +0,0 @@
/* =============================================================
* bootstrap-typeahead.js v2.3.1
* http://twitter.github.com/bootstrap/javascript.html#typeahead
* =============================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============================================================ */
!function($){
"use strict"; // jshint ;_;
/* TYPEAHEAD PUBLIC CLASS DEFINITION
* ================================= */
var Typeahead = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, $.fn.typeahead.defaults, options)
this.matcher = this.options.matcher || this.matcher
this.sorter = this.options.sorter || this.sorter
this.highlighter = this.options.highlighter || this.highlighter
this.updater = this.options.updater || this.updater
this.source = this.options.source
this.$menu = $(this.options.menu)
this.shown = false
this.listen()
}
Typeahead.prototype = {
constructor: Typeahead
, select: function () {
var val = this.$menu.find('.active').attr('data-value')
this.$element
.val(this.updater(val))
.change()
return this.hide()
}
, updater: function (item) {
return item
}
, show: function () {
var pos = $.extend({}, this.$element.position(), {
height: this.$element[0].offsetHeight
})
this.$menu
.insertAfter(this.$element)
.css({
top: pos.top + pos.height
, left: pos.left
})
.show()
this.shown = true
return this
}
, hide: function () {
this.$menu.hide()
this.shown = false
return this
}
, lookup: function (event) {
var items
this.query = this.$element.val()
if (!this.query || this.query.length < this.options.minLength) {
return this.shown ? this.hide() : this
}
items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
return items ? this.process(items) : this
}
, process: function (items) {
var that = this
items = $.grep(items, function (item) {
return that.matcher(item)
})
items = this.sorter(items)
if (!items.length) {
return this.shown ? this.hide() : this
}
return this.render(items.slice(0, this.options.items)).show()
}
, matcher: function (item) {
return ~item.toLowerCase().indexOf(this.query.toLowerCase())
}
, sorter: function (items) {
var beginswith = []
, caseSensitive = []
, caseInsensitive = []
, item
while (item = items.shift()) {
if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
else if (~item.indexOf(this.query)) caseSensitive.push(item)
else caseInsensitive.push(item)
}
return beginswith.concat(caseSensitive, caseInsensitive)
}
, highlighter: function (item) {
var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
return '<strong>' + match + '</strong>'
})
}
, render: function (items) {
var that = this
items = $(items).map(function (i, item) {
i = $(that.options.item).attr('data-value', item)
i.find('a').html(that.highlighter(item))
return i[0]
})
items.first().addClass('active')
this.$menu.html(items)
return this
}
, next: function (event) {
var active = this.$menu.find('.active').removeClass('active')
, next = active.next()
if (!next.length) {
next = $(this.$menu.find('li')[0])
}
next.addClass('active')
}
, prev: function (event) {
var active = this.$menu.find('.active').removeClass('active')
, prev = active.prev()
if (!prev.length) {
prev = this.$menu.find('li').last()
}
prev.addClass('active')
}
, listen: function () {
this.$element
.on('focus', $.proxy(this.focus, this))
.on('blur', $.proxy(this.blur, this))
.on('keypress', $.proxy(this.keypress, this))
.on('keyup', $.proxy(this.keyup, this))
if (this.eventSupported('keydown')) {
this.$element.on('keydown', $.proxy(this.keydown, this))
}
this.$menu
.on('click', $.proxy(this.click, this))
.on('mouseenter', 'li', $.proxy(this.mouseenter, this))
.on('mouseleave', 'li', $.proxy(this.mouseleave, this))
}
, eventSupported: function(eventName) {
var isSupported = eventName in this.$element
if (!isSupported) {
this.$element.setAttribute(eventName, 'return;')
isSupported = typeof this.$element[eventName] === 'function'
}
return isSupported
}
, move: function (e) {
if (!this.shown) return
switch(e.keyCode) {
case 9: // tab
case 13: // enter
case 27: // escape
e.preventDefault()
break
case 38: // up arrow
e.preventDefault()
this.prev()
break
case 40: // down arrow
e.preventDefault()
this.next()
break
}
e.stopPropagation()
}
, keydown: function (e) {
this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27])
this.move(e)
}
, keypress: function (e) {
if (this.suppressKeyPressRepeat) return
this.move(e)
}
, keyup: function (e) {
switch(e.keyCode) {
case 40: // down arrow
case 38: // up arrow
case 16: // shift
case 17: // ctrl
case 18: // alt
break
case 9: // tab
case 13: // enter
if (!this.shown) return
this.select()
break
case 27: // escape
if (!this.shown) return
this.hide()
break
default:
this.lookup()
}
e.stopPropagation()
e.preventDefault()
}
, focus: function (e) {
this.focused = true
}
, blur: function (e) {
this.focused = false
if (!this.mousedover && this.shown) this.hide()
}
, click: function (e) {
e.stopPropagation()
e.preventDefault()
this.select()
this.$element.focus()
}
, mouseenter: function (e) {
this.mousedover = true
this.$menu.find('.active').removeClass('active')
$(e.currentTarget).addClass('active')
}
, mouseleave: function (e) {
this.mousedover = false
if (!this.focused && this.shown) this.hide()
}
}
/* TYPEAHEAD PLUGIN DEFINITION
* =========================== */
var old = $.fn.typeahead
$.fn.typeahead = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('typeahead')
, options = typeof option == 'object' && option
if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.typeahead.defaults = {
source: []
, items: 8
, menu: '<ul class="typeahead dropdown-menu"></ul>'
, item: '<li><a href="#"></a></li>'
, minLength: 1
}
$.fn.typeahead.Constructor = Typeahead
/* TYPEAHEAD NO CONFLICT
* =================== */
$.fn.typeahead.noConflict = function () {
$.fn.typeahead = old
return this
}
/* TYPEAHEAD DATA-API
* ================== */
$(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
var $this = $(this)
if ($this.data('typeahead')) return
$this.typeahead($this.data())
})
}(window.jQuery);

File diff suppressed because one or more lines are too long

@ -1,182 +0,0 @@
// https://raw.githubusercontent.com/getzola/zola/master/docs/static/search.js
function debounce(func, wait) {
var timeout;
return function () {
var context = this;
var args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function () {
timeout = null;
func.apply(context, args);
}, wait);
};
}
// Taken from mdbook
// The strategy is as follows:
// First, assign a value to each word in the document:
// Words that correspond to search terms (stemmer aware): 40
// Normal words: 2
// First word in a sentence: 8
// Then use a sliding window with a constant number of words and count the
// sum of the values of the words within the window. Then use the window that got the
// maximum sum. If there are multiple maximas, then get the last one.
// Enclose the terms in <b>.
function makeTeaser(body, terms) {
var TERM_WEIGHT = 40;
var NORMAL_WORD_WEIGHT = 2;
var FIRST_WORD_WEIGHT = 8;
var TEASER_MAX_WORDS = 30;
var stemmedTerms = terms.map(function (w) {
return elasticlunr.stemmer(w.toLowerCase());
});
var termFound = false;
var index = 0;
var weighted = []; // contains elements of ["word", weight, index_in_document]
// split in sentences, then words
var sentences = body.toLowerCase().split(". ");
for (var i in sentences) {
var words = sentences[i].split(" ");
var value = FIRST_WORD_WEIGHT;
for (var j in words) {
var word = words[j];
if (word.length > 0) {
for (var k in stemmedTerms) {
if (elasticlunr.stemmer(word).startsWith(stemmedTerms[k])) {
value = TERM_WEIGHT;
termFound = true;
}
}
weighted.push([word, value, index]);
value = NORMAL_WORD_WEIGHT;
}
index += word.length;
index += 1; // ' ' or '.' if last word in sentence
}
index += 1; // because we split at a two-char boundary '. '
}
if (weighted.length === 0) {
return body;
}
var windowWeights = [];
var windowSize = Math.min(weighted.length, TEASER_MAX_WORDS);
// We add a window with all the weights first
var curSum = 0;
for (var i = 0; i < windowSize; i++) {
curSum += weighted[i][1];
}
windowWeights.push(curSum);
for (var i = 0; i < weighted.length - windowSize; i++) {
curSum -= weighted[i][1];
curSum += weighted[i + windowSize][1];
windowWeights.push(curSum);
}
// If we didn't find the term, just pick the first window
var maxSumIndex = 0;
if (termFound) {
var maxFound = 0;
// backwards
for (var i = windowWeights.length - 1; i >= 0; i--) {
if (windowWeights[i] > maxFound) {
maxFound = windowWeights[i];
maxSumIndex = i;
}
}
}
var teaser = [];
var startIndex = weighted[maxSumIndex][2];
for (var i = maxSumIndex; i < maxSumIndex + windowSize; i++) {
var word = weighted[i];
if (startIndex < word[2]) {
// missing text from index to start of `word`
teaser.push(body.substring(startIndex, word[2]));
startIndex = word[2];
}
// add <em/> around search terms
if (word[1] === TERM_WEIGHT) {
teaser.push("<b>");
}
startIndex = word[2] + word[0].length;
teaser.push(body.substring(word[2], startIndex));
if (word[1] === TERM_WEIGHT) {
teaser.push("</b>");
}
}
teaser.push("…");
return teaser.join("");
}
function formatSearchResultItem(item, terms) {
return '<div class="search-results__item">'
+ `<a href="${item.ref}">${item.doc.title}</a>`
+ `<div>${makeTeaser(item.doc.body, terms)}</div>`
+ '</div>';
}
function initSearch() {
var $searchInput = document.getElementById("search");
var $searchResults = document.querySelector(".search-results");
var $searchResultsItems = document.querySelector(".search-results__items");
var MAX_ITEMS = 10;
var options = {
bool: "AND",
fields: {
title: {boost: 2},
body: {boost: 1},
}
};
var currentTerm = "";
var index = elasticlunr.Index.load(window.searchIndex);
$searchInput.addEventListener("keyup", debounce(function() {
var term = $searchInput.value.trim();
if (term === currentTerm || !index) {
return;
}
$searchResults.style.display = term === "" ? "none" : "block";
$searchResultsItems.innerHTML = "";
if (term === "") {
return;
}
var results = index.search(term, options);
if (results.length === 0) {
$searchResults.style.display = "none";
return;
}
currentTerm = term;
for (var i = 0; i < Math.min(results.length, MAX_ITEMS); i++) {
var item = document.createElement("li");
item.innerHTML = formatSearchResultItem(results[i], term.split(" "));
$searchResultsItems.appendChild(item);
}
}, 150));
}
if (document.readyState === "complete" ||
(document.readyState !== "loading" && !document.documentElement.doScroll)
) {
initSearch();
} else {
document.addEventListener("DOMContentLoaded", initSearch);
}

@ -1,5 +0,0 @@
_386 = {
fastLoad: false,
onePass: true,
speedFactor: 1
};

@ -1,22 +0,0 @@
{% extends "index.html" %}
{% block title %}{{ config.title }} - 404{% endblock title %}
{% block header %}
<header class="bg-error">
<h1 class="text-white">404 - Not found</h1>
</header>
{% endblock header %}
{% block main %}
<p>
The page you requested was not found.<br>
You can try to find it by browsing the menus.
</p>
<p>
<a href="{{ config.base_url }}" class="btn btn-info" role="button">Home</a>
</p>
{% endblock main %}
{% block sidebar %}
{% endblock sidebar %}

@ -1,19 +0,0 @@
{% extends "index.html" %}
{% block title %}{{ config.title }} - {{ config.extra.label_categories }}{% endblock title %}
{% block header %}
<div class="page-header">
<h1>{{ config.extra.label_categories }}</h1>
</div>
{% endblock header %}
{% block main %}
<ul>
{% for category in terms %}
<li>
<a href="{{ category.permalink }}">{{ category.name }}</a> ({{ category.pages | length }})
</li>
{% endfor %}
</ul>
{% endblock main %}

@ -1,17 +0,0 @@
{% extends "index.html" %}
{% block title %}{{ config.title }} - {{ config.extra.label_categories }}{% endblock title %}
{% block header %}
<div class="page-header">
<h1>{{ config.extra.label_category }}: {{ term.name }}</h1>
</div>
{% endblock header %}
{% block main %}
<ul>
{% for page in term.pages %}
<li>{{ macro::post_min(page=page) }}</li>
{% endfor %}
</ul>
{% endblock main %}

@ -1,47 +0,0 @@
{% extends "index.html" %}
{% block main %}
<p>Hi there! I am a programmer, OpenSource enthusiast and hacker based in Berlin, Germany.</p>
<p>
I call myself a code artist because programming can and should be seen as a creative process. Therefore code is art.
I love to craft pieces of art with code that are beautiful and elegant in their simplicity, readability and
architecture.
</p>
<h1>Experience</h1>
<p>
Pretty early in my life I realized that I work best on my own terms. That does not mean that I prefer to work alone.
Working with clients, team mates, designers and managers is a crucial part of any development process.
</p>
<p>
Some time in the year 2009 I decided to not only live up to my way of working but also share my experience even more.
I decided to become a freelancing programmer and consultant. Since then many different places benefited from my work.
Start-Ups in their first months as well as known companies like <a rel="noopener nofollow" href="https://www.here.com"
target="_blank">HERE</a> and <a rel="noopener nofollow" href="https://laboratories.telekom.com"
target="_blank">Deutsche Telekom Labs</a>.
</p>
<p>
Together with entrepreneurs, UI/UX experts and engineers of many fields I created novel and beautiful applications
that still influence the live of thousands of people.
</p>
<p>Please see <a href="/cv">my CV</a> for a more detailed list.</p>
<h1>Coaching</h1>
<p>
Im the organizer of <a rel="noopener nofollow" href="https://vuejs.berlin" target="_blank">Vuejs // Berlin</a>, a
monthly meetup group around <a rel="noopener nofollow" href="https://vuejs.org" target="_blank">Vue</a> and web
technologies in general.
</p>
<p>
Many people want to learn and grow. Whenever I can I try to help those people by sharing my experience and knowledge.
I already voluntarily coached at <a rel="noopener nofollow" href="https://www.codecurious.org/" target="_blank">Code
Curious</a>, <a rel="noopener nofollow" href="https://frauenloop.org" target="_blank">Frauenloop</a> and <a
rel="noopener nofollow" href="https://jugendhackt.de" target="_blank">Jugend Hackt</a>. I also helped children with
their first steps into the world of programming at the Berlin <a rel="noopener nofollow" href="https://coderdojo.com"
target="_blank">CoderDojo</a>.
</p>
{% endblock main %}

@ -1,103 +0,0 @@
{% import "macros.html" as macro %}
<!DOCTYPE html>
<html lang="{% if page.extra.lang %}{{ page.extra.lang }}{% else %}{{ lang }}{% endif %}" itemscope
itemtype="http://schema.org/Blog">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
<link rel="stylesheet" href="{{ get_url(path='site.css', trailing_slash=false) | safe }}">
<title>{% block title %}{{ config.title }}{% endblock title %}</title>
{% if config.generate_rss %}
<link rel="alternate" type="application/rss+xml" title="RSS" href="{{ get_url(path='rss.xml') }}">
{% endif %}
<meta name="description" itemprop="about" content="{{ config.description }}">
<meta name="keywords" itemprop="keywords" content="{{ config.extra.keywords }}">
<meta name="author" itemprop="author" content="{{ config.extra.author }}">
<meta itemprop="headline" content="{{ config.title }}">
<meta itemprop="copyrightYear" content="{{ config.extra.year }}">
<link rel="icon" href="{{ get_url(path='images/favicon.ico') }}" type="image/x-icon">
<link rel="manifest" href="{{ get_url(path='images/manifest.json') }}">
<meta name="msapplication-TileColor" content="{{ config.extra.theme_color }}">
<meta name="theme-color" content="{{ config.extra.theme_color }}">
<meta property="og:title" content="{% block ogtitle %}{{ config.title }}{% endblock ogtitle %}">
<meta property="og:description" content="{% block ogdesc %}{{ config.description }}{% endblock ogdesc %}">
<meta property="og:url" content="{% block ogurl %}{{ config.base_url }}{% endblock ogurl%}">
<meta property="og:site_name" content="{{ config.title }}">
{% if config.extra.image %}
<meta property="og:image" content="{% block ogimg %}{{ config.extra.image }}{% endblock ogimg %}">
{% endif %}
<meta name="twitter:card" content="summary">
{% if config.extra.twitter_user %}
<meta name="twitter:site" content="{{ config.extra.twitter_user }}">
<meta name="twitter:creator" content="{{ config.extra.twitter_user }}">
<meta name="twitter:image:alt" content="{% block ogaltimg %}{{ config.title }}{% endblock ogaltimg %}">
{% endif %}
</head>
<body>
<main class="container">
{% block breadcrumb %}{% endblock breadcrumb %}
{% block header %}
<header>
<h1>{{ config.title }} <small>{{ config.description }}</small></h1>
</header>
{% endblock header %}
{% block meta %}{% endblock meta %}
<div class="flex-row gap">
<div class="w-3/4">
{% block main %}
{% for page in paginator.pages %}
{{ macro::post_max(page=page) }}
{% endfor %}
{{ macro::paginator(ref=paginator, extra=config.extra) }}
{% endblock main %}
</div>
<aside class="w-1/4">
{% block sidebar %}
{% for page in config.extra.sidebars %}
<nav class="box">
<header>{{ page.title }}</header>
<menu>
{% for item in page.items %}
<li class="{% if item.path == current_path %}active{% endif %}">
{% if page.internal %}
<a href="{{ item.path }}">{{ item.name }}</a>
{% else %}
<a href="{{ item.path }}" target="_blank" rel="noopener">{{ item.name }}</a>
{% endif %}
</li>
{% endfor %}
</menu>
</nav>
{% endfor %}
{% endblock sidebar %}
</aside>
</div> <!-- row -->
</main>
<footer class="container">
<hr class="soften">
<p>
{{ config.extra.year }} &copy;
<a href="{{ config.base_url }}">{{ config.extra.author }}</a>
|
Built on <a href="https://getzola.org" rel="noopener" target="_blank">Zola</a>
</p>
</footer>
</body>
</html>

@ -1,81 +0,0 @@
{% macro post_max(page) %}
<div>
<h1><a href="{{ page.permalink }}">{{ page.title }}</a></h1>
<p>{{ page.description }}</p>
<dl class="dl-horizontal">
<dt>{{ config.extra.label_date }}</dt>
<dd>{{ page.date | date(format="%Y-%m-%d") }}</dd>
<dt>{{ config.extra.label_author }}</dt>
<dd>
{% if page.extra.author %}
{{page.extra.author}}
{% else %}
{{config.extra.author}}
{% endif %}
</dd>
{% if page.taxonomies.categories %}
<dt>{{ config.extra.label_taxonomy }}</dt>
<dd>
<a href="{{ get_taxonomy_url(kind="categories", name=page.taxonomies.categories[0]) }}">
{{ page.taxonomies.categories[0] }}
</a>
{% if page.taxonomies.tags %}
|
{% for tag in page.taxonomies.tags %}
<a href="{{ get_taxonomy_url(kind="tags", name=tag) }}">{{ tag }}</a>{% if page.taxonomies.tags | length > 1 %}{% if loop.index != page.taxonomies.tags | length %},{% endif %}{% endif %}
{% endfor %}
{% endif %}
</a>
</dd>
{% endif %}
<dt>{{ config.extra.label_reading }}</dt>
<dd>{{ page.reading_time }}'</dd>
</dl>
<p>
<a href="{{ page.permalink }}" class="btn btn-info" role="button">{{ config.extra.label_read_more }}</a>
</p>
<hr class="soften">
<p></p>
</div>
{% endmacro post_max %}
{% macro post_min(page) %}
<a href="{{ page.permalink }}">{{ page.date }} | {{ page.title }}</a>
{% endmacro post_min %}
{% macro paginator(ref, extra) %}
<div class="pagination pagination-centered">
<ul>
{% if ref.current_index != 1 %}
<li><a href="{{ ref.first }}">&larrb;</a></li>
{% else %}
<li class="disabled"><a href="{{ ref.first }}">&larrb;</a></li>
{% endif %}
{% if ref.next %}
<li><a href="{{ ref.previous }}">&larr;</a></li>
{% else %}
<li class="disabled"><a href="#">&larr;</a></li>
{% endif %}
<li class="disabled"><a href="#">{{ ref.current_index }}/{{ ref.number_pagers }}</a></li>
{% if ref.next %}
<li><a href="{{ ref.next }}">&rarr;</a></li>
{% else %}
<li class="disabled"><a href="#">&rarr;</a></li>
{% endif %}
{% if ref.current_index != ref.number_pagers %}
<li><a href="{{ ref.last }}">&rarrb;</a></li>
{% else %}
<li class="disabled"><a href="{{ ref.last }}">&rarrb;</a></li>
{% endif %}
</ul>
</div>
{% endmacro paginator %}

@ -1,67 +0,0 @@
{% extends "index.html" %}
{% block title %}{{ config.title}} - {{ page.title }}{% endblock title %}
{% block ogtitle %}{{ config.title}} - {{ page.title }}{% endblock ogtitle %}
{% block ogdesc %}{{ page.description }}{% endblock ogdesc %}
{% block ogurl %}{% if page.slug %}{{ config.base_url }}/{{ page.slug }}{% endif %}{% endblock ogurl %}
{% block ogimg %}{% if page.extra.image %}{{ page.extra.image }}{% endif %}{% endblock ogimg %}
{% block breadcrumb %}
<p class="lead">
<span>&gt;&gt;</span>
<a href="{{ config.base_url }}">Home</a>
{% if page.taxonomies %}
<span class="divider">/</span>
{% if page.taxonomies.categories %}
<a class="category" href="{{ get_taxonomy_url(kind="categories", name=page.taxonomies.categories[0]) }}">{{ page.taxonomies.categories[0] }}</a>
{% endif %}
{% if page.taxonomies.tags %}
<span class="divider">/</span>
{% for tag in page.taxonomies.tags %}
<a href="{{ get_taxonomy_url(kind="tags", name=tag) }}">{{ tag }}</a>{% if page.taxonomies.tags | length > 1 %}{% if loop.index != page.taxonomies.tags | length %},{% endif %}{% endif %}
{% endfor %}
{% endif %}
{% endif %}
</p>
{% endblock breadcrumb %}
{% block header %}
<div class="page-header">
<h1>{{ page.title }}</h1>
</div>
{% endblock header %}
{% block meta %}
<p class="text-right">
<span class="label label-success">
&becaus;
{% if page.extra.author %}
{{ page.extra.author }}
{% else %}
{{ config.extra.author }}
{% endif %}
</span>
<span class="label label-success">&there4; {{ page.date }}</span>
<span class="label label-success">&infin; {{ page.reading_time }}'</span>
</p>
{% endblock meta %}
{% block main %}
{{ page.content | safe }}
{% if config.extra.disqus and page.extra.comments %}
<div id="disqus">
<div id="disqus_thread"></div>
<script>
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://{{config.extra.disqus}}.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>
{% endif %}
{% endblock main %}

@ -1,26 +0,0 @@
{% if not width %}
{% set width = 240 %}
{% endif %}
{% if not height %}
{% if width %}
{% set height = width %}
{% else %}
{% set height = 180 %}
{% endif %}
{% endif %}
{% if not op %}
{% set op = 'fill' %}
{% endif %}
{% if caption %}
<figure>
<a href="{{ get_url(path=path) }}"><img src="{{ resize_image(path=path, width=width, height=height, op=op) }}"/></a>
<figcaption>{{ caption }}</figcaption>
</figure>
{% elif figure %}
<figure>
<img src="{{ resize_image(path=path, width=width, height=height, op=op) }}"/>
</figure>
{% else %}
<img src="{{ resize_image(path=path, width=width, height=height, op=op) }}"/>
{% endif %}

@ -1,19 +0,0 @@
{% extends "index.html" %}
{% block title %}{{ config.title }} - {{ config.extra.label_tags }}{% endblock title %}
{% block header %}
<div class="page-header">
<h1>{{ config.extra.label_tags }}</h1>
</div>
{% endblock header %}
{% block main %}
<ul>
{% for category in terms %}
<li>
<a href="{{ category.permalink }}">{{ category.name }}</a> ({{ category.pages | length }})
</li>
{% endfor %}
</ul>
{% endblock main %}

@ -1,17 +0,0 @@
{% extends "index.html" %}
{% block title %}{{ config.title }} - {{ config.extra.label_tags }}{% endblock title %}
{% block header %}
<div class="page-header">
<h1>{{ config.extra.label_tag }}: {{ term.name }}</h1>
</div>
{% endblock header %}
{% block main %}
<ul>
{% for page in term.pages %}
<li>{{ macro::post_min(page=page) }}</li>
{% endfor %}
</ul>
{% endblock main %}

@ -1,10 +0,0 @@
name = "zola.386"
description = "Zola port of the BOOTSTRA.386 theme."
license = "MIT"
homepage = "https://github.com/lopes/zola.386"
min_version = "0.10.1"
demo = "https://zola386.netlify.com"
[author]
name = "José Lopes"
homepage = "https://github.com/lopes"
Loading…
Cancel
Save