Move to hugo
This commit is contained in:
parent
7e9da6e61a
commit
3b4f2f6312
55 changed files with 277 additions and 1569 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,7 +1,7 @@
|
|||
public/
|
||||
resources/
|
||||
|
||||
.DS_Store
|
||||
_site
|
||||
.jekyll-assets-cache
|
||||
_drafts
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "themes/terminal"]
|
||||
path = themes/terminal
|
||||
url = https://github.com/panr/hugo-theme-terminal.git
|
9
404.html
9
404.html
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
layout: default
|
||||
title: "404: Page not found"
|
||||
---
|
||||
|
||||
<div class="page">
|
||||
<h1 class="page-title">404: Page not found</h1>
|
||||
<p class="lead">Sorry, we've misplaced that URL or it's pointing to something that doesn't exist. <a href="{{ site.baseurl }}">Head back home</a> to try finding it again.</p>
|
||||
</div>
|
8
Gemfile
8
Gemfile
|
@ -1,8 +0,0 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'jekyll', '~> 2.5.3'
|
||||
|
||||
group :extensions do
|
||||
gem 'jekyll-assets', '~> 1.0.0'
|
||||
gem 'yui-compressor', '~> 0.12.0'
|
||||
end
|
96
Gemfile.lock
96
Gemfile.lock
|
@ -1,96 +0,0 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
addressable (2.3.8)
|
||||
blankslate (2.1.2.4)
|
||||
classifier-reborn (2.0.4)
|
||||
fast-stemmer (~> 1.0)
|
||||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.9.1.1)
|
||||
colorator (0.1)
|
||||
execjs (2.6.0)
|
||||
fast-stemmer (1.0.2)
|
||||
fastimage (1.7.0)
|
||||
addressable (~> 2.3, >= 2.3.5)
|
||||
ffi (1.9.10)
|
||||
hike (1.2.3)
|
||||
jekyll (2.5.3)
|
||||
classifier-reborn (~> 2.0)
|
||||
colorator (~> 0.1)
|
||||
jekyll-coffeescript (~> 1.0)
|
||||
jekyll-gist (~> 1.0)
|
||||
jekyll-paginate (~> 1.0)
|
||||
jekyll-sass-converter (~> 1.0)
|
||||
jekyll-watch (~> 1.1)
|
||||
kramdown (~> 1.3)
|
||||
liquid (~> 2.6.1)
|
||||
mercenary (~> 0.3.3)
|
||||
pygments.rb (~> 0.6.0)
|
||||
redcarpet (~> 3.1)
|
||||
safe_yaml (~> 1.0)
|
||||
toml (~> 0.1.0)
|
||||
jekyll-assets (1.0.0)
|
||||
fastimage (~> 1.6)
|
||||
jekyll (>= 2)
|
||||
mini_magick (~> 4.1)
|
||||
sass (~> 3.2)
|
||||
sprockets (~> 2.10)
|
||||
sprockets-helpers
|
||||
sprockets-sass
|
||||
jekyll-coffeescript (1.0.1)
|
||||
coffee-script (~> 2.2)
|
||||
jekyll-gist (1.3.5)
|
||||
jekyll-paginate (1.1.0)
|
||||
jekyll-sass-converter (1.3.0)
|
||||
sass (~> 3.2)
|
||||
jekyll-watch (1.3.0)
|
||||
listen (~> 3.0)
|
||||
kramdown (1.9.0)
|
||||
liquid (2.6.3)
|
||||
listen (3.0.4)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9)
|
||||
mercenary (0.3.5)
|
||||
mini_magick (4.3.6)
|
||||
multi_json (1.11.2)
|
||||
parslet (1.5.0)
|
||||
blankslate (~> 2.0)
|
||||
posix-spawn (0.3.11)
|
||||
pygments.rb (0.6.3)
|
||||
posix-spawn (~> 0.3.6)
|
||||
yajl-ruby (~> 1.2.0)
|
||||
rack (1.6.4)
|
||||
rb-fsevent (0.9.6)
|
||||
rb-inotify (0.9.5)
|
||||
ffi (>= 0.5.0)
|
||||
redcarpet (3.3.3)
|
||||
safe_yaml (1.0.4)
|
||||
sass (3.4.19)
|
||||
sprockets (2.12.4)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
sprockets-helpers (1.2.1)
|
||||
sprockets (>= 2.2)
|
||||
sprockets-sass (1.3.1)
|
||||
sprockets (~> 2.0)
|
||||
tilt (~> 1.1)
|
||||
tilt (1.4.1)
|
||||
toml (0.1.2)
|
||||
parslet (~> 1.5.0)
|
||||
yajl-ruby (1.2.3)
|
||||
yui-compressor (0.12.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
jekyll (~> 2.5.3)
|
||||
jekyll-assets (~> 1.0.0)
|
||||
yui-compressor (~> 0.12.0)
|
||||
|
||||
BUNDLED WITH
|
||||
1.16.1
|
30
Makefile
30
Makefile
|
@ -1,30 +0,0 @@
|
|||
all: compile compress upload superfeedr
|
||||
|
||||
compile: clean
|
||||
@echo "=== Generating static files"
|
||||
@bundle exec jekyll build --lsi
|
||||
@echo "Done."
|
||||
|
||||
compress: compile
|
||||
@echo "=== Compressing generated files"
|
||||
@find ./_site -type f | xargs zopfli --gzip --i30
|
||||
@find ./_site -type f ! -name "*.gz" | xargs -I {} brotli --quality=11 --output={}.br {}
|
||||
@find ./_site -type f -name "*.br" | xargs chmod 644
|
||||
@echo "Done."
|
||||
|
||||
upload:
|
||||
@echo "=== Syncing files"
|
||||
@rsync --rsync-path="sudo rsync" -avz --no-o --no-g -e ssh --chmod=og=r -p --delete _site/ kempkens.io:/iocage/jails/webserver/root/var/www/blog
|
||||
@echo "Done."
|
||||
@echo "=== Changing permissions"
|
||||
@ssh kempkens.io sudo /usr/home/daniel/bin/chmodweb /iocage/jails/webserver/root/var/www/blog
|
||||
@echo "Done."
|
||||
|
||||
superfeedr:
|
||||
@echo "=== Notifying Superfeedr"
|
||||
@curl -X POST https://kempkens.superfeedr.com -d "hub.mode=publish" -d "hub.url=https://blog.kempkens.io/feed.xml"
|
||||
@curl -X POST https://kempkens.superfeedr.com -d "hub.mode=publish" -d "hub.url=https://blog.kempkens.io/feed-with-links.xml"
|
||||
@echo "Done."
|
||||
|
||||
clean:
|
||||
@rm -rf ./_site
|
|
@ -1,5 +0,0 @@
|
|||
/*
|
||||
*= require poole
|
||||
*= require syntax
|
||||
*= require hyde
|
||||
*/
|
|
@ -1,250 +0,0 @@
|
|||
/*
|
||||
* __ __
|
||||
* /\ \ /\ \
|
||||
* \ \ \___ __ __ \_\ \ __
|
||||
* \ \ _ `\/\ \/\ \ /'_` \ /'__`\
|
||||
* \ \ \ \ \ \ \_\ \/\ \_\ \/\ __/
|
||||
* \ \_\ \_\/`____ \ \___,_\ \____\
|
||||
* \/_/\/_/`/___/> \/__,_ /\/____/
|
||||
* /\___/
|
||||
* \/__/
|
||||
*
|
||||
* Designed, built, and released under MIT license by @mdo. Learn more at
|
||||
* https://github.com/poole/hyde.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Contents
|
||||
*
|
||||
* Global resets
|
||||
* Sidebar
|
||||
* Container
|
||||
* Reverse layout
|
||||
* Themes
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Global resets
|
||||
*
|
||||
* Update the foundational and global aspects of the page.
|
||||
*/
|
||||
|
||||
html {
|
||||
font-family: "PT Sans", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
@media (min-width: 48em) {
|
||||
html {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 58em) {
|
||||
html {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sidebar
|
||||
*
|
||||
* Flexible banner for housing site name, intro, and "footer" content. Starts
|
||||
* out above content in mobile and later moves to the side with wider viewports.
|
||||
*/
|
||||
|
||||
.sidebar {
|
||||
text-align: center;
|
||||
padding: 2rem 1rem;
|
||||
color: rgba(255,255,255,.5);
|
||||
background-color: #202020;
|
||||
}
|
||||
@media (min-width: 48em) {
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 18rem;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sidebar links */
|
||||
.sidebar a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* About section */
|
||||
.sidebar-about h1 {
|
||||
color: #fff;
|
||||
margin-top: 0;
|
||||
font-family: "Abril Fatface", serif;
|
||||
font-size: 3.25rem;
|
||||
}
|
||||
|
||||
/* Sidebar nav */
|
||||
.sidebar-nav {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.sidebar-nav-item {
|
||||
display: block;
|
||||
line-height: 1.75;
|
||||
}
|
||||
a.sidebar-nav-item:hover,
|
||||
a.sidebar-nav-item:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.sidebar-nav-item.active {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Sticky sidebar
|
||||
*
|
||||
* Add the `sidebar-sticky` class to the sidebar's container to affix it the
|
||||
* contents to the bottom of the sidebar in tablets and up.
|
||||
*/
|
||||
|
||||
@media (min-width: 48em) {
|
||||
.sidebar-sticky {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
bottom: 1rem;
|
||||
left: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Container
|
||||
*
|
||||
* Align the contents of the site above the proper threshold with some margin-fu
|
||||
* with a 25%-wide `.sidebar`.
|
||||
*/
|
||||
|
||||
.content {
|
||||
padding-top: 4rem;
|
||||
padding-bottom: 4rem;
|
||||
}
|
||||
|
||||
@media (min-width: 48em) {
|
||||
.content {
|
||||
max-width: 38rem;
|
||||
margin-left: 20rem;
|
||||
margin-right: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 64em) {
|
||||
.content {
|
||||
margin-left: 22rem;
|
||||
margin-right: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reverse layout
|
||||
*
|
||||
* Flip the orientation of the page by placing the `.sidebar` on the right.
|
||||
*/
|
||||
|
||||
@media (min-width: 48em) {
|
||||
.layout-reverse .sidebar {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
.layout-reverse .content {
|
||||
margin-left: 2rem;
|
||||
margin-right: 20rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 64em) {
|
||||
.layout-reverse .content {
|
||||
margin-left: 4rem;
|
||||
margin-right: 22rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Themes
|
||||
*
|
||||
* As of v1.1, Hyde includes optional themes to color the sidebar and links
|
||||
* within blog posts. To use, add the class of your choosing to the `body`.
|
||||
*/
|
||||
|
||||
/* Base16 (http://chriskempson.github.io/base16/#default) */
|
||||
|
||||
/* Red */
|
||||
.theme-base-08 .sidebar {
|
||||
background-color: #ac4142;
|
||||
}
|
||||
.theme-base-08 .content a,
|
||||
.theme-base-08 .related-posts li a:hover {
|
||||
color: #ac4142;
|
||||
}
|
||||
|
||||
/* Orange */
|
||||
.theme-base-09 .sidebar {
|
||||
background-color: #d28445;
|
||||
}
|
||||
.theme-base-09 .content a,
|
||||
.theme-base-09 .related-posts li a:hover {
|
||||
color: #d28445;
|
||||
}
|
||||
|
||||
/* Yellow */
|
||||
.theme-base-0a .sidebar {
|
||||
background-color: #f4bf75;
|
||||
}
|
||||
.theme-base-0a .content a,
|
||||
.theme-base-0a .related-posts li a:hover {
|
||||
color: #f4bf75;
|
||||
}
|
||||
|
||||
/* Green */
|
||||
.theme-base-0b .sidebar {
|
||||
background-color: #90a959;
|
||||
}
|
||||
.theme-base-0b .content a,
|
||||
.theme-base-0b .related-posts li a:hover {
|
||||
color: #90a959;
|
||||
}
|
||||
|
||||
/* Cyan */
|
||||
.theme-base-0c .sidebar {
|
||||
background-color: #75b5aa;
|
||||
}
|
||||
.theme-base-0c .content a,
|
||||
.theme-base-0c .related-posts li a:hover {
|
||||
color: #75b5aa;
|
||||
}
|
||||
|
||||
/* Blue */
|
||||
.theme-base-0d .sidebar {
|
||||
background-color: #6a9fb5;
|
||||
}
|
||||
.theme-base-0d .content a,
|
||||
.theme-base-0d .related-posts li a:hover {
|
||||
color: #6a9fb5;
|
||||
}
|
||||
|
||||
/* Magenta */
|
||||
.theme-base-0e .sidebar {
|
||||
background-color: #aa759f;
|
||||
}
|
||||
.theme-base-0e .content a,
|
||||
.theme-base-0e .related-posts li a:hover {
|
||||
color: #aa759f;
|
||||
}
|
||||
|
||||
/* Brown */
|
||||
.theme-base-0f .sidebar {
|
||||
background-color: #8f5536;
|
||||
}
|
||||
.theme-base-0f .content a,
|
||||
.theme-base-0f .related-posts li a:hover {
|
||||
color: #8f5536;
|
||||
}
|
|
@ -1,465 +0,0 @@
|
|||
/*
|
||||
* ___
|
||||
* /\_ \
|
||||
* _____ ___ ___\//\ \ __
|
||||
* /\ '__`\ / __`\ / __`\\ \ \ /'__`\
|
||||
* \ \ \_\ \/\ \_\ \/\ \_\ \\_\ \_/\ __/
|
||||
* \ \ ,__/\ \____/\ \____//\____\ \____\
|
||||
* \ \ \/ \/___/ \/___/ \/____/\/____/
|
||||
* \ \_\
|
||||
* \/_/
|
||||
*
|
||||
* Designed, built, and released under MIT license by @mdo. Learn more at
|
||||
* https://github.com/poole/poole.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Contents
|
||||
*
|
||||
* Body resets
|
||||
* Custom type
|
||||
* Messages
|
||||
* Container
|
||||
* Masthead
|
||||
* Posts and pages
|
||||
* Pagination
|
||||
* Reverse layout
|
||||
* Themes
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Body resets
|
||||
*
|
||||
* Update the foundational and global aspects of the page.
|
||||
*/
|
||||
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
@media (min-width: 38em) {
|
||||
html {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
color: #515151;
|
||||
background-color: #fff;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
/* No `:visited` state is required by default (browsers will use `a`) */
|
||||
a {
|
||||
color: #268bd2;
|
||||
text-decoration: none;
|
||||
}
|
||||
a strong {
|
||||
color: inherit;
|
||||
}
|
||||
/* `:focus` is linked to `:hover` for basic accessibility */
|
||||
a:hover,
|
||||
a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Headings */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-bottom: .5rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.25;
|
||||
color: #313131;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
h2 {
|
||||
margin-top: 1rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
h3 {
|
||||
margin-top: 1.5rem;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
h4, h5, h6 {
|
||||
margin-top: 1rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Body text */
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
strong {
|
||||
color: #303030;
|
||||
}
|
||||
|
||||
|
||||
/* Lists */
|
||||
ul, ol, dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
dd {
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
/* Misc */
|
||||
hr {
|
||||
position: relative;
|
||||
margin: 1.5rem 0;
|
||||
border: 0;
|
||||
border-top: 1px solid #eee;
|
||||
border-bottom: 1px solid #fff;
|
||||
}
|
||||
|
||||
abbr {
|
||||
font-size: 85%;
|
||||
font-weight: bold;
|
||||
color: #555;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
abbr[title] {
|
||||
cursor: help;
|
||||
border-bottom: 1px dotted #e5e5e5;
|
||||
}
|
||||
|
||||
/* Code */
|
||||
code,
|
||||
pre {
|
||||
font-family: Menlo, Monaco, "Courier New", monospace;
|
||||
}
|
||||
code {
|
||||
padding: .25em .5em;
|
||||
font-size: 85%;
|
||||
color: #bf616a;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 3px;
|
||||
}
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
padding: 1rem;
|
||||
font-size: .8rem;
|
||||
line-height: 1.4;
|
||||
white-space: pre;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
pre code {
|
||||
padding: 0;
|
||||
font-size: 100%;
|
||||
color: inherit;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* Pygments via Jekyll */
|
||||
.highlight {
|
||||
margin-bottom: 1rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.highlight pre {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Gist via GitHub Pages */
|
||||
.gist .gist-file {
|
||||
font-family: Menlo, Monaco, "Courier New", monospace !important;
|
||||
}
|
||||
.gist .markdown-body {
|
||||
padding: 15px;
|
||||
}
|
||||
.gist pre {
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
.gist .gist-file .gist-data {
|
||||
font-size: .8rem !important;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.gist code {
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
background-color: transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* Quotes */
|
||||
blockquote {
|
||||
padding: .5rem 1rem;
|
||||
margin: .8rem 0;
|
||||
color: #7a7a7a;
|
||||
border-left: .25rem solid #e5e5e5;
|
||||
}
|
||||
blockquote p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@media (min-width: 30em) {
|
||||
blockquote {
|
||||
padding-right: 5rem;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
margin: 0 0 1rem;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
table {
|
||||
margin-bottom: 1rem;
|
||||
width: 100%;
|
||||
border: 1px solid #e5e5e5;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
td,
|
||||
th {
|
||||
padding: .25rem .5rem;
|
||||
border: 1px solid #e5e5e5;
|
||||
}
|
||||
tbody tr:nth-child(odd) td,
|
||||
tbody tr:nth-child(odd) th {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Custom type
|
||||
*
|
||||
* Extend paragraphs with `.lead` for larger introductory text.
|
||||
*/
|
||||
|
||||
.lead {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Messages
|
||||
*
|
||||
* Show alert messages to users. You may add it to single elements like a `<p>`,
|
||||
* or to a parent if there are multiple elements to show.
|
||||
*/
|
||||
|
||||
.message {
|
||||
margin-bottom: 1rem;
|
||||
padding: 1rem;
|
||||
color: #717171;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Container
|
||||
*
|
||||
* Center the page content.
|
||||
*/
|
||||
|
||||
.container {
|
||||
max-width: 38rem;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Masthead
|
||||
*
|
||||
* Super small header above the content for site name and short description.
|
||||
*/
|
||||
|
||||
.masthead {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
.masthead-title {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
color: #505050;
|
||||
}
|
||||
.masthead-title a {
|
||||
color: #505050;
|
||||
}
|
||||
.masthead-title small {
|
||||
font-size: 75%;
|
||||
font-weight: 400;
|
||||
color: #c0c0c0;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Posts and pages
|
||||
*
|
||||
* Each post is wrapped in `.post` and is used on default and post layouts. Each
|
||||
* page is wrapped in `.page` and is only used on the page layout.
|
||||
*/
|
||||
|
||||
.page,
|
||||
.post {
|
||||
margin-bottom: 4em;
|
||||
}
|
||||
|
||||
/* Blog post or page title */
|
||||
.page-title,
|
||||
.post-title,
|
||||
.post-title a {
|
||||
color: #303030;
|
||||
}
|
||||
.page-title,
|
||||
.post-title {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Meta data line below post title */
|
||||
.post-date {
|
||||
display: block;
|
||||
margin-top: -.5rem;
|
||||
margin-bottom: 1rem;
|
||||
color: #9a9a9a;
|
||||
}
|
||||
|
||||
/* Related posts */
|
||||
.related {
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
.related-posts {
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.related-posts h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
.related-posts li small {
|
||||
font-size: 75%;
|
||||
color: #999;
|
||||
}
|
||||
.related-posts li a:hover {
|
||||
color: #268bd2;
|
||||
text-decoration: none;
|
||||
}
|
||||
.related-posts li a:hover small {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Pagination
|
||||
*
|
||||
* Super lightweight (HTML-wise) blog pagination. `span`s are provide for when
|
||||
* there are no more previous or next posts to show.
|
||||
*/
|
||||
|
||||
.pagination {
|
||||
overflow: hidden; /* clearfix */
|
||||
margin-left: -1rem;
|
||||
margin-right: -1rem;
|
||||
font-family: "PT Sans", Helvetica, Arial, sans-serif;
|
||||
color: #ccc;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Pagination items can be `span`s or `a`s */
|
||||
.pagination-item {
|
||||
display: block;
|
||||
padding: 1rem;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
.pagination-item:first-child {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
/* Only provide a hover state for linked pagination items */
|
||||
a.pagination-item:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
|
||||
/* Custom */
|
||||
.post-date a {
|
||||
color: #9a9a9a;
|
||||
}
|
||||
.post-date a:hover {
|
||||
color: #303030;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.post-link > span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 3rem;
|
||||
font-size: 75%;
|
||||
}
|
||||
.footer-links {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
text-align: center;
|
||||
}
|
||||
.footer-links li {
|
||||
display: inline;
|
||||
}
|
||||
.footer-links li.divider:after {
|
||||
content: "|";
|
||||
color: #ccc;
|
||||
}
|
||||
.footer-links li a {
|
||||
color: #515151;
|
||||
}
|
||||
|
||||
@media (min-width: 30em) {
|
||||
.pagination {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
.pagination-item {
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
.pagination-item:first-child {
|
||||
margin-bottom: 0;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
.pagination-item:last-child {
|
||||
margin-left: -1px;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
.highlight .hll { background-color: #ffc; }
|
||||
.highlight .c { color: #999; } /* Comment */
|
||||
.highlight .err { color: #a00; background-color: #faa } /* Error */
|
||||
.highlight .k { color: #069; } /* Keyword */
|
||||
.highlight .o { color: #555 } /* Operator */
|
||||
.highlight .cm { color: #09f; font-style: italic } /* Comment.Multiline */
|
||||
.highlight .cp { color: #099 } /* Comment.Preproc */
|
||||
.highlight .c1 { color: #999; } /* Comment.Single */
|
||||
.highlight .cs { color: #999; } /* Comment.Special */
|
||||
.highlight .gd { background-color: #fcc; border: 1px solid #c00 } /* Generic.Deleted */
|
||||
.highlight .ge { font-style: italic } /* Generic.Emph */
|
||||
.highlight .gr { color: #f00 } /* Generic.Error */
|
||||
.highlight .gh { color: #030; } /* Generic.Heading */
|
||||
.highlight .gi { background-color: #cfc; border: 1px solid #0c0 } /* Generic.Inserted */
|
||||
.highlight .go { color: #aaa } /* Generic.Output */
|
||||
.highlight .gp { color: #009; } /* Generic.Prompt */
|
||||
.highlight .gs { } /* Generic.Strong */
|
||||
.highlight .gu { color: #030; } /* Generic.Subheading */
|
||||
.highlight .gt { color: #9c6 } /* Generic.Traceback */
|
||||
.highlight .kc { color: #069; } /* Keyword.Constant */
|
||||
.highlight .kd { color: #069; } /* Keyword.Declaration */
|
||||
.highlight .kn { color: #069; } /* Keyword.Namespace */
|
||||
.highlight .kp { color: #069 } /* Keyword.Pseudo */
|
||||
.highlight .kr { color: #069; } /* Keyword.Reserved */
|
||||
.highlight .kt { color: #078; } /* Keyword.Type */
|
||||
.highlight .m { color: #f60 } /* Literal.Number */
|
||||
.highlight .s { color: #d44950 } /* Literal.String */
|
||||
.highlight .na { color: #4f9fcf } /* Name.Attribute */
|
||||
.highlight .nb { color: #366 } /* Name.Builtin */
|
||||
.highlight .nc { color: #0a8; } /* Name.Class */
|
||||
.highlight .no { color: #360 } /* Name.Constant */
|
||||
.highlight .nd { color: #99f } /* Name.Decorator */
|
||||
.highlight .ni { color: #999; } /* Name.Entity */
|
||||
.highlight .ne { color: #c00; } /* Name.Exception */
|
||||
.highlight .nf { color: #c0f } /* Name.Function */
|
||||
.highlight .nl { color: #99f } /* Name.Label */
|
||||
.highlight .nn { color: #0cf; } /* Name.Namespace */
|
||||
.highlight .nt { color: #2f6f9f; } /* Name.Tag */
|
||||
.highlight .nv { color: #033 } /* Name.Variable */
|
||||
.highlight .ow { color: #000; } /* Operator.Word */
|
||||
.highlight .w { color: #bbb } /* Text.Whitespace */
|
||||
.highlight .mf { color: #f60 } /* Literal.Number.Float */
|
||||
.highlight .mh { color: #f60 } /* Literal.Number.Hex */
|
||||
.highlight .mi { color: #f60 } /* Literal.Number.Integer */
|
||||
.highlight .mo { color: #f60 } /* Literal.Number.Oct */
|
||||
.highlight .sb { color: #c30 } /* Literal.String.Backtick */
|
||||
.highlight .sc { color: #c30 } /* Literal.String.Char */
|
||||
.highlight .sd { color: #c30; font-style: italic } /* Literal.String.Doc */
|
||||
.highlight .s2 { color: #c30 } /* Literal.String.Double */
|
||||
.highlight .se { color: #c30; } /* Literal.String.Escape */
|
||||
.highlight .sh { color: #c30 } /* Literal.String.Heredoc */
|
||||
.highlight .si { color: #a00 } /* Literal.String.Interpol */
|
||||
.highlight .sx { color: #c30 } /* Literal.String.Other */
|
||||
.highlight .sr { color: #3aa } /* Literal.String.Regex */
|
||||
.highlight .s1 { color: #c30 } /* Literal.String.Single */
|
||||
.highlight .ss { color: #fc3 } /* Literal.String.Symbol */
|
||||
.highlight .bp { color: #366 } /* Name.Builtin.Pseudo */
|
||||
.highlight .vc { color: #033 } /* Name.Variable.Class */
|
||||
.highlight .vg { color: #033 } /* Name.Variable.Global */
|
||||
.highlight .vi { color: #033 } /* Name.Variable.Instance */
|
||||
.highlight .il { color: #f60 } /* Literal.Number.Integer.Long */
|
||||
|
||||
.css .o,
|
||||
.css .o + .nt,
|
||||
.css .nt + .nt { color: #999; }
|
38
_config.yml
38
_config.yml
|
@ -1,38 +0,0 @@
|
|||
# Dependencies
|
||||
markdown: kramdown
|
||||
highlighter: pygments
|
||||
|
||||
# Permalinks
|
||||
permalink: /:categories/:title/
|
||||
relative_permalinks: true
|
||||
|
||||
# Setup
|
||||
title: tail call
|
||||
tagline: Ramblings in software development
|
||||
description: The ramblings of a 28-year-old software developer from Germany.
|
||||
url: https://blog.kempkens.io
|
||||
hub_url: https://kempkens.superfeedr.com
|
||||
baseurl: /
|
||||
|
||||
author:
|
||||
name: Daniel Kempkens
|
||||
location: Wassenberg, North Rhine-Westphalia, Germany
|
||||
url: https://kempkens.io
|
||||
email: daniel+blog@kempkens.io
|
||||
twitter: '@nifoc_'
|
||||
|
||||
paginate: 5
|
||||
|
||||
include: [".htaccess"]
|
||||
exclude: ["tmp", "Gemfile", "Gemfile.lock", "Makefile"]
|
||||
|
||||
# Custom
|
||||
assets:
|
||||
gzip: []
|
||||
css_compressor: yui
|
||||
|
||||
disqus_shortname: blog-kempkens-io
|
||||
|
||||
footer:
|
||||
github: nifoc
|
||||
ipv6_check: kempkens.io
|
|
@ -1,36 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<title>{{ site.title | append: include.title }}</title>
|
||||
<link rel="self" href="{{ include.path | prepend: site.url }}" />
|
||||
<link href="{{ site.url }}/" />
|
||||
<link rel="hub" href="{{ site.hub_url }}/" />
|
||||
<updated>{{ site.time | date_to_xmlschema }}</updated>
|
||||
<id>{{ site.url | append: include.id }}</id>
|
||||
<author>
|
||||
<name>{{ site.author.name }}</name>
|
||||
<email>{{ site.author.email }}</email>
|
||||
</author>
|
||||
|
||||
{% for post in include.posts %}
|
||||
<entry>
|
||||
<id>{{ site.url }}{{ post.id }}</id>
|
||||
<title>{% if post.category == "links" %}Link: {% endif %}{{ post.title }}</title>
|
||||
<link href="{{ post.url | prepend: site.url }}" />
|
||||
<published>{{ post.date | date_to_xmlschema }}</published>
|
||||
{% if post.modified != nil %}
|
||||
<updated>{{ post.modified | date_to_xmlschema }}</updated>
|
||||
{% else %}
|
||||
<updated>{{ post.date | date_to_xmlschema }}</updated>
|
||||
{% endif %}
|
||||
{% if post.category == "links" %}
|
||||
<content type="html">
|
||||
{% capture linktext %}<p><strong>Link:</strong> <a href="{{ post.link }}">{{ post.link | hostname }}</a></p>{% endcapture %}
|
||||
{{ linktext | xml_escape }}
|
||||
{{ post.content | xml_escape }}
|
||||
</content>
|
||||
{% else %}
|
||||
<content type="html">{{ post.content | xml_escape }}</content>
|
||||
{% endif %}
|
||||
</entry>
|
||||
{% endfor %}
|
||||
</feed>
|
|
@ -1,13 +0,0 @@
|
|||
<div class="footer">
|
||||
<ul class="footer-links">
|
||||
<li><a href="{{ "feed.xml" | prepend: site.baseurl }}">Feed</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="{{ "feed-with-links.xml" | prepend: site.baseurl }}">Feed (with links)</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="{{ site.footer.github | prepend: "https://github.com/" }}">GitHub</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="{{ site.footer.ipv6_check | prepend: "http://ip6.nl/#!" }}">IPv6</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="https://www.freebsd.org">FreeBSD</a></li>
|
||||
</ul>
|
||||
</div>
|
|
@ -1,51 +0,0 @@
|
|||
<head>
|
||||
<link href="http://gmpg.org/xfn/11" rel="profile">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
|
||||
<!-- Enable responsiveness on mobile devices-->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
|
||||
|
||||
<title>
|
||||
{% if page.title == "Home" %}
|
||||
{{ site.title }} · {{ site.tagline }}
|
||||
{% else %}
|
||||
{{ page.title }} · {{ site.title }}
|
||||
{% endif %}
|
||||
</title>
|
||||
|
||||
<!-- CSS -->
|
||||
{% stylesheet app %}
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=PT+Sans:400,400italic,700|Abril+Fatface">
|
||||
|
||||
<!-- Icons -->
|
||||
<link rel="shortcut icon" href="{{ "favicon.ico" | prepend: site.baseurl }}">
|
||||
<link rel="icon" type="image/png" href="{{ "favicon.png" | prepend: site.baseurl }}" />
|
||||
|
||||
<!-- RSS -->
|
||||
<link rel="alternate" type="application/atom+xml" title="{{ site.title }} Feed" href="{{ "/feed.xml" | prepend: site.url }}">
|
||||
<link rel="alternate" type="application/atom+xml" title="{{ site.title }} Feed (with links)" href="{{ "/feed-with-links.xml" | prepend: site.url }}">
|
||||
|
||||
<!-- humans.txt -->
|
||||
<link rel="author" href="{{ "humans.txt" | prepend: site.baseurl }}">
|
||||
|
||||
{% if page.category == "posts" %}
|
||||
<!-- Twitter -->
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:site" content="@nifoc_">
|
||||
<meta name="twitter:title" content="{{ page.title }}">
|
||||
<meta name="twitter:description" content="{{ page.description }}">
|
||||
<meta name="twitter:url" content="{{ site.url }}{{ page.url }}">
|
||||
|
||||
<!-- Facebook -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="{{ site.title }}">
|
||||
<meta property="og:title" content="{{ page.title }}">
|
||||
<meta property="og:description" content="{{ page.description }}">
|
||||
<meta property="og:url" content="{{ site.url }}{{ page.url }}">
|
||||
|
||||
<!-- Schema.org -->
|
||||
<meta itemprop="name" content="{{ page.title }}">
|
||||
<meta itemprop="description" content="{{ page.description }}">
|
||||
{% endif %}
|
||||
</head>
|
|
@ -1,32 +0,0 @@
|
|||
<div class="sidebar">
|
||||
<div class="container sidebar-sticky">
|
||||
<div class="sidebar-about">
|
||||
<h1>
|
||||
<a href="{{ site.baseurl }}">
|
||||
{{ site.title }}
|
||||
</a>
|
||||
</h1>
|
||||
<p class="lead">{{ site.description }}</p>
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav">
|
||||
<a class="sidebar-nav-item{% if page.url == site.baseurl %} active{% endif %}" href="{{ site.baseurl }}">Home</a>
|
||||
|
||||
{% comment %}
|
||||
The code below dynamically generates a sidebar nav of pages with
|
||||
`layout: page` in the front-matter. See readme for usage.
|
||||
{% endcomment %}
|
||||
|
||||
{% assign pages_list = site.pages %}
|
||||
{% for node in pages_list %}
|
||||
{% if node.title != null %}
|
||||
{% if node.layout == "page" %}
|
||||
<a class="sidebar-nav-item{% if page.url == node.url %} active{% endif %}" href="{{ node.url }}">{{ node.title }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</nav>
|
||||
|
||||
<p>© {{ site.time | date: '%Y' }}. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
|
@ -1,16 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en-us">
|
||||
|
||||
{% include head.html %}
|
||||
|
||||
<body>
|
||||
|
||||
{% include sidebar.html %}
|
||||
|
||||
<div class="content container">
|
||||
{{ content }}
|
||||
|
||||
{% include foot.html %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
<div class="post">
|
||||
<h1 class="post-title">⚓ {{ page.title }}</h1>
|
||||
<span class="post-date">{{ page.date | date_to_string }}</span>
|
||||
|
||||
<p class="post-link"><span>Link:</span> <a href="{{ page.link }}" rel="external">{{ page.link | hostname }}</a></p>
|
||||
|
||||
{{ content }}
|
||||
</div>
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
<div class="page">
|
||||
<h1 class="page-title">{{ page.title }}</h1>
|
||||
{{ content }}
|
||||
</div>
|
|
@ -1,45 +0,0 @@
|
|||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
<div class="post">
|
||||
<h1 class="post-title">{{ page.title }}</h1>
|
||||
<span class="post-date">{{ page.date | date_to_string }}</span>
|
||||
{{ content }}
|
||||
</div>
|
||||
|
||||
<div class="related">
|
||||
<h2>Related Posts</h2>
|
||||
<ul class="related-posts">
|
||||
{% for post in site.related_posts limit:3 %}
|
||||
<li>
|
||||
<h3>
|
||||
<a href="{{ post.url }}">
|
||||
{% if post.category == "links" %}⚓{% endif %}
|
||||
{{ post.title }}
|
||||
<small>{{ post.date | date_to_string }}</small>
|
||||
</a>
|
||||
</h3>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% if false %}
|
||||
<div class="comments">
|
||||
<h2>Comments</h2>
|
||||
<div id="disqus_thread"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
|
||||
var disqus_shortname = '{{ site.disqus_shortname }}';
|
||||
|
||||
/* * * DON'T EDIT BELOW THIS LINE * * */
|
||||
(function() {
|
||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
||||
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
|
||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||
})();
|
||||
</script>
|
||||
{% endif %}
|
|
@ -1,2 +0,0 @@
|
|||
require 'bundler'
|
||||
Bundler.require(:extensions)
|
|
@ -1,12 +0,0 @@
|
|||
require 'uri'
|
||||
|
||||
module Jekyll
|
||||
module HostnameFilter
|
||||
def hostname(input)
|
||||
parsed_uri = URI.parse(input)
|
||||
parsed_uri.host
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Liquid::Template.register_filter(Jekyll::HostnameFilter)
|
|
@ -1,23 +0,0 @@
|
|||
---
|
||||
layout: page
|
||||
title: Post Archive
|
||||
---
|
||||
|
||||
{% for post in site.posts %}
|
||||
{% capture month %}{{ post.date | date: '%m%Y' }}{% endcapture %}
|
||||
{% capture nmonth %}{{ post.next.date | date: '%m%Y' }}{% endcapture %}
|
||||
|
||||
{% if month != nmonth %}
|
||||
{% if forloop.index != 1 %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
<h3>{{ post.date | date: '%B %Y' }}</h3>
|
||||
<ul>
|
||||
{% endif %}
|
||||
|
||||
<li>
|
||||
{% if post.category == "links" %}⚓{% endif %}
|
||||
<a href="{{ post.url }}">{{ post.title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
layout: page
|
||||
title: Tag Archive
|
||||
---
|
||||
|
||||
{% capture site_tags %}{% for tag in site.tags %}{{ tag | first }}{% unless forloop.last %},{% endunless %}{% endfor %}{% endcapture %}
|
||||
{% assign tags_list = site_tags | split:',' | sort %}
|
||||
|
||||
{% for tag in tags_list %}
|
||||
<h2 id="tag-{{ tag }}">{{ tag }}</h2>
|
||||
<ul>
|
||||
{% for post in site.tags[tag] %}
|
||||
{% if post.title != null %}
|
||||
<li>
|
||||
<a href="{{ post.url }}">{{ post.title }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
38
config.toml
Normal file
38
config.toml
Normal file
|
@ -0,0 +1,38 @@
|
|||
baseURL = "https://blog.kempkens.io"
|
||||
languageCode = "en-en"
|
||||
title = "tail call"
|
||||
theme = "terminal"
|
||||
paginate = 5
|
||||
|
||||
[params]
|
||||
contentTypeName = "posts"
|
||||
themeColor = "orange"
|
||||
showMenuItems = 2
|
||||
showLanguageSelector = false
|
||||
fullWidthTheme = false
|
||||
centerTheme = true
|
||||
showLastUpdated = false
|
||||
|
||||
[languages]
|
||||
[languages.en]
|
||||
languageName = "English"
|
||||
title = "tail call"
|
||||
subtitle = "The ramblings of a software developer from Germany"
|
||||
owner = "Daniel Kempkens"
|
||||
keywords = ""
|
||||
copyright = ""
|
||||
menuMore = "Show more"
|
||||
readMore = "Read more"
|
||||
readOtherPosts = "Read other posts"
|
||||
newerPosts = "Newer posts"
|
||||
olderPosts = "Older posts"
|
||||
missingContentMessage = "Page not found..."
|
||||
missingBackButtonLabel = "Back to home page"
|
||||
|
||||
[languages.en.params.logo]
|
||||
logoText = "tail call"
|
||||
logoHomeLink = "/"
|
||||
|
||||
[outputFormats]
|
||||
[outputFormats.RSS]
|
||||
baseName = "feed"
|
|
@ -1,18 +1,19 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2014-02-16T15:30:00Z"
|
||||
description: Description and implementation of a function that joins a list of binaries.
|
||||
tags:
|
||||
- erlang
|
||||
- programming
|
||||
- english
|
||||
slug: joining-a-list-of-binaries-in-erlang
|
||||
title: Joining a List of Binaries in Erlang
|
||||
description: "Description and implementation of a function that joins a list of binaries."
|
||||
date: 2014-02-16 15:30:00 CET
|
||||
category: posts
|
||||
tags: [erlang, programming, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
The binary module in Erlang provides an easy way to split binaries using `split/2,3`, but what if you want to join a list of binaries back together?
|
||||
|
||||
There is no built-in function to do this, so I've decided to write my own.
|
||||
|
||||
{% highlight erlang %}
|
||||
{{< highlight erlang >}}
|
||||
-spec binary_join([binary()], binary()) -> binary().
|
||||
binary_join([], _Sep) ->
|
||||
<<>>;
|
||||
|
@ -20,13 +21,13 @@ binary_join([Part], _Sep) ->
|
|||
Part;
|
||||
binary_join([Head|Tail], Sep) ->
|
||||
lists:foldl(fun (Value, Acc) -> <<Acc/binary, Sep/binary, Value/binary>> end, Head, Tail).
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
It works just like you would expect:
|
||||
|
||||
{% highlight erlang %}
|
||||
{{< highlight erlang >}}
|
||||
binary_join([<<"Hello">>, <<"World">>], <<", ">>) % => <<"Hello, World">>
|
||||
binary_join([<<"Hello">>], <<"...">>) % => <<"Hello">>
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
Hope you find this useful!
|
|
@ -1,24 +1,26 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2014-02-17T21:45:00Z"
|
||||
description: Simple nginx configuration that allows you to proxy most of Microsoft Exchange.
|
||||
tags:
|
||||
- nginx
|
||||
- exchange
|
||||
- ops
|
||||
- english
|
||||
slug: exchange-reverse-proxy-using-nginx
|
||||
title: Exchange Reverse Proxy Using nginx
|
||||
description: "Simple nginx configuration that allows you to proxy most of Microsoft Exchange."
|
||||
date: 2014-02-17 21:45:00 CET
|
||||
category: posts
|
||||
tags: [nginx, exchange, ops, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
As it turns out, setting up [nginx](http://nginx.org) as a reverse proxy for Microsoft Exchange is not as easy as [some](http://blog.friedlandreas.net/2013/07/reverseproxy-fur-eas-exchange-activesync-und-owa-outlookwebapp-mit-nginx/) [posts](http://www.administrator.de/wissen/ngnix-als-reverse-proxy-für-exchange-2010-192711.html) suggest.
|
||||
|
||||
The issue that for some calls (Autodiscovery, RPC, …) IIS asks for an `Authorization` header, which nginx can pass through by doing:
|
||||
|
||||
{% highlight nginx %}
|
||||
{{< highlight nginx >}}
|
||||
proxy_pass_header Authorization;
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
Only problem is: It doesn't work. Thankfully someone on StackOverflow already had a [solution](http://stackoverflow.com/a/19714696) for this:
|
||||
|
||||
{% highlight nginx %}
|
||||
{{< highlight nginx >}}
|
||||
proxy_http_version 1.1;
|
||||
proxy_pass_request_headers on;
|
||||
proxy_pass_header Date;
|
||||
|
@ -31,12 +33,12 @@ more_set_input_headers 'Authorization: $http_authorization';
|
|||
proxy_set_header Accept-Encoding "";
|
||||
more_set_headers -s 401 'WWW-Authenticate: Basic realm="your.mail.host"';
|
||||
proxy_pass https://your.mail.host;
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
You'll need the [HttpHeadersMore](http://wiki.nginx.org/HttpHeadersMoreModule) module for this to work. On Ubuntu 12.04 (using the [nginx/stable PPA](https://launchpad.net/~nginx/+archive/stable)) all you need to install is:
|
||||
|
||||
{% highlight bash %}
|
||||
{{< highlight bash >}}
|
||||
apt-get install nginx-extras
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
And you're good to go!
|
|
@ -1,16 +1,18 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2014-02-24T22:00:00Z"
|
||||
description: Some links regarding Telegram and its security model.
|
||||
tags:
|
||||
- telegram
|
||||
- whatsapp
|
||||
- app
|
||||
- english
|
||||
slug: telegram-and-security
|
||||
title: Telegram and Security
|
||||
description: "Some links regarding Telegram and its security model."
|
||||
date: 2014-02-24 22:00:00 CET
|
||||
category: posts
|
||||
tags: [telegram, whatsapp, app, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
Ever since [Facebook bought WhatsApp](http://techcrunch.com/2014/02/19/facebook-buying-whatsapp-for-16b-in-cash-and-stock-plus-3b-in-rsus/) more and more of the people I know switch to [Telegram](https://telegram.org). One of the main reasons they choose Telegram is because it's "secure" and Telegram itself seems really keen on being seen as a secure, privacy-focused WhatsApp alternative.
|
||||
|
||||
People that are way smarter than I am when it comes to cryptography have a sligtly different opinion on the "secure, privacy-focused" part …
|
||||
People that are way smarter than I am when it comes to cryptography have a slightly different opinion on the "secure, privacy-focused" part …
|
||||
|
||||
- [Telegram, AKA "Stand back, we have Math PhDs!"](http://unhandledexpression.com/2013/12/17/telegram-stand-back-we-know-maths/)
|
||||
- [A Crypto Challenge For The Telegram Developers](http://thoughtcrime.org/blog/telegram-crypto-challenge/)
|
|
@ -1,18 +1,19 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2014-03-23T20:00:00Z"
|
||||
description: Blow up a polyline to search inside the generated polygon.
|
||||
tags:
|
||||
- javascript
|
||||
- programming
|
||||
- english
|
||||
slug: buffered-polyline
|
||||
title: Buffered Polyline
|
||||
description: "Blow up a polyline to search inside the generated polygon."
|
||||
date: 2014-03-23 20:00:00 CET
|
||||
category: posts
|
||||
tags: [javascript, programming, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
At work, we needed a simple way to buffer a polyline in order to search for stuff along the route from A to B. I'll explain how we used Google's Maps API and [JSTS](https://github.com/bjornharrtell/jsts) in order to achieve this easily.
|
||||
|
||||
The first thing we had to do was to "transform" each element in the `overview_path` (which the `DirectionsService` returns) to GeoJSON, because that's what JSTS understands.
|
||||
|
||||
{% highlight javascript linenos %}
|
||||
{{< highlight javascript "linenos=table" >}}
|
||||
var overviewPath = response.routes[0].overview_path,
|
||||
overviewPathGeo = [];
|
||||
for(var i = 0; i < overviewPath.length; i++) {
|
||||
|
@ -20,11 +21,11 @@ for(var i = 0; i < overviewPath.length; i++) {
|
|||
[overviewPath[i].lng(), overviewPath[i].lat()]
|
||||
);
|
||||
}
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
The next step was getting `overviewPathGeo` into JSTS and letting it do the work of buffering the line.
|
||||
|
||||
{% highlight javascript linenos %}
|
||||
{{< highlight javascript "linenos=table" >}}
|
||||
var distance = 10/111.12, // Roughly 10km
|
||||
geoInput = {
|
||||
type: "LineString",
|
||||
|
@ -34,7 +35,7 @@ var geoReader = new jsts.io.GeoJSONReader(),
|
|||
geoWriter = new jsts.io.GeoJSONWriter();
|
||||
var geometry = geoReader.read(geoInput).buffer(distance);
|
||||
var polygon = geoWriter.write(geometry);
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
The `polygon` variable now contains a polygon that neatly fits around the `overviewPath`, with a *distance* (buffer size) of roughly 10km.
|
||||
|
||||
|
@ -42,4 +43,4 @@ Since it is nested, you need to call `polygon.coordinates[0]` in order to get ba
|
|||
|
||||
You could then use the the coordinates to draw the generated polygon on the map (along with the route), in order to produce something like this:
|
||||
|
||||
{% image buffered-polyline-1.png %}
|
||||
![Example image of a buffered polyline](/posts/buffered-polyline-1.png)
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2014-03-26T13:55:00Z"
|
||||
description: Collection of some interesting DEF CON videos.
|
||||
tags:
|
||||
- defcon
|
||||
- videos
|
||||
- english
|
||||
slug: some-defcon-videos
|
||||
title: Some DEF CON Videos
|
||||
description: "Collection of some interesting DEF CON videos."
|
||||
date: 2014-03-26 13:55:00 CET
|
||||
category: posts
|
||||
tags: [defcon, videos, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
Over the weekend I watched some [DEF CON](https://www.defcon.org) videos on [YouTube](https://www.youtube.com/user/DEFCONConference/videos) and thought I should share some of the interesting ones on here. The two talks on Bitsquatting (by Stucke and Schultz) are especially entertaining and scary.
|
|
@ -1,12 +1,15 @@
|
|||
---
|
||||
layout: post
|
||||
title: OCSP Stapling with nginx
|
||||
description: "A general explanation of how to set up OCSP stapling with nginx."
|
||||
date: 2014-03-30 21:30:00 CEST
|
||||
date: "2014-03-30T21:30:00Z"
|
||||
description: A general explanation of how to set up OCSP stapling with nginx.
|
||||
modified: 2015-08-03 20:55:00 CEST
|
||||
category: posts
|
||||
tags: [nginx, ocsp, ssl, ops, english]
|
||||
comments: true
|
||||
tags:
|
||||
- nginx
|
||||
- ocsp
|
||||
- ssl
|
||||
- ops
|
||||
- english
|
||||
slug: ocsp-stapling-with-nginx
|
||||
title: OCSP Stapling with nginx
|
||||
---
|
||||
|
||||
Setting up [OCSP stapling](https://en.wikipedia.org/wiki/OCSP_stapling) with [nginx](http://nginx.org/) is more or less straightforward, but depending on what's in your `ssl_certificate` you might run into some issues with it silently failing. So I've decided to write about how I set up OCSP stapling with certificates from [StartSSL](https://www.startssl.com/) and [CAcert](http://www.cacert.org/).
|
||||
|
@ -15,14 +18,14 @@ I have only tested this using nginx version 1.5.12, but the configuration option
|
|||
|
||||
To enable OCSP stapling, you simply have to add the following lines to your (already SSL enabled) site:
|
||||
|
||||
{% highlight nginx %}
|
||||
{{< highlight nginx >}}
|
||||
resolver 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 valid=300s;
|
||||
resolver_timeout 10s;
|
||||
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
ssl_trusted_certificate /etc/nginx/certs/startssl.stapling.crt;
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
The important thing here is the usage of `ssl_trusted_certificate`. The [nginx documentation](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_stapling_verify) states that:
|
||||
|
||||
|
@ -34,25 +37,25 @@ You have to include the root certificate (and intermediate certificates) for OCS
|
|||
|
||||
For CAcert (and unless you have a Class 3 certificate) you only have to include the Class 1 certificate in your stapling file.
|
||||
|
||||
{% highlight text %}
|
||||
{{< highlight text >}}
|
||||
03/08/2015 Removed. Get the Class 1 certificate here: http://www.cacert.org/index.php?id=3
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
## StartSSL
|
||||
|
||||
StartSSL - using a Class 1 certificate again - has an intermediate certificate in their chain, so you have to include this one in your stapling file, too.
|
||||
|
||||
{% highlight text %}
|
||||
{{< highlight text >}}
|
||||
03/08/2015: Removed. Get the root certificate and the intermediate certificate here: https://www.startssl.com/certs/
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
After you've done all that, you can restart nginx or reload the configuration and you should be good to go!
|
||||
|
||||
You can verify that everything works using the `openssl` command line tool.
|
||||
|
||||
{% highlight bash %}
|
||||
{{< highlight bash >}}
|
||||
openssl s_client -servername blog.kempkens.io -connect blog.kempkens.io:443 -tls1 -tlsextdebug -status
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
Both of those should include a section (with data) named "OCSP Response Data".
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2014-04-06T20:15:00Z"
|
||||
description: Property-based testing in Erlang, with some basic usage examples.
|
||||
tags:
|
||||
- erlang
|
||||
- quickcheck
|
||||
- testing
|
||||
- programming
|
||||
- english
|
||||
slug: property-based-testing-with-proper
|
||||
title: Property-based Testing with PropEr
|
||||
description: "Property-based testing in Erlang, with some basic usage examples."
|
||||
date: 2014-04-06 20:15:00 CEST
|
||||
category: posts
|
||||
tags: [erlang, quickcheck, testing, programming, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
[PropEr](http://proper.softlab.ntua.gr/) is a [QuickCheck](https://en.wikipedia.org/wiki/QuickCheck)-inspired property-based testing tool for Erlang. In contrast to traditional testing methodologies, the tester only has to provide the generic structure of valid inputs and some properties, which specify the relation between input and output. The testing tool will then produce progressively more complex valid inputs and compare the results it gets to what it expected (based on the defined properties).
|
||||
|
@ -13,28 +16,28 @@ PropEr is one such testing tool for Erlang. It is [open-source](https://github.c
|
|||
|
||||
Assuming you already have your `$ERL_LIBS` set up, you can simply run the following commands to install PropEr and make it available *globally*.
|
||||
|
||||
{% highlight bash linenos %}
|
||||
{{< highlight bash "linenos=table" >}}
|
||||
cd $ERL_LIBS
|
||||
git clone git://github.com/manopapad/proper.git
|
||||
cd proper
|
||||
make fast
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
After that, you can use PropEr in *all* your Erlang projects.
|
||||
|
||||
I like using [EUnit](http://www.erlang.org/doc/apps/eunit/chapter.html) as the runner for my property based tests. There are [some caveats](https://github.com/manopapad/proper#using-proper-in-conjunction-with-eunit), but all in all it works without any issues.
|
||||
What I don't like is defining my property-based tests in the same module as my unit tests, because it feels wrong to do so. I generally define one `_test_` function that calls `proper:module/2`.
|
||||
|
||||
{% highlight erlang linenos %}
|
||||
{{< highlight erlang "linenos=table" >}}
|
||||
proper_module_test_() ->
|
||||
{timeout, 180, ?_assertEqual([], proper:module(example_utils_prop, [long_result, {to_file, user}]))}.
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
This allows me to have all of the unit tests in `example_utils_test` and all of the property-based tests in `example_utils_prop`.
|
||||
|
||||
Let's write a simple property-based test for the `binary_join` function I've [introduced in February]({{ site.url }}/posts/joining-a-list-of-binaries-in-erlang/).
|
||||
|
||||
{% highlight erlang linenos %}
|
||||
{{< highlight erlang "linenos=table" >}}
|
||||
prop_binary_join() ->
|
||||
?FORALL({Bs, S}, {list(binary()), binary()}, begin
|
||||
ExpectedLength = if
|
||||
|
@ -44,7 +47,7 @@ prop_binary_join() ->
|
|||
end,
|
||||
ExpectedLength =:= byte_size(example_utils:binary_join(Bs, S))
|
||||
end).
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
This will test if the size of the output of `example_utils:binary_join/2` is what we would expect:
|
||||
|
||||
|
@ -60,11 +63,11 @@ The `?FORALL` macro takes three aguments:
|
|||
|
||||
If you actually run the test, the output will look something like this:
|
||||
|
||||
{% highlight text %}
|
||||
{{< highlight text >}}
|
||||
Testing example_utils_prop:prop_binary_join/0
|
||||
....................................................................................................
|
||||
OK: Passed 100 test(s).
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
By default, PropEr will generate 100 random valid inputs and compare the output to the (length) properties we defined above.
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2014-04-12T21:25:00Z"
|
||||
description: Short description of how to install Erlang/OTP 17.0 using kerl on Mac OS X.
|
||||
tags:
|
||||
- erlang
|
||||
- programming
|
||||
- english
|
||||
slug: installing-erlang-17-0-using-kerl
|
||||
title: Installing Erlang 17.0 On Mac OS X
|
||||
description: "Short description of how to install Erlang/OTP 17.0 using kerl on Mac OS X."
|
||||
date: 2014-04-12 21:25:00 CEST
|
||||
category: posts
|
||||
tags: [erlang, programming, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
It's been a few days since [Erlang/OTP 17.0](http://www.erlang.org/news/73) has been released. Installing 64 Bit Erlang (with [Observer](http://www.erlang.org/doc/man/observer.html) support) on Mac OS X has always been a bit tricky, but with 17.0 it has gotten significantly easier.
|
||||
|
@ -18,36 +19,36 @@ First you need to install/get some prerequisites:
|
|||
|
||||
After you've gotten these three, we start by installing *wxWidgets*. It's required in order to use the Observer GUI.
|
||||
|
||||
{% highlight bash %}
|
||||
{{< highlight bash >}}
|
||||
brew install wxmac
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
Compiling *wxWidgets* might take some time. After it's done, you should create a `~/.kerlrc` file. It's basically a configuration file for *kerl*, which will be used for every Erlang version you compile. You can find the list of available options in the [*kerl* readme](https://github.com/spawngrid/kerl#tuning). Mine looks like this:
|
||||
|
||||
{% highlight bash linenos %}
|
||||
{{< highlight bash "linenos=table" >}}
|
||||
CPPFLAGS="-march=native -mtune=native -O3 -g"
|
||||
KERL_CONFIGURE_OPTIONS="--disable-debug --without-javac --enable-shared-zlib --enable-dynamic-ssl-lib --enable-smp-support --enable-threads --enable-hipe --enable-kernel-poll --enable-darwin-64bit --with-wx"
|
||||
KERL_DEFAULT_INSTALL_DIR="$KERL_BASE_DIR/installs"
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
We can now move on to actually installing Erlang/OTP 17.0.
|
||||
|
||||
{% highlight bash %}
|
||||
{{< highlight bash >}}
|
||||
kerl update releases
|
||||
kerl build 17.0 17.0
|
||||
kerl install 17.0 17.0
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
After the installation is finished, *kerl* will output instructions on how to enable a specific Erlang version globally. In general, you will put something like the following in your `~/.zshrc` or `~/.bash_profile`:
|
||||
|
||||
{% highlight bash %}
|
||||
{{< highlight bash >}}
|
||||
source $HOME/.kerl/installs/17.0/activate
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
The following `alias` makes it easier to start the Observer from a terminal. The only command you have to remember is `erlobserver`.
|
||||
|
||||
{% highlight bash %}
|
||||
{{< highlight bash >}}
|
||||
alias erlobserver='erl -sname observer -run observer -detached'
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
{% image installing-erlang-17-0-using-kerl-1.png %}
|
||||
![Image of a running Observer instance](/posts/installing-erlang-17-0-using-kerl-1.png)
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2014-04-18T20:25:00Z"
|
||||
description: Simple workaround for supporting deprecated types and warnings_as_errors.
|
||||
tags:
|
||||
- erlang
|
||||
- programming
|
||||
- english
|
||||
slug: erlang-17-0-supporting-deprecated-types-without-removing-warnings_as_errors
|
||||
title: 'Erlang 17.0: Supporting Deprecated Types Without Removing warnings_as_errors'
|
||||
description: "Simple workaround for supporting deprecated types and warnings_as_errors."
|
||||
date: 2014-04-18 20:25:00 CEST
|
||||
category: posts
|
||||
tags: [erlang, programming, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
Erlang 17.0 [deprecated some pre-defined types](http://www.erlang.org/download/otp_src_17.0.readme) like `dict()` and `gb_tree()` in favor of `dict:dict()` and `gb_tree:tree()`. The workaround they suggest (`nowarn_deprecated_type`) works in 17.0, but would break once the deprecated types are removed.
|
||||
|
@ -25,22 +26,22 @@ A rather nice solution to this issue an option that [rebar](https://github.com/r
|
|||
|
||||
This allows us to set a `namespaced_types` option on 17.0+ only.
|
||||
|
||||
{% highlight erlang %}
|
||||
{{< highlight erlang >}}
|
||||
{erl_opts, [
|
||||
{platform_define, "^[0-9]+", namespaced_types},
|
||||
debug_info,
|
||||
warnings_as_errors
|
||||
]}.
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
In your source files you can then check if the option is set and define an (internal) type accordingly.
|
||||
|
||||
{% highlight erlang linenos %}
|
||||
{{< highlight erlang "linenos=table" >}}
|
||||
-ifdef(namespaced_types).
|
||||
-type xxx_dict() :: dict:dict().
|
||||
-else.
|
||||
-type xxx_dict() :: dict().
|
||||
-endif.
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
I learned about this trick by looking at how [meck](https://github.com/eproxus/meck) handles Erlang 17.0 support.
|
|
@ -1,11 +1,14 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2014-05-04T21:55:00Z"
|
||||
description: Introductory post about the Riemann client I've written.
|
||||
tags:
|
||||
- erlang
|
||||
- programming
|
||||
- riemann
|
||||
- katja
|
||||
- english
|
||||
slug: katja-riemann-client-written-in-erlang
|
||||
title: 'Katja: Riemann Client Written In Erlang'
|
||||
description: "Introductory post about the Riemann client I've written."
|
||||
date: 2014-05-04 21:55:00 CEST
|
||||
category: posts
|
||||
tags: [erlang, programming, riemann, katja, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
[Riemann](http://riemann.io) is a network monitoring system written in Clojure, it offers a rather simple [protobuf](https://de.wikipedia.org/wiki/Protocol_Buffers)-based API. I have just tagged [Katja](https://github.com/nifoc/katja) [version 0.1](https://github.com/nifoc/katja/tree/v0.1), my Riemann client written in Erlang.
|
||||
|
@ -22,12 +25,12 @@ Katja only supports Erlang/OTP R16B01+. This is mostly because in releases befor
|
|||
|
||||
## Sending Events
|
||||
|
||||
{% highlight erlang linenos %}
|
||||
{{< highlight erlang "linenos=table" >}}
|
||||
Event = [{service, "katja demo"}, {metric, 9000.1}],
|
||||
ok = katja:send_event(Event),
|
||||
Event2 = [{service, <<"katja demo">>}, {metric, 9000.1}, {tags, ["demo"]}],
|
||||
ok = katja:send_events([Event, Event2]).
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
Katja allows you to send either a single event or multiple ones. Events are simple property lists with the following (possible) keys: time, state, service, host, description, tags, ttl, attributes, metric.
|
||||
|
||||
|
@ -35,12 +38,12 @@ The entire `katja:event()` type definition can be found on [GitHub](https://gith
|
|||
|
||||
## Sending States
|
||||
|
||||
{% highlight erlang linenos %}
|
||||
{{< highlight erlang "linenos=table" >}}
|
||||
State = [{service, "katja demo"}, {state, "testing"}],
|
||||
ok = katja:send_state(State),
|
||||
State2 = [{service, "katja demo"}, {state, "testing"}, {tags, ["demo"]}],
|
||||
ok = katja:send_states([State, State2]).
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
States and events are very similar, so much so that the (possible) keys of a state property list are almost identical to the keys of an event property list: time, state, service, host, description, tags, ttl, once.
|
||||
|
||||
|
@ -48,9 +51,9 @@ Once again, the entire `katja:state()` type definition can be found on [GitHub](
|
|||
|
||||
## Querying Events
|
||||
|
||||
{% highlight erlang linenos %}
|
||||
{{< highlight erlang "linenos=table" >}}
|
||||
{ok, Events} = katja:query("service = \"katja demo\"").
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
`katja:query/1` will return a list of events. Events are a property list of type `katja:event()`, so what you send to Riemann is also what you get back when querying. There is one important thing to keep in mind: All `undefined` or `[]` values will be removed from the returned property list(s).
|
||||
|
||||
|
@ -58,11 +61,11 @@ You can find example queries in the [Riemann test suite](https://github.com/aphy
|
|||
|
||||
## Sending Entities
|
||||
|
||||
{% highlight erlang linenos %}
|
||||
{{< highlight erlang "linenos=table" >}}
|
||||
Event = [{service, "katja demo"}, {metric, 9000.1}],
|
||||
State = [{service, "katja demo"}, {state, "testing"}],
|
||||
ok = katja:send_entities([{events, [Event]}, {states, [State]}]).
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
Katja also allows you to send mutiple events and/or states in a single request via `katja:send_entities/1`.
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2014-12-07T22:59:00Z"
|
||||
description: Example GitLab CI setup that can run tests for Erlang projects.
|
||||
tags:
|
||||
- erlang
|
||||
- testing
|
||||
- programming
|
||||
- gitlabci
|
||||
- english
|
||||
slug: gitlab-ci-for-erlang-projects
|
||||
title: GitLab CI for Erlang Projects
|
||||
description: "Example GitLab CI setup that can run tests for Erlang projects."
|
||||
date: 2014-12-07 22:59:00 CET
|
||||
category: posts
|
||||
tags: [erlang, testing, programming, gitlabci, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
[GitLab CI](https://about.gitlab.com/gitlab-ci/) is GitLab's continuous integration software. It integrates with [GitLab](https://about.gitlab.com) and runs your tests every time a commit is pushed to the remote repository. Getting it to run tests for projects written in Erlang can be a bit of hassle, so in this post I will share and explain my setup.
|
||||
|
@ -16,7 +19,7 @@ The CI runner (v5.0.0) is installed on an Ubuntu 14.04 machine and it talks to G
|
|||
|
||||
The build script that is used to run Erlang tests looks like this:
|
||||
|
||||
{% highlight bash %}
|
||||
{{< highlight bash >}}
|
||||
# Setup
|
||||
source "$HOME/.kerl/installs/17.3/activate"
|
||||
gitlabdir=$(basename "$(pwd)")
|
||||
|
@ -39,7 +42,7 @@ ls -rt $(find ./logs -name "cover.html") | tail -n 1 | xargs cat | grep -F 'Tota
|
|||
cd ..
|
||||
mv "$appdir" "$gitlabdir"
|
||||
cd "$gitlabdir"
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
**Setup**
|
||||
|
||||
|
@ -59,9 +62,9 @@ My projects use [erlang.mk](https://github.com/ninenines/erlang.mk), which is wh
|
|||
|
||||
The test coverage is extracted from the latest `cover.html` file. It will be printed to *stdout* like this:
|
||||
|
||||
{% highlight text %}
|
||||
{{< highlight text >}}
|
||||
Total97 %742
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
Since we're only interest in the `97`, we can set the "Test coverage parsing" option to this regular expression: `Total(\d+)\s\%`.
|
||||
|
|
@ -1,28 +1,29 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2014-12-22T19:45:00Z"
|
||||
description: Choosing a small number of newer ciphers prevents SSH bots from connecting.
|
||||
tags:
|
||||
- ssh
|
||||
- ops
|
||||
- english
|
||||
slug: ssh-bots-do-not-know-about-my-ciphers
|
||||
title: SSH Bots Don't Know about My Ciphers
|
||||
description: "Choosing a small number of newer ciphers prevents SSH bots from connecting."
|
||||
date: 2014-12-22 19:45:00 CET
|
||||
category: posts
|
||||
tags: [ssh, ops, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
Last weekend I decided to update my `sshd_config` to include a very limited set of ciphers, MACs and key exchange algorithms. I did this to tighten the security of my `sshd` and not because I wanted to prevent bots from trying (and failing) to log in to my servers. I'm already using [fail2ban](http://www.fail2ban.org) for that.
|
||||
However, after I updated my configuration I noticed failed login attempts basically dropped to zero, because all these bots do not support my very restrictive set of ciphers.
|
||||
|
||||
{% highlight text %}
|
||||
{{< highlight text >}}
|
||||
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
|
||||
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
|
||||
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
In order to use these settings, you need a recent version of [OpenSSH](http://www.openssh.com). I'm running 6.6 locally and on my servers, the minimum version that supports these settings is 6.4.
|
||||
|
||||
After these changes your `auth.log` will probably contain this line rather often:
|
||||
|
||||
{% highlight text %}
|
||||
{{< highlight text >}}
|
||||
fatal: no matching cipher found: client aes128-ctr,aes192-ctr,aes256-ctr,aes256-cbc,rijndael-cbc@lysator.liu.se,aes192-cbc,aes128-cbc,blowfish-cbc,arcfour128,arcfour,cast128-cbc,3des-cbc server chacha20-poly1305@openssh.com,aes256-gcm@openssh.com [preauth]
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
Please keep in mind that this will not prevent bots from attacking you (in the future) and that you have to mitigate these attacks by other means. I only wrote this post because I thought it was kind of interesting that SSH bots do not support these settings *right now*.
|
|
@ -1,39 +1,40 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2014-12-24T13:25:00Z"
|
||||
description: Simple workaround for supporting deprecated types and warnings_as_errors with erlang.mk.
|
||||
tags:
|
||||
- erlang
|
||||
- programming
|
||||
- english
|
||||
slug: supporting-deprecated-types-with-erlang-mk
|
||||
title: Supporting Deprecated Types with erlang.mk
|
||||
description: "Simple workaround for supporting deprecated types and warnings_as_errors with erlang.mk."
|
||||
date: 2014-12-24 13:25:00 CET
|
||||
category: posts
|
||||
tags: [erlang, programming, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
In April I wrote about how I use the `platform_define` feature of [rebar](https://github.com/rebar/rebar) to make deprecated types work without removing `warnings_as_errors`. I have switched to [erlang.mk](https://github.com/ninenines/erlang.mk) since then, but needed a similar feature for [one of my libraries](https://github.com/nifoc/noesis).
|
||||
|
||||
Since erlang.mk only uses [make](http://en.wikipedia.org/wiki/Make_(software)), adding support for a `platform_define`-like feature is very straightforward.
|
||||
|
||||
{% highlight makefile %}
|
||||
{{< highlight makefile >}}
|
||||
otp_release = $(shell erl -noshell -eval 'io:format("~s", [erlang:system_info(otp_release)]), init:stop()')
|
||||
otp_17plus = $(shell echo $(otp_release) | grep -q -E "^[[:digit:]]+$$" ; echo $$?)
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
The first variable (`otp_release`) will contain the OTP version (e.g. `17`). The second variable (`otp_17plus`) will be either `0` or `1`, depending on wether or not `otp_release` matches a regular expression. The regular expression checks if `otp_release` is just a number (e.g. `17`) or not (e.g. `R16B03-1`).
|
||||
|
||||
That's enough to conditionally add options to `erlc`.
|
||||
|
||||
{% highlight makefile %}
|
||||
{{< highlight makefile >}}
|
||||
ifeq ($(otp_17plus),0)
|
||||
ERLC_OPTS += -Dnamespaced_types=1
|
||||
TEST_ERLC_OPTS += -Dnamespaced_types=1
|
||||
endif
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
This will define `namespaced_types` only on Erlang 17+, allowing us to use the same `ifdef`-switch from April.
|
||||
|
||||
{% highlight erlang linenos %}
|
||||
{{< highlight erlang "linenos=table" >}}
|
||||
-ifdef(namespaced_types).
|
||||
-type xxx_dict() :: dict:dict().
|
||||
-else.
|
||||
-type xxx_dict() :: dict().
|
||||
-endif.
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
|
@ -1,11 +1,14 @@
|
|||
---
|
||||
layout: link
|
||||
date: "2014-12-31T16:33:00Z"
|
||||
description: 'Link: [media.ccc.de](http://media.ccc.de/browse/congress/2014/31c3_-_6369_-_en_-_saal_1_-_201412272145_-_ecchacks_-_djb_-_tanja_lange.html#video)'
|
||||
tags:
|
||||
- links
|
||||
url: links/a-gentle-introduction-to-elliptic-curve-cryptography
|
||||
title: A Gentle Introduction to Elliptic-Curve Cryptography
|
||||
date: 2014-12-31 16:33:00 CET
|
||||
category: links
|
||||
link: http://media.ccc.de/browse/congress/2014/31c3_-_6369_-_en_-_saal_1_-_201412272145_-_ecchacks_-_djb_-_tanja_lange.html#video
|
||||
---
|
||||
|
||||
Link: [media.ccc.de](http://media.ccc.de/browse/congress/2014/31c3_-_6369_-_en_-_saal_1_-_201412272145_-_ecchacks_-_djb_-_tanja_lange.html#video)
|
||||
|
||||
A talk by djb and Tanja Lange.
|
||||
|
||||
> This talk will explain how to work with elliptic curves constructively to obtain secure and efficient implementations, and will highlight pitfalls that must be avoided when implementing elliptic-curve crypto (ECC). The talk will also explain what all the buzz in curve choices for TLS is about. This talk does not require any prior exposure to ECC.
|
|
@ -1,11 +1,14 @@
|
|||
---
|
||||
layout: link
|
||||
date: "2015-01-05T17:39:00Z"
|
||||
description: 'Link: [www.marco.org](http://www.marco.org/2015/01/04/apple-lost-functional-high-ground)'
|
||||
tags:
|
||||
- links
|
||||
url: links/apple-has-lost-the-functional-high-ground
|
||||
title: Apple Has Lost the Functional High Ground
|
||||
date: 2015-01-05 17:39:00 CET
|
||||
category: links
|
||||
link: http://www.marco.org/2015/01/04/apple-lost-functional-high-ground
|
||||
---
|
||||
|
||||
Link: [www.marco.org](http://www.marco.org/2015/01/04/apple-lost-functional-high-ground)
|
||||
|
||||
Marco Arment's view on the rapid decline in Apple's software quality.
|
||||
|
||||
> I fear that Apple’s leadership doesn’t realize quite how badly and deeply their software flaws have damaged their reputation, because if they realized it, they’d make serious changes that don’t appear to be happening. Instead, the opposite appears to be happening: the pace of rapid updates on multiple product lines seems to be expanding and accelerating.
|
|
@ -1,11 +1,13 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2015-02-01T20:59:00Z"
|
||||
description: Explanation of how to use spiped to encrypt HTTP traffic to backend systems.
|
||||
tags:
|
||||
- spiped
|
||||
- nginx
|
||||
- ops
|
||||
- english
|
||||
slug: securing-http-traffic-with-spiped
|
||||
title: Securing HTTP Traffic with spiped
|
||||
description: "Explanation of how to use spiped to encrypt HTTP traffic to backend systems."
|
||||
date: 2015-02-01 20:59:00 CET
|
||||
category: posts
|
||||
tags: [spiped, nginx, ops, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
[spiped](http://www.tarsnap.com/spiped.html) - the secure pipe daemon - is a utility for creating symmetrically encrypted and authenticated pipes between socket addresses. I recently used it to encrypt HTTP traffic from my main webserver to a Raspberry Pi that I run at home.
|
||||
|
@ -16,25 +18,25 @@ I'm using [nginx](http://nginx.org) on the main webserver and the Raspberry Pi,
|
|||
|
||||
After installing spiped, the first thing you have to do is to create a (private) key. I ran the following command on my webserver:
|
||||
|
||||
{% highlight bash %}
|
||||
{{< highlight bash >}}
|
||||
dd if=/dev/urandom bs=32 count=1 of=/usr/local/etc/nginx/certs/spiped.key
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
After that, the key has to be securely copied to the backend machine. You can - for example - do this using `scp`. I copied it to `/etc/nginx/certs/spiped.key`, but your paths may vary.
|
||||
|
||||
That's it. You can now start spiped.
|
||||
|
||||
{% highlight bash %}
|
||||
{{< highlight bash >}}
|
||||
spiped -D -e -s [127.0.0.1]:9080 -t rpi.kempkens.io:9080 -k /usr/local/etc/nginx/certs/spiped.key
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
That command tells spiped to listen on `127.0.0.1:9080`, encrypt the incoming data and send it to `rpi.kempkens.io:9080`.
|
||||
|
||||
To set up the receiving end of the pipe, you have to run something like this:
|
||||
|
||||
{% highlight bash %}
|
||||
{{< highlight bash >}}
|
||||
spiped -D -d -s [0.0.0.0]:9080 -t [127.0.0.1]:80 -k /etc/nginx/certs/spiped.key
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
spiped will listen for incoming connections on port 9080, decrypt the data it receives and forward it to `127.0.0.1:80`.
|
||||
|
||||
|
@ -42,11 +44,11 @@ And that's it.
|
|||
|
||||
On the main webserver I have defined an `upstream` that forwards traffic to `127.0.0.1:9080`.
|
||||
|
||||
{% highlight nginx %}
|
||||
{{< highlight nginx >}}
|
||||
upstream rpi {
|
||||
server 127.0.0.1:9080;
|
||||
}
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
The nginx installation on the Raspberry Pi listens on port 80, so there is nothing special you have to set up there. It will simply receive the decrypted HTTP traffic from spiped. The only thing that you have to keep in mind is that the server name (`Host`-header) has to be the same on the main webserver and the Raspberry Pi.
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2015-03-12T22:03:00Z"
|
||||
description: Description and implementation of functions that encode and decode polylines.
|
||||
tags:
|
||||
- erlang
|
||||
- programming
|
||||
- english
|
||||
slug: encoding-and-decoding-polylines-with-erlang
|
||||
title: Encoding and Decoding Polylines with Erlang
|
||||
description: "Description and implementation of functions that encode and decode polylines."
|
||||
date: 2015-03-12 22:03:00 CET
|
||||
category: posts
|
||||
tags: [erlang, programming, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
If you have ever worked with the [Google Directions API](https://developers.google.com/maps/documentation/directions/?csw=1) you probably came across [encoded polylines](https://developers.google.com/maps/documentation/utilities/polylinealgorithm). I wanted to decode and encode these using Erlang but was unable to find an existing implementation. So I decided to write my own.
|
||||
|
@ -14,14 +15,14 @@ If you have ever worked with the [Google Directions API](https://developers.goog
|
|||
* A path, i.e. a decoded polyline, is represented as a list of point tuples
|
||||
* An encoded polyline is represented as a simple binary string
|
||||
|
||||
{% highlight erlang %}
|
||||
{{< highlight erlang >}}
|
||||
Point = {Lng, Lat},
|
||||
Path = [{Lng, Lat}, {Lng2, Lat2}].
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
The `encode/1` function takes a path and returns an encoded polyline.
|
||||
|
||||
{% highlight erlang linenos %}
|
||||
{{< highlight erlang "linenos=table" >}}
|
||||
encode(Path) -> encode_acc(Path, 0, 0, <<>>).
|
||||
|
||||
% Private
|
||||
|
@ -41,11 +42,11 @@ encode_part(Num, Result) when Num < 32 -> <<Result/binary, (Num + 63)>>;
|
|||
encode_part(Num, Result) ->
|
||||
Value = (32 bor (Num band 31)) + 63,
|
||||
encode_part(Num bsr 5, <<Result/binary, Value>>).
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
The `decode/1` function takes an encoded polyline and returns a path.
|
||||
|
||||
{% highlight erlang linenos %}
|
||||
{{< highlight erlang "linenos=table" >}}
|
||||
decode(Line) -> decode_acc(Line, 0, 0, []).
|
||||
|
||||
% Private
|
||||
|
@ -68,7 +69,7 @@ decode_part(<<C:8, Rest/binary>>, _OldB, Shift, Result) ->
|
|||
B = C - 63,
|
||||
Result2 = Result bor ((B band 31) bsl Shift),
|
||||
decode_part(Rest, B, Shift + 5, Result2).
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
I have written these functions for [noesis](https://github.com/nifoc/noesis), which is a library that contains useful utility functions. Right now the implementation is only available in the [development branch](https://github.com/nifoc/noesis/blob/development/src/noesis_polyline.erl). It is tested using [EUnit](https://github.com/nifoc/noesis/blob/f3e9ae21d53e09bea9ca48fe4a56ddd006952e0a/test/noesis_polyline_test.erl) and [QuickCheck](https://github.com/nifoc/noesis/blob/f3e9ae21d53e09bea9ca48fe4a56ddd006952e0a/test/noesis_polyline_triq.erl).
|
||||
|
|
@ -1,18 +1,19 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2015-07-12T18:46:00Z"
|
||||
description: Introducing my port of the pcsensor utility to FreeBSD.
|
||||
tags:
|
||||
- pcsensor
|
||||
- freebsd
|
||||
- english
|
||||
slug: porting-pcsensor-to-freebsd
|
||||
title: Porting pcsensor to FreeBSD
|
||||
description: "Introducing my port of the pcsensor utility to FreeBSD."
|
||||
date: 2015-07-12 18:46:00 CEST
|
||||
category: posts
|
||||
tags: [pcsensor, freebsd, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
Last week, it got rather hot where I live and so I got interested in measuring the temperature of the room where I keep my NAS and various other devices. I started looking for cheap USB thermometers and quickly found [this one](http://www.amazon.de/gp/product/B009RETJIO). It has some decent reviews and costs only around 16€, which seemed perfect to simply play around with.
|
||||
|
||||
The device only comes bundled with Windows software, but there is an open source utility called `pcsensor` which allows you to use it via the command line on Linux. I don't have any Linux devices in the room that I wanted to measure. Since the source code was pretty straightforward and only minimal changes were required to port the utility to FreeBSD, I did just that! You can find the ported source code on [GitHub](https://github.com/nifoc/pcsensor-freebsd).
|
||||
|
||||
{% highlight text %}
|
||||
{{< highlight text >}}
|
||||
$ pcsensor -h
|
||||
pcsensor version 1.0.3
|
||||
Aviable options:
|
||||
|
@ -26,6 +27,6 @@ pcsensor version 1.0.3
|
|||
-d output with Bus and Device number
|
||||
-D display device list
|
||||
-D[n] specific device number
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
If you want to read the temperature from the device, you might have to prefix the call to `pcsensor` with `sudo`.
|
|
@ -1,20 +1,21 @@
|
|||
---
|
||||
layout: post
|
||||
date: "2016-01-31T17:46:00Z"
|
||||
description: Description of how to easily anonymize IPs using HAProxy.
|
||||
tags:
|
||||
- haproxy
|
||||
- ops
|
||||
- english
|
||||
slug: anonymizing-ips-using-haproxy
|
||||
title: Anonymizing IPs Using HAProxy
|
||||
description: "Description of how to easily anonymize IPs using HAProxy."
|
||||
date: 2016-01-31 17:46:00 CET
|
||||
category: posts
|
||||
tags: [haproxy, ops, english]
|
||||
comments: true
|
||||
---
|
||||
|
||||
At work, I had to come up with an easy way to anonymize the last octet of a logged IP address in order to comply with German data protection laws. If you're using [HAProxy](http://www.haproxy.org) (1.5+), you can do this in one line.
|
||||
|
||||
If you want to forward the source IP address to a backend server, you would usually use `option forwardfor`. Sadly you can't set or change the forwarded IP using that option, so instead you have to set the `X-Forwarded-For` header manually.
|
||||
|
||||
{% highlight text %}
|
||||
{{< highlight text >}}
|
||||
http-request set-header X-Forwarded-For %[src,ipmask(24)]
|
||||
{% endhighlight %}
|
||||
{{< / highlight >}}
|
||||
|
||||
This will set the last octet of the source IP address to zero.
|
||||
|
BIN
favicon.ico
BIN
favicon.ico
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
BIN
favicon.png
BIN
favicon.png
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
layout: null
|
||||
---
|
||||
{% include feed.xml id="/feed-with-links.xml" path="/feed-with-links.xml" title=" (with links)" posts=site.posts %}
|
4
feed.xml
4
feed.xml
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
layout: null
|
||||
---
|
||||
{% include feed.xml path="/feed.xml" posts=site.categories.posts %}
|
12
humans.txt
12
humans.txt
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
layout: null
|
||||
---
|
||||
/* TEAM */
|
||||
Author: {{ site.author.name }}
|
||||
Contact: {{ site.author.email }}
|
||||
Twitter: {{ site.author.twitter }}
|
||||
From: {{ site.author.location }}
|
||||
|
||||
/* SITE */
|
||||
Last update: {{ site.time | date: '%Y/%m/%d' }}
|
||||
Software: Jekyll, MacVim
|
30
impressum.md
30
impressum.md
|
@ -1,30 +0,0 @@
|
|||
---
|
||||
layout: page
|
||||
permalink: /impressum/
|
||||
title: Impressum
|
||||
---
|
||||
|
||||
Daniel Kempkens
|
||||
Kugelsberger Weg 6
|
||||
41849 Wassenberg
|
||||
|
||||
Email: {{ site.author.email }}
|
||||
|
||||
## Domains
|
||||
|
||||
* [blog.kempkens.io](https://blog.kempkens.io)
|
||||
* [daniel.xxx](https://daniel.xxx)
|
||||
|
||||
## Security
|
||||
|
||||
### HTTP
|
||||
|
||||
This blog makes use of [HSTS](http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security), [strong ciphers](https://www.ssllabs.com/ssltest/analyze.html?d={{ site.url | hostname }}&hideResults=on) and various other security-related technologies.
|
||||
|
||||
_German law demands the following statements, too._
|
||||
|
||||
## Datenschutzerklärung
|
||||
|
||||
Die Nutzung unserer Webseite ist in der Regel ohne Angabe personenbezogener Daten möglich. Soweit auf unseren Seiten personenbezogene Daten (beispielsweise Name, Anschrift oder eMail-Adressen) erhoben werden, erfolgt dies, soweit möglich, stets auf freiwilliger Basis.
|
||||
|
||||
Der Nutzung von im Rahmen der Impressumspflicht veröffentlichten Kontaktdaten durch Dritte zur Übersendung von nicht ausdrücklich angeforderter Werbung und Informationsmaterialien wird hiermit ausdrücklich widersprochen. Die Betreiber der Seiten behalten sich ausdrücklich rechtliche Schritte im Falle der unverlangten Zusendung von Werbeinformationen, etwa durch Spam-Mails, vor.
|
47
index.html
47
index.html
|
@ -1,47 +0,0 @@
|
|||
---
|
||||
layout: default
|
||||
title: Home
|
||||
---
|
||||
|
||||
<div class="posts">
|
||||
{% for post in paginator.posts %}
|
||||
<div class="post">
|
||||
<h1 class="post-title">
|
||||
{% if post.category == "links" %}
|
||||
⚓ <a href="{{ post.link }}" rel="external">{{ post.title }}</a>
|
||||
{% else %}
|
||||
<a href="{{ post.url }}">{{ post.title }}</a>
|
||||
{% endif %}
|
||||
</h1>
|
||||
|
||||
<span class="post-date">
|
||||
{{ post.date | date_to_string }}
|
||||
·
|
||||
<a href="{{ post.url }}" title="Permalink">∞</a>
|
||||
</span>
|
||||
|
||||
{% if post.category == "links" %}
|
||||
{{ post.content }}
|
||||
{% else %}
|
||||
{{ post.excerpt }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="pagination">
|
||||
{% if paginator.next_page %}
|
||||
<a class="pagination-item older" href="{{ site.baseurl }}page{{paginator.next_page}}">Older</a>
|
||||
{% else %}
|
||||
<span class="pagination-item older">Older</span>
|
||||
{% endif %}
|
||||
{% if paginator.previous_page %}
|
||||
{% if paginator.page == 2 %}
|
||||
<a class="pagination-item newer" href="{{ site.baseurl }}">Newer</a>
|
||||
{% else %}
|
||||
<a class="pagination-item newer" href="{{ site.baseurl }}page{{paginator.previous_page}}">Newer</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="pagination-item newer">Newer</span>
|
||||
{% endif %}
|
||||
</div>
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
layout: null
|
||||
---
|
||||
User-agent: *
|
||||
Allow: /
|
||||
Sitemap: {{ "/sitemap.xml" | prepend: site.url }}
|
29
sitemap.xml
29
sitemap.xml
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
layout: null
|
||||
---
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>{{ site.url }}</loc>
|
||||
<lastmod>{{ site.time | date_to_xmlschema }}</lastmod>
|
||||
</url>
|
||||
|
||||
{% for page in site.pages %}
|
||||
{% if page.title != null and page.url != '/404.html' %}
|
||||
<url>
|
||||
<loc>{{ site.url }}{{ page.url }}</loc>
|
||||
</url>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% for post in site.posts %}
|
||||
<url>
|
||||
<loc>{{ site.url }}{{ post.url }}</loc>
|
||||
{% if post.modified != nil %}
|
||||
<lastmod>{{ post.modified | date_to_xmlschema }}</lastmod>
|
||||
{% else %}
|
||||
<lastmod>{{ post.date | date_to_xmlschema }}</lastmod>
|
||||
{% endif %}
|
||||
</url>
|
||||
{% endfor %}
|
||||
</urlset>
|
Before Width: | Height: | Size: 228 KiB After Width: | Height: | Size: 228 KiB |
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
1
themes/terminal
Submodule
1
themes/terminal
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit cd36a63fd00bbc2f155ac950a945f81131ae3531
|
Loading…
Reference in a new issue