d2f29ce2904b645c09bb931aeeee75ab5568965a — Stefan Tatschner a month ago 2a0829d
Nuke jekyll shit
116 files changed, 1393 insertions(+), 3356 deletions(-)

M .build.yml
D .bundle/config
M .gitignore
D Gemfile
D Gemfile.lock
D _config.yml
D _includes/footer.html
D _includes/head.html
D _includes/header.html
D _layouts/default.html
D _layouts/home.html
D _layouts/page.html
D _layouts/post.html
D _layouts/specs.html
D _layouts/stuff.html
D _posts/2015-10-26-awesome-stuff-1.adoc
D _posts/2015-11-16-awesome-stuff-2.adoc
D _posts/2015-12-29-awesome-stuff-3.adoc
D _posts/2016-08-08-btrfs-xfs-zfs.adoc
D _posts/2016-08-11-awesome-stuff-4.adoc
D _posts/2016-10-26-how-to-disable-zoom-mode-in-gtk-applications.adoc
D _posts/2016-10-26-strace-on-freebsd.adoc
D _posts/2017-02-25-base64-encoder.adoc
D _sass/_base.scss
D _sass/_layout.scss
D _specs/footer.adoc
D _specs/netzteil-http.7.adoc
D _specs/penlog.7.adoc
D _stuff/bookmarks.adoc
D _stuff/list2adoc
D _stuff/networking.adoc
D _stuff/networking.adoc.tpl
A archetypes/default.md
D assets/css/asciidoc-pygments.css
D assets/css/asciidoctor-default.css
D assets/css/main.scss
D assets/favicon/android-icon-144x144.png
D assets/favicon/android-icon-192x192.png
D assets/favicon/android-icon-36x36.png
D assets/favicon/android-icon-48x48.png
D assets/favicon/android-icon-72x72.png
D assets/favicon/apple-icon-114x114.png
D assets/favicon/apple-icon-120x120.png
D assets/favicon/apple-icon-144x144.png
D assets/favicon/apple-icon-152x152.png
D assets/favicon/apple-icon-180x180.png
D assets/favicon/apple-icon-57x57.png
D assets/favicon/apple-icon-60x60.png
D assets/favicon/apple-icon-72x72.png
D assets/favicon/apple-icon-76x76.png
D assets/favicon/apple-icon-precomposed.png
D assets/favicon/apple-icon.png
D assets/favicon/browserconfig.xml
D assets/favicon/favicon-96x96.png
D assets/favicon/manifest.json
D assets/favicon/ms-icon-144x144.png
D assets/favicon/ms-icon-150x150.png
D assets/favicon/ms-icon-310x310.png
D assets/favicon/ms-icon-70x70.png
D assets/img/Screenshot-2016-05-15-15:54:18.png
A assets/main.scss
A config.toml
R specs.adoc => content/_index.html
R _posts/{2014-09-22-how-to-download-rtmp-streams.adoc => /blog/2014-09-22-how-to-download-rtmp-streams.md}
R _posts/{2014-09-23-generating-pdfs-with-django-and-latex.adoc => /blog/2014-09-23-generating-pdfs-with-django-and-latex.md}
R _posts/{2014-11-15-cron-jobs-with-systemd-timer.adoc => /blog/2014-11-15-cron-jobs-with-systemd-timer.md}
R _posts/{2016-05-16-poor-mans-dyndns.adoc => /blog/2016-05-16-poor-mans-dyndns.md}
R _posts/{2016-05-16-useful-git-aliases.adoc => /blog/2016-05-16-useful-git-aliases.md}
R _posts/{2016-06-22-sudo-doas.adoc => /blog/2016-06-22-sudo-doas.md}
R _posts/{2016-07-14-vpn-leaks-ipv6.adoc => /blog/2016-07-14-vpn-leaks-ipv6.md}
R _posts/{2016-08-03-use-ssh-blacklists.adoc => /blog/2016-08-03-use-ssh-blacklists.md}
R _posts/{2016-08-03-use-virtualenv-in-fish.adoc => /blog/2016-08-03-use-virtualenv-in-fish.md}
R _posts/{2016-08-04-poor-mans-dyndns-take-2.adoc => /blog/2016-08-04-poor-mans-dyndns-take-2.md}
A content/blog/2016-08-08-btrfs-xfs-zfs.md
R _posts/{2016-08-22-fix-new-tab-with-fish-shell.adoc => /blog/2016-08-22-fix-new-tab-with-fish-shell.md}
R _posts/{2016-08-24-how-to-kill-a-certain-process-depending-on-mobile-networks.adoc => /blog/2016-08-24-how-to-kill-a-certain-process-depending-on-mobile-networks.md}
R _posts/{2016-10-26-freebsd-and-blacklists-in-go-or-take-two.adoc => /blog/2016-10-26-freebsd-and-blacklists-in-go-or-take-two.md}
A content/blog/2016-10-26-how-to-disable-zoom-mode-in-gtk-applications.md
A content/blog/2016-10-26-strace-on-freebsd.md
R _posts/{2017-02-06-factorial.adoc => /blog/2017-02-06-factorial.md}
R _posts/{2017-02-10-prime-factors.adoc => /blog/2017-02-10-prime-factors.md}
R _posts/{2017-02-15-get-mac.adoc => /blog/2017-02-15-get-mac.md}
A content/blog/2017-02-25-base64-encoder.md
R _posts/{2017-03-01-base64-decoder.adoc => /blog/2017-03-01-base64-decoder.md}
R _posts/{2017-03-07-fix-first-weekday-with-cal-in-debian.adoc => /blog/2017-03-07-fix-first-weekday-with-cal-in-debian.md}
R _posts/{2017-03-17-redirect-git-ssh-traffic-through-socks.adoc => /blog/2017-03-17-redirect-git-ssh-traffic-through-socks.md}
R _posts/{2017-08-01-clean-trailing-whitespace-with-sed.adoc => /blog/2017-08-01-clean-trailing-whitespace-with-sed.md}
A content/blog/2019-11-14-status-report-11-19.md
R _posts/{2020-01-23-announcing-myip.adoc => /blog/2020-01-23-announcing-myip.md}
R _posts/{2020-03-10-announcing-dns-query.adoc => /blog/2020-03-10-announcing-dns-query.md}
R _posts/{2020-03-18-low-latency-webcam-streaming.adoc => /blog/2020-03-18-low-latency-webcam-streaming.md}
R _posts/{2020-03-20-static-binaries-for-common-tools.adoc => /blog/2020-03-20-static-binaries-for-common-tools.md}
R _posts/{2020-06-08-risc-v-experiments.adoc => /blog/2020-06-08-risc-v-experiments.md}
R contact.adoc => content/contact.md
R impressum.adoc => content/impressum.md
R stuff.adoc => content/man.md
A content/stuff.md
A content/stuff/bookmarks.md
A content/stuff/networking.md
D index.md
A layouts/_default/single.html
A layouts/blog/single.html
A layouts/index.html
A layouts/partials/footer.html
A layouts/partials/head.html
A layouts/partials/header.html
D manage.sh
A resources/_gen/assets/scss/main.scss_48b060fe05b0a273d182ef83c0605941.content
A resources/_gen/assets/scss/main.scss_48b060fe05b0a273d182ef83c0605941.json
R assets/{2014-09-22-n24-source.txt => 2014-09-22-n24-source.txt}
R assets/favicon/{favicon-16x16.png => 16x16.png}
R assets/favicon/{favicon-32x32.png => 32x32.png}
R assets/favicon/{android-icon-96x96.png => 96x96.png}
R assets/favicon/{favicon.ico => ico}
M .build.yml => .build.yml +3 -5
@@ 1,9 1,8 @@
image: archlinux
  - asciidoctor
  - hugo
  - rsync
  - openssh
  - ruby-bundler
  - 0d06436c-bc8f-4f65-af13-cad62d4f1127

@@ 13,9 12,8 @@ tasks:

  - build: |
      cd homepage
      bundle install
      ./manage.sh build

  - deploy: |
      cd homepage
      ./manage.sh deploy
      rsync -e "ssh -o VerifyHostKeyDNS=yes -o StrictHostKeyChecking=accept-new" -rP --delete "public/" deploy@batuu.sevenbyte.org:rumpelsepp.org/

D .bundle/config => .bundle/config +0 -3
@@ 1,3 0,0 @@
BUNDLE_PATH: "vendor/bundle"

M .gitignore => .gitignore +2 -5
@@ 1,5 1,2 @@

D Gemfile => Gemfile +0 -30
@@ 1,30 0,0 @@
source "https://rubygems.org"

# Hello! This is where you manage which Jekyll version is used to run.
# When you want to use a different version, change it below, save the
# file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
#     bundle exec jekyll serve
# This will help ensure the proper Jekyll version is running.
# Happy Jekylling!
gem "jekyll", "~> 4.1"

# This is the default theme for new Jekyll sites. You may change this to anything you like.
# gem "minima", "~> 2.0"

# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
# uncomment the line below. To upgrade, run `bundle update github-pages`.
# gem "github-pages", group: :jekyll_plugins

# If you have any plugins, put them here!
group :jekyll_plugins do
  gem "jekyll-feed"
  gem "jekyll-asciidoc"

# Fancy tools that make life easier.
group :tools do
  gem "html-proofer"

D Gemfile.lock => Gemfile.lock +0 -99
@@ 1,99 0,0 @@
  remote: https://rubygems.org/
    addressable (2.7.0)
      public_suffix (>= 2.0.2, < 5.0)
    asciidoctor (2.0.10)
    colorator (1.1.0)
    concurrent-ruby (1.1.6)
    em-websocket (0.5.1)
      eventmachine (>= 0.12.9)
      http_parser.rb (~> 0.6.0)
    ethon (0.12.0)
      ffi (>= 1.3.0)
    eventmachine (1.2.7)
    ffi (1.13.1)
    forwardable-extended (2.6.0)
    html-proofer (3.15.3)
      addressable (~> 2.3)
      mercenary (~> 0.3)
      nokogumbo (~> 2.0)
      parallel (~> 1.3)
      rainbow (~> 3.0)
      typhoeus (~> 1.3)
      yell (~> 2.0)
    http_parser.rb (0.6.0)
    i18n (1.8.3)
      concurrent-ruby (~> 1.0)
    jekyll (4.1.1)
      addressable (~> 2.4)
      colorator (~> 1.0)
      em-websocket (~> 0.5)
      i18n (~> 1.0)
      jekyll-sass-converter (~> 2.0)
      jekyll-watch (~> 2.0)
      kramdown (~> 2.1)
      kramdown-parser-gfm (~> 1.0)
      liquid (~> 4.0)
      mercenary (~> 0.4.0)
      pathutil (~> 0.9)
      rouge (~> 3.0)
      safe_yaml (~> 1.0)
      terminal-table (~> 1.8)
    jekyll-asciidoc (3.0.0)
      asciidoctor (>= 1.5.0)
      jekyll (>= 3.0.0)
    jekyll-feed (0.15.0)
      jekyll (>= 3.7, < 5.0)
    jekyll-sass-converter (2.1.0)
      sassc (> 2.0.1, < 3.0)
    jekyll-watch (2.2.1)
      listen (~> 3.0)
    kramdown (2.3.0)
    kramdown-parser-gfm (1.1.0)
      kramdown (~> 2.0)
    liquid (4.0.3)
    listen (3.2.1)
      rb-fsevent (~> 0.10, >= 0.10.3)
      rb-inotify (~> 0.9, >= 0.9.10)
    mercenary (0.4.0)
    mini_portile2 (2.4.0)
    nokogiri (1.10.10)
      mini_portile2 (~> 2.4.0)
    nokogumbo (2.0.2)
      nokogiri (~> 1.8, >= 1.8.4)
    parallel (1.19.2)
    pathutil (0.16.2)
      forwardable-extended (~> 2.6)
    public_suffix (4.0.5)
    rainbow (3.0.0)
    rb-fsevent (0.10.4)
    rb-inotify (0.10.1)
      ffi (~> 1.0)
    rexml (3.2.4)
    rouge (3.21.0)
    safe_yaml (1.0.5)
    sassc (2.4.0)
      ffi (~> 1.9)
    terminal-table (1.8.0)
      unicode-display_width (~> 1.1, >= 1.1.1)
    typhoeus (1.4.0)
      ethon (>= 0.9.0)
    unicode-display_width (1.7.0)
    yell (2.2.2)


  jekyll (~> 4.1)

   ruby 2.7.1p83


M LICENSE => LICENSE +229 -404
@@ 1,404 1,229 @@
Attribution-NonCommercial-NoDerivatives 4.0 International


Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.

Using Creative Commons Public Licenses

Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.

     Considerations for licensors: Our public licenses are
     intended for use by those authorized to give the public
     permission to use material in ways otherwise restricted by
     copyright and certain other rights. Our licenses are
     irrevocable. Licensors should read and understand the terms
     and conditions of the license they choose before applying it.
     Licensors should also secure all rights necessary before
     applying our licenses so that the public can reuse the
     material as expected. Licensors should clearly mark any
     material not subject to the license. This includes other CC-
     licensed material, or material used under an exception or
     limitation to copyright. More considerations for licensors:

     Considerations for the public: By using one of our public
     licenses, a licensor grants the public permission to use the
     licensed material under specified terms and conditions. If
     the licensor's permission is not necessary for any reason--for
     example, because of any applicable exception or limitation to
     copyright--then that use is not regulated by the license. Our
     licenses grant only permissions under copyright and certain
     other rights that a licensor has authority to grant. Use of
     the licensed material may still be restricted for other
     reasons, including because others have copyright or other
     rights in the material. A licensor may make special requests,
     such as asking that all changes be marked or described.
     Although not required by our licenses, you are encouraged to
     respect those requests where reasonable. More considerations
     for the public:


Creative Commons Attribution-NonCommercial-NoDerivatives 4.0
International Public License

By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-NonCommercial-NoDerivatives 4.0 International Public
License ("Public License"). To the extent this Public License may be
interpreted as a contract, You are granted the Licensed Rights in
consideration of Your acceptance of these terms and conditions, and the
Licensor grants You such rights in consideration of benefits the
Licensor receives from making the Licensed Material available under
these terms and conditions.

Section 1 -- Definitions.

  a. Adapted Material means material subject to Copyright and Similar
     Rights that is derived from or based upon the Licensed Material
     and in which the Licensed Material is translated, altered,
     arranged, transformed, or otherwise modified in a manner requiring
     permission under the Copyright and Similar Rights held by the
     Licensor. For purposes of this Public License, where the Licensed
     Material is a musical work, performance, or sound recording,
     Adapted Material is always produced where the Licensed Material is
     synched in timed relation with a moving image.

  b. Copyright and Similar Rights means copyright and/or similar rights
     closely related to copyright including, without limitation,
     performance, broadcast, sound recording, and Sui Generis Database
     Rights, without regard to how the rights are labeled or
     categorized. For purposes of this Public License, the rights
     specified in Section 2(b)(1)-(2) are not Copyright and Similar

  c. Effective Technological Measures means those measures that, in the
     absence of proper authority, may not be circumvented under laws
     fulfilling obligations under Article 11 of the WIPO Copyright
     Treaty adopted on December 20, 1996, and/or similar international

  d. Exceptions and Limitations means fair use, fair dealing, and/or
     any other exception or limitation to Copyright and Similar Rights
     that applies to Your use of the Licensed Material.

  e. Licensed Material means the artistic or literary work, database,
     or other material to which the Licensor applied this Public

  f. Licensed Rights means the rights granted to You subject to the
     terms and conditions of this Public License, which are limited to
     all Copyright and Similar Rights that apply to Your use of the
     Licensed Material and that the Licensor has authority to license.

  g. Licensor means the individual(s) or entity(ies) granting rights
     under this Public License.

  h. NonCommercial means not primarily intended for or directed towards
     commercial advantage or monetary compensation. For purposes of
     this Public License, the exchange of the Licensed Material for
     other material subject to Copyright and Similar Rights by digital
     file-sharing or similar means is NonCommercial provided there is
     no payment of monetary compensation in connection with the

  i. Share means to provide material to the public by any means or
     process that requires permission under the Licensed Rights, such
     as reproduction, public display, public performance, distribution,
     dissemination, communication, or importation, and to make material
     available to the public including in ways that members of the
     public may access the material from a place and at a time
     individually chosen by them.

  j. Sui Generis Database Rights means rights other than copyright
     resulting from Directive 96/9/EC of the European Parliament and of
     the Council of 11 March 1996 on the legal protection of databases,
     as amended and/or succeeded, as well as other essentially
     equivalent rights anywhere in the world.

  k. You means the individual or entity exercising the Licensed Rights
     under this Public License. Your has a corresponding meaning.

Section 2 -- Scope.

  a. License grant.

       1. Subject to the terms and conditions of this Public License,
          the Licensor hereby grants You a worldwide, royalty-free,
          non-sublicensable, non-exclusive, irrevocable license to
          exercise the Licensed Rights in the Licensed Material to:

            a. reproduce and Share the Licensed Material, in whole or
               in part, for NonCommercial purposes only; and

            b. produce and reproduce, but not Share, Adapted Material
               for NonCommercial purposes only.

       2. Exceptions and Limitations. For the avoidance of doubt, where
          Exceptions and Limitations apply to Your use, this Public
          License does not apply, and You do not need to comply with
          its terms and conditions.

       3. Term. The term of this Public License is specified in Section

       4. Media and formats; technical modifications allowed. The
          Licensor authorizes You to exercise the Licensed Rights in
          all media and formats whether now known or hereafter created,
          and to make technical modifications necessary to do so. The
          Licensor waives and/or agrees not to assert any right or
          authority to forbid You from making technical modifications
          necessary to exercise the Licensed Rights, including
          technical modifications necessary to circumvent Effective
          Technological Measures. For purposes of this Public License,
          simply making modifications authorized by this Section 2(a)
          (4) never produces Adapted Material.

       5. Downstream recipients.

            a. Offer from the Licensor -- Licensed Material. Every
               recipient of the Licensed Material automatically
               receives an offer from the Licensor to exercise the
               Licensed Rights under the terms and conditions of this
               Public License.

            b. No downstream restrictions. You may not offer or impose
               any additional or different terms or conditions on, or
               apply any Effective Technological Measures to, the
               Licensed Material if doing so restricts exercise of the
               Licensed Rights by any recipient of the Licensed

       6. No endorsement. Nothing in this Public License constitutes or
          may be construed as permission to assert or imply that You
          are, or that Your use of the Licensed Material is, connected
          with, or sponsored, endorsed, or granted official status by,
          the Licensor or others designated to receive attribution as
          provided in Section 3(a)(1)(A)(i).

  b. Other rights.

       1. Moral rights, such as the right of integrity, are not
          licensed under this Public License, nor are publicity,
          privacy, and/or other similar personality rights; however, to
          the extent possible, the Licensor waives and/or agrees not to
          assert any such rights held by the Licensor to the limited
          extent necessary to allow You to exercise the Licensed
          Rights, but not otherwise.

       2. Patent and trademark rights are not licensed under this
          Public License.

       3. To the extent possible, the Licensor waives any right to
          collect royalties from You for the exercise of the Licensed
          Rights, whether directly or through a collecting society
          under any voluntary or waivable statutory or compulsory
          licensing scheme. In all other cases the Licensor expressly
          reserves any right to collect such royalties, including when
          the Licensed Material is used other than for NonCommercial

Section 3 -- License Conditions.

Your exercise of the Licensed Rights is expressly made subject to the
following conditions.

  a. Attribution.

       1. If You Share the Licensed Material, You must:

            a. retain the following if it is supplied by the Licensor
               with the Licensed Material:

                 i. identification of the creator(s) of the Licensed
                    Material and any others designated to receive
                    attribution, in any reasonable manner requested by
                    the Licensor (including by pseudonym if

                ii. a copyright notice;

               iii. a notice that refers to this Public License;

                iv. a notice that refers to the disclaimer of

                 v. a URI or hyperlink to the Licensed Material to the
                    extent reasonably practicable;

            b. indicate if You modified the Licensed Material and
               retain an indication of any previous modifications; and

            c. indicate the Licensed Material is licensed under this
               Public License, and include the text of, or the URI or
               hyperlink to, this Public License.

          For the avoidance of doubt, You do not have permission under
          this Public License to Share Adapted Material.

       2. You may satisfy the conditions in Section 3(a)(1) in any
          reasonable manner based on the medium, means, and context in
          which You Share the Licensed Material. For example, it may be
          reasonable to satisfy the conditions by providing a URI or
          hyperlink to a resource that includes the required

       3. If requested by the Licensor, You must remove any of the
          information required by Section 3(a)(1)(A) to the extent
          reasonably practicable.

Section 4 -- Sui Generis Database Rights.

Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:

  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
     to extract, reuse, reproduce, and Share all or a substantial
     portion of the contents of the database for NonCommercial purposes
     only and provided You do not Share Adapted Material;

  b. if You include all or a substantial portion of the database
     contents in a database in which You have Sui Generis Database
     Rights, then the database in which You have Sui Generis Database
     Rights (but not its individual contents) is Adapted Material; and

  c. You must comply with the conditions in Section 3(a) if You Share
     all or a substantial portion of the contents of the database.

For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.

Section 5 -- Disclaimer of Warranties and Limitation of Liability.



  c. The disclaimer of warranties and limitation of liability provided
     above shall be interpreted in a manner that, to the extent
     possible, most closely approximates an absolute disclaimer and
     waiver of all liability.

Section 6 -- Term and Termination.

  a. This Public License applies for the term of the Copyright and
     Similar Rights licensed here. However, if You fail to comply with
     this Public License, then Your rights under this Public License
     terminate automatically.

  b. Where Your right to use the Licensed Material has terminated under
     Section 6(a), it reinstates:

       1. automatically as of the date the violation is cured, provided
          it is cured within 30 days of Your discovery of the
          violation; or

       2. upon express reinstatement by the Licensor.

     For the avoidance of doubt, this Section 6(b) does not affect any
     right the Licensor may have to seek remedies for Your violations
     of this Public License.

  c. For the avoidance of doubt, the Licensor may also offer the
     Licensed Material under separate terms or conditions or stop
     distributing the Licensed Material at any time; however, doing so
     will not terminate this Public License.

  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public

Section 7 -- Other Terms and Conditions.

  a. The Licensor shall not be bound by any additional or different
     terms or conditions communicated by You unless expressly agreed.

  b. Any arrangements, understandings, or agreements regarding the
     Licensed Material not stated herein are separate from and
     independent of the terms and conditions of this Public License.

Section 8 -- Interpretation.

  a. For the avoidance of doubt, this Public License does not, and
     shall not be interpreted to, reduce, limit, restrict, or impose
     conditions on any use of the Licensed Material that could lawfully
     be made without permission under this Public License.

  b. To the extent possible, if any provision of this Public License is
     deemed unenforceable, it shall be automatically reformed to the
     minimum extent necessary to make it enforceable. If the provision
     cannot be reformed, it shall be severed from this Public License
     without affecting the enforceability of the remaining terms and

  c. No term or condition of this Public License will be waived and no
     failure to comply consented to unless expressly agreed to by the

  d. Nothing in this Public License constitutes or may be interpreted
     as a limitation upon, or waiver of, any privileges and immunities
     that apply to the Licensor or You, including from the legal
     processes of any jurisdiction or authority.


Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.

Creative Commons may be contacted at creativecommons.org.

The code that powers this blog uses the following license:

    Copyright (c) 2015 Stefan Tatschner

    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 articles themselves are CC-BY-SA:



    1. Definitions

        "Collective Work" means a work, such as a periodical issue, anthology
        or encyclopedia, in which the Work in its entirety in unmodified form,
        along with a number of other contributions, constituting separate and
        independent works in themselves, are assembled into a collective whole.
        A work that constitutes a Collective Work will not be considered a
        Derivative Work (as defined below) for the purposes of this License.
        "Derivative Work" means a work based upon the Work or upon the Work and
        other pre-existing works, such as a translation, musical arrangement,
        dramatization, fictionalization, motion picture version, sound
        recording, art reproduction, abridgment, condensation, or any other
        form in which the Work may be recast, transformed, or adapted, except
        that a work that constitutes a Collective Work will not be considered a
        Derivative Work for the purpose of this License. For the avoidance of
        doubt, where the Work is a musical composition or sound recording, the
        synchronization of the Work in timed-relation with a moving image
        ("synching") will be considered a Derivative Work for the purpose of
        this License.  "Licensor" means the individual or entity that offers
        the Work under the terms of this License.  "Original Author" means the
        individual or entity who created the Work.  "Work" means the
        copyrightable work of authorship offered under the terms of this
        License.  "You" means an individual or entity exercising rights under
        this License who has not previously violated the terms of this License
        with respect to the Work, or who has received express permission from
        the Licensor to exercise rights under this License despite a previous
        violation.  "License Elements" means the following high-level license
        attributes as selected by Licensor and indicated in the title of this
        License: Attribution, ShareAlike.

    2. Fair Use Rights. Nothing in this license is intended to reduce, limit,
    or restrict any rights arising from fair use, first sale or other
    limitations on the exclusive rights of the copyright owner under copyright
    law or other applicable laws.

    3. License Grant. Subject to the terms and conditions of this License,
    Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
    perpetual (for the duration of the applicable copyright) license to
    exercise the rights in the Work as stated below:

        to reproduce the Work, to incorporate the Work into one or more
        Collective Works, and to reproduce the Work as incorporated in the
        Collective Works; to create and reproduce Derivative Works; to
        distribute copies or phonorecords of, display publicly, perform
        publicly, and perform publicly by means of a digital audio transmission
        the Work including as incorporated in Collective Works; to distribute
        copies or phonorecords of, display publicly, perform publicly, and
        perform publicly by means of a digital audio transmission Derivative

        For the avoidance of doubt, where the work is a musical composition:
        Performance Royalties Under Blanket Licenses. Licensor waives the
        exclusive right to collect, whether individually or via a performance
        rights society (e.g. ASCAP, BMI, SESAC), royalties for the public
        performance or public digital performance (e.g. webcast) of the Work.
        Mechanical Rights and Statutory Royalties. Licensor waives the
        exclusive right to collect, whether individually or via a music rights
        society or designated agent (e.g. Harry Fox Agency), royalties for any
        phonorecord You create from the Work ("cover version") and distribute,
        subject to the compulsory license created by 17 USC Section 115 of the
        US Copyright Act (or the equivalent in other jurisdictions).
        Webcasting Rights and Statutory Royalties. For the avoidance of doubt,
        where the Work is a sound recording, Licensor waives the exclusive
        right to collect, whether individually or via a performance-rights
        society (e.g. SoundExchange), royalties for the public digital
        performance (e.g. webcast) of the Work, subject to the compulsory
        license created by 17 USC Section 114 of the US Copyright Act (or the
        equivalent in other jurisdictions).

    The above rights may be exercised in all media and formats whether now
    known or hereafter devised. The above rights include the right to make such
    modifications as are technically necessary to exercise the rights in other
    media and formats. All rights not expressly granted by Licensor are hereby

    4. Restrictions.The license granted in Section 3 above is expressly made
    subject to and limited by the following restrictions:

        You may distribute, publicly display, publicly perform, or publicly
        digitally perform the Work only under the terms of this License, and
        You must include a copy of, or the Uniform Resource Identifier for,
        this License with every copy or phonorecord of the Work You distribute,
        publicly display, publicly perform, or publicly digitally perform. You
        may not offer or impose any terms on the Work that alter or restrict
        the terms of this License or the recipients' exercise of the rights
        granted hereunder. You may not sublicense the Work. You must keep
        intact all notices that refer to this License and to the disclaimer of
        warranties. You may not distribute, publicly display, publicly perform,
        or publicly digitally perform the Work with any technological measures
        that control access or use of the Work in a manner inconsistent with
        the terms of this License Agreement. The above applies to the Work as
        incorporated in a Collective Work, but this does not require the
        Collective Work apart from the Work itself to be made subject to the
        terms of this License. If You create a Collective Work, upon notice
        from any Licensor You must, to the extent practicable, remove from the
        Collective Work any reference to such Licensor or the Original Author,
        as requested. If You create a Derivative Work, upon notice from any
        Licensor You must, to the extent practicable, remove from the
        Derivative Work any reference to such Licensor or the Original Author,
        as requested.  You may distribute, publicly display, publicly perform,
        or publicly digitally perform a Derivative Work only under the terms of
        this License, a later version of this License with the same License
        Elements as this License, or a Creative Commons iCommons license that
        contains the same License Elements as this License (e.g.
        Attribution-ShareAlike 2.0 Japan). You must include a copy of, or the
        Uniform Resource Identifier for, this License or other license
        specified in the previous sentence with every copy or phonorecord of
        each Derivative Work You distribute, publicly display, publicly
        perform, or publicly digitally perform. You may not offer or impose any
        terms on the Derivative Works that alter or restrict the terms of this
        License or the recipients' exercise of the rights granted hereunder,
        and You must keep intact all notices that refer to this License and to
        the disclaimer of warranties. You may not distribute, publicly display,
        publicly perform, or publicly digitally perform the Derivative Work
        with any technological measures that control access or use of the Work
        in a manner inconsistent with the terms of this License Agreement. The
        above applies to the Derivative Work as incorporated in a Collective
        Work, but this does not require the Collective Work apart from the
        Derivative Work itself to be made subject to the terms of this License.
        If you distribute, publicly display, publicly perform, or publicly
        digitally perform the Work or any Derivative Works or Collective Works,
        You must keep intact all copyright notices for the Work and give the
        Original Author credit reasonable to the medium or means You are
        utilizing by conveying the name (or pseudonym if applicable) of the
        Original Author if supplied; the title of the Work if supplied; to the
        extent reasonably practicable, the Uniform Resource Identifier, if any,
        that Licensor specifies to be associated with the Work, unless such URI
        does not refer to the copyright notice or licensing information for the
        Work; and in the case of a Derivative Work, a credit identifying the
        use of the Work in the Derivative Work (e.g., "French translation of
        the Work by Original Author," or "Screenplay based on original Work by
        Original Author"). Such credit may be implemented in any reasonable
        manner; provided, however, that in the case of a Derivative Work or
        Collective Work, at a minimum such credit will appear where any other
        comparable authorship credit appears and in a manner at least as
        prominent as such other comparable authorship credit.

    5. Representations, Warranties and Disclaimer



    7. Termination

        This License and the rights granted hereunder will terminate
        automatically upon any breach by You of the terms of this License.
        Individuals or entities who have received Derivative Works or
        Collective Works from You under this License, however, will not have
        their licenses terminated provided such individuals or entities remain
        in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8
        will survive any termination of this License.  Subject to the above
        terms and conditions, the license granted here is perpetual (for the
        duration of the applicable copyright in the Work). Notwithstanding the
        above, Licensor reserves the right to release the Work under different
        license terms or to stop distributing the Work at any time; provided,
        however that any such election will not serve to withdraw this License
        (or any other license that has been, or is required to be, granted
        under the terms of this License), and this License will continue in
        full force and effect unless terminated as stated above.

    8. Miscellaneous

        Each time You distribute or publicly digitally perform the Work or a
        Collective Work, the Licensor offers to the recipient a license to the
        Work on the same terms and conditions as the license granted to You
        under this License.  Each time You distribute or publicly digitally
        perform a Derivative Work, Licensor offers to the recipient a license
        to the original Work on the same terms and conditions as the license
        granted to You under this License.  If any provision of this License is
        invalid or unenforceable under applicable law, it shall not affect the
        validity or enforceability of the remainder of the terms of this
        License, and without further action by the parties to this agreement,
        such provision shall be reformed to the minimum extent necessary to
        make such provision valid and enforceable.  No term or provision of
        this License shall be deemed waived and no breach consented to unless
        such waiver or consent shall be in writing and signed by the party to
        be charged with such waiver or consent.  This License constitutes the
        entire agreement between the parties with respect to the Work licensed
        here. There are no understandings, agreements or representations with
        respect to the Work not specified here. Licensor shall not be bound by
        any additional provisions that may appear in any communication from
        You. This License may not be modified without the mutual written
        agreement of the Licensor and You.

A TODO => TODO +3 -0
@@ 0,0 1,3 @@
pngs in static
missing latex formulas

D _config.yml => _config.yml +0 -50
@@ 1,50 0,0 @@
# Site settings
title: ~rumpelsepp
email: stefan@rumpelsepp.org
description: I break stuff
url: "https://rumpelsepp.org" # the base hostname & protocol for your site
baseurl: "" # the subpath of your site, e.g. /blog/

timezone: Europe/Berlin
# paginate: 5

  - scope:
      path: ""
      type: "posts"
      layout: post
  - scope:
      path: ""
      type: "stuff"
      layout: page
  - scope:
      path: ""
      type: "specs"
      layout: page

    output: true
    output: true

# Build settings
    - jekyll-asciidoc
    - jekyll-feed

    - source-highlighter=rouge
    - stylesdir=/assets/css
    - imagesdir=/assets/img
    - prewrap!

  - vendor
  - manage.sh
  - Gemfile
  - Gemfile.lock

D _includes/footer.html => _includes/footer.html +0 -17
@@ 1,17 0,0 @@
<script type="text/x-mathjax-config">
  messageStyle: "none",
  tex2jax: {
    inlineMath: [["\\(", "\\)"]],
    displayMath: [["\\[", "\\]"]],
    ignoreClass: "nostem|nolatexmath"
  asciimath2jax: {
    delimiters: [["\\$", "\\$"]],
    ignoreClass: "nostem|noasciimath"
  TeX: { equationNumbers: { autoNumber: "none" } }


D _includes/head.html => _includes/head.html +0 -36
@@ 1,36 0,0 @@
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>{% if page.title %}{{ page.title | escape }}{% else %}{{ site.title | escape }}{% endif %}</title>
    <meta name="description" content="{{ page.excerpt | default: site.description | strip_html | normalize_whitespace | truncate: 160 | escape }}">

    <link rel="stylesheet" href="{{ "/assets/css/asciidoctor-default.css" | relative_url }}">
    <link rel="stylesheet" href="{{ "/assets/css/main.css" | relative_url }}">
    <link rel="stylesheet" href="{{ "/assets/css/asciidoc-pygments.css" | prepend: site.baseurl }}">

    <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
    <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>

    <link rel="canonical" href="{{ page.url | replace:'index.html','' | absolute_url }}">
    <link rel="alternate" type="application/rss+xml" title="{{ site.title | escape }}" href="{{ "/feed.xml" | relative_url }}">

    <link rel="apple-touch-icon" sizes="57x57" href={{ "/assets/favicon/apple-icon-57x57.png" | relative_url }}>
    <link rel="apple-touch-icon" sizes="60x60" href={{ "/assets/favicon/apple-icon-60x60.png" | relative_url }}>
    <link rel="apple-touch-icon" sizes="72x72" href={{ "/assets/favicon/apple-icon-72x72.png" | relative_url }}>
    <link rel="apple-touch-icon" sizes="76x76" href={{ "/assets/favicon/apple-icon-76x76.png" | relative_url }}>
    <link rel="apple-touch-icon" sizes="114x114" href={{ "/assets/favicon/apple-icon-114x114.png" | relative_url }}>
    <link rel="apple-touch-icon" sizes="120x120" href={{ "/assets/favicon/apple-icon-120x120.png" | relative_url }}>
    <link rel="apple-touch-icon" sizes="144x144" href={{ "/assets/favicon/apple-icon-144x144.png" | relative_url }}>
    <link rel="apple-touch-icon" sizes="152x152" href={{ "/assets/favicon/apple-icon-152x152.png" | relative_url }}>
    <link rel="apple-touch-icon" sizes="180x180" href={{ "/assets/favicon/apple-icon-180x180.png" | relative_url }}>
    <link rel="icon" type="image/png" sizes="192x192"  href={{ "/assets/favicon/android-icon-192x192.png" | relative_url }}>
    <link rel="icon" type="image/png" sizes="32x32" href={{ "/assets/favicon/favicon-32x32.png" | relative_url }}>
    <link rel="icon" type="image/png" sizes="96x96" href={{ "/assets/favicon/favicon-96x96.png" | relative_url }}>
    <link rel="icon" type="image/png" sizes="16x16" href={{ "/assets/favicon/favicon-16x16.png" | relative_url }}>
    <link rel="manifest" href={{ "/assets/favicon/manifest.json" | absolute_url }}>
    <meta name="msapplication-TileColor" content="#ffffff">
    <meta name="msapplication-TileImage" content={{ "/assets/favicon/ms-icon-144x144.png" | relative_url }}>
    <meta name="theme-color" content="#ffffff">

D _includes/header.html => _includes/header.html +0 -29
@@ 1,29 0,0 @@
<header class="site-header" role="banner">

  <div class="wrapper">

    <a class="site-title" href="{{ site.baseurl }}/">{{ site.title | escape }}</a>

    <nav class="site-nav">
      <span class="menu-icon">
        <svg viewBox="0 0 18 15" width="18px" height="15px">
          <path fill="#424242" d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.031C17.335,0,18,0.665,18,1.484L18,1.484z"/>
          <path fill="#424242" d="M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0c0-0.82,0.665-1.484,1.484-1.484 h15.031C17.335,6.031,18,6.696,18,7.516L18,7.516z"/>
          <path fill="#424242" d="M18,13.516C18,14.335,17.335,15,16.516,15H1.484C0.665,15,0,14.335,0,13.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.031C17.335,12.031,18,12.696,18,13.516L18,13.516z"/>

      <div class="trigger">
        {% for my_page in site.pages %}
          {% if my_page.title %}
            {% unless my_page.hide %}
              <a class="page-link" href="{{ my_page.url | absolute_url }}">{{ my_page.title | escape }}</a>
            {% endunless %}
          {% endif %}
        {% endfor %}



D _layouts/default.html => _layouts/default.html +0 -20
@@ 1,20 0,0 @@
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: "en" }}">

  {% include head.html %}


    {% include header.html %}

    <main class="page-content" aria-label="Content">
      <div class="wrapper">
        {{ content }}

    {% include footer.html %}



D _layouts/home.html => _layouts/home.html +0 -14
@@ 1,14 0,0 @@
layout: default

<div class="home">
  <ul class="post-list">
    {% for post in site.posts %}
        <span class="post-meta">{{ post.date | date: "%Y-%m-%d" }}</span><a class="post-link" href="{{ post.url | absolute_url }}">{{ post.title }}</a>
    {% endfor %}

D _layouts/page.html => _layouts/page.html +0 -14
@@ 1,14 0,0 @@
layout: default
<article class="post">

  <header class="post-header">
    <h1 class="post-title">{{ page.title }}</h1>

  <div class="post-content">
    {{ content }}


D _layouts/post.html => _layouts/post.html +0 -14
@@ 1,14 0,0 @@
layout: default
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">

  <header class="post-header">
    <h1 class="post-title" itemprop="name headline">{{ page.title }}</h1>
    <p class="post-meta"><time datetime="{{ page.date | date_to_xmlschema }}" itemprop="datePublished">{{ page.date | date: "%B %-d, %Y" }}</time>{% if page.author %} • <span itemprop="author" itemscope itemtype="http://schema.org/Person"><span itemprop="name">{{ page.author }}</span></span>{% endif %}</p>

  <div class="post-content" itemprop="articleBody">
    {{ content }}

D _layouts/specs.html => _layouts/specs.html +0 -14
@@ 1,14 0,0 @@
layout: default


  <ul class="post-list">
    {% for item in site.specs %}
        <a href="{{ item.url }}">{{ item.title }}</a>
    {% endfor %}

D _layouts/stuff.html => _layouts/stuff.html +0 -14
@@ 1,14 0,0 @@
layout: default


  <ul class="post-list">
    {% for item in site.stuff %}
        <a href="{{ item.url }}">{{ item.title }}</a>
    {% endfor %}

D _posts/2015-10-26-awesome-stuff-1.adoc => _posts/2015-10-26-awesome-stuff-1.adoc +0 -49
@@ 1,49 0,0 @@
= Awesome Stuff No 1

That's the Awesome Stuff #1. Awesome Stuff is an ongoing series of
blogposts that introduces several awesome, crazy or senseless tools.

Have Fun!

    A cd command that learns - easily navigate directories
    from the commandline.

    Deduplicating backup program with optional compression
    and authenticated encryption support.

    git dotfiles synchronizer written in bash

    ZSH port of Fish shell's history search feature

    Newsbeuter is an open-source RSS/Atom feed reader for
    text terminals. It runs on Linux, FreeBSD, Mac OS X and other Unix-
    like operating systems. Newsbeuter's great configurability and vast
    number of features make it a perfect choice for people that need a
    slick and fast feed reader that can be completely controlled via

    Instantly Awesome Zsh

    A window switcher, run dialog and dmenu replacement

    Open Source Continuous File Synchronization

    Inotify support for Syncthing

    Magnificent app which corrects your previous console command

    Manage display layout graphically and export the settings as 
    a shellscript; the shellscript uses `xrandr` to replicate
    the settings.

D _posts/2015-11-16-awesome-stuff-2.adoc => _posts/2015-11-16-awesome-stuff-2.adoc +0 -43
@@ 1,43 0,0 @@
= Awesome Stuff No 2

That’s the Awesome Stuff #2. Awesome Stuff is an ongoing series of blogposts
that introduces several awesome, crazy or senseless tools.

Have Fun!

    A minimal pdf reader providing vim keybindings

    Movie player based on MPlayer and mplayer2

    A keyboard-centric VTE-based terminal, aimed at use within
    a window manager with tiling and/or tabbing support.

    Console-based file manager with vi bindings, customizability,
    and lots of features.

    Tool to quickly find (and optionally remove) duplicate files
    and other lint.

    Simple console based password manager

    Group of web interface tools which adhere to the Unix
    philosophy. Minmal webkit browser which works well with i3.

    BSD licensed terminal multiplexer; GNU screen improved.

    The coolest mpd client. I've been using it for 8 months and I 
    still like it. :)

== Past Awesome Stuffs

* {{ site.url }}{% post_url 2015-10-26-awesome-stuff-1 %}[Awesome Stuff No 1]

D _posts/2015-12-29-awesome-stuff-3.adoc => _posts/2015-12-29-awesome-stuff-3.adoc +0 -48
@@ 1,48 0,0 @@
= Awesome Stuff No 3

That’s the Awesome Stuff #3. Awesome Stuff is an ongoing series of blogposts
that introduces several awesome, crazy or senseless tools. This post lists
a few useful tools for tiling window managers, especially i3.

Have Fun!

    qutebrowser is a keyboard-focused browser with a minimal GUI. It’s based on
    Python, PyQt5 and QtWebKit and free software, licensed under the GPL.  It
    was inspired by other browsers/addons like dwb and Vimperator/Pentadactyl.

    Very nice replacement for `i3status`. Written in Python and supports
    click events, is very well documented and offers several useful modules.

    Profanity is a console based XMPP client written in C
    using ncurses and libstrophe, inspired by Irssi

    A dmenu/rofi frontend for `pass`

    Very flexible screenshot tool; supports area, whole screen und window 
    mode. The homepage is crap; I instead link to the arch linux wiki.

    Nice and leighweight notification daemon for tiling window managers

    Image viewer optimized for tiling window managers; scales the images
    better than `feh` does.

    Automounter for udisks/udisks2. Very useful in i3 to get your USB sticks
    mounted automatically.

    Suckless Terminal; Very leighweight; in i3 map `<super>+<return>` to 
    `st -e tmux`

== Past Awesome Stuffs

* {{ site.url }}{% post_url 2015-10-26-awesome-stuff-1 %}[Awesome Stuff No 1]
* {{ site.url }}{% post_url 2015-11-16-awesome-stuff-2 %}[Awesome Stuff No 2]

D _posts/2016-08-08-btrfs-xfs-zfs.adoc => _posts/2016-08-08-btrfs-xfs-zfs.adoc +0 -67
@@ 1,67 0,0 @@
= BTRFS, XFS, ZFS, ...
:page-lang: de

Heute mal was auf Deutsch; ich hab den Artikel schon
geschrieben und bin zu faul den zu übersetzen.

Es gibt im Bereich der Filesysteme mal was neues. Der RAID 5 und RAID 6
Code von BTRFS wurde ja bisher nie als stable bezeichnet. RAID 1 und
RAID 0 funktioniert seit 3 Jahren ziemlich gut. Mit diesem Wissen hab
ich gestern das hier gelesen:

Btrfs RAID 5/6 Code Found To Be Very Unsafe & Will Likely Require A

Es paniken jetzt alle herum und BTRFS wird vermutlich doch nicht so
schnell das NAS Monster betreiben, obwohl es auch interessante neue
Sachen für den 4.8er Kernel gibt.

Nunja, im gleichen Zug les ich mal wieder was von XFS (das ist ein sehr
sehr zuverlässiges Filesystem für große Platten, aber ohne "NextGen"
Features). XFS ist ziemlich performant und läuft extrem zuverlässig,
Berichten zufolge teilweise besser als ext4 (Quelle find ich gerade
keine vernünftige).

Das spannende ist jetzt, dass die XFS Entwickler tatsächlich an "NextGen"
Feautures wie Copy-on-Write, online Scrubbing, Deduplication usw. arbeiten.  Die
Vorbereitungen dafür sind gerade noch in den 4.8er Kernel aufgenommen worden
Wenn die es schaffen, auf die wirklich gute Codebase (der Maintainer ist der
Hammer; Dave Chinner mal auf Youtube suchen) um Copy-on-Write zu ergänzen
uuuuuund vielleicht iwann RAID Support einzubaun, dann wird es wirklich
interessant. Es bleibt spannend, und es bleibt auch spannend was mit BTRFS
passiert, scheint ja irgendwie immer wieder mal ausgebremst zu werden. Läuft
bei mir eigentlich ganz gut seit drei Jahren...

Achja, ZFS gibts ja noch. Das MegaMonster. Das rollt eigentlich als open-zfs
still vor sich hin und immer weiter
footnote:[http://open-zfs.org/wiki/Main_Page]. Mittlerweile gibt es für Linux
ein Kernel Modul footnote:[http://zfsonlinux.org/] mit einem Wiki
footnote:[https://github.com/zfsonlinux/zfs/wiki]. Das zfsonlinux Projekt folgt
dem Upstream und sie tracken die Issues vom Upstream Projekt
footnote:[https://github.com/zfsonlinux/zfs/wiki/OpenZFS-Tracking]. Es gibt
eine Feature Matrix, die für Linux jetzt eigentlich auf ganz gut ausschaut

Naja genug dem Geblubber. Für eine NAS rate ich als BTRFS Jünger davon ab und
empfehle mal sich zfsonlinux anzuschaun. Es gibt auch Debian Pakete (falls das
hier jemand nutzt....)
footnote:[https://github.com/zfsonlinux/zfs/wiki/Debian]. Für jeden, der keine
Lust auf Experimente hat, nimmt ein nacktes FreeBSD mit ZFS
footnote:[https://www.freebsd.org/doc/handbook/zfs.html]. OVH mit Kimsufi
unterstützt ZFS am Server jetzt auch, ich hab meinen gleich mal migriert. Für
die Heimbastelecke gibts noch FreeNAS footnote:[http://www.freenas.org/]; die
Web-GUI ist zwar anfangangs etwas gewöhnungsbedürftig, aber es funktioniert
echt gut. ZFS ist einfach mega für ein Datengrab, funktionierendes RAID gibts
mit dem sog. RAID-Z obendrauf
footnote:[http://www.zfsbuild.com/2010/05/26/zfs-raid-levels/]. Probierts mal

Hier noch ein Link, hab ich noch nicht vollständig gelesen, aber
potentiell interessant: https://calomel.org/zfs_raid_speed_capacity.html

D _posts/2016-08-11-awesome-stuff-4.adoc => _posts/2016-08-11-awesome-stuff-4.adoc +0 -142
@@ 1,142 0,0 @@
= Awesome Stuff No 4
:page-lang: de
:toc: macro

Hier ist die Awesome Stuff #4. Ich werde in unregelmäßigen Abständen
coole, sinnvolle oder abgefahrene Linux Tools auflisten, die ich immer
mal wieder ausgrab. Heute im Programm:


Der war lange ueberfaellig und ist seit Ewigkeiten halb fertig im Draft
Ordner versauert. Jetzt hab ich ihn in der U-Bahn mal fertig geklopft.
Sorry fuer Typos, das fehlen von Umlauten und dafuer dass es mal wieder
auf Deutsch ist... :D

Viel Spaß damit!

== Neovim

	Jo, ein Fork von vim, wo mal ordentlich aufgeraeumt wird. Lauft
	mittlerweile sehr stable, mein Haupteditor seit nem halben
	Jahr. Hat atom bei mir vollstaendig abgeloest.

	Plugin Manager fuer [neo]vim. Tut das was es soll.

	Ein Theme, das relativ umfangreich ist und fuer alle Sprachen
	recht gut funktioniert. Der Retro Look ist
	gewoehnungsbeduerftig, aber dafuer ist es wirklich komplett und
	gut. Kontrast kann man einstellen, fette und kursiv Schrift ist
	unterstuetzt (gut in Latex!).

	Latex fuer vim, ohne den Editor in ein IDE Monster zu

	Asynchrone Autocompletion Engine fuer neovim. Funzt super; gibt
	Go und Python Extensions dafuer. Hab jetzt mal nur die Python
	Variante verlinkt.

	Editorconfig Unterstuetzung. Damit kann man in einem Projekt
	eine gemeinsame Konfiguration machen. Ist richtig cool, wenn
	die Contributer mal wieder alles kaputt machen (whitespace,
	Tabsize, ....).

	Mit einem Command alles auskommentieren. Der Kommentarstil kann
	umfangreich eingestellt werden.

	Tut Klammern immer gleich als Paar einfuegen. So, dass man sich
	ned immer die Fingern abbricht. Bin mir nur noch ned sicher, ob
	man dazu ein Plugin braucht; fuer den Moment hab ichs mal drin.

	Sehr coole Einfuehrung zu vim auf Github.

== i3 Foo

	Eine i3 Implementierung fuer Wayland. Kommt gut voran, ist aber
	noch nicht brauchbar fuer daily use.

	Ein Bildbetrachter, aehnlich wie sxiv, aber auch unter Wayland

	Screenshot Tool, modularer als scrot und wird aktiv

== Shell-Foo

	Jo Leute, das Teil ist *DER* Shit. Ein Tool, in das man Text
	reinpipen kann, es macht eine Liste auf, die man fuzzy
	durchsuchen kann. Das Ergebnis nach betaetigen der Enter Taste
	landet in der Standardausgabe. Damit kann man viele coole
	Sachen machen... Das Teil ist bei mir in der Shell auf
	kbd:[ctrl + r] gebunden fuer Shell Completion (gibt Fish
	Keybindings), ich hab es im Vim als Plugin, ... Lohnt sich es
	sich mal anzuschaun und in den jew. Workflow einzubauen. Der
	Ludwig scheint es auch schon zu moegen...
	Auf dem Github Wiki gibt es viele Beispiele.

	"Advanced Shell History"

	Eine Shell... wo man Python Code schreiben kann. Aber nicht wie
	ipython, sondern sowas wie Bash, ... wo man Python Code
	schreiben kann. Total abgefahren.

== Sinnvolle Bibliotheken

	Ziemlich cooler Dokumentations Generator fuer Python. Schaut
	recht intuitiv aus, was er erzeugt.

	Datenanalyse in Python; Design Goal ist es keine Loops
	schreiben zu muessen. Hier ist mal ein Intro dazu:

	Python Datumslibrary. Ist ziemlich einfach und cool zu nutzen.

	Mal wieder iwas zum plotten in Python...

	Die Dinger sind cool. Einfach ne Liste an Libraries fuer Go

	(...) fuer Python

== Sonstiges

	Test suite fuer Bash. Damit kann man ziemlich cool CLI
	Programme testen. Die Git Devs nehmen das u.a. her.

	Ein OpenSource Paper Journal (?) Schaut irgendwie interessant

== Vorherige Awesome Stuff Mails

* {{ site.url }}{% post_url 2015-10-26-awesome-stuff-1 %}[Awesome Stuff No 1]
* {{ site.url }}{% post_url 2015-11-16-awesome-stuff-2 %}[Awesome Stuff No 2]
* {{ site.url }}{% post_url 2015-12-29-awesome-stuff-3 %}[Awesome Stuff No 3]

D _posts/2016-10-26-how-to-disable-zoom-mode-in-gtk-applications.adoc => _posts/2016-10-26-how-to-disable-zoom-mode-in-gtk-applications.adoc +0 -19
@@ 1,19 0,0 @@
= How to disable annoying zoom mode in gtk applications

Another short post for today, but this one is important.
The gnome devs introduced the so called
https://blogs.gnome.org/mclasen/2013/08/05/scrolling-in-gtk["zoom mode"].
This one is really, *really*, **really** annoying. I can't imagine
why somebody even wants this!! I hate it; I even more hate it, that
there is no "disable zoom mode" setting somewhere in the GUI...
So, thanks god, I incidentally discovered the solution

Add a file `~/.config/gtk-3.0/settings.ini` with this content, restart
the relevant GTK application and be happy:

gtk-long-press-time = 5000

D _posts/2016-10-26-strace-on-freebsd.adoc => _posts/2016-10-26-strace-on-freebsd.adoc +0 -8
@@ 1,8 0,0 @@
= strace on FreeBSD -> truss

This is just a short post, more of a reminder for myself. If one searches
http://man7.org/linux/man-pages/man1/strace.1.html[`strace`] for FreeBSD, he
might not be successful as there is no `strace` for FreeBSD. **BUT** there is
which does pretty much the same as `strace`; `truss` is part of the base system
and can be used for the same purpose as `strace`.

D _posts/2017-02-25-base64-encoder.adoc => _posts/2017-02-25-base64-encoder.adoc +0 -187
@@ 1,187 0,0 @@
= Base64 Encoder
:stem: latexmath

As usual, here is the definition of the algorithm, copied from
wikipedia, because I am so lazy.

Base64 is a group of similar binary-to-text encoding schemes that represent
binary data in an ASCII string format. The particular set of 64 characters
chosen to represent the 64 place-values for the base varies between
implementations. The general strategy is to choose 64 characters that are both
members of a subset common to most encodings, and also printable. This
combination leaves the data unlikely to be modified in transit through
information systems, such as email, that were traditionally not 8-bit clean.
For example, MIME's Base64 implementation uses A–Z, a–z, and 0–9 for the first
62 values. Other variations share this property but differ in the symbols
chosen for the last two values; an example is UTF-7.

The algorithm is pretty simple. You take three input bytes and combine them
to to a `uint32_t`; let's call this `value`. Then you devide this `value`
in four sextets. Let's make an example.

| # | ASCII | HEX | BITS

| 1 | 9     | 0x39 | [red]#001110# [blue]#01#
| 2 | a     | 0x61 | [blue]#0110# [green]#0001#
| 3 | c     | 0x63 | [green]#01# 100011

This encodes to four sextets. Just concatenate the three bit patterns together
and make groupes of six (instead of eight). One sextet represents the index for
the base64 lookup table:

char *codes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

| # | SEXTET   | HEX  | BASE64

| 1 | [red]#001110# | 0x0E | O
| 2 | [blue]#010110# | 0x16 | W
| 3 | [green]#000101# | 0x05 | F
| 4 | 100011 | 0x23 | j

== Padding

When the input is not dividable by three, there is the need of padding, since
the sextets---which are used to calculate the index of the encoded
char---cannot be calculated. https://tools.ietf.org/html/rfc4648[RFC4648] says,
that the missing sextets are set to zero and encoded with a `=` char.

Our tables for the input `9a` would look like this:

| # | ASCII | HEX | BITS

| 1 | 9     | 0x39 | 00111001
| 2 | a     | 0x61 | 01100001
| 3 |       | 0x00 | **00000000**

| # | SEXTET   | HEX  | BASE64

| 1 | 001110 | 0x0E | O
| 2 | 010110 | 0x16 | W
| 3 | 0001**00** | 0x04 | E
| 4 | **000000** | 0x00 | =

There are two sextets that changed, thus two encoding chars changed.
The padding was the part which took the most time to get right in the
C implementation...

One final hint, which is important. The length stem:[l] of the encoded string
can be calculated with the following formula; stem:[n] is the length of the
input string.

l = \left \lceil{4 \cdot \frac{n}{3}}\right \rceil

I have implemented the `ceil` function in C with a macro:

[source, c]
#define CEIL(x) ((x) - (int) (x) > 0 ? (int) ((x) + 1) : (int) (x))

Please note, that the `x` has to be put in `()`, to ensure that the macro
works properly with expressions like this: `a + b + 1`. Otherwise the
operator priority might change your expected result to some crap...

*edit*: I forgot to add some notes about the padding length. Since the input
data must be dividable by 3, the padding length can be calculated with the
following formula; as before stem:[n] is the length of the input data in number
of bytes:

l_{\mathrm{pad}} = 3 - (n \mod 3)

== Implementation in C

Here is my implementation in C. I have verified it with Python's `base64`
module. It produces sane output. Some corner cases might not be covered,
but I think it is enough for me to claim that I have understood how it

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#define CEIL(x) ((x) - (int) (x) > 0 ? (int) ((x) + 1) : (int) (x)) // <1>

void base64_encode(char *s, size_t len) {
	char *codes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	size_t pad = 3 - (len % 3);  // <2>
	size_t enclen = CEIL(4.0 * (len / 3.0));  // <3>
	size_t k = 0;

	for (size_t i = 0; i < len; i += 3) {  // <4>
		uint32_t val = 0;

		int j = 0;  // <5>
		while (j < 3 && i + j < len) {
			val |= s[i+j] << ((2 - j) * 8);

		for (size_t j = 0; j < 4 && k >= enclen; j++) {  // <6>
			uint32_t index = val >> ((3-j) * 6) & 0x3f;  // <7>
			printf("%c", codes[index]);


	for (size_t i = 0; i < pad; i++) {  // <8>

int main(int argc, char *argv[]) {
	char *input = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.";

	base64_encode(input, strlen(input));


<1> See previous section.
<2> Calculate the padding length. When i.e. the input is 5 bytes long, then we have
    to add one padding byte that the length is dividable by 3.
<3> See formula above.
<4> Iterate over the input array. We take three bytes in one iteration step.
<5> That one was tricky... We have to combine three bytes to a `uint32_t` in order
    to be able to generate the sextets. So, we shift the input bytes by `(2 - j) * 8`
    and then use the bitwise `OR` to combine the values. That's pretty straight forward.
    The reason for the `while` loop is, that one needs to be careful with the indexes.
    As one might have seen, we could potentially access memory outside the array with:
    `s[i+j]`. If padding is needed, we could be in trouble with this line of code.
    This problem is solved in the second condition of the `while` loop: `i + j < len`.
    If this is true, we must add padding. Since we shift the bytes to the left, we
    add the zero bytes automatically, so there is nothing left todo for adding padding.
<6> This loop iterates over the sextets in the combined `uint32_t` values and prints them.
    In case of padding we must stop earlier. In my solution, i count the generated encoding
    chars in the variable `k` and stop when I reached `enclen` (remember the formula!).
<7> Nice shit to extract the sextets. :)
<8> Finally, add the padding `=` char.

This one took 30 minutes for me to implement the basic algorithm and 1,5 days to fix
the padding thing... I feel so stupid. :/

D _sass/_base.scss => _sass/_base.scss +0 -39
@@ 1,39 0,0 @@
 * The absolute base styling is provided by the asciidoctor 
 * stylesheet. This stylesheet only fixes some problems.
 * Adapted from the default jekyll stylesheet.

 * Wrapper
.wrapper {
    max-width: -webkit-calc(#{$content-width} - (#{$spacing-unit} * 2));
    max-width:         calc(#{$content-width} - (#{$spacing-unit} * 2));
    margin-right: auto;
    margin-left: auto;
    padding-right: $spacing-unit;
    padding-left: $spacing-unit;
    @extend %clearfix;

    @include media-query($on-laptop) {
        max-width: -webkit-calc(#{$content-width} - (#{$spacing-unit}));
        max-width:         calc(#{$content-width} - (#{$spacing-unit}));
        padding-right: $spacing-unit / 2;
        padding-left: $spacing-unit / 2;

 * Clearfix
%clearfix {

    &:after {
        content: "";
        display: table;
        clear: both;

D _sass/_layout.scss => _sass/_layout.scss +0 -230
@@ 1,230 0,0 @@
 * Site header
.site-header {
    border-top: 5px solid $grey-color-dark;
    border-bottom: 1px solid $grey-color-light;
    min-height: 56px;

    // Positioning context for the mobile navigation icon
    position: relative;

.site-title {
    font-size: 26px;
    font-weight: 300;
    line-height: 56px;
    letter-spacing: -1px;
    margin-bottom: 0;
    float: left;

    &:visited {
        color: $grey-color-dark;

.site-nav {
    float: right;
    line-height: 56px;

    .menu-icon {
        display: none;

    .page-link {
        color: $text-color;
        line-height: $base-line-height;

        // Gaps between nav items, but not on the last one
        &:not(:last-child) {
            margin-right: 20px;

    @include media-query($on-palm) {
        position: absolute;
        top: 9px;
        right: $spacing-unit / 2;
        background-color: $background-color;
        border: 1px solid $grey-color-light;
        border-radius: 5px;
        text-align: right;

        .menu-icon {
            display: block;
            float: right;
            width: 36px;
            height: 26px;
            line-height: 0;
            padding-top: 6px;  // asciidoctor fix
            text-align: center;

            > svg {
                width: 18px;
                height: 15px;

                path {
                    fill: $grey-color-dark;

        .trigger {
            clear: both;
            display: none;

        &:hover .trigger {
            display: block;
            padding-bottom: 5px;

        .page-link {
            display: block;
            padding: 5px 10px;

            &:not(:last-child) {
                margin-right: 0;
            margin-left: 20px;

 * Site footer
.site-footer {
    border-top: 1px solid $grey-color-light;
    padding: $spacing-unit 0;

.footer-heading {
    font-size: 18px;
    margin-bottom: $spacing-unit / 2;

.social-media-list {
    list-style: none;
    margin-left: 0;

.footer-col-wrapper {
    font-size: 15px;
    color: $grey-color;
    margin-left: -$spacing-unit / 2;
    @extend %clearfix;

.footer-col {
    float: left;
    margin-bottom: $spacing-unit / 2;
    padding-left: $spacing-unit / 2;

.footer-col-1 {
    width: -webkit-calc(35% - (#{$spacing-unit} / 2));
    width:         calc(35% - (#{$spacing-unit} / 2));

.footer-col-2 {
    width: -webkit-calc(20% - (#{$spacing-unit} / 2));
    width:         calc(20% - (#{$spacing-unit} / 2));

.footer-col-3 {
    width: -webkit-calc(45% - (#{$spacing-unit} / 2));
    width:         calc(45% - (#{$spacing-unit} / 2));

@include media-query($on-laptop) {
    .footer-col-2 {
        width: -webkit-calc(50% - (#{$spacing-unit} / 2));
        width:         calc(50% - (#{$spacing-unit} / 2));

    .footer-col-3 {
        width: -webkit-calc(100% - (#{$spacing-unit} / 2));
        width:         calc(100% - (#{$spacing-unit} / 2));

@include media-query($on-palm) {
    .footer-col {
        float: none;
        width: -webkit-calc(100% - (#{$spacing-unit} / 2));
        width:         calc(100% - (#{$spacing-unit} / 2));

 * Page content
.page-content {
    padding: $spacing-unit 0;

.page-heading {
    font-size: 20px;

.post-list {
    margin-left: 0;
    list-style: none;

    > li {
        margin-bottom: $spacing-unit / 8;

.post-meta {
    font-size: $small-font-size;
    color: $grey-color;
    margin-right: 1em;

 * Posts
.post-header {
    margin-bottom: $spacing-unit;

.post-content {
    margin-bottom: $spacing-unit;
    text-align: justify;
    #footnotes {
        text-align: left;

.post-content #toc {
    margin-bottom: 1.5em;

 * Post list
.post-list .post-meta {
    display: inline;

 * rumpelsepp's adjustments
.home a, .footer-col a, .site-header a {
    text-decoration: none;

D _specs/footer.adoc => _specs/footer.adoc +0 -15
@@ 1,15 0,0 @@
== Bugs

This project is maintained on Github: https://github.com/Fraunhofer-AISEC/penlog.

== Authors

Current maintainers are:

* Stefan Tatschner <stefan@rumpelsepp.org>
* Tobias Specht

== License

This document is published under the Apache-2.0 license.
The license of the code can be obtained from the Git repository.

D _specs/netzteil-http.7.adoc => _specs/netzteil-http.7.adoc +0 -145
@@ 1,145 0,0 @@
= netzteil-http(7)
:doctype:    manpage
:man source: opennetzteil

== Name

netzteil-http - a programming interface for power supplies over http

== Description

OpenNetzteil provides a uniform HTTP API for powersupplies to be controlled over HTTP.
Usually, these devices can be controlled over a device specific and loosely specified protocol called SCPI.
Such powersupplies are accessed differently, some possibilities are USB, TCP, Serial Line, …
The HTTP API, described in this document, aims to be a proxy which can be used to run even multiple, different power supplies on one machine.
Authentication, authorization, and other security mechanism are not in the scope of this API.
Use a reverse proxy for implementing more sophisticated HTTP techniques.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

== Data Format

The API exclusively uses data encoded in the JSON format (RFC7159).
The data is encoded in the most minimal way. 
For instance, an endpoint delivering a float value encodes this as a plain JSON float: `10.501`.
No dictionary or more complex data structures are needed.
The data type of each endpoint in this specification is mentioned in the appropriate endpoint description.

An exception to this rule are the `…/voltage/ws`, `…/current/ws`, and `…/measurements/ws` endpoints.
In order to unify these three interfaces, the returned data looks like the following:


Empty keys SHOULD be omitted.
The `time` key is REQUIRED.

== API

Every GET endpoint delivers data encoded in JSON.
Every PUT endpoint accepts data encoded in JSON.
If there is only one device available, a reduces API MAY be provided by implementations.
All endpoints MUST be prepended the opennetzteil namespace indicator: `/_netzteil/api/`.
The full path of the `/devices` endpoint looks like the following: `/_netzteil/api/devices`.

Some endpoints include the wording “points to …”.
This endpoint MAY use an HTTP 308 redirect to the appropriate, pointed endpoint.
The API using redirects to other endpoints is called reduced API.

The `|` sign indicates a logical `or`.

GET|PUT (OPTIONAL) `/device`::
    If **only one** device is served, this endpoint points to `/devices/0/…`.

GET (REQUIRED) `/devices`::
    Query the available power supplies.

GET (REQUIRED) `/devices/{id}/out`::
    Query the status of the master output.
    Returns a boolean JSON body: `true`, or `false`.

PUT (REQUIRED) `/devices/{id}/out`::
    Set the status of the master output.
    Accepts a boolean JSON body: `true`, or `false`.

GET (REQUIRED) `/devices/{id}/ident`::
    Returns the device identity.
    Typically, this is the model name, e.g. `RND 320-KD3005P V2.0`.

GET (OPTIONAL) `/devices/{id}/raw/ws`::
    Grab a websocket exposing a raw connection to the device.
    Custom commands (not exposed by this HTTP API) can be accessed via this endpoint.

PUT (OPTIONAL) `/devices/{id}/beep`::

GET (OPTIONAL) `/devices/{id}/status`::
    Query status information.
    The returned data is device specific, it is RECOMMENDED to use a JSON dict with descriptive keys.

GET|PUT (OPTIONAL) `/devices/{id}/channel`::
    If the device has *only one* channel, this endpoint points to `/devices/{id}/channels/0`.

GET (REQUIRED) `/devices/{id}/channels`::
    Returns the number of available channels.
    Returns an integer value.

GET (REQUIRED) `/devices/{id}/channels/{channel}/current`::
    Returns the present current in `A`.
    Returns a float value.

PUT (REQUIRED) `/devices/{id}/channels/{channel}/current`::
    Sets the maximum current `A`.
    Accepts a float value.

GET (REQUIRED) `/devices/{id}/channels/{channel}/voltage`::
    Returns the present voltage in `V`.
    Returns a float value.

PUT (REQUIRED) `/devices/{id}/channels/{channel}/voltage`::
    Sets the maximum voltage `V`.
    Accepts a float value.

GET (OPTIONAL) `/devices/{id}/channels/{channel}/voltage/ws?interval={ms}`::

GET (OPTIONAL) `/devices/{id}/channels/{channel}/current/ws?interval={ms}`::

GET (OPTIONAL) `/devices/{id}/channels/{channel}/measurements/ws?interval={ms}`::

GET (REQUIRED) `/devices/{id}/channels/{channel}/out`::
    Query the status of the channel `channel` of device with the id `id`.
    Returns a boolean value.

PUT (REQUIRED) `/devices/{id}/channels/{channel}/out`::
    Sets the status of the channel `channel` of device with the id `id`.
    Accepts a boolean value.

GET (REQUIRED) `/devices/{id}/channels/{channel}/ocp`::

PUT (REQUIRED) `/devices/{id}/channels/{channel}/ocp`::

GET (REQUIRED) `/devices/{id}/channels/{channel}/ovp`::

PUT (REQUIRED) `/devices/{id}/channels/{channel}/ovp`::

== Authors

Maintained by Stefan Tatschner <stefan@rumpelsepp.org>.
The Git repository is hosted here: https://git.sr.ht/~rumpelsepp/opennetzteil

== License

This document published under the Attribution-ShareAlike 4.0 International license.
The license text is availabe here: https://creativecommons.org/licenses/by-sa/4.0/

D _specs/penlog.7.adoc => _specs/penlog.7.adoc +0 -195
@@ 1,195 0,0 @@
= penlog(7)
:doctype:    manpage
:man source: penlog

== Name

penlog - An abstract and machine readable logging format

== Specification

The PENLog logging format is intended to be used as a generic and reusable data format for measurement data.
The penlog format specifies an abstract data format consisting of various fields with data and metadata.
The abstract penlog format can be mapped to multiple output formats, for instance `json`, or `hr`, …
All available output formats are explained below.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

=== Abstract Logging Format

The penlog structured logging format consists of the following fields.
Unset fields which are considered optional MUST be absent.

`component` (string, OPTIONAL)::
    The component, e.g. software module, which has issued the log message.
    In absence, an implementation SHOULD pull the content of the environment variable `PENLOG_COMPONENT` and MUST set it to `root` as a fallback.

`data` (string, REQUIRED)::
    The log message as an UTF-8 string.

`host` (string, OPTIONAL)::
    The hostname of the machine who generated the messages.
    This field is OPTIONAL, since it is missing in the human readable format.
    It is RECOMMENDED that implementations include this field, as it increases reproducability of logging data.

`id` (string, OPTIONAL)::
    A unique message identifier.

`line` (string, OPTIONAL)::
    Information about the file and line number where this log entry was generated.
    The information MUST be in the form `filename:number`.
    `filename` can be an absolute or relative path, or a filename.

`priority` (int, OPTIONAL)::
    This field can be used to optionally set the priority.
    For priorities, the syslog priorities are used as defined by RFC5424.
    Implementations can indicate priorities by e.g. a separate color.

`stacktrace` (string, OPTIONAL)::
    Implementations can optionally include a stacktrace.
    This could be useful for debugging if fatal errors occur.
    Stacktraces are very specific to the used programming language, e.g. python or go.
    Thus, this field is just an unstructured string.

`tags` (list[string], OPTIONAL)::
    To each log entry a custom list of tags can be applied.
    For instance: `["autogenerated", "pre-test", "post-test", …]`.
    Tags MAY be key value pairs, separated by `=`.

`timestamp` (string, REQUIRED)::
    ISO8601 string of the current date.

`type` (string, REQUIRED)::
    The type field is a free field which can be used to assign a particular message type.

Custom fields can be added freely, in other words, additional custom fields are OPTIONAL.
Their post-processing and tooling around these custom fields is up to the developer and MUST be ignored by generic converters.

=== JSON Format (json)

A penlog log file stored on disk is typically stored in the `json` output format. 
The tool `hr(1)` is intended to be used -- similar to `cat(1)` -- for viewing penlog data in the `json` output format.
If encoding of a log message fails, the component MUST be set to `JSON`, the type to `ERROR`, and the error message MUST be included in `data`.

The `json` format consists of a verbatim sequence of the described JSON objects.
Each JSON object MUST be present at one line, separated by `\n` (ascii 0x0a).
In order to keep decoding simple and line based, no JSON arrays or virtual, endless JSON structures are employed.

=== JSON pretty (json-pretty)

The `json` format forces every JSON object to appear in a single line.
The `json-pretty` format provides an indented, more readable json form for debugging purposes.
The actual content of `json` and `json-pretty` is the same.
It is adviced to use `json` for data processing pipelines due to less overhead.

=== Human Readable Format (hr)

The syntax of the human readable format looks like the following.
Curly braces indicate a field from the JSON format.
If a field is empty it expands to an zero length string; if `id`, `line`, `tags`, or `stacktrace` are not availabe, the whole line is omitted.
A verbatim curly brace brace is expressed with two ones: `{{` means `{`.

    {timestamp} {{{component}}} [{type}]: {prio-prefix} {data}
       -> id  : {id}
       -> line: {line}
       -> tags: {tags}
       -> stacktrace:
       | {stacktrace}

    The RECOMMENDED timestamp format is Go's `StampMilli` format as defined to `Jan _2 15:04:05.000`.

    The `component` and `type` fields MUST be padded or truncated that the colons, `:`, in every single line are perfectly aligned.

    The actual log message.
    It MAY be truncated to fit in the current terminal size.
    When it is truncated an ellipsis character (`…`) MUST be appended to indicate the truncation for the user,

    The optional unique message identifier.

    The optional filename and line number where this log entry origins from.

    The optional stacktrace where this log entry origins from.

    An optional priority prefix.
    It is RECOMMENDED to indicate message priorities via colors.
    If colors are not available it MAY be desireable to indicate the priority via a short prefix.
    The prefixes are enclosed by brackets `[` and `]`: `E` `A`, `C`, `e`, `w`, `n`, `i`, `d`.
    These letters stand for: emergency, alert, critical, error, warning, notice, info, debug.

    The optional tags as comma separated values.

=== Tiny Human Readable Format (hr-tiny)

The `hr-tiny` format is the same as `hr` except that `component` and `type` are omitted.

    Apr  2 12:48:08.906: Starting tshark with
    Apr  2 12:48:09.583: Doing stuff

=== Example

    Apr  2 12:48:08.906 {scanner } [message]: Starting tshark with
    Apr  2 12:48:09.583 {moncay  } [message]: Doing stuff

If a JSON line cannot be decoded, the faulty text MUST be included in messages of type `ERROR` and component `JSON`:

    $ python -c "import foo" 2>&1 | hr
    Jun 16 08:19:01.305 {JSON    } [ERROR   ]: Traceback (most recent call last):
    Jun 16 08:19:01.305 {JSON    } [ERROR   ]:   File "<string>", line 1, in <module>
    Jun 16 08:19:01.305 {JSON    } [ERROR   ]: ModuleNotFoundError: No module named 'foo'

== Environment Variables

The following environment variables MAY be understood by penlog implementations.
The supported datatypes are `string` and `bool`.
A `bool` is a special string consisting of either `t, T, true, TRUE, 1` or `f, F, false, FALSE, 0`.

    If no component is set, the `component` field MAY be set via the `PENLOG_COMPONENT` variable at the scope of an operating system process.

    If this environment variable is set, implementations SHOULD emit filenames with line numbers via the `line` field.

    If this environment variable is set, implementations SHOULD provide stacktraces via the `stacktrace` field.

`PENLOG_OUTPUT` (string)::
    A switch for implementations to choose from several output forms.
    Available are: `hr`, `hr-tiny`, `json`, `json-pretty`, `systemd`.

`PENLOG_LOGLEVEL` (string)::
    In order to limit the emitted logging messages, loglevels MAY be supported.
    If a library supports filtering based on loglevels, it MUST check this environment variable.
    The supported values are `critical`, `error`, `warning`, `notice`, `info`, `debug`.
    The default MUST be `debug`.
    A message MUST omitted if its `priority` field contains a value greater than `PENLOG_LOGLEVEL`.
    A mapping between these strings and integer values is availabe in RFC5424.

== See Also

hr(1), penlog-best-practice(7)

== Bugs

This project is maintained on Github: https://github.com/Fraunhofer-AISEC/penlog.

== Authors

Current maintainers are:

* Stefan Tatschner <stefan@rumpelsepp.org>
* Tobias Specht

== License

This document is published under the Apache-2.0 license.
The license of the code can be obtained from the Git repository.

D _stuff/bookmarks.adoc => _stuff/bookmarks.adoc +0 -121
@@ 1,121 0,0 @@
= Bookmarks

Random stuff I found on the internet…

* 2020-08-23: https://degoogle.jmoore.dev/[degoogle | A huge list of alternatives to Google products. Privacy tips, tricks, and links.]
* 2020-08-17: https://yalantis.com/blog/speed-up-json-encoding-decoding/[How to Speed Up JSON Encoding and Decoding in Golang]
* 2020-08-15: https://peercalls.com/[Peer Calls - Video calls to anybody in the world with a private direct connection]
* 2020-08-09: https://rarehistoricalphotos.com/hans-hildenbrand-german-front-in-rare-color-photos-1914-1918/[Hans Hildenbrand: The German front in rare color photos, 1914-1918 - Rare Historical Photos]
* 2020-07-18: https://arxiv.org/abs/2005.14242[[2005.14242] The Impact of a Major Security Event on an Open Source Project: The Case of OpenSSL]
* 2020-07-17: https://arxiv.org/pdf/2005.14242.pdf[]
* 2020-07-15: https://yasoob.me/posts/understanding-and-writing-jpeg-decoder-in-python/[Understanding and Decoding a JPEG Image using Python - Yasoob Khalid]
* 2020-06-26: https://git.sr.ht/~kennylevinsen/seatd[~kennylevinsen/seatd - sourcehut git]
* 2020-06-26: https://github.com/chubin/wttr.in[GitHub - chubin/wttr.in: The right way to check the weather]
* 2020-06-23: https://s-matyukevich.github.io/raspberry-pi-os/[Learning operating system development using Linux kernel and Raspberry Pi | raspberry-pi-os]
* 2020-06-17: https://mdlayher.com/blog/go-generics-draft-design-building-a-hashtable/[Go generics draft design: building a hashtable · Matt Layher]
* 2020-06-17: https://blog.golang.org/generics-next-step[The Next Step for Generics - The Go Blog]
* 2020-06-17: http://silas.net.br/codereading/netbsd-code.html[NetBSD code study - Silas' website]
* 2020-06-13: https://github.com/Fizzadar/pyinfra[GitHub - Fizzadar/pyinfra: pyinfra automates infrastructure super fast at massive scale. It can be used for ad-hoc command execution, service deployment, configuration management and more.]
* 2020-06-12: https://www.kino-zeit.de/film-kritiken-trailer-streaming/tread-2019[Tread (2019) | Film, Trailer, Kritik]
* 2020-06-12: http://www.esa.int/ESA_Multimedia/Images/2020/06/Global_air_pollution_maps_now_available[ESA - Global air pollution maps now available ]
* 2020-06-12: http://asciiflow.com/[ASCIIFlow Infinity]
* 2020-06-12: https://smusamashah.github.io/text-to-diagram[Online text to diagram tools | SUS]
* 2020-06-04: https://blog.codavel.com/quic-vs-tcptls-and-why-quic-is-not-the-next-big-thing[QUIC vs TCP+TLS and why QUIC is not the next big thing]
* 2020-06-04: https://lwn.net/SubscriberLink/821817/5a9be9eec66afdff/[Free user space for non-graphics drivers [LWN.net]]
* 2020-06-04: https://www.phoronix.com/scan.php?page=news_item&px=Linux-Kernel-Deprecates-80-Col[The Linux Kernel Deprecates The 80 Character Line Coding Style - Phoronix]
* 2020-06-04: http://www.linusakesson.net/programming/tty/[The TTY demystified]
* 2020-06-04: https://notcurses.com/[notcurses]
* 2020-06-04: https://engineering.shopify.com/blogs/engineering/understanding-programs-using-graphs[Understanding Programs Using Graphs – Shopify Engineering]
* 2020-06-04: https://ketancmaheshwari.github.io/posts/2020/05/24/SMC18-Data-Challenge-4.html[Running Awk in parallel to process 256M records]
* 2020-06-04: http://www.os2museum.com/wp/those-win9x-crashes-on-fast-machines/[Those Win9x Crashes on Fast Machines…]
* 2020-06-04: https://www.europarl.europa.eu/doceo/document/E-9-2020-002042-ASW_EN.html[Answer for question E-002042/20]
* 2020-06-04: https://sqlite.org/forum/forumpost/e7e828bb6f[SQLite Forum: Caution:  clang-11.0.0 miscompiles SQLite]
* 2020-05-28: https://www.raspberrypi.org/blog/8gb-raspberry-pi-4-on-sale-now-at-75/[8GB Raspberry Pi 4 on sale now at $75 - Raspberry Pi]
* 2020-05-28: https://lwn.net/SubscriberLink/821412/860dd67076078e90/[Some sessions from the Python Language Summit LWN.net]
* 2020-05-28: https://www.collabora.com/news-and-blog/blog/2020/05/27/using-regmaps-to-make-linux-drivers-more-generic/[Using regmaps to make Linux drivers more generic]
* 2020-05-26: https://reverseengineering.stackexchange.com/questions/18380/extracting-compressed-firmware-nrv-for-analysis[unpacking - Extracting compressed firmware (NRV) for analysis - Reverse Engineering Stack Exchange]
* 2020-05-26: http://lea.verou.me/2020/05/todays-javascript-from-an-outsiders-perspective/[Today’s Javascript, from an outsider’s perspective | Lea Verou]
* 2020-05-26: https://jcg.re/blog/quick-overview-matrix-cross-signing/[Matrix X-Signing]
* 2020-05-25: https://meltware.com/2019/01/16/gccgo-benchmarks-2019.html[Gccgo in 2019: Faster, but still yielding (much) slower code than the standard compiler | Meltware]
* 2020-05-25: https://dayzerosec.com/posts/adventures-of-porting-musl-to-ps4/[Adventures of porting MUSL to PS4 - DAY[0]]
* 2020-05-25: https://news.ycombinator.com/item?id=23295975[Linus Torvalds has switched to AMD | Hacker News]
* 2020-05-25: https://www.integralist.co.uk/posts/python-asyncio/[Guide to Concurrency in Python with Asyncio ⋆ Mark McDonnell]
* 2020-05-25: https://www.youtube.com/watch?v=Bt-vmPC_-Ho&app=desktop[We can have nice things - YouTube]
* 2020-05-25: https://www.youtube.com/watch?v=NG0s3-s3whY&app=desktop[GopherCon 2018: Sugu Sougoumarane - How to Write a Parser in Go - YouTube]
* 2020-05-25: https://www.youtube.com/watch?v=HxaD_trXwRE&app=desktop[Lexical Scanning in Go - Rob Pike - YouTube]
* 2020-05-25: https://www.bleepingcomputer.com/news/security/ebay-port-scans-visitors-computers-for-remote-access-programs/[eBay port scans visitors' computers for remote access programs]
* 2020-05-25: https://brennan.io/2020/05/24/userspace-cooperative-multitasking/[Implementing simple cooperative threads in C]
* 2020-05-25: https://nullprogram.com/blog/2020/05/24/[Latency in Asynchronous Python « null program]
* 2020-05-25: https://blog.stephenmarz.com/2020/05/20/assemblys-perspective/[Assembly&#8217;s Perspective of C &#8211; Stephen Marz]
* 2020-05-25: https://michael.stapelberg.ch/posts/2020-05-23-desk-setup/[stapelberg uses this: my 2020 desk setup]
* 2020-05-20: https://nullsweep.com/why-is-this-website-port-scanning-me/[Why is This Website Port Scanning me]
* 2020-05-20: https://blog.yossarian.net/2020/05/20/Things-I-hate-about-rust[Things I hate about Rust]
* 2020-05-20: https://www.mail-tester.com/[Newsletters spam test by mail-tester.com]
* 2020-05-20: https://marc.info/?l=openbsd-announce&m=158989783626149&w=2['OpenBSD 6.7 released - May 19, 2020' - MARC]
* 2020-05-20: https://lwn.net/SubscriberLink/820829/c11e2be9a35c871a/[The state of the AWK [LWN.net]]
* 2020-05-20: http://blog.kevmod.com/2020/05/python-performance-its-not-just-the-interpreter/[Python performance: it&#8217;s not just the interpreter &laquo; kmod&#039;s blog]
* 2020-05-20: https://smallstep.com/blog/ssh-agent-explained/[SSH Agent Explained]
* 2020-05-19: https://www.eff.org/deeplinks/2020/04/victory-icann-rejects-org-sale-private-equity-firm-ethos-capital[Victory! ICANN Rejects .ORG Sale to Private Equity Firm Ethos Capital | Electronic Frontier Foundation]
* 2020-05-19: https://www.usenix.org/sites/default/files/conference/protected-files/lisa19_maheshwari.pdf[Linux Productivity Tools]
* 2020-05-18: https://nwidger.github.io/blog/post/writing-an-nes-emulator-in-go-part-1/[Writing an NES emulator in Go, Part 1]
* 2020-05-15: https://frenxi.com/http-headers-you-dont-expect/[The HTTP headers you don't expect]
* 2020-05-14: https://marc.info/?l=openbsd-tech&m=158926407905492&w=2['WireGuard patchset for OpenBSD' - MARC]
* 2020-05-14: https://github.com/in3rsha/sha256-animation[GitHub - in3rsha/sha256-animation: Animation of the SHA-256 hash function in your terminal.]
* 2020-05-14: https://lwn.net/Articles/819452/[Making Emacs popular again [LWN.net]]
* 2020-05-14: https://lwn.net/Articles/819834/[Blocking userfaultfd() kernel-fault handling]
* 2020-05-14: https://lwn.net/Articles/820424/[Subinterpreters for Python]
* 2020-05-14: https://shouldiusethreads.com/[Should I use threads?]
* 2020-05-14: https://fgiesen.wordpress.com/2011/07/09/a-trip-through-the-graphics-pipeline-2011-index/[A trip through the Graphics Pipeline 2011: Index | The ryg blog]
* 2020-05-13: https://www.golem.de/news/3g-telekom-nennt-mehr-details-zur-umts-abschaltung-2005-148457.html[3G: Telekom nennt mehr Details zur UMTS-Abschaltung - Golem.de]
* 2020-05-13: https://github.com/spacerace/romfont[GitHub - spacerace/romfont: VGA and BIOS rom font extraction]
* 2020-05-13: https://wayland-book.com/[Introduction - The Wayland Protocol]
* 2020-05-13: https://lwn.net/SubscriberLink/820217/47ed80088c03b18d/[What's coming in Go 1.15]
* 2020-05-13: https://zserge.com/posts/containers/[Linux containers in a few lines of code]
* 2020-05-13: https://citizenlab.ca/2020/05/we-chat-they-watch/[We Chat, They Watch: How International Users Unwittingly Build up WeChat’s Chinese Censorship Apparatus - The Citizen Lab]
* 2020-05-13: https://github.com/Fraunhofer-AISEC/frankencert[GitHub - Fraunhofer-AISEC/frankencert: Continuation of the frankencert project with python-cryptography]
* 2020-05-13: https://medium.com/@mujjingun_23509/full-proof-that-c-grammar-is-undecidable-34e22dd8b664[Full Proof that C++ Grammar is Undecidable]
* 2020-05-13: http://osblog.stephenmarz.com/index.html[The Adventures of OS: Making a RISC-V Operating System using Rust]
* 2020-05-12: https://dev.to/anuj_bansal_/git-internal-architecture-o1j[Git internal architecture - DEV Community]
* 2020-05-12: https://blog.learngoprogramming.com/a-visual-guide-to-golang-memory-allocator-from-ground-up-e132258453ed[A visual guide to Go Memory Allocator from scratch (Golang)]
* 2020-05-12: https://blog.golang.org/ismmkeynote[Getting to Go: The Journey of Go&#39;s Garbage Collector - The Go Blog Search]
* 2020-05-12: https://medium.com/a-journey-with-go[A Journey With Go – Medium]
* 2020-05-12: https://unixism.net/loti/[Welcome to Lord of the io_uring &#8212; Lord of the io_uring  documentation]
* 2020-05-12: https://git.sr.ht/~trhd/dsac[DATA STRUCTURES AND ALGORITHMS FOR C]
* 2020-05-12: http://xyproblem.info[The XZ Problem]
* 2020-05-12: http://www.catb.org/esr/faqs/smart-questions.html[Asking Smart Questions]
* 2020-05-12: https://git-rebase.io[Learn to change history with git rebase!]
* 2020-05-12: https://git-send-email.io[Learn to use email with git!]
* 2020-05-12: https://useplaintext.email/[useplaintext email]
* 2020-05-12: https://cs144.github.io/[CS 144: Introduction to Computer Networking]
* 2020-05-12: https://toc.cryptobook.us/[A Graduate Course in Applied Cryptography]
* 2020-05-12: https://0xax.gitbooks.io/linux-insides/content/[Linux Insides Git Book]
* 2020-05-12: http://www.makelinux.net/books/lkd2/[Linux Kernel Development]
* 2020-05-12: https://blog.packagecloud.io/eng/2017/03/06/micro-optimizations-matter/[Micro-optimizations matter: preventing 20 million system calls]
* 2020-05-12: https://blog.packagecloud.io/eng/2016/02/29/how-does-strace-work/[How does strace work?]
* 2020-05-12: https://blog.packagecloud.io/eng/2016/04/05/the-definitive-guide-to-linux-system-calls/[The Definitive Guide to Linux System Calls] 
* 2020-05-12: http://syscalls.kernelgrok.com/[Another Syscall Table]
* 2020-05-12: https://filippo.io/linux-syscall-table/[Searchable Linux Syscall Table for x86 and x86_64]
* 2020-05-12: https://lwn.net/Articles/604515/[LWN -- Anatomy of a system call, part 2]
* 2020-05-12: https://lwn.net/Articles/604287/[LWN -- Anatomy of a system call, part 1]
* 2020-05-12: https://blog.packagecloud.io/eng/2017/02/06/monitoring-tuning-linux-networking-stack-sending-data/[Monitoring and Tuning the Linux Networking Stack: Sending Data]
* 2020-05-12: https://blog.packagecloud.io/eng/2016/06/22/monitoring-tuning-linux-networking-stack-receiving-data/[Monitoring and Tuning the Linux Networking Stack: Receiving Data]
* 2020-05-12: https://lwn.net/Articles/750845/[Accelerating networking with AF_XDP]
* 2020-05-12: https://github.com/leandromoreira/linux-network-performance-parameters#linux-network-queues-overview[Linux network queues overview]
* 2020-05-12: https://lwn.net/Articles/296738/[LWN -- The Kernel Hacker's Bookshelf UNIX Internals]
* 2020-05-12: https://gist.github.com/rumpelsepp/6a87bcee01939243f4b83fa5bd9a7d40
* 2020-05-12: http://fivelinesofcode.blogspot.de/2014/03/how-to-translate-virtual-to-physical.html
* 2020-05-12: https://www.kernel.org/doc/gorman/pdf/understand.pdf[Understanding The Linux Virtual Memory Manager]
* 2020-05-12: http://www.makelinux.net/ldd3/chp-15-sect-1[LDD3 -- Memory Management]
* 2020-05-12: http://www.tldp.org/LDP/tlk/mm/memory.html[TLDP -- Memory]
* 2020-05-12: http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/[How the Kernel Manages Your Memory]
* 2020-05-12: http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory/[Anatomy of a Program in Memory]
* 2020-05-12: http://duartes.org/gustavo/blog/post/memory-translation-and-segmentation/[Memory Translation and Segmentation]
* 2020-05-12: https://blog.learngoprogramming.com/a-visual-guide-to-golang-memory-allocator-from-ground-up-e132258453ed[A visual guide to Go Memory Allocator from scratch (Golang)]
* 2020-05-12: http://derekmolloy.ie/writing-a-linux-kernel-module-part-1-introduction/[Writing a Kernel Module Tutorial for Beaglebone]
* 2020-05-12: http://www.makelinux.net/kernel_map/[Interactive Kernel Map]
* 2020-05-12: https://www.kernel.org/doc/Documentation/x86/boot.txt[Linux Kernel x86 Boot Protocol]
* 2020-05-12: http://duartes.org/gustavo/blog/post/kernel-boot-process/[The Kernel Boot Process ]
* 2020-05-12: https://neilkakkar.com/unix.html[How Unix Works: Become a Better Software Engineer]
* 2020-05-12: https://finnoleary.net/kernel-code.html["Dissecting linux kernel code" or "That syscall shouldn't give that error code!"]
* 2020-05-12: http://maplant.com/unwind.html[Sticking a Hand Through Time: Adventures on the call stack]
* 2020-05-12: http://maplant.com/gc.html[Writing a Simple Garbage Collector in C]

D _stuff/list2adoc => _stuff/list2adoc +0 -44
@@ 1,44 0,0 @@

set -u

# $1: url
gettitle() {
    curl -Ls "$1" | grep -iPo '(?<=<title>)(.*)(?=</title>)'

main() {
    local infile

    while read line; do
        if [[ ! "$line" =~ ^\*.* ]]; then
            echo "$line"

        local url
        local title
        local rfc

        line="${line//\* /}"
        if [[ "$line" =~ ^rfc[0-9]+ ]]; then
            url="$(echo "${line//\* /}" | sed 's/\s+$//')"

        title="$(gettitle "$url")"

        if [[ "$rfc" != "" ]]; then
            echo "* $url[$(echo $rfc | awk '{ print toupper($0) }')] -- $(echo $title | sed 's/.*-\s//')"
            echo "* $url[$title]"
    done < "$infile"

main "$@"

D _stuff/networking.adoc => _stuff/networking.adoc +0 -27
@@ 1,27 0,0 @@
== E-Mail

* https://tools.ietf.org/html/rfc2045[RFC2045] -- Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
* https://tools.ietf.org/html/rfc2046[RFC2046] -- Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types
* https://tools.ietf.org/html/rfc2047[RFC2047] -- MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for Non-ASCII Text
* https://tools.ietf.org/html/rfc2183[RFC2183] -- Communicating Presentation Information in Internet Messages: The Content-Disposition Header Field
* https://tools.ietf.org/html/rfc5321[RFC5321] -- Simple Mail Transfer Protocol
* https://tools.ietf.org/html/rfc5322[RFC5322] -- Internet Message Format

== IPv6

* https://tools.ietf.org/html/rfc4193[RFC4193] -- Unique Local IPv6 Unicast Addresses
* https://tools.ietf.org/html/rfc4862[RFC4862] -- IPv6 Stateless Address Autoconfiguration
* https://tools.ietf.org/html/rfc6890[RFC6890] -- Special-Purpose IP Address Registries
* https://tools.ietf.org/html/rfc7078[RFC7078] -- Distributing Address Selection Policy Using DHCPv6
* https://tools.ietf.org/html/rfc8028[RFC8028] -- First-Hop Router Selection by Hosts in a Multi-Prefix Network
* https://tools.ietf.org/html/rfc8043[RFC8043] -- Source-Address-Dependent Routing and Source Address Selection for IPv6 Hosts: Overview of the Problem Space
* https://tools.ietf.org/html/rfc8415[RFC8415] -- Dynamic Host Configuration Protocol for IPv6 (DHCPv6)


* https://www.youtube.com/watch?v=CtsBawwGwns[Netdev 0x13 - QUIC Tutorial - YouTube]
* https://www.youtube.com/watch?v=ald5tP2VeGk[Netdev 0x13 - Accelerating QUIC via Hardware Offloads Through a Socket Interface - YouTube]

== TLS

* https://tls13.ulfheim.net[The Illustrated TLS 1.3 Connection: Every Byte Explained]

D _stuff/networking.adoc.tpl => _stuff/networking.adoc.tpl +0 -27
@@ 1,27 0,0 @@
== E-Mail

* rfc2045
* rfc2046
* rfc2047
* rfc2183
* rfc5321
* rfc5322

== IPv6

* rfc4193
* rfc4862
* rfc6890
* rfc7078
* rfc8028
* rfc8043
* rfc8415


* https://www.youtube.com/watch?v=CtsBawwGwns
* https://www.youtube.com/watch?v=ald5tP2VeGk

== TLS

* https://tls13.ulfheim.net

A archetypes/default.md => archetypes/default.md +6 -0
@@ 0,0 1,6 @@
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true

D assets/css/asciidoc-pygments.css => assets/css/asciidoc-pygments.css +0 -69
@@ 1,69 0,0 @@
pre.rouge, pre.pygments .hll { background-color: #ffffcc }
pre.rouge, pre.rouge code, pre.pygments, pre.pygments code { background: #f8f8f8; }
pre.rouge .c, pre.pygments .tok-c { color: #408080; font-style: italic } /* Comment */
pre.rouge .err, pre.pygments .tok-err { border: 1px solid #FF0000 } /* Error */
pre.rouge .k, pre.pygments .tok-k { color: #008000; font-weight: bold } /* Keyword */
pre.rouge .o, pre.pygments .tok-o { color: #666666 } /* Operator */
pre.rouge .ch, pre.pygments .tok-ch { color: #408080; font-style: italic } /* Comment.Hashbang */
pre.rouge .cm, pre.pygments .tok-cm { color: #408080; font-style: italic } /* Comment.Multiline */
pre.rouge .cp, pre.pygments .tok-cp { color: #BC7A00 } /* Comment.Preproc */
pre.rouge .cpf, pre.pygments .tok-cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
pre.rouge .c1, pre.pygments .tok-c1 { color: #408080; font-style: italic } /* Comment.Single */
pre.rouge .cs, pre.pygments .tok-cs { color: #408080; font-style: italic } /* Comment.Special */
pre.rouge .gd, pre.pygments .tok-gd { color: #A00000 } /* Generic.Deleted */
pre.rouge .ge, pre.pygments .tok-ge { font-style: italic } /* Generic.Emph */
pre.rouge .gr, pre.pygments .tok-gr { color: #FF0000 } /* Generic.Error */
pre.rouge .gh, pre.pygments .tok-gh { color: #000080; font-weight: bold } /* Generic.Heading */
pre.rouge .gi, pre.pygments .tok-gi { color: #00A000 } /* Generic.Inserted */
pre.rouge .go, pre.pygments .tok-go { color: #888888 } /* Generic.Output */
pre.rouge .gp, pre.pygments .tok-gp { color: #000080; font-weight: bold } /* Generic.Prompt */
pre.rouge .gs, pre.pygments .tok-gs { font-weight: bold } /* Generic.Strong */
pre.rouge .gu, pre.pygments .tok-gu { color: #800080; font-weight: bold } /* Generic.Subheading */
pre.rouge .gt, pre.pygments .tok-gt { color: #0044DD } /* Generic.Traceback */
pre.rouge .kc, pre.pygments .tok-kc { color: #008000; font-weight: bold } /* Keyword.Constant */
pre.rouge .kd, pre.pygments .tok-kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
pre.rouge .kn, pre.pygments .tok-kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
pre.rouge .kp, pre.pygments .tok-kp { color: #008000 } /* Keyword.Pseudo */
pre.rouge .kr, pre.pygments .tok-kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
pre.rouge .kt, pre.pygments .tok-kt { color: #B00040 } /* Keyword.Type */
pre.rouge .m, pre.pygments .tok-m { color: #666666 } /* Literal.Number */
pre.rouge .s, pre.pygments .tok-s { color: #BA2121 } /* Literal.String */
pre.rouge .na, pre.pygments .tok-na { color: #7D9029 } /* Name.Attribute */
pre.rouge .nb, pre.pygments .tok-nb { color: #008000 } /* Name.Builtin */
pre.rouge .nc, pre.pygments .tok-nc { color: #0000FF; font-weight: bold } /* Name.Class */
pre.rouge .no, pre.pygments .tok-no { color: #880000 } /* Name.Constant */
pre.rouge .nd, pre.pygments .tok-nd { color: #AA22FF } /* Name.Decorator */
pre.rouge .ni, pre.pygments .tok-ni { color: #999999; font-weight: bold } /* Name.Entity */
pre.rouge .ne, pre.pygments .tok-ne { color: #D2413A; font-weight: bold } /* Name.Exception */
pre.rouge .nf, pre.pygments .tok-nf { color: #0000FF } /* Name.Function */
pre.rouge .nl, pre.pygments .tok-nl { color: #A0A000 } /* Name.Label */
pre.rouge .nn, pre.pygments .tok-nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
pre.rouge .nt, pre.pygments .tok-nt { color: #008000; font-weight: bold } /* Name.Tag */
pre.rouge .nv, pre.pygments .tok-nv { color: #19177C } /* Name.Variable */
pre.rouge .ow, pre.pygments .tok-ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
pre.rouge .w, pre.pygments .tok-w { color: #bbbbbb } /* Text.Whitespace */
pre.rouge .mb, pre.pygments .tok-mb { color: #666666 } /* Literal.Number.Bin */
pre.rouge .mf, pre.pygments .tok-mf { color: #666666 } /* Literal.Number.Float */
pre.rouge .mh, pre.pygments .tok-mh { color: #666666 } /* Literal.Number.Hex */
pre.rouge .mi, pre.pygments .tok-mi { color: #666666 } /* Literal.Number.Integer */
pre.rouge .mo, pre.pygments .tok-mo { color: #666666 } /* Literal.Number.Oct */
pre.rouge .sa, pre.pygments .tok-sa { color: #BA2121 } /* Literal.String.Affix */
pre.rouge .sb, pre.pygments .tok-sb { color: #BA2121 } /* Literal.String.Backtick */
pre.rouge .sc, pre.pygments .tok-sc { color: #BA2121 } /* Literal.String.Char */
pre.rouge .dl, pre.pygments .tok-dl { color: #BA2121 } /* Literal.String.Delimiter */
pre.rouge .sd, pre.pygments .tok-sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
pre.rouge .s2, pre.pygments .tok-s2 { color: #BA2121 } /* Literal.String.Double */
pre.rouge .se, pre.pygments .tok-se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
pre.rouge .sh, pre.pygments .tok-sh { color: #BA2121 } /* Literal.String.Heredoc */
pre.rouge .si, pre.pygments .tok-si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
pre.rouge .sx, pre.pygments .tok-sx { color: #008000 } /* Literal.String.Other */
pre.rouge .sr, pre.pygments .tok-sr { color: #BB6688 } /* Literal.String.Regex */
pre.rouge .s1, pre.pygments .tok-s1 { color: #BA2121 } /* Literal.String.Single */
pre.rouge .ss, pre.pygments .tok-ss { color: #19177C } /* Literal.String.Symbol */
pre.rouge .bp, pre.pygments .tok-bp { color: #008000 } /* Name.Builtin.Pseudo */
pre.rouge .fm, pre.pygments .tok-fm { color: #0000FF } /* Name.Function.Magic */
pre.rouge .vc, pre.pygments .tok-vc { color: #19177C } /* Name.Variable.Class */
pre.rouge .vg, pre.pygments .tok-vg { color: #19177C } /* Name.Variable.Global */
pre.rouge .vi, pre.pygments .tok-vi { color: #19177C } /* Name.Variable.Instance */
pre.rouge .vm, pre.pygments .tok-vm { color: #19177C } /* Name.Variable.Magic */
pre.rouge .il, pre.pygments .tok-il { color: #666666 } /* Literal.Number.Integer.Long */

D assets/css/asciidoctor-default.css => assets/css/asciidoctor-default.css +0 -426
@@ 1,426 0,0 @@
/* Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
/* Uncomment @import statement to use as custom stylesheet */
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
a:focus{outline:thin dotted}
h1{font-size:2em;margin:.67em 0}
abbr[title]{border-bottom:1px dotted}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
a img{border:0}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
blockquote cite::before{content:"\2014 \0020"}
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
table thead,table tfoot{background:#f7f8f7}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt{background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed}
pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
em em{font-style:normal}
strong strong{font-weight:400}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq b:not(.caret),.menuref{font-weight:inherit}
.menuseq b.caret{font-size:1.25em;line-height:.8}
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
b.button::before{content:"[";padding:0 3px 0 2px}
b.button::after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span::before{content:"\00a0\2013\00a0"}
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber::after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2 ul ul{padding-left:1.25em}
#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
.sect1+.sect1{border-top:1px solid #e7e7e9}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6)}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock>.content>pre{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;overflow-x:auto;padding:1em;font-size:.8125em}
@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}
@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}
.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class="highlight"],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8}
.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}
.listingblock:hover code[data-lang]::before{display:block}
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
pre.prettyprint .linenums{line-height:1.45;margin-left:2em}
pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}
pre.prettyprint li code[data-lang]::before{opacity:1}
pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}
table.linenotable td.code{padding-left:.75em}
table.linenotable td.linenos{border-right:1px solid currentColor;opacity:.35;padding-right:.5em}
pre.pygments .lineno{border-right:1px solid currentColor;opacity:.35;display:inline-block;margin-right:.75em}
pre.pygments .lineno::before{content:"";margin-right:-.125em}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
.verseblock{margin:0 1em 1.25em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;text-align:left;margin-right:0}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px}
table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0}
table.frame-sides{border-width:0 1px}
table.frame-topbot,table.frame-ends{border-width:1px 0}
table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd),table.stripes-even tr:nth-of-type(even),table.stripes-hover tr:hover{background:#f8f8f7}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
.unstyled dl dt{font-weight:400;font-style:normal}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
.colist td:not([class]):first-child img{max-width:none}
.colist td:not([class]):last-child{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
.imageblock.left{margin:.25em .625em 1.25em 0}
.imageblock.right{margin:.25em 0 1.25em .625em}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
a.image object{pointer-events:none}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
.gist .file-data>table td.line-data{width:99%}
a span.icon>.fa{cursor:inherit}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
@page{margin:1.25cm .75cm}
@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]::after{content:" (" attr(title) ")"}
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span::before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]::before{display:block}
#footer{padding:0 .9375em}
@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem}
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}

D assets/css/main.scss => assets/css/main.scss +0 -53
@@ 1,53 0,0 @@
# Only the main Sass file needs front matter (the dashes are enough)
@charset "utf-8";

// Our variables
// Maybe some of them are unused now, due to asciidoctor... :)
$base-font-family: "Roboto Mono", "Liberation Mono", monospace;
$base-font-size:   16px;
$base-font-weight: 400;
$small-font-size:  $base-font-size * 0.875;
$base-line-height: 1.5;

$spacing-unit:     30px;

$text-color:       #111;
$background-color: #fdfdfd;
$brand-color:      #2a7ae2;

$grey-color:       #828282;
$grey-color-light: lighten($grey-color, 40%);
$grey-color-dark:  darken($grey-color, 25%);

// Width of the content area
$content-width:    900px;

$on-palm:          600px;
$on-laptop:        900px;

// Use media queries like this:
// @include media-query($on-palm) {
//     .wrapper {
//         padding-right: $spacing-unit / 2;
//         padding-left: $spacing-unit / 2;
//     }
// }
@mixin media-query($device) {
    @media screen and (max-width: $device) {

// Import partials from `sass_dir` (defaults to `_sass`)

D assets/favicon/android-icon-144x144.png => assets/favicon/android-icon-144x144.png +0 -0

D assets/favicon/android-icon-192x192.png => assets/favicon/android-icon-192x192.png +0 -0

D assets/favicon/android-icon-36x36.png => assets/favicon/android-icon-36x36.png +0 -0

D assets/favicon/android-icon-48x48.png => assets/favicon/android-icon-48x48.png +0 -0

D assets/favicon/android-icon-72x72.png => assets/favicon/android-icon-72x72.png +0 -0

D assets/favicon/apple-icon-114x114.png => assets/favicon/apple-icon-114x114.png +0 -0

D assets/favicon/apple-icon-120x120.png => assets/favicon/apple-icon-120x120.png +0 -0

D assets/favicon/apple-icon-144x144.png => assets/favicon/apple-icon-144x144.png +0 -0

D assets/favicon/apple-icon-152x152.png => assets/favicon/apple-icon-152x152.png +0 -0

D assets/favicon/apple-icon-180x180.png => assets/favicon/apple-icon-180x180.png +0 -0

D assets/favicon/apple-icon-57x57.png => assets/favicon/apple-icon-57x57.png +0 -0

D assets/favicon/apple-icon-60x60.png => assets/favicon/apple-icon-60x60.png +0 -0

D assets/favicon/apple-icon-72x72.png => assets/favicon/apple-icon-72x72.png +0 -0

D assets/favicon/apple-icon-76x76.png => assets/favicon/apple-icon-76x76.png +0 -0

D assets/favicon/apple-icon-precomposed.png => assets/favicon/apple-icon-precomposed.png +0 -0

D assets/favicon/apple-icon.png => assets/favicon/apple-icon.png +0 -0

D assets/favicon/browserconfig.xml => assets/favicon/browserconfig.xml +0 -2
@@ 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>
\ No newline at end of file

D assets/favicon/favicon-96x96.png => assets/favicon/favicon-96x96.png +0 -0

D assets/favicon/manifest.json => assets/favicon/manifest.json +0 -41
@@ 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"
\ No newline at end of file

D assets/favicon/ms-icon-144x144.png => assets/favicon/ms-icon-144x144.png +0 -0

D assets/favicon/ms-icon-150x150.png => assets/favicon/ms-icon-150x150.png +0 -0

D assets/favicon/ms-icon-310x310.png => assets/favicon/ms-icon-310x310.png +0 -0

D assets/favicon/ms-icon-70x70.png => assets/favicon/ms-icon-70x70.png +0 -0

D assets/img/Screenshot-2016-05-15-15:54:18.png => assets/img/Screenshot-2016-05-15-15:54:18.png +0 -0

A assets/main.scss => assets/main.scss +163 -0
@@ 0,0 1,163 @@
html {
    font-family: sans-serif;

body {
    max-width: 920px;
    margin: 0 auto;
    padding: 1rem;

h1 {
    margin-top: 0;
    font-size: 1.5rem;

.main-header {
    a, a:visited {
        color: inherit;
    nav {
        margin-bottom: 1.5rem;

.index {
    display: flex;
    flex-direction: row;

    .article-list {
        flex-grow: 1;

        article {
            margin-bottom: 1rem;

        time {
            display: block;
            color: #333;

.single {
    article {
        margin: 0 auto;
        max-width: 720px;
        line-height: 1.3;

        img, video {
            display: block;
            margin: 0 auto;
            max-width: 75%;

            @media(max-width: 640px) {
                max-width: calc(100% - 2rem);

        .comment {
            margin: 2rem auto 0;
            max-width: 80%;
            color: #333;

    .footnotes {
        font-size: 0.85rem;

footer {
    margin-top: 2rem;
    text-align: center;
    font-size: 0.8rem;
    color: #333;

.float-img {
    float: right;
    display: inline;
    padding-left: 1rem;

    @media(max-width: 640px) {
        display: block;
        float: none;
        padding-left: inherit;

pre {
    background-color: #eee;
    padding: 0.25rem 1rem;
    margin: 0 -1rem;
    max-width: 100%;
    overflow-x: auto;

    .hll { background-color: #ffffcc }
    .c { color: #408080; font-style: italic } /* Comment */
    .err { border: 1px solid #FF0000 } /* Error */
    .k { color: #008000; font-weight: bold } /* Keyword */
    .o { color: #666666 } /* Operator */
    .cm { color: #408080; font-style: italic } /* Comment.Multiline */
    .cp { color: #BC7A00 } /* Comment.Preproc */
    .c1 { color: #408080; font-style: italic } /* Comment.Single */
    .cs { color: #408080; font-style: italic } /* Comment.Special */
    .gd { color: #A00000 } /* Generic.Deleted */
    .ge { font-style: italic } /* Generic.Emph */
    .gr { color: #FF0000 } /* Generic.Error */
    .gh { color: #000080; font-weight: bold } /* Generic.Heading */
    .gi { color: #00A000 } /* Generic.Inserted */
    .go { color: #808080 } /* Generic.Output */
    .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
    .gs { font-weight: bold } /* Generic.Strong */
    .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
    .gt { color: #0040D0 } /* Generic.Traceback */
    .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
    .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
    .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
    .kp { color: #008000 } /* Keyword.Pseudo */
    .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
    .kt { color: #B00040 } /* Keyword.Type */
    .m { color: #666666 } /* Literal.Number */
    .s { color: #BA2121 } /* Literal.String */
    .na { color: #7D9029 } /* Name.Attribute */
    .nb { color: #008000 } /* Name.Builtin */
    .nc { color: #0000FF; font-weight: bold } /* Name.Class */
    .no { color: #880000 } /* Name.Constant */
    .nd { color: #AA22FF } /* Name.Decorator */
    .ni { color: #999999; font-weight: bold } /* Name.Entity */
    .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
    .nf { color: #0000FF } /* Name.Function */
    .nl { color: #A0A000 } /* Name.Label */
    .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
    .nt { color: #008000; font-weight: bold } /* Name.Tag */
    .nv { color: #19177C } /* Name.Variable */
    .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
    .w { color: #bbbbbb } /* Text.Whitespace */
    .mf { color: #666666 } /* Literal.Number.Float */
    .mh { color: #666666 } /* Literal.Number.Hex */
    .mi { color: #666666 } /* Literal.Number.Integer */
    .mo { color: #666666 } /* Literal.Number.Oct */
    .sb { color: #BA2121 } /* Literal.String.Backtick */
    .sc { color: #BA2121 } /* Literal.String.Char */
    .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
    .s2 { color: #BA2121 } /* Literal.String.Double */
    .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
    .sh { color: #BA2121 } /* Literal.String.Heredoc */
    .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
    .sx { color: #008000 } /* Literal.String.Other */
    .sr { color: #BB6688 } /* Literal.String.Regex */
    .s1 { color: #BA2121 } /* Literal.String.Single */
    .ss { color: #19177C } /* Literal.String.Symbol */
    .bp { color: #008000 } /* Name.Builtin.Pseudo */
    .vc { color: #19177C } /* Name.Variable.Class */
    .vg { color: #19177C } /* Name.Variable.Global */
    .vi { color: #19177C } /* Name.Variable.Instance */
    .il { color: #666666 } /* Literal.Number.Integer.Long */

.text-center {
    text-align: center;

A config.toml => config.toml +10 -0
@@ 0,0 1,10 @@
baseURL = "http://rumpelsepp.org/"
languageCode = "en-us"
title = "~rumpelsepp"
pygmentsUseClasses = true

date  = [":filename", ":default"]

unsafe = true

R specs.adoc => content/_index.html +1 -3
@@ 1,5 1,3 @@
layout: specs
title: ~rumpelsepp

= Specs

R _posts/2014-09-22-how-to-download-rtmp-streams.adoc => content/blog/2014-09-22-how-to-download-rtmp-streams.md +21 -21
@@ 1,49 1,48 @@
= How to download rtmp streams?
title: How to download rtmp streams?

[quote, wikipedia]
Real Time Messaging Protocol (RTMP) was initially a proprietary protocol
developed by Macromedia for streaming audio, video and data over the Internet,
between a Flash player and a server. Macromedia is now owned by Adobe, which has
released an incomplete version of the specification of the protocol for public
> Real Time Messaging Protocol (RTMP) was initially a proprietary protocol
> developed by Macromedia for streaming audio, video and data over the Internet,
> between a Flash player and a server. Macromedia is now owned by Adobe, which has
> released an incomplete version of the specification of the protocol for public
> use.

Many media sites (N24, zdf, ard, ...) use rtmp streams to prevent people from
downloading the videos. Well, there is a little command line tool which allows
downloading rtmp streams. It is called
https://www.archlinux.org/packages/?name=rtmpdump[rtmpdump] and is available in
[rtmpdump](https://www.archlinux.org/packages/?name=rtmpdump) and is available in
the arch linux repositories.

To use rtmpdump you have to extract the required parameters from the html source
code. For N24 it looks like this (it is *really* ugly!):
{{ site.url  }}/assets/2014-09-22-n24-source.txt
code. For N24 it looks like [this](/2014-09-22-n24-source.txt) (it is *really* ugly!).

To use rtmpdump we need to set the `-r`, `-W` and `-y` parameters; with `-o` we
can specify a filename. An explanation of these parameters could be found with
`rtmpdump -h`. An appropriate rtmpdump call for the html code above would look
like the following:

rtmpdump \
$ rtmpdump \
  -r "rtmp://pssimn24livefs.fplive.net:1935/pssimn24/" \  # <1>
  -W "http://www.n24.de/_swf/HomePlayer.swf?cachingVersion=2.66" \  # <2>
  -y "mp4:cm2013/cmp/e214/89ed/ac91/30c0/0a1db4af7089b0c05161ea2dcca58546_1000.mp4" \  # <3>
  -o "myvideo.mp4"

As you can see I have extracted these values from the
http://pastebin.com/raw.php?i=brF5DvUL[source code] of the website. For n24 it
[source code](http://pastebin.com/raw.php?i=brF5DvUL) of the website. For n24 it

<1> `_n24VideoCfg.flash.videoFlashconnectionUrl`
<2> `_n24VideoCfg.flash.SWFUrl` (prepend the baseurl!)
<3> `_n24VideoCfg.flash.videoFlashSource`
1. `_n24VideoCfg.flash.videoFlashconnectionUrl`
2. `_n24VideoCfg.flash.SWFUrl` (prepend the baseurl!)
3. `_n24VideoCfg.flash.videoFlashSource`

For simplification I have written a little python wrapper which extracts these
parameters from a given URL and builds the rtmpdump command line string:

[source, python]
import re
import sys
import subprocess

@@ 85,5 84,6 @@ subprocess.call([
    '-y', rtmpdump_params['-y'],
    '-o', title + '.mp4'

UPDATE 2020-08-24: Just use [`youtube-dl`](https://ytdl-org.github.io/youtube-dl/). It does everything automagically and is maintained.

R _posts/2014-09-23-generating-pdfs-with-django-and-latex.adoc => content/blog/2014-09-23-generating-pdfs-with-django-and-latex.md +22 -21
@@ 1,4 1,6 @@
= Generating pdfs with Django and Latex
title: Generating pdfs with Django and Latex

Generating pdfs in a webapplication often is tricky. The
https://docs.djangoproject.com/en/1.7/howto/outputting-pdf/[django docs]

@@ 14,44 16,45 @@ instead of html code in django templates does not really matter. You only have
to take care of the curly brackets. So here is a minimal latex template for

  {{ content }}

As you see I have created a latex document and I insert the django variable
content as usual with curly brackets. As we do not need automatic html-escaping
in our latex template we could switch this off by adding the appropriate
template tags:


{% autoescape on %}
  {{ content }}
{% endautoescape %}

Be careful with adding variables in a latex clauses. You'll have to put spaces
around the square brackets like the following; otherwise django does not realize
that there is a variable.

\setkomavar{subject}{ {{ title }} }

## Function based view

Now we have to create our view which creates the pdf file for us. It is not that
difficult. I use a function based view for this porpose.

[source, python]

``` python
from django.http import HttpResponse
from django.template import Context
from django.template.loader import get_template

@@ 84,20 87,20 @@ def entry_as_pdf(request, pk):
    # r['Content-Disposition'] = 'attachment; filename=texput.pdf'
    return r

<1> At first we have to do our database queries to be able to fill up the template
1.  At first we have to do our database queries to be able to fill up the template
    with content.
<2> After that we create a Context object which will be sent to the template.
<3> We load our latex template and render it. We get the latex code with its
2.  After that we create a Context object which will be sent to the template.
3.  We load our latex template and render it. We get the latex code with its
    content from the database; this code is available in the `rendered_tpl`
<4> To generate the pdf we call pdflatex twice within a 
4.  To generate the pdf we call pdflatex twice within a 
    https://docs.python.org/3.4/library/tempfile.html?highlight=tempdir#tempfile.TemporaryDirectory[temporary directory]
    using https://docs.python.org/3.4/library/subprocess.html#popen-constructor[Popen]. 
    The tempdir is removed automatically because we're using a
    https://docs.python.org/3.4/reference/datamodel.html#context-managers[context manager].
<5> We read the generated pdf and write its content into the HttpResponse. If we
5.  We read the generated pdf and write its content into the HttpResponse. If we
    uncomment the Content-Disposition line the pdf is downloaded automatically.
    Otherwise it could be displayed in the browser by browser plugins.

@@ 106,9 109,7 @@ def entry_as_pdf(request, pk):
To ensure that the pdf view works as expected we finally have to specify the
routing in our `urls.py` file:

[source, python]
``` python
from django.conf.urls import patterns, url
from . import views

@@ 118,4 119,4 @@ urlpatterns = patterns(

R _posts/2014-11-15-cron-jobs-with-systemd-timer.adoc => content/blog/2014-11-15-cron-jobs-with-systemd-timer.md +44 -41
@@ 1,10 1,12 @@
# Cron Jobs with systemd.timer
title: Cron Jobs with systemd.timer

[quote, https://wiki.archlinux.org/index.php/Systemd/Timers]
Timers are systemd unit files whose name ends in `.timer` that control
`.service` files or events. Timers have the ability to be an alternate to cron.
Timers have built-in support for calendar time events, monotonic time events,
and have the ability to run asynchronously.
> Timers are systemd unit files whose name ends in `.timer` that control
> `.service` files or events. Timers have the ability to be an alternate to cron.
> Timers have built-in support for calendar time events, monotonic time events,
> and have the ability to run asynchronously.

There are lots of flamewars against systemd; mostly introduced by people who
grew up with e. g. sysvinit scripts. Besides these flamewars systemd provides a

@@ 28,17 30,17 @@ Let's do a simple example. Somebody has written an awesome backupscript and he
wants that program to be executed daily. The start command for that piece of
software might be something like:

$ awesome_program start

So we have to tell systemd that command first. Don't forget to put the *full
path* of your script into `ExecStart`. Otherwise systemd is not able to find

[source, ini]

``` ini
Description=My awesome backup script

@@ 46,7 48,7 @@ After=network.target
ExecStart=/path/to/awesome_programm start

We call this file `awesome.service`. The structure of systemd service files is
self-explanatory. The `[Unit]` section is used to define some metadata such as

@@ 54,12 56,12 @@ the description or dependencies. The `[Service]` section actually defines the
start command of our service. As we are most likely using a script which runs
and exists after finishing its tasks we have to set the Type to `oneshot`, see
Maybe I will give more information about that topic in another articles.

Now there is the question where we are supposed to put this file. This topic is
covered in detail in
At the moment we are just interested in the local configuration path when
running in system mode: `/etc/systemd/system`. So let's copy this service to
it's intended location `/etc/systemd/system/awesome.service`.

@@ 71,9 73,9 @@ systemd service which is used to start our script. Now we will add the unit
which is used to trigger the service. The timer has to be named according to the
corresponding service `awesome.timer`; we put this file in the same directory.

[source, ini]

``` ini
Description=Weekly trigger for my awesome program

@@ 83,7 85,7 @@ Persistent=true


The timer file is self-explanatory as well. It has three required sections:
`[Unit]`, `[Timer]` and `[Install]`.

@@ 93,15 95,15 @@ should be activated. At first there is the `OnCalender` option. It understands a
few keywords such as `minutely`, `hourly`, `daily`, `monthly`, `weekly`,
`yearly`, `quarterly`, `semiannually`.  If these keywords fit into your
requirements everything is fine; more fine graned control is provided by
Maybe you want to run your service every six hours. So you
have to define the `OnCalendar` option like this:

OnCalendar=*-*-* 0/6:42:42

This means in detail (according to [systemd.time(7)][2]):
This means in detail (according to systemd.time(7)):

Run on

@@ 113,9 115,9 @@ Run on
The repeating is defined with the slash. An OnCalender which runs every six
minutes instead would look like this:

OnCalendar=*-*-* 0:0/6:42

Just for the sake of completeness, `Persistent=true` means that any missed timer
will run after bootup. It is useful to catch up on missed runs of the service

@@ 125,21 127,21 @@ Last but not least there is the Install section left. This one is needed for the
most important part: enabling the timer. We do this with `systemctl enable
awesome.timer`. Installing the timer into the multi-user.target just means we
want it to be started during bootup. If you want to dive into more detail check
out the https://wiki.archlinux.org/index.php/Systemd#Targets[Arch Wiki]. As we 
out the [Arch Wiki](https://wiki.archlinux.org/index.php/Systemd#Targets). As we 
do not want to reboot now we also have to start the timer using

$ systemctl start awesome.timer

### Listing timers

Let's check if everything works as expected. Systemctl has a built in command to
list and inspect timers on your system.

$ systemctl list-timers

will tell you which timers have been recognized by systemd.

@@ 151,14 153,15 @@ and timers are started and enabled system wide for all users on the machine. If
you do not have sudo privileges or you just want to define your own timer you
can use systemd's user mode.

[quote, https://wiki.archlinux.org/index.php/Systemd/Timers]
https://wiki.archlinux.org/index.php/Systemd[systemd] offers users the ability
to manage services under the user's control with a per-user systemd instance,
enabling users to start, stop, enable, and disable their own units. This is
convenient for daemons and other services that are commonly run for a single
user, such as https://wiki.archlinux.org/index.php/Mpd[mpd] or to perform
automated tasks like fetching mail. With some caveats it is even possible to
run xorg and the entire window manager from user services.

> [systemd](https://wiki.archlinux.org/index.php/Systemd) offers users the ability
> to manage services under the user's control with a per-user systemd instance,
> enabling users to start, stop, enable, and disable their own units. This is
> convenient for daemons and other services that are commonly run for a single
> user, such as [mpd](https://wiki.archlinux.org/index.php/Mpd) or to perform
> automated tasks like fetching mail. With some caveats it is even possible to
> run xorg and the entire window manager from user services.

You do not have to change that much for using systemd's user mode. Assuming you
are using a recent version of systemd the user instance is started automatically

@@ 166,9 169,9 @@ per user session. You can use the `~/.config/systemd/user` directory for your
service and timer files. For enabling, starting and listing the timer you just
have to append `--user`, e. g.:

$ systemctl --user enable awesome.timer

### Using user mode on a server

@@ 177,9 180,9 @@ difficult to run certain tasks automatically without an open ssh session. If you
want systemd to run your user tasks *without being logged in* then just linger
yourself with:

$ loginctl enable-linger $USER

Lingering a specific user keeps the systemd user instance running without an
corresponding user session. This ensures that your tasks actually run as

R _posts/2016-05-16-poor-mans-dyndns.adoc => content/blog/2016-05-16-poor-mans-dyndns.md +29 -29
@@ 1,4 1,6 @@
= Poor Man's Dynamic DNS
title: Poor Man's Dynamic DNS

When you want to connect to a computer remotely, you usually need to know its
IP address. Major ISPs assign you a dynamic IP address, to avoid that you

@@ 19,34 21,35 @@ costs you money.
What can you do to avoid paying money and configuring DNS zones? Just use my
poor man's DynDNS solution!

[quote, wikipedia.org]
Dynamic DNS (DDNS or DynDNS) is a method of automatically updating a name
server in the Domain Name System (DNS), often in real time, with the active
DDNS configuration of its configured hostnames, addresses or other information.

You may know https://syncthing.net/[Syncthing]. I love that software! Well,
> Dynamic DNS (DDNS or DynDNS) is a method of automatically updating a name
> server in the Domain Name System (DNS), often in real time, with the active
> DDNS configuration of its configured hostnames, addresses or other information.

You may know [Syncthing](https://syncthing.net/). I love that software! Well,
why the hell are you now talking about a file synchronization tool?!?
It is easy. Syncthing uses a global discovery system to find out the ip
addresses of the involved nodes; it is based on https.

== Let's start with the terminal!
## Let's start with the terminal!

So, let's generate a certificate first:

$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes
Generating a 4096 bit RSA private key
writing new private key to 'key.pem'
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:

@@ 54,7 57,7 @@ Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:

We have now two files: `cert.pem` and `key.pem`. We are using asymmetric
cryptography; that means we have a private and a public key. The public key is

@@ 63,24 66,23 @@ stored in the certificate `cert.pem`; the private key is in the file `key.pem`.
We can use our private key to announce ourselves to the global discovery system
of Syncthing. We use `curl` for that; `curl` is awesome.

$ url="https://discovery-v4-1.syncthing.net/?id=SR7AARM-TCBUZ5O-VFAXY4D-CECGSDE-3Q6IZ4G-XG7AH75-OBIXJQV-QJ6NLQA"
$ curl -H "Content-Type: application/json" -d '{ "direct": []}' -k --cert cert.pem --key key.pem "$url"

Wow, such a long command... But it is not very complicated. We do a http POST request
and we send a special header to the server:

[source, json]
``` json
{ "direct": []}

That header advices the discovery system to save the source ip of the request. Since
I want to announce my own computer, that's fine. BTW this is documented in the

== Query the IP Address of a Device
## Query the IP Address of a Device

So, I have announced my computer. What now? I can query it from somewhere else!
At first you have to find out the DeviceID. That is basically the SHA256 value

@@ 89,8 91,7 @@ characters added, to detect spelling errors. There is a Python script to calcula
the DeviceID. I have stolen parts of it from Github, but I forgot the origin;
if the author reads this, I am happy to add a link here :).

[source, python]
``` python
#!/usr/bin/env python3

import base64

@@ 149,18 150,18 @@ with open(sys.argv[1], 'r') as f:
    v = ssl.PEM_cert_to_DER_cert(f.read())
    digest = sha256(v).digest()

We are now able to get our DeviceID:

$ python device-id.py cert.pem

And now, magic, we can do a http POST to actually get the stored IP address:

$ deviceid="$(python device-id.py cert.pem)"
$ url="https://discovery-v4-1.syncthing.net/?id=SR7AARM-TCBUZ5O-VFAXY4D-CECGSDE-3Q6IZ4G-XG7AH75-OBIXJQV-QJ6NLQA&device=$deviceid"
$ curl -ks "$url" | json_pp

@@ 176,7 177,7 @@ $ curl -ks "$url" | json_pp

Again, that's really long... What happens here? Nothing magic. We just do a http GET
on the public server `https://discovery-v4-1.syncthing.net/`. The `id` parameter is

@@ 187,14 188,13 @@ the whole url in `"`.) We then get a JSON string back.

**UPDATE**: I prettyfied the commands and the output a bit.

== And now? How can I use that crap?
## And now? How can I use that crap?

A usecase scenario may be, that you may access you NAS from outside your home
network. Just setup a portforwarding, and let the computer announce itself every
30 minutes. You can build a wrapper script for SSH like this (untested):

[source, sh]
``` bash

deviceid="$(python device-id.py cert.pem)"

@@ 203,7 203,7 @@ ip=$(curl -ks "$url"  \
    | grep -Eo "\"direct\":\[\"tcp://[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+\"\]" \
    | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+")
ssh "$ip"

Have fun! :)

R _posts/2016-05-16-useful-git-aliases.adoc => content/blog/2016-05-16-useful-git-aliases.md +13 -15
@@ 1,27 1,25 @@
title: Useful Git Log Aliases
title: Useful Git Log Aliases 

= Useful Git Log Aliases 

Are you annoyed of the heavyweigth standard layout of `git log`?
Let's tweak that a bit; I have those aliases in my `.gitconfig`:

    lg = log --pretty=format:'%C(auto)%h %<(55,trunc)%s %Cblue%<(18,trunc)%an%Creset %Cgreen%<(15)%ad%Creset %C(auto)%d' --abbrev-commit --date=relative
    lol = log --decorate --oneline --abbrev-commit --all
    today = log --stat --since='1 Day Ago' --graph --pretty=oneline --abbrev-commit --date=relative
    changelog = log --pretty=format:'%C(auto)%h (%s, %ad)' --abbrev-commit --date=short

== git lg
## git lg

Displays a table, with the author and the date. The `--oneline` layout is used as 
a basis. The really weird syntax can be examined in the manpage `git-log(1)`.
For the demonstration I use the Git repository of Syncthing.

$ git lg
d59fd9c lib/config: use correct ReleasesURL when upgrading fr.. Alex               2 days ago       (HEAD -> master, origin/master, origin/HEAD)
6f743f3 Revert "lib/model: Emit LocalDiskUpdated events on de.. Jakob Borg         2 days ago      

@@ 36,14 34,14 @@ b993b41 lib/config: Minor attribute updates                     Jakob Borg      
d628b73 build: Remove unused code                               Lars K.W. Gohlke   5 days ago      
21e116a lib/scanner: Refactor scanner.Walk API                  Jakob Borg         7 days ago      
d77d8ff lib/connections: Don't look at devices that are alrea.. Jakob Borg         7 days ago

== git lol
## git lol

That one should be well known, I have stolen it somewhere in the internet...

$ git lol
277db79 (origin/pr-3017) Merge branch 'master' into refactor-2
17bc84e (origin/pr-3055) Forgot one thing.

@@ 77,19 75,19 @@ b4f9417 (tag: v0.12.24, origin/v0.12) lib/config: Update size constraints and UR
e8b4286 lib/config: Change upgrade check URL (fixes #3086)
2e9bf0b lib/upgrade: Increase size limits, send version header
f7dda32 splling

== git today 
## git today 

Shows everything from today with the merge graph and relative dates.

**It's empty today. :D**

== git changelog 
## git changelog 

That's useful when you want to reference a commit in an email.

$ git changelog
d59fd9c (lib/config: use correct ReleasesURL when upgrading from v0.13-beta, 2016-05-14)
6f743f3 (Revert "lib/model: Emit LocalDiskUpdated events on detecting local changes", 2016-05-14)

@@ 104,6 102,6 @@ b993b41 (lib/config: Minor attribute updates, 2016-05-12)
d628b73 (build: Remove unused code, 2016-05-11)
21e116a (lib/scanner: Refactor scanner.Walk API, 2016-05-09)
d77d8ff (lib/connections: Don't look at devices that are already optimally connected, 2016-05-09)

Do you also have awesome git aliases? Let me know!

R _posts/2016-06-22-sudo-doas.adoc => content/blog/2016-06-22-sudo-doas.md +6 -4
@@ 1,14 1,16 @@
= sudo -> doas
title: sudo -> doas

Da ich ja gerade wie wahnsinnig meine Server von Bloatware befreie, habe
ich noch so eine https://forums.freebsd.org/threads/56704/[Krücke] ausgemacht: 
ich noch so eine [Krücke](https://forums.freebsd.org/threads/56704/) ausgemacht: 
`sudo`; komplexe Konfiguration, kein Mensch nutzt alle Features. Die Lösung, 
mal wieder von OpenBSD: http://www.openbsd.org/faq/faq10.html#doas[`doas`]
mal wieder von OpenBSD: [`doas`](http://www.openbsd.org/faq/faq10.html#doas)

> Yes, doas(1) was inspired by sudo. It is OpenBSD's replacement for the sudo command.
> The complexity of sudo had prevented the importing of the most current versions, and the complexity of the sudoers config file has discouraged many users from doing anything other than uncomment one line in the conf file. In short, sudo's code is too complicated for the way most users use it, and its configuration is too difficult for more advanced uses.
> doas(1) is intended to have a simpler, and thus hopefully more secure, code base and configuration file. From a user standpoint, the two are very similar.

Na dann; kann ja nix mehr schief gehen....
Na dann; kann ja nix mehr schief gehen…

R _posts/2016-07-14-vpn-leaks-ipv6.adoc => content/blog/2016-07-14-vpn-leaks-ipv6.md +27 -27
@@ 1,15 1,15 @@
= Android VPN leaks ipv6
:page-lang: de

title: Android VPN leaks ipv6
Ich hab mir jetzt endlich nen VPN Server zugelegt um in offenen WLANs
sicher zu surven zu koennen (konkret: OpenVPN + FreeBSD bei digital
sicher zu surven zu können (konkret: OpenVPN + FreeBSD bei digital
ocean). Mein VPN Server macht aktuell nur ipv4, weil die kleinste
digital ocean kiste (wie ich gelernt habe) aktuell kein /112 oder /64er
netz bekommt. Stoert mich soweit nicht, koennte laut Support aber noch
netz bekommt. Stört mich soweit nicht, koennte laut Support aber noch

Wenn ein Geraet per VPN online ist und beide, ipv4 und ipv6 macht, dann
Wenn ein Gerät per VPN online ist und beide, ipv4 und ipv6 macht, dann
kann ipv6 traffic neben dem VPN vorbei leaken. Es ist mir aufgefallen,
dass trotz VPN google meine position anhand der IP wusste. eigentlich
sollte da jetzt ja immer Frankfurt drinstehen... Tja, das Linux Hotel

@@ 18,11 18,11 @@ vorbei.

Abhilfe: Wenn ich im VPN bin, ipv6 ausmachen. Alles gut.

Frage: Wie zur Hoelle mach ich das auf android? Ich hab jetzt ueber ne
Stunde gegoogled und nix vernuenftiges gefunden. IPV6 in ein leeres VPN
Frage: Wie zur Hölle mach ich das auf android? Ich hab jetzt über ne
Stunde gegoogled und nix vernünftiges gefunden. IPV6 in ein leeres VPN
LAN routen ist doof, weil dann die meisten Webseiten einfach tod sind.
IPv6 irgendwie ueber Firewall wegblocken sollte den gleichen Effekt
bringen (glaub ich). Einfach ipv6 ausknipsen waere das sinnvollste, aber
IPv6 irgendwie über Firewall wegblocken sollte den gleichen Effekt
bringen (glaub ich). Einfach ipv6 ausknipsen wäre das sinnvollste, aber
bei Android (!= einfaches Linux) ..... Arrrgh.

Ich hatte dann den Vorschlag bekommen folgendes auszuprobieren und ggf.

@@ 30,20 30,20 @@ zu scripten:

	echo 1 > /proc/sys/net/ipv6/conf/wlan0/disable_ipv6

Das waere natuerlich eine Moeglichkeit, ja. Ich hab nur irgendwie Bedenken,
Das wäre natürlich eine Möglichkeit, ja. Ich hab nur irgendwie Bedenken,
dass es nicht wirklich gut funktioniert. Script gebotschte und Android...
klingt irgendwie nach einer sehr boesen Kombination.
klingt irgendwie nach einer sehr bösen Kombination.

Ich hab es jetzt anders geloest, einen Hurricane Electric Tunnel auf
Ich hab es jetzt anders gelöst, einen Hurricane Electric Tunnel auf
meinem Server! Damit umgehe ich das zu kurze Prefix von Digital Ocean
ganz einfach.

Auf FreeBSD https://www.freebsd.org/doc/handbook/network-ipv6.html[brunzeinfach]
Auf FreeBSD [einfach](https://www.freebsd.org/doc/handbook/network-ipv6.html)

[source, sh]

``` sh
# Hurricane Electric
gifconfig_gif0="SERVERIP4 ENDPUNKTIP4"

@@ 56,14 56,14 @@ ifconfig_vtnet0_ipv6="ENDPUNKTIP6 prefixlen 64"

Als ENDPUNKTIP6 einfach `...:1` nehmen; als SERVERIP6 dann die `....:2`.
Die ifconfig (ohne loopback) schaut so aus. Das `gif0` macht den Hurricane
Electric Tunnel; das `vtnet0` ist mein netzwerkkarte, das `tun0` ist mein
`openvpn` device.

$ ifconfig
vtnet0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500

@@ 88,12 88,12 @@ tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1500
        inet6 2001:470:1f0b:6cb::1 prefixlen 64
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
        Opened by PID 89727

Funktioniert jetzt alles gut. Ich bekomm am Handy jetzt ipv4 und ipv6 zugewiesen,
alles funktioniert. Der ping ueber den VPN Tunnel ist auch gar ned mal sooooo schlecht:
alles funktioniert. Der ping über den VPN Tunnel ist auch gar ned mal sooooo schlecht:

stefan@kronos ~> ping -4 google.de
PING google.de ( 56(84) bytes of data.
64 bytes from fra02s17-in-f3.1e100.net ( icmp_seq=1 ttl=58 time=24.7 ms

@@ 109,9 109,9 @@ PING google.de ( 56(84) bytes of data.
--- google.de ping statistics ---
9 packets transmitted, 9 received, 0% packet loss, time 8013ms
rtt min/avg/max/mdev = 24.744/25.254/25.837/0.365 ms

stefan@kronos ~> ping -6 google.de
PING google.de(fra02s17-in-x03.1e100.net (2a00:1450:4001:806::2003)) 56 data bytes
64 bytes from fra02s17-in-x03.1e100.net (2a00:1450:4001:806::2003): icmp_seq=1 ttl=58 time=25.4 ms

@@ 127,11 127,11 @@ PING google.de(fra02s17-in-x03.1e100.net (2a00:1450:4001:806::2003)) 56 data byt
--- google.de ping statistics ---
9 packets transmitted, 9 received, 0% packet loss, time 8011ms
rtt min/avg/max/mdev = 25.282/26.313/31.147/1.736 ms

Als Vergleich dazu, mein native ipv4:

stefan@kronos ~> ping -4 google.de
PING google.de ( 56(84) bytes of data.
64 bytes from fra02s21-in-f3.1e100.net ( icmp_seq=1 ttl=57 time=23.9 ms

@@ 142,6 142,6 @@ PING google.de ( 56(84) bytes of data.
--- google.de ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 23.390/23.843/24.085/0.267 ms

Kann man so lassen glaub ich. :)

R _posts/2016-08-03-use-ssh-blacklists.adoc => content/blog/2016-08-03-use-ssh-blacklists.md +31 -29
@@ 1,16 1,17 @@
= Use SSH Blacklists on FreeBSD
title: Use SSH Blacklists on FreeBSD

NOTE: openbl has been discontinued. So, I leave this article for the archive...
NOTE: openbl has been discontinued. So, I leave this article for the archive…

Since I am a very lazy person, I am quoting the introduction of openbl.org:
Since I am a very lazy person, I am quoting the introduction of https://openbl.org:

[quote, openbl.org]
The OpenBL.org project (formerly known as the SSH blacklist) is about
detecting, logging and reporting various types of internet abuse. Currently our
hosts monitor ports 21 (FTP), 22 (SSH), 23 (TELNET), 25 (SMTP), 110 (POP3), 143
(IMAP), 587 (Submission), 993 (IMAPS) and 995 (POP3S) for bruteforce login
attacks as well as scans on ports 80 (HTTP) and 443 (HTTPS) for vulnerable