diff options
60 files changed, 3 insertions, 2289 deletions
diff --git a/.gitattributes b/.gitattributes index 91bfadd..176a458 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1 @@ * text=auto - -*.bat text eol=crlf -*.sh text eol=lf diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 57510a2..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_site/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 704ca11..0000000 --- a/.travis.yml +++ /dev/null @@ -1,31 +0,0 @@ -os: linux -dist: bionic -language: ruby - -# Travis doesn't build gh-pages by default: -# https://docs.travis-ci.com/user/customizing-the-build/#building-specific-branches -branches: - only: - - gh-pages - - /.*/ - -jobs: - fast_finish: true - - include: - - stage: Build - name: Build using Bundler - install: bundle install --jobs=3 --retry=3 - script: bundle exec jekyll build --config _config.yml,_config_dev.yml --drafts - - name: Build using latest github-pages - install: - # `jekyll build` seems to be using Bundler if Gemfile is present: - - rm -f -- Gemfile Gemfile.lock - - gem install github-pages - script: jekyll build - - stage: Verify - name: Check integrity - install: bundle install --jobs=3 --retry=3 - script: - - nohup bundle exec jekyll serve --config _config.yml,_config_dev.yml --drafts & - - sleep 3 && wget --no-verbose --recursive --convert-links --adjust-extension --directory-prefix=/tmp -- http://localhost:4000/ diff --git a/Gemfile b/Gemfile deleted file mode 100644 index f037f19..0000000 --- a/Gemfile +++ /dev/null @@ -1,5 +0,0 @@ -source 'https://rubygems.org' -gem 'github-pages', '200' -# For some reason, I get `LoadError` if I omit the gems below. -gem 'json' -gem 'bigdecimal' diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 0e91adb..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,253 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - activesupport (4.2.11.1) - i18n (~> 0.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - addressable (2.7.0) - public_suffix (>= 2.0.2, < 5.0) - bigdecimal (1.4.4) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.11.1) - colorator (1.1.0) - commonmarker (0.17.13) - ruby-enum (~> 0.5) - concurrent-ruby (1.1.5) - dnsruby (1.61.3) - addressable (~> 2.5) - 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) - execjs (2.7.0) - faraday (0.16.2) - multipart-post (>= 1.2, < 3) - ffi (1.11.1) - forwardable-extended (2.6.0) - gemoji (3.0.1) - github-pages (200) - activesupport (= 4.2.11.1) - github-pages-health-check (= 1.16.1) - jekyll (= 3.8.5) - jekyll-avatar (= 0.6.0) - jekyll-coffeescript (= 1.1.1) - jekyll-commonmark-ghpages (= 0.1.5) - jekyll-default-layout (= 0.1.4) - jekyll-feed (= 0.11.0) - jekyll-gist (= 1.5.0) - jekyll-github-metadata (= 2.12.1) - jekyll-mentions (= 1.4.1) - jekyll-optional-front-matter (= 0.3.0) - jekyll-paginate (= 1.1.0) - jekyll-readme-index (= 0.2.0) - jekyll-redirect-from (= 0.14.0) - jekyll-relative-links (= 0.6.0) - jekyll-remote-theme (= 0.4.0) - jekyll-sass-converter (= 1.5.2) - jekyll-seo-tag (= 2.5.0) - jekyll-sitemap (= 1.2.0) - jekyll-swiss (= 0.4.0) - jekyll-theme-architect (= 0.1.1) - jekyll-theme-cayman (= 0.1.1) - jekyll-theme-dinky (= 0.1.1) - jekyll-theme-hacker (= 0.1.1) - jekyll-theme-leap-day (= 0.1.1) - jekyll-theme-merlot (= 0.1.1) - jekyll-theme-midnight (= 0.1.1) - jekyll-theme-minimal (= 0.1.1) - jekyll-theme-modernist (= 0.1.1) - jekyll-theme-primer (= 0.5.3) - jekyll-theme-slate (= 0.1.1) - jekyll-theme-tactile (= 0.1.1) - jekyll-theme-time-machine (= 0.1.1) - jekyll-titles-from-headings (= 0.5.1) - jemoji (= 0.10.2) - kramdown (= 1.17.0) - liquid (= 4.0.0) - listen (= 3.1.5) - mercenary (~> 0.3) - minima (= 2.5.0) - nokogiri (>= 1.10.4, < 2.0) - rouge (= 2.2.1) - terminal-table (~> 1.4) - github-pages-health-check (1.16.1) - addressable (~> 2.3) - dnsruby (~> 1.60) - octokit (~> 4.0) - public_suffix (~> 3.0) - typhoeus (~> 1.3) - html-pipeline (2.12.0) - activesupport (>= 2) - nokogiri (>= 1.4) - http_parser.rb (0.6.0) - i18n (0.9.5) - concurrent-ruby (~> 1.0) - jekyll (3.8.5) - addressable (~> 2.4) - colorator (~> 1.0) - em-websocket (~> 0.5) - i18n (~> 0.7) - jekyll-sass-converter (~> 1.0) - jekyll-watch (~> 2.0) - kramdown (~> 1.14) - liquid (~> 4.0) - mercenary (~> 0.3.3) - pathutil (~> 0.9) - rouge (>= 1.7, < 4) - safe_yaml (~> 1.0) - jekyll-avatar (0.6.0) - jekyll (~> 3.0) - jekyll-coffeescript (1.1.1) - coffee-script (~> 2.2) - coffee-script-source (~> 1.11.1) - jekyll-commonmark (1.3.1) - commonmarker (~> 0.14) - jekyll (>= 3.7, < 5.0) - jekyll-commonmark-ghpages (0.1.5) - commonmarker (~> 0.17.6) - jekyll-commonmark (~> 1) - rouge (~> 2) - jekyll-default-layout (0.1.4) - jekyll (~> 3.0) - jekyll-feed (0.11.0) - jekyll (~> 3.3) - jekyll-gist (1.5.0) - octokit (~> 4.2) - jekyll-github-metadata (2.12.1) - jekyll (~> 3.4) - octokit (~> 4.0, != 4.4.0) - jekyll-mentions (1.4.1) - html-pipeline (~> 2.3) - jekyll (~> 3.0) - jekyll-optional-front-matter (0.3.0) - jekyll (~> 3.0) - jekyll-paginate (1.1.0) - jekyll-readme-index (0.2.0) - jekyll (~> 3.0) - jekyll-redirect-from (0.14.0) - jekyll (~> 3.3) - jekyll-relative-links (0.6.0) - jekyll (~> 3.3) - jekyll-remote-theme (0.4.0) - addressable (~> 2.0) - jekyll (~> 3.5) - rubyzip (>= 1.2.1, < 3.0) - jekyll-sass-converter (1.5.2) - sass (~> 3.4) - jekyll-seo-tag (2.5.0) - jekyll (~> 3.3) - jekyll-sitemap (1.2.0) - jekyll (~> 3.3) - jekyll-swiss (0.4.0) - jekyll-theme-architect (0.1.1) - jekyll (~> 3.5) - jekyll-seo-tag (~> 2.0) - jekyll-theme-cayman (0.1.1) - jekyll (~> 3.5) - jekyll-seo-tag (~> 2.0) - jekyll-theme-dinky (0.1.1) - jekyll (~> 3.5) - jekyll-seo-tag (~> 2.0) - jekyll-theme-hacker (0.1.1) - jekyll (~> 3.5) - jekyll-seo-tag (~> 2.0) - jekyll-theme-leap-day (0.1.1) - jekyll (~> 3.5) - jekyll-seo-tag (~> 2.0) - jekyll-theme-merlot (0.1.1) - jekyll (~> 3.5) - jekyll-seo-tag (~> 2.0) - jekyll-theme-midnight (0.1.1) - jekyll (~> 3.5) - jekyll-seo-tag (~> 2.0) - jekyll-theme-minimal (0.1.1) - jekyll (~> 3.5) - jekyll-seo-tag (~> 2.0) - jekyll-theme-modernist (0.1.1) - jekyll (~> 3.5) - jekyll-seo-tag (~> 2.0) - jekyll-theme-primer (0.5.3) - jekyll (~> 3.5) - jekyll-github-metadata (~> 2.9) - jekyll-seo-tag (~> 2.0) - jekyll-theme-slate (0.1.1) - jekyll (~> 3.5) - jekyll-seo-tag (~> 2.0) - jekyll-theme-tactile (0.1.1) - jekyll (~> 3.5) - jekyll-seo-tag (~> 2.0) - jekyll-theme-time-machine (0.1.1) - jekyll (~> 3.5) - jekyll-seo-tag (~> 2.0) - jekyll-titles-from-headings (0.5.1) - jekyll (~> 3.3) - jekyll-watch (2.2.1) - listen (~> 3.0) - jemoji (0.10.2) - gemoji (~> 3.0) - html-pipeline (~> 2.2) - jekyll (~> 3.0) - json (2.2.0) - kramdown (1.17.0) - liquid (4.0.0) - listen (3.1.5) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - ruby_dep (~> 1.2) - mercenary (0.3.6) - mini_portile2 (2.4.0) - minima (2.5.0) - jekyll (~> 3.5) - jekyll-feed (~> 0.9) - jekyll-seo-tag (~> 2.1) - minitest (5.12.2) - multipart-post (2.1.1) - nokogiri (1.10.4) - mini_portile2 (~> 2.4.0) - octokit (4.14.0) - sawyer (~> 0.8.0, >= 0.5.3) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (3.1.1) - rb-fsevent (0.10.3) - rb-inotify (0.10.0) - ffi (~> 1.0) - rouge (2.2.1) - ruby-enum (0.7.2) - i18n - ruby_dep (1.5.0) - rubyzip (2.0.0) - safe_yaml (1.0.5) - sass (3.7.4) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - sawyer (0.8.2) - addressable (>= 2.3.5) - faraday (> 0.8, < 2.0) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - thread_safe (0.3.6) - typhoeus (1.3.1) - ethon (>= 0.9.0) - tzinfo (1.2.5) - thread_safe (~> 0.1) - unicode-display_width (1.6.0) - -PLATFORMS - ruby - -DEPENDENCIES - bigdecimal - github-pages (= 200) - json - -BUNDLED WITH - 1.16.2 diff --git a/README.md b/README.md deleted file mode 100644 index 68da3b5..0000000 --- a/README.md +++ /dev/null @@ -1,111 +0,0 @@ -Egor's blog -=========== - -Egor's blog on programming. -Hosted on [GitHub Pages] at https://egor-tensin.github.io/blog/. - -[GitHub Pages]: https://pages.github.com - -Prerequisites -------------- - -[Jekyll] is used to build a set of static HTML pages from a collection of -templates and resources. -[Bundler] is used to manage project's dependencies. -Make sure you have the `bundler` gem installed; project dependencies can then -be installed by executing - - bundle install - -in the project's root directory. - -[Jekyll]: https://jekyllrb.com/ -[Bundler]: http://bundler.io/ - -Usage ------ - -To run a local web server, execute - - bundle exec jekyll serve --watch --drafts --config _config.yml,_config_dev.yml - -in the project's root directory. -You can then review your changes at http://localhost:4000/. - -If you can't get Jekyll to properly `--watch` for file modifications on -Windows, try adding `--force_polling` to `jekyll`s options: - - bundle exec jekyll serve --watch --force_polling --drafts --config _config.yml,_config_dev.yml - -It might still not work though, but you can always re-run `jekyll` manually. - -Note that `_config_dev.yml` is included to rewrite some of the `site` fields -from `_config.yml` during development. -In particular, it - -* sets `minified_externals` to `false` so that the properly formatted versions -of external CSS stylesheets and JavaScript files are included instead of the -`min`ified versions, -* sets `include_comments` to `false` to exclude the Disqus comments section -from the posts, -* sets `baseurl` to an empty string so that the website can be accessed from -local web server's root directory (i.e. from http://localhost:4000/ instead of -http://localhost:4000/blog/). - -### Access via file:// - -Jekyll doesn't provide native support for generating a static website which can -be browsed without running an instance of Jekyll's web server. -One easy workaround is to `wget` the website and convert the links: - - wget --convert-links --recursive http://localhost:4000/ - -### Typesetting math - -[MathJax] can be used to typeset mathematics using LaTeX. -To use MathJax, set `mathjax` to `true` in page's front matter. -Then you can do things like this: - -``` -This is an inline formula: $$y = kx + b$$. -This is a formula in a separate block: - -$$ -y = kx + b -$$ -``` - -[MathJax]: https://www.mathjax.org/ - -#### GitHub workarounds - -MathJax version 3 is used, which is unsupported by Kramdown (which produces -`<script type="math/tex; ..."` tags, suitable only for MathJax 2. -This is why `math_engine` is set to `null` in _config.yml, making Kramdown -output block formulas wrapped in `$$` and inline formulas in `$` respectively -([inside `<span class="kdmath">` elements][kramdown issue]). -Because if this, MathJax is additionally customized to recognize `$` as an -inline formula delimiter in _includes/common/mathjax.html. - -GitHub Pages [helpfully overrides] the `math_engine` setting in your -_config.yml, hardcoding it to `mathjax` instead of `null` (there's a related -[pull request]). -I couldn't find a better way than to override the setting in the markdown -document itself using - - {::options math_engine="+nil+" /} - -[kramdown issue]: https://github.com/gettalong/kramdown/issues/342 -[helpfully overrides]: https://help.github.com/en/articles/configuring-jekyll -[pull request]: https://github.com/github/pages-gem/pull/644 - -License -------- - -Distributed under the MIT License. -See [LICENSE.txt] for details. - -This website is build upon the Twitter Bootstrap framework, which is also MIT -Licensed and copyright 2015 Twitter. - -[LICENSE.txt]: LICENSE.txt diff --git a/_config.yml b/_config.yml deleted file mode 100644 index 5290a16..0000000 --- a/_config.yml +++ /dev/null @@ -1,71 +0,0 @@ -plugins: - - jekyll-paginate - - jekyll-github-metadata - -exclude: - - .travis.yml - - build.sh - - Gemfile - - Gemfile.lock - - LICENSE.txt - - serve.bat - - serve.sh - - README.md - -paginate: 10 - -collections: - notes: - output: true - sort_by: title # Doesn't work? - -defaults: - - scope: - path: "" - type: pages - values: - layout: default - navbar_priority: 999 - - scope: - path: "" - type: posts - values: - layout: post - - scope: - path: "" - type: notes - values: - layout: note - - scope: - path: categories - type: pages - values: - layout: category - -excerpt_separator: "" -include_comments: true -minified_externals: true - -highlighter: rouge - -markdown: kramdown - -kramdown: - math_engine: null # Ignored by GitHub Pages, yay, how fun! - syntax_highlighter_opts: - span: - disable: true - -bootstrap_version: 3.3.7 -jquery_version: 1.12.4 -html5shiv_version: 3.7.3 -respond_version: 1.4.2 - -project: - name: Blog - description: Egor's blog on programming -baseurl: /blog -repository: egor-tensin/blog -personal_info: - name: Egor Tensin - email: Egor.Tensin@gmail.com diff --git a/_config_dev.yml b/_config_dev.yml deleted file mode 100644 index c6fad0e..0000000 --- a/_config_dev.yml +++ /dev/null @@ -1,4 +0,0 @@ -include_comments: false -minified_externals: false - -baseurl: "" diff --git a/_drafts/.gitkeep b/_drafts/.gitkeep deleted file mode 100644 index e69de29..0000000 --- a/_drafts/.gitkeep +++ /dev/null diff --git a/_includes/common/header.html b/_includes/common/header.html index a17ea71..ce6e493 100644 --- a/_includes/common/header.html +++ b/_includes/common/header.html @@ -9,12 +9,12 @@ {% include common/bootstrap_css.html %} - <link rel="stylesheet" href="{{ site.baseurl }}/css/common/footer.css"> - <link rel="stylesheet" href="{{ site.baseurl }}/css/common/misc.css"> + <link rel="stylesheet" href="{{ site.baseurl }}/assets/css/common/footer.css"> + <link rel="stylesheet" href="{{ site.baseurl }}/assets/css/common/misc.css"> {% if page.custom_css %} {% for css in page.custom_css %} - <link rel="stylesheet" href="{{ site.baseurl }}/css/{{ css }}"/> + <link rel="stylesheet" href="{{ site.baseurl }}/assets/css/{{ css }}"/> {% endfor %} {% endif %} diff --git a/_notes/bash.md b/_notes/bash.md deleted file mode 100644 index 353f011..0000000 --- a/_notes/bash.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: GNU bash ---- -(Associative) arrays --------------------- - -### Declaration - -`"${#xs[@]}"` doesn't work with `nounset` if `xs` wasn't defined, i.e. was -declared with either of - - local -a xs - declare -a xs - local -A xs - declare -A xs - -Therefore, if you want to extract the length of an array, append `=()` to the -statements above. - - local -a xs=() - declare -a xs=() - ... - -And now `"${#xs[@]}"` works with `nounset`. -It doesn't affect expansion (see below) though. - -### Expansion - -#### Do - - func ${arr[@]+"${arr[@]}"} - -#### Don't - - func "${arr[@]}" # Doesn't work with `nounset`. - func "${arr[@]+"${arr[@]}"}" # Doesn't work properly with `declare -a arr=('')`. - -### `unset` - -#### Do - - unset -v 'arr[x]' - unset -v 'arr[$i]' - -#### Don't - - unset -v arr[x] # May break due to globbing. - unset -v arr[$i] # The same as above + a possible problem with quotation. - unset -v 'arr["x"]' # Doesn't work for some reason. - unset -v 'arr["]"]' # The same as above; just highlighting the problem with funny characters in array indices. - unset -v 'arr["$i"]' # Also rejected. - - # An insightful discussion on the topic: https://lists.gnu.org/archive/html/help-bash/2016-09/msg00020.html. - -`errexit` ---------- - -### Do - - bar_output="$( bar )" - foo "$bar_output" - -### Don't - - foo "$( bar )" # With `errexit`, foo will still get executed. - # I don't know why. diff --git a/_notes/latex.md b/_notes/latex.md deleted file mode 100644 index c131efe..0000000 --- a/_notes/latex.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Basic LaTeX document -custom_css: - - syntax.css ---- -A more-or-less complete, but still very basic LaTeX document follows. - -```tex -\documentclass[11pt]{article} - -% Basic setup -\usepackage{cmap} -\usepackage[utf8]{inputenc} -\usepackage[T2A]{fontenc} -\usepackage[russian]{babel} - -% Completely arbitrary settings follow: - -% Sans serif font by default -\renewcommand\familydefault{\sfdefault} - -% Document margins -\usepackage[margin=2.5cm]{geometry} - -% Paragraph indents -\usepackage{parskip} -\setlength\parindent{0cm} -\setlength\parskip{0cm} - -% URLs -\usepackage[colorlinks=true,urlcolor=blue]{hyperref} - -\begin{document} - -Привет, \LaTeX! -Ссылка на репозиторий: \href{https://github.com/egor-tensin/notes}{https://github.com/egor-tensin/notes}. - -\end{document} -``` diff --git a/_notes/markdown.md b/_notes/markdown.md deleted file mode 100644 index dee25f4..0000000 --- a/_notes/markdown.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Markdown style guide ---- - -* `diff`- and HTML-friendliness is valued over human-readability. -* Every sentence starts on a new line ("semantic newlines"). -* Lines are at most 79 characters long, not counting neither the carriage -return, nor the line feed characters. - * Not 80 characters, because when you display a 80-character line with a -line feed at the end in Windows' `cmd`, an extra empty line is added. -* No hanging indents in lists. - * Nested lists are indented with 4 spaces. - * No hanging indents in those also. - * Longer items wrap at 79 characters and continue from the leftmost -character column. -Additional sentences start there also. -* Prefer reference-style links over inline links. -Omit the second pair of brackets `[]` entirely where appropriate. -For example, [Google] is preferred over both [Google](https://ya.ru) and -[I'm feeeling lucky][google] (see [this document's source]). -* First- and second-level headers are underlined with strings of `=` and `-`. -The number of `=`/`-` signs must be equal to the number of characters in the -header. -* File paths are enclosed in double quotes. -Environment variable names are enclosed in a pair of backticks (\`) unless it's -a part of a path. -Executable names are enclosed in a pair of backticks (\`) unless it's a part of -a path, a link or a header. -* Code blocks are indented with 4 spaces. - - Code blocks inside lists are indented according to the spec - (https://github.github.com/gfm/#list-items), i.e. the column of the first - non-whitespace character in the item + 4. - -* Don't mix fenced code blocks with indented code blocks in a single document. - -| In a table, | the first | row | is underlined. -| ----------- | --------- | ----- | -------------- -| Leftmost | vertical | lines | are required. -| Rightmost | vertical | lines | are omitted. -{: .table .table-bordered } - -[Google]: https://www.google.com/ -[this document's source]: https://raw.githubusercontent.com/{{ site.github.repository_nwo }}/{{ site.github.source.branch }}/{{ page.path }} diff --git a/_posts/2015-07-03-std-call-once-bug.md b/_posts/2015-07-03-std-call-once-bug.md deleted file mode 100644 index 0aa0249..0000000 --- a/_posts/2015-07-03-std-call-once-bug.md +++ /dev/null @@ -1,258 +0,0 @@ ---- -title: std::call_once bug in Visual C++ 2012/2013 -excerpt: > - In this post I will describe a nasty bug I've stumbled upon in the C++ - Standard Library implementation shipped with Microsoft Visual Studio - 2012/2013. -category: C++ -custom_css: - - syntax.css ---- -I've recently come across a nasty standard library bug in the implementation -shipped with Microsoft Visual Studio 2012/2013. -[StackOverflow was of no help], so I had to somehow report the bug to the -maintainers. -Oddly enough, Visual Studio's [Connect page] wouldn't let me report one, -complaining about the lack of permissions, even though I was logged in from my -work account, associated with my Visual Studio 2013 installation. - -Fortunately, I've come across the personal website of this amazing guy, -[Stephan T. Lavavej], who appears to be the chief maintainer of Microsoft's -standard library implementation. -He seems to be your go-to guy when it comes to obvious standard library -misbehaviours. - -[StackOverflow was of no help]: https://stackoverflow.com/questions/26477070/concurrent-stdcall-once-calls -[Connect page]: https://connect.microsoft.com/VisualStudio -[Stephan T. Lavavej]: http://nuwen.net/stl.html - -C++11 and singletons --------------------- - -Anyway, the story begins with me trying to implement the singleton pattern -using C++11 facilities like this: - -```c++ -#include <mutex> - -template <typename Derived> -class Singleton { -public: - static Derived& get_instance() { - std::call_once(initialized_flag, &initialize_instance); - return Derived::get_instance_unsafe(); - } - -protected: - Singleton() = default; - ~Singleton() = default; - - static Derived& get_instance_unsafe() { - static Derived instance; - return instance; - } - -private: - static void initialize_instance() { - Derived::get_instance_unsafe(); - } - - static std::once_flag initialized_flag; - - Singleton(const Singleton&) = delete; - Singleton& operator=(const Singleton&) = delete; -}; - -template <typename Derived> -std::once_flag Singleton<Derived>::initialized_flag; -``` - -Neat, huh? -Now other classes can inherit from `Singleton`, implementing the singleton -pattern effortlessly: - -```c++ -class Logger : public Singleton<Logger> { -private: - Logger() = default; - ~Logger() = default; - - friend class Singleton<Logger>; -}; -``` - -Note that the [N2660] standard proposal isn't/wasn't implemented in the -compilers shipped with Visual Studio 2012/2013. -If it was, I wouldn't, of course, need to employ this `std::call_once` -trickery, and the implementation would be much simpler, i.e. something like -this: - -```c++ -class Logger { -public: - static Logger& get_instance() { - static Logger instance; - return instance; - } - -private: - Logger() = default; - ~Logger() = default; -}; -``` - -<div class="alert alert-info" markdown="1"> - -The point is that the `Logger::get_instance` routine above wasn't thread-safe -until C++11. -Imagine what might happen if `Logger`'s constructor takes some time to -initialize the instance. -If a couple of threads then call `get_instance`, the first thread might begin -the initialization process, making the other thread believe that the instance -had already been intialized. -This other thread might then return a reference to the instance which hasn't -yet completed its initialization and is most likely unsafe to use. - -Since C++11 includes the proposal mentioned above, this routine would indeed be -thread-safe in C++11. -Unfortunately, the compilers shipped with Visual Studio 2012/2013 don't/didn't -implement this particular proposal, which caused me to look at -`std::call_once`, which seemed to implement exactly what I needed. - -</div> - -[N2660]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm - -Problem -------- - -Unfortunately, matters became a bit more complicated when I tried to introduce -two singletons, one having a dependency on the other. -I had `Logger`, like in the example above, and some kind of a "master" -singleton (let's call it `Duke`). -`Duke`'s constructor was complicated and time-consuming, and definetely -required some logging to be done. -I thought that I could simply call `Logger::get_instance` inside `Duke`'s -constructor, and everything looked fine at first glance. - -```c++ -#include <chrono> -#include <thread> - -class Logger : public Singleton<Logger> { -public: - Logger& operator<<(const char* msg) { - // Actual logging is stripped for brevity. - return *this; - } - -private: - Logger() { - // Opening log files, etc. - std::this_thread::sleep_for(std::chrono::seconds{3}); - } - - ~Logger() = default; - - friend class Singleton<Logger>; -}; - -class Duke : public Singleton<Duke> { -private: - Duke() { - Logger::get_instance() << "started Duke's initialization"; - // It's a lot of work to be done. - std::this_thread::sleep_for(std::chrono::seconds{10}); - Logger::get_instance() << "finishing Duke's initialization"; - } - - ~Duke() = default; - - friend class Singleton<Duke>; -}; -``` - -Now, what happens if I have two threads, one using the `Duke` instance, and the -other logging something? -Like in this example: - -```c++ -#include <thread> - -namespace { - -void get_logger() { - entered(__FUNCTION__); - Logger::get_instance(); - exiting(__FUNCTION__); -} - -void get_duke() { - entered(__FUNCTION__); - Duke::get_instance(); - exiting(__FUNCTION__); -} - -} - -int main() { - std::thread t1{&get_duke}; - std::thread t2{&get_logger}; - t1.join(); - t2.join(); - return 0; -} -``` - -`entered` and `exiting` are utility functions to print timestamps. -The implementation is included in the [complete code sample]. -{: .alert .alert-info } - -The first thread is supposed to have the total running time of about 13 -seconds, right? -Three seconds to initialize the `Logger` instance and ten to initialize the -`Duke` instance. -The second thread, similarly, is supposed to be done in about 3 seconds -required for the initialization of `Logger`. - -Weirdly, this program produces the following output when compiled using Visual -Studio 2013's compiler: - - Entered `anonymous-namespace'::get_duke at Fri Jul 03 02:26:16 2015 - Entered `anonymous-namespace'::get_logger at Fri Jul 03 02:26:16 2015 - Exiting `anonymous-namespace'::get_duke at Fri Jul 03 02:26:29 2015 - Exiting `anonymous-namespace'::get_logger at Fri Jul 03 02:26:29 2015 - -Isn't it wrong that the second thread actually took the same 13 seconds as the -first thread? -Better check with some other compiler in case it was me who made a mistake. -Unfortunately, the program behaves as expected when compiled using GCC: - - Entered get_logger at Fri Jul 3 02:27:12 2015 - Entered get_duke at Fri Jul 3 02:27:12 2015 - Exiting get_logger at Fri Jul 3 02:27:15 2015 - Exiting get_duke at Fri Jul 3 02:27:25 2015 - -So it appears that the implementation of `std::call_once` shipped with Visual -Studio 2012/2013 relies on some kind of a global lock, which causes even the -simple example above to misbehave. - -The [complete code sample] to demonstrate the misbehaviour described above can -be found in this blog's repository. - -[complete code sample]: {{ site.github.repository_url }}/tree/master/std_call_once_bug - -Resolution ----------- - -So, since I couldn't submit the bug via Visual Studio's [Connect page], I wrote -to Mr. Lavavej directly, not hoping for an answer. -Amazingly, it took him less than a day to reply. -He told me he was planning to overhaul `std::call_once` for Visual Studio 2015. -Meanwhile, I had to stick to something else; I think I either dropped logging -from `Duke`'s constructor or initialized all the singleton instances manually -before actually using any of them. -In a few months, Mr. Lavavej replied to me that the bug has been fixed in -Visual Studio 2015 RTM. -I would like to thank him for the professionalism and responsibility he's -shown. diff --git a/_posts/2017-01-07-building-boost.md b/_posts/2017-01-07-building-boost.md deleted file mode 100644 index 052bb26..0000000 --- a/_posts/2017-01-07-building-boost.md +++ /dev/null @@ -1,248 +0,0 @@ ---- -title: Building Boost on Windows -excerpt: > - This post describes the process of building Boost on Windows using either - Visual Studio or the combination of Cygwin + MinGW-w64. -category: C++ -custom_css: - - syntax.css ---- -Below you can find the steps required to build Boost libraries on Windows. -These steps tightly fit my typical workflow, which is to use Boost libraries in -CMake builds using either Visual Studio or the combination of Cygwin + -MinGW-w64. -I would expect, however, that the procedure for the latter toolset can easily -be adjusted for generic GCC distributions (including vanilla GCCs found in -popular Linux distributions). - -One of the features of this workflow is that I build throwaway, "run -everywhere, record the results, and scrap it" executables more often than not, -so I prefer to link everything statically, including, for instance, C/C++ -runtimes. -This is implemented by passing `runtime-link=static` to Boost's build utility -`b2`; change this to `runtime-link=dynamic` to link the runtime dynamically. - -Excerpts from shell sessions in this post feature a few different commands -besides Boost's `b2` and `cmake`, like `cd` and `cat`. -They are used to hint at my personal directory layout, display various -auxiliary files, etc. -Windows' `cd`, for example, simply prints the current working directory; -Cygwin's `pwd` serves the same purpose. -`cat` is used to display files. -Windows' command prompts are denoted with `>`s at the beginning of each line; -Cygwin's — with `$`s. - -Visual Studio -------------- - -Statically-linked Boost libraries are built, both the debug and the release -versions of them (these are default settings). -While it is required to keep x86 and x64 libraries in different directories (to -avoid file name clashes), it's not necessary to separate debug libraries from -their release counterparts, because that information is actually encoded in -file names (the "gd" suffix). - -### x86 - -``` -> cd -D:\workspace\third-party\boost_1_61_0\msvc - -> bootstrap -... - -> b2 --stagedir=stage\x86 ^ - runtime-link=static ^ - --with-filesystem ^ - --with-program_options ^ - ... -... -``` - -### x64 - -The only important difference is that you have to pass `address-model=64` to -`b2` (notice also the different "staging" directory). - -``` -> cd -D:\workspace\third-party\boost_1_61_0\msvc - -> bootstrap -... - -> b2 --stagedir=stage\x64 ^ - runtime-link=static ^ - address-model=64 ^ - --with-filesystem ^ - --with-program_options ^ - ... -... -``` - -Cygwin + MinGW-w64 ------------------- - -Contrary to the Visual Studio example above, it is required to store debug and -release libraries *as well as* x86 and x64 libraries in different directories. -It is required to avoid file name clashes; unlike the Visual Studio "toolset" -(in Boost's terms), GCC-derived toolsets don't encode any information (like -whether the debug or the release version of a library was built) in file names. - -Also, linking the runtime statically doesn't really make sense for MinGW, as it -always links to msvcrt.dll, which is [simply the Visual Studio 6.0 runtime]. - -[simply the Visual Studio 6.0 runtime]: https://sourceforge.net/p/mingw-w64/wiki2/The%20case%20against%20msvcrt.dll/ - -In the examples below, only the debug versions of the libraries are built. -Build the release versions by executing the same command, and substituting -`variant=release` instead of `variant=debug` and either -`--stagedir=stage/x86/release` or `--stagedir=stage/x64/release`, depending -on the target architecture. - -### x86 - -``` -$ pwd -/cygdrive/d/workspace/third-party/boost_1_61_0/mingw - -$ ./bootstrap.sh -... - -$ cat user-config-x86.jam -using gcc : : i686-w64-mingw32-g++ ; - -$ ./b2 toolset=gcc-mingw \ - target-os=windows \ - link=static \ - variant=debug \ - --stagedir=stage/x86/debug \ - --user-config=user-config-x86.jam \ - --with-filesystem \ - --with-program_options \ - ... -... -``` - -The "user" configuration file above stopped working at some point; not sure as -to who's to blame, Cygwin or Boost. -If you see something like "`error: provided command 'i686-w64-mingw32-g++' not -found`", add ".exe" to the binary name above, so that the whole file reads -"`using gcc : : i686-w64-mingw32-g++.exe ;`". -{: .alert .alert-info } - -### x64 - -Notice the two major differences from the x86 example: - -* the addition of `address-model=64` (as in the example for Visual Studio), -* the different "user" configuration file, pointing to `x86_64-w64-mingw32-g++` -instead of `i686-w64-mingw32-g++`. - -Again, as in the example for Visual Studio, a different "staging" directory -needs to be specified using the `--stagedir` parameter. - -``` -$ cd -/cygdrive/d/workspace/third-party/boost_1_61_0/mingw - -$ ./bootstrap.sh -... - -$ cat user-config-x64.jam -using gcc : : x86_64-w64-mingw32-g++ ; - -$ ./b2 toolset=gcc-mingw \ - address-model=64 \ - target-os=windows \ - link=static \ - variant=debug \ - --stagedir=stage/x64/debug \ - --user-config=user-config-x64.jam \ - --with-filesystem \ - --with-program_options \ - ... -... -``` - -The "user" configuration file above stopped working at some point; not sure as -to who's to blame, Cygwin or Boost. -If you see something like "`error: provided command 'x86_64-w64-mingw32-g++' -not found`", add ".exe" to the binary name above, so that the whole file reads -"`using gcc : : x86_64-w64-mingw32-g++.exe ;`". -{: .alert .alert-info } - -Usage in CMake --------------- - -### Visual Studio - -Examples below apply to Visual Studio 2015. -You may want to adjust the paths. - -#### x86 - -``` -> cd -D:\workspace\build\test_project\msvc\x64 - -> cmake -G "Visual Studio 14 2015" ^ - -D BOOST_ROOT=D:\workspace\third-party\boost_1_61_0\msvc ^ - -D BOOST_LIBRARYDIR=D:\workspace\third-party\boost_1_61_0\msvc\stage\x86\lib ^ - -D Boost_USE_STATIC_LIBS=ON ^ - -D Boost_USE_STATIC_RUNTIME=ON ^ - ... -``` - -#### x64 - -``` -> cd -D:\workspace\build\test_project\msvc\x86 - -> cmake -G "Visual Studio 14 2015 Win64" ^ - -D BOOST_ROOT=D:\workspace\third-party\boost_1_61_0\msvc ^ - -D BOOST_LIBRARYDIR=D:\workspace\third-party\boost_1_61_0\msvc\stage\x64\lib ^ - -D Boost_USE_STATIC_LIBS=ON ^ - -D Boost_USE_STATIC_RUNTIME=ON ^ - ... -``` - -### Cygwin & MinGW-w64 - -Examples below only apply to debug CMake builds. -Notice that, contrary to the Visual Studio examples above, debug and release -builds must be kept in separate directories. -You may also want to adjust the paths. - -#### x86 - -``` -$ pwd -/cygdrive/d/workspace/build/test_project/mingw/x86/debug - -$ cmake -G "Unix Makefiles" \ - -D CMAKE_BUILD_TYPE=Debug \ - -D CMAKE_C_COMPILER=i686-w64-mingw32-gcc \ - -D CMAKE_CXX_COMPILER=i686-w64-mingw32-g++ \ - -D BOOST_ROOT=/cygdrive/d/workspace/third-party/boost_1_61_0/mingw \ - -D BOOST_LIBRARYDIR=/cygdrive/d/workspace/third-party/boost_1_61_0/mingw/stage/x86/debug/lib \ - -D Boost_USE_STATIC_LIBS=ON \ - ... -``` - -#### x64 - -``` -$ pwd -/cygdrive/d/workspace/build/test_project/mingw/x64/debug - -$ cmake -G "Unix Makefiles" \ - -D CMAKE_BUILD_TYPE=Debug \ - -D CMAKE_C_COMPILER=x86_64-w64-mingw32-gcc \ - -D CMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++ \ - -D BOOST_ROOT=/cygdrive/d/workspace/third-party/boost_1_61_0/mingw \ - -D BOOST_LIBRARYDIR=/cygdrive/d/workspace/third-party/boost_1_61_0/mingw/stage/x64/debug/lib \ - -D Boost_USE_STATIC_LIBS=ON \ - ... -``` diff --git a/_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md b/_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md deleted file mode 100644 index 4cb0960..0000000 --- a/_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md +++ /dev/null @@ -1,279 +0,0 @@ ---- -title: static vs. inline vs. namespace { -excerpt: > - Should I use `static`, `inline` or unnamed namespaces for function - definitions? -category: C++ -custom_css: - - snippets.css - - syntax.css -snippets_root_directory: snippets/static_vs_inline_vs_unnamed_namespaces -snippets_language: c++ -snippets: - static: - - static/main.cpp - - static/proxy.cpp - - static/proxy.hpp - - static/shared.hpp - inline: - - inline/shared.hpp - inline_weird: - - inline/weird/main.cpp - - inline/weird/another.cpp - - inline/weird/another.hpp - unnamed_namespaces_weird: - - unnamed_namespaces/weird/main.cpp - - unnamed_namespaces/weird/another.cpp - - unnamed_namespaces/weird/another.hpp - unnamed_namespaces_ok: - - unnamed_namespaces/ok/main.cpp - - unnamed_namespaces/ok/another.cpp - - unnamed_namespaces/ok/another.hpp - static_and_inline: - - static_and_inline/main.cpp - - static_and_inline/proxy.cpp - - static_and_inline/proxy.hpp - - static_and_inline/shared.hpp - unnamed_namespace_and_inline: - - unnamed_namespace_and_inline/main.cpp - - unnamed_namespace_and_inline/proxy.cpp - - unnamed_namespace_and_inline/proxy.hpp - - unnamed_namespace_and_inline/shared.hpp - separate_method_definitions: - - separate_method_definitions/main.cpp - - separate_method_definitions/another.cpp - - separate_method_definitions/another.hpp - - separate_method_definitions/shared.hpp ---- -In this post I'll try to figure out whether I should use `static`, `inline` or -unnamed namespaces for function definitions. - -`static` --------- - -It's an old C-style method of defining functions in header files. -This way, every translation unit gets its own copy of a function. -What does that mean? -The most obvious implication that pops into my head is that every local static -variable defined inside that function gets an independent replica in every -translation unit. -For example, the program below would print - -``` -1 -1 -``` - -due to the fact that both main.cpp and proxy.cpp get their own versions of `n` -from `shared()`. - -{% include snippets/section.html section_id='static' %} - -In C, this is the only way to share function definitions between translation -units (apart from the usual way of declaring a function in a header file and -putting its definition to a .c file). - -### Properties - -* Using `static`, you can share function definitions between multiple -translation units. -* Each unit gets its own replica of the function: they have different -addresses, their local static variables are independent, etc. -* If different translation units define different functions with the same -name using the `static` specifier, each unit can use its function without any -issues. -This might seem like an trivial claim, but other approaches sometimes disallow -this, which is discussed below. - -`inline` --------- - -It's well-known that this keyword has pretty much nothing to do with whether a -function will actually be inlined or not. -It's used much more often to define functions in header files, since every -function defined this way will be the same (as in "will have the same address") -in every translation unit. -Let's try and adjust the definition of `shared()` accordingly: - -{% include snippets/section.html section_id='inline' %} - -The same program would then print - -``` -1 -2 -``` - -since both `main()` and `proxy()` would call the same `shared()`, incrementing -the same `n`. - -Weird things happen when different translation units define different `inline` -functions with the same name. - -{% include snippets/section.html section_id='inline_weird' %} - -According to my simple experiments, this program produces different output -based on which .cpp file was specified first on the command line during -compilation. -For example, this is the output of test.exe produced with either `cl /W4 /EHsc -main.cpp another.cpp /Fe:test.exe` or `g++ -Wall -Wextra -std=c++11 main.cpp -another.cpp -o test.exe`. - -``` -main.cpp: shared() -main.cpp: shared() -``` - -If we swap the order of .cpp files (`another.cpp main.cpp` instead of `main.cpp -another.cpp`), the output becomes - -``` -another.cpp: shared() -another.cpp: shared() -``` - -No warnings/errors are emitted, making the situation truly disturbing. -I tested this with GNU compiler version 5.4.0 and Microsoft compiler version -19.00.24210. - -This behaviour can be easily fixed either by making these functions `static` or -by using unnamed namespaces (see below). - -### Properties - -* Using `inline`, you can share function definitions between multiple -translation units. -* Each translation unit will use the same function: it will have the same -address in every translation unit, its local static variables will be shared, -etc. -* Defining different `inline` functions with the same name in different -translation units is undefined behaviour. - -Two inline functions might be different even if they are the same textually. -For example, they might reference two global variables which have the same -name, but are defined in different translation units. -{: .alert .alert-info } - -`namespace {` -------------- - -With respect to function definitions, unnamed namespaces are, according to my -understanding, quite similar to the `static` keyword. -The additional value they provide is that they provide a way to apply `static` -not only to functions, but to classes also. -Remember the weirdness that happens when multiple translation units define -different `inline` functions with the same name? -Arguably, it gets even worse if we add classes to the equation. - -{% include snippets/section.html section_id='unnamed_namespaces_weird' %} - -Compiling this program the same way we did in the `inline` example (`cl /W4 -/EHsc main.cpp another.cpp /Fe:test.exe`/`g++ -Wall -Wextra -std=c++11 main.cpp -another.cpp -o test.exe`) yields different outputs depending on which .cpp file -was specified first. - -``` -main.cpp: Test::Test() -1 -main.cpp: Test::Test() -``` - -``` -another.cpp: Test::Test() -1065353216 -another.cpp: Test::Test() -``` - -I'm not sure why anybody would want that. -This can be easily fixed by putting both `Test` classes into unnamed -namespaces. -The program than reads - -{% include snippets/section.html section_id='unnamed_namespaces_ok' %} - -After the adjustment, it produces the same output regardless of compilation -options. - -``` -main.cpp: Test::Test() -1 -another.cpp: Test::Test() -``` - -Notice how sharing classes defined in header files isn't discussed here. -The standard actually guarantees that if a class is defined in a header file, -all translation units that use it share the definition. - -### Properties - -* Essentially, unnamed namespaces allow the `static` keyword to be applied to -classes. -* Similar to the `static` approach, each translation unit gets its own replica -of a function/class, including their own local static variables, etc. -* Defining different classes with the same name in different translation units -(without utilizing unnamed namespaces) is undefined behaviour. - -Conclusion ----------- - -Here's my attempt to build an algorithm to decide whether a class/function -should be defined with either of the `static`/`inline` specifiers or put into -an unnamed namespace. -The first question I answer is: is the entity defined in a header file or in a -.cpp file? - -* **In a header** — Is it a class or a function? - * **Class** — There's no need to do anything. - * **Function** — Do you want it to behave differently for each -translation unit (may be useful, for example, for logging)? - * **Yes** — Use `static`. - * **No** — Use `inline`. -* **In a .cpp file** — Put it into an unnamed namespace. - -Tricky cases ------------- - -### `static` + `inline` - -In case a function is defined as `static inline`, `static` wins, and `inline` -is ignored. -The program below outputs - -``` -1 -1 -``` - -{% include snippets/section.html section_id='static_and_inline' %} - -In general, I can't think of a reason to define a `static inline` function. - -### `namespace {` + `inline` - -If an `inline` function is defined in an unnamed namespace, the unnamed -namespace wins. -The program below outputs - -``` -1 -1 -``` - -{% include snippets/section.html section_id='unnamed_namespace_and_inline' %} - -In general, I can't think of a reason to define an `inline` function in an -unnamed namespace. - -### Separate method definitions - -If you want to separate your class declaration from its method definitions -while keeping them in the same header file, each method must be explicitly -defined `inline`. -The program below outputs - -``` -1 -2 -``` - -{% include snippets/section.html section_id='separate_method_definitions' %} diff --git a/_posts/2018-02-18-peculiar-indentation.md b/_posts/2018-02-18-peculiar-indentation.md deleted file mode 100644 index 7832194..0000000 --- a/_posts/2018-02-18-peculiar-indentation.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: Peculiar Haskell indentation -excerpt: > - An explanation for nasty `parse error`s I used to get for nested `do` - blocks. -category: Haskell -custom_css: - - syntax.css ---- -I've fallen into a Haskell indentation pitfall. -I think it must be common, so I'm describing it here. - -The problem is that indentation rules in `do` blocks are not intuitive to me. -For example, the following function is valid Haskell syntax: - -```haskell -foo1 :: IO () -foo1 = - alloca $ \a -> - alloca $ \b -> - alloca $ \c -> do - poke a (1 :: Int) - poke b (1 :: Int) - poke c (1 :: Int) - return () -``` - -In fact, this funnier version is also OK: - -```haskell -foo2 :: IO () -foo2 = alloca $ \a -> - alloca $ \b -> - alloca $ \c -> do - poke a (1 :: Int) - poke b (1 :: Int) - poke c (1 :: Int) - return () -``` - -If you add an outer `do` however, things become a little more complicated. -For example, this is the valid version of the functions above with an outer -`do`: - -```haskell -foo3 :: IO () -foo3 = do - alloca $ \a -> - alloca $ \b -> - alloca $ \c -> do - poke a (1 :: Int) - poke b (1 :: Int) - poke c (1 :: Int) - return () -``` - -Notice the extra indentation for each of the `alloca`s. -When I tried to remove these seemingly excessive indents, GHC complained with -the usual `parse error (possibly incorrect indentation or mismatched -brackets)`. - -```haskell -foo4 :: IO () -foo4 = do - alloca $ \a -> - alloca $ \b -> - alloca $ \c -> do - poke a (1 :: Int) - poke b (1 :: Int) - poke c (1 :: Int) - return () -``` - -The truth is, the rules for desugaring `do` blocks are surprisingly simple and -literal. -GHC inserts semicolons according to the rules [found in the Wikibook]. -So it inserts semicolons between the `alloca`s on the same level, so `foo4` -becomes: - -```haskell -foo4 :: IO () -foo4 = do - { alloca $ \a -> - ; alloca $ \b -> - ; alloca $ \c -> do - { poke a (1 :: Int) - ; poke b (1 :: Int) - ; poke c (1 :: Int) - ; return () - } - } -``` - -[found in the Wikibook]: https://en.wikibooks.org/wiki/Haskell/Indentation#Explicit_characters_in_place_of_indentation - -The semicolons after `->` are clearly invalid Haskell syntax, hence the error. - -P.S. To compile the functions above, you need to include them in a module and -add proper imports, e.g. - -```haskell -module PeculiarIndentation where - -import Foreign.Marshal.Alloc (alloca) -import Foreign.Storable (poke) -``` diff --git a/_posts/2019-09-30-recurring-decimals.md b/_posts/2019-09-30-recurring-decimals.md deleted file mode 100644 index 741d083..0000000 --- a/_posts/2019-09-30-recurring-decimals.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: Recurring decimals -excerpt: > - Eighth-grader thoughts on recurring decimals. -category: Math -mathjax: true ---- -{% include common/mathjax_workaround.md %} - -First, let's determine that - -$$ -\newcommand\naturals{\mathbb{N}} -\newcommand\rationals{\mathbb{Q}} -\newcommand\reals{\mathbb{R}} - -\newcommand\xs{x_{1}x_{2}\dots x_n} -\newcommand\nines{\overbrace{99\dots 9}^n} -\newcommand\pq{\frac{p}{q}} -\newcommand\qp{\frac{q}{p}} - -0.(9) = 1 -$$ - -This may seem counter-intuitive, but demonstrably true. -If $$0.(9) \neq 1$$, then $$\exists n \in \reals: 0.(9) < n < 1$$. -To put it another way, there must be a number greater than 0.(9) and lesser -than 1, equal to neither. -Thinking about it makes it obvious this is not true. - -Slightly more formally, - -$$ -\begin{align*} -1 - 0.9 &= \frac{1}{10} \\ -1 - 0.99 &= \frac{1}{100} \\ -1 - 0.999 &= \frac{1}{10^{-3}} \\ -\dots \\ -1 - 0.\nines &= \frac{1}{10^n} \\ -\end{align*} -$$ - -If $$0.(9) \neq 1$$, the following must hold: - -$$ -\forall n \in \naturals, \exists x \in \reals: x < \frac{1}{10^n} -$$ - -It's clear that the only such number is 0, making 0.(9) and 1 equal. - -Let $$n \in [1,9]$$. -Is there $$\pq \in \rationals: \pq = 0.(n)$$? - -For $$n = 9$$, we've established $$p = 1, q = 1$$. -For the other values of $$n$$ we can observe that - -$$ -\begin{align*} -0.(1) \times 9 &= 0.(9) = 1 \\ -0.(2) \times 9/2 &= 0.(9) = 1 \\ -0.(3) \times 9/3 &= 0.(9) \\ -\dots \\ -0.(8) \times 9/8 &= 0.(9) \\ -0.(9) \times 1 &= 0.(9) -\end{align*} -$$ - -So, - -$$ -\forall n \in [1,9], \frac{n}{9} = 0.(n) -$$ - -In general, let's demonstrate that - -$$ -\forall n \in \naturals, n > 0, \forall 0.(x_{1}x_{2}\dots x_n), \exists \pq \in \rationals: \pq = 0.(\xs) -$$ - -Let $$p = \xs, q =\,\nines$$. -It's clear that - -$$ -\begin{align*} -0.(\xs) \times \qp &= 0.(\xs) \times \frac{\nines}{\xs} \\ -&= \left(\frac{\xs}{10^n} + \frac{\xs}{10^{2n}} + \dots\right) \times \frac{\nines}{\xs} \\ -&= \left(\frac{1}{10^n} + \frac{1}{10^{2n}} + \dots\right) \times\,\nines \\ -&= 0.(9) \\ -&= 1 -\end{align*} -$$ - -Finally, $$0.(\xs) \times \qp = 1 \implies \pq = 0.(\xs)$$. diff --git a/_posts/2020-02-24-ssh-tunnel-windows.md b/_posts/2020-02-24-ssh-tunnel-windows.md deleted file mode 100644 index a847ff4..0000000 --- a/_posts/2020-02-24-ssh-tunnel-windows.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -title: Persistent SSH tunnel -excerpt: ... using Cygwin. ---- -SSH tunneling is awesome. -For some reason, I've only recently learned about this feature, but I've been -immediately blown away by how useful it can be. - -Basically, to use SSH tunneling (a.k.a. port forwarding) you need to have a SSH -client (`ssh`) with an access to a SSH server. -You can then access any port on any host your SSH server has access to. -It works like this: - -* your SSH client establishes a connection to the SSH server, -* the client asks the server to forward incoming requests to the destination -host, -* the client listens to the proxy port on the local machine, and forwards -requests to the SSH server. - -Say, you have access to SSH server `gateway` on port 22, and you want to gain -access to HTTPS server `dest` on port 443, which is only accessible from the -network both it and the SSH server belong to. -You can then run something like - -``` -ssh -L 4433:dest:443 gateway -p 22 -``` - -And now you can access `dest` at `https://localhost:4433/`. -That's brilliant, really. - -But there's more. -You can make a _reverse_ tunnel, allowing you to give access to any host your -client computer has access to, via a remote SSH server. -It works like this: - -* your SSH client establishes a connection with the SSH server, -* the client asks the server to listen to a port of your choosing and forward -incoming requests to the client, -* the client forwards incoming requests to the destination host. - -This, as I've recently learned, is a common pattern to subvert corporate -firewalls, which frequently forbid incoming connections. -Say, you want to access your work computer from home via RDP. -Both your home and your work computers have access to a SSH server `gateway` on -port 22 (you might want to change it to port 80 or 443 if your outside -connections are filtered). - -You can then run something like (notice the `-R`) - -``` -ssh -R 13389:127.0.0.1:3389 gateway -p 22 -``` - -and now you can connect to `gateway:13389` from your home computer using a RDP -client. -Even more brilliant! - -You might need to set the `GatewayPorts` setting to `yes` or `clientspecified` -on your SSH server (typically in "/etc/ssh/sshd_config"). - -Batch mode ----------- - -If you want to establish a reverse SSH tunnel automatically, some tweaking is -required. -First, set some SSH client options: - -* `-F /dev/null` to disregard the user config, -* `-oBatchMode=yes` to run non-interactively, -* `-oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null` to disable server -verification (optional), -* `-oExitOnForwardFailure=yes` to exit if port forwarding fails, -* `-oServerAliveCountMax=3 -oServerAliveInterval=15` to break the connection if -the server or the network is down, -* `-N -n -T` to only forward the ports and not execute the shell or any -additional commands. - -Thus, the full command would be something like - -``` -ssh \ - -F /dev/null \ - -oBatchMode=yes \ - -oStrictHostKeyChecking=no \ - -oUserKnownHostsFile=/dev/null \ - -oExitOnForwardFailure=yes \ - -oServerAliveCountMax=3 \ - -oServerAliveInterval=15 \ - -N -n -T \ - -R 13389:127.0.0.1:3389 \ - user@gateway -p 22 \ - -i ~/.ssh/tunnel -``` - -Adjust the `user@gateway -p 22` part accordingly. - -Notice also `-i ~/.ssh/tunnel`. -It's the path to the SSH key used to authenticate with the server. -It can't have a passphrase, since the command will be run non-interactively, -and the public key must be in the server's authorized_keys file. - -For best results, you should also adjust some settings on the SSH server. -Namely, you should enable client keep-alives on the server using something like - -``` -ClientAliveCountMax 3 -ClientAliveInterval 15 -``` - -Unless you do that, even if the client breaks the connection, you won't be able -to re-establish it for a long-ish time, since the server wouldn't know that the -original connection is no longer valid. - -As a service ------------- - -Cygwin is awesome. -I've been using for 10+ years, and it has never failed me. -It comes with a SSH server, a client (you need to install the `openssh` package -for both of these), and a service manager, `cygrunsrv`. -`cygrunsrv` is similar to [NSSM], as it allows to wrap any executable into a -native Windows service. - -[NSSM]: https://nssm.cc/ - -Using `cygrunsrv`, you can create a Windows service to establish a reverse SSH -tunnel automatically. - -``` -cygrunsrv \ - -I ssh_tunnel \ - -p /usr/bin/ssh \ - --args '-F /dev/null -oBatchMode=yes -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oExitOnForwardFailure=yes -oServerAliveCountMax=3 -oServerAliveInterval=15 -N -n -T -R 13389:127.0.0.1:3389 user@gateway -p 22 -i ~/.ssh/tunnel' \ - --disp 'Reverse SSH tunnels' \ - --user user \ - --neverexits \ - --preshutdown -``` - -Adjust the `--user` and the `--args` values accordingly. - -You can then run `services.msc` and adjust the recovery settings for the -service to restart if `ssh` fails: - -<div class="row"> - <div class="col-xs-12 col-sm-8 col-md-6"> - <a href="{{ site.baseurl }}/img/ssh_tunnel_services.png" class="thumbnail"> - <img class="img-responsive" alt="services.msc" src="{{ site.baseurl }}/img/ssh_tunnel_services.png"> - </a> - </div> -</div> - -And voilà, you have an automatic reverse SSH tunnel on Windows for you! diff --git a/_posts/2020-05-06-docker-bind-mounts.md b/_posts/2020-05-06-docker-bind-mounts.md deleted file mode 100644 index 9853331..0000000 --- a/_posts/2020-05-06-docker-bind-mounts.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -title: 'Docker: bind mounts & file ownership' -excerpt: Docker + bind mounts + non-root users = pain. ---- -If you want to: - -1. run your Docker service as a user other than root, -2. share a writable directory between your host and the container, - -you're in for a treat! -The thing is, files stored in the shared directory retain their ownership (and -by that I mean their UIDs and GIDs, as they're the only thing that matters) -after being mounted in the container. - -Case in point: - - docker run -it --rm -v "$( pwd ):/data" alpine touch /data/test.txt - -would create file ./test.txt owned by root:root. - -You can fix that by using the `--user` parameter: - - docker run -it --rm -v "$( pwd ):/data" --user "$( id -u ):$( id -g )" alpine touch /data/test.txt - -That would create file ./test.txt owned by the current user (if the current -working directory is writable by the current user, of course). - -More often though, instead of a simple `touch` call, you have a 24/7 service, -which absolutely mustn't run as root, regardless of whether `--user` was -specified or not. -In such cases, the logical solution would be to create a regular user in the -container, and use it to run the service. -In fact, that's what many popular images do, i.e. [Redis][Redis Dockerfile] and -[MongoDB][MongoDB Dockerfile]. - -[Redis Dockerfile]: https://github.com/docker-library/redis/blob/cc1b618d51eb5f6bf6e3a03c7842317b38dbd7f9/6.0/Dockerfile#L4 -[MongoDB Dockerfile]: https://github.com/docker-library/mongo/blob/5cbf7be9a486932b7e472a39e432c9a444628465/4.2/Dockerfile#L4 - -How do you run the service as regular user though? -It's tempting to use the `USER` directive in the Dockerfile, but that can be -overridden by `--user`: - - $ cat Dockerfile - FROM alpine - - RUN addgroup --gid 9099 test-group && \ - adduser \ - --disabled-password \ - --gecos '' \ - --home /home/test-user \ - --ingroup test-group \ - --uid 9099 \ - test-user - - RUN touch /root.txt - USER test-user:test-group - RUN touch /home/test-user/test-user.txt - - CMD id && stat -c '%U %G' /root.txt && stat -c '%U %G' /home/test-user/test-user.txt - - $ docker build -t id . - ... - - $ docker run -it --rm id - uid=9099(test-user) gid=9099(test-group) - root root - test-user test-group - - $ docker run -it --rm --user root id - uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) - root root - test-user test-group - -I suppose that's the reason why many popular images override ENTRYPOINT, using -a custom script (and `gosu`, which is basically `sudo`, I think) to forcefully -drop privileges (for example, see [Redis][Redis entrypoint], -[MongoDB][MongoDB entrypoint]). - -[Redis entrypoint]: https://github.com/docker-library/redis/blob/cc1b618d51eb5f6bf6e3a03c7842317b38dbd7f9/6.0/docker-entrypoint.sh#L11 -[MongoDB entrypoint]: https://github.com/docker-library/mongo/blob/5cbf7be9a486932b7e472a39e432c9a444628465/4.2/docker-entrypoint.sh#L12 - -Now, what if such service needs persistent storage? -A good solution would be to use Docker volumes. -For development though, you often need to just share a directory between your -host and the container, and it has to be writable by both the host and the -container process. -This can be accomplished using _bind mounts_. -For example, let's try to map ./data to /data inside a Redis container (this -assumes ./data doesn't exist and you're running as regular user with UID 1000; -press Ctrl+C to stop Redis): - - $ mkdir data - - $ stat -c '%u' data - 1000 - - $ docker run -it --rm --name redis -v "$( pwd )/data:/data" redis:6.0 - ... - - $ stat -c '%u' data - 999 - -As you can see, ./data changed its owner from user with UID 1000 (the host -user) to user with UID 999 (the `redis` user inside the container). -This is done in Redis' ENTRYPOINT script, just before dropping root privileges -so that the `redis-server` process owns the /data directory and thus can write -to it. - -If you want to preserve ./data ownership, Redis' image (and many others) -explicitly accomodates for it by _not_ changing its owner if the container is -run as anybody other than root. -For example: - - $ mkdir data - - $ stat -c '%u' data - 1000 - - $ docker run -it --rm --name redis -v "$( pwd )/data:/data" --user "$( id -u ):$( id -g )" redis:6.0 - ... - - $ stat -c '%u' data - 1000 - -Sometimes `--user` is not enough though. -That specified user is almost certainly missing from container's /etc/passwd, -it doesn't have a $HOME, etc. -All of that could cause problems with some applications. - -One scenario I had to deal with is making an image that bundles all the gems -(and a specific Ruby version) for my Ruby web application. -That application shouldn't be run as root, but it must be able to pick up code -changes on the fly, and I should be able `docker exec` into the container, -update the dependencies (along with Gemfile[.lock], and those changes should be -reflected on the host without messing up file metadata), and restart the app. -It's quite easy to install the dependencies in the Dockerfile, but they (along -with the mapped Gemfile[.lock]) should be writable by the user running the -service. -The solution often suggested is to create a container user with a fixed UID -(that would match the host user UID). -That way, it would be able to update the dependencies stored in the container, -as well as write to the bind mount owned by the host user with the same UID. -Additionally, file ownership info would be preserved on the host! - -We can create a user with a fixed UID when - -1. building the image (using build `ARG`uments), -2. first starting the container by passing the required UID using environment -variables. - -The advantages of creating the user when building the image is that we can also -install the dependencies in the Dockerfile, thus eliminating the need to -rebuild them for every other application. -The disadvantage is that the image would need to be rebuilt for every user on -every machine. - -Creating the user when first starting the container has the advantage of not -requiring image rebuilds. -But, as the dependencies need to be installed after creating the user, you'd -have to waste resources by installing them for every user and every app on -every machine (each time when creating a container). - -For my project [jekyll-docker] I opted for the former approach, making sure the -`jekyll` process runs with the same UID as the user who built the image (unless -it was built by root, in which case it falls back to a custom UID of 999). - -[jekyll-docker]: https://github.com/egor-tensin/jekyll-docker - -Useful links ------------- - -* [Docker and \-\-userns-remap, how to manage volume permissions to share data between host and container?](https://stackoverflow.com/q/35291520/514684) -* [What is the (best) way to manage permissions for Docker shared volumes?](https://stackoverflow.com/q/23544282/514684) -* [Handling Permissions with Docker Volumes](https://denibertovic.com/posts/handling-permissions-with-docker-volumes/) -* [File Permissions: the painful side of Docker](https://blog.gougousis.net/file-permissions-the-painful-side-of-docker/) -* [Avoiding Permission Issues With Docker-Created Files](https://vsupalov.com/docker-shared-permissions/) diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/shared.hpp deleted file mode 100644 index 796ea85..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/shared.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -inline int shared() { - static int n = 0; - return ++n; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.cpp deleted file mode 100644 index 330ba80..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "another.hpp" - -#include <iostream> - -inline void shared() { - std::cout << "another.cpp: shared()\n"; -} - -void another() { - shared(); -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.hpp deleted file mode 100644 index 9c26d3f..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void another(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/main.cpp deleted file mode 100644 index e278b9f..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/main.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "another.hpp" - -#include <iostream> - -inline void shared() { - std::cout << "main.cpp: shared()\n"; -} - -int main() { - shared(); - another(); - return 0; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.cpp deleted file mode 100644 index f13b3a1..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "another.hpp" -#include "shared.hpp" - -void another() { - Test test; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.hpp deleted file mode 100644 index 9c26d3f..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void another(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/main.cpp deleted file mode 100644 index b3118c1..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "another.hpp" -#include "shared.hpp" - -int main() { - Test test; - another(); - return 0; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/shared.hpp deleted file mode 100644 index ef4da34..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/shared.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include <iostream> - -struct Test { - Test(); -}; - -inline Test::Test() { - static int x = 0; - std::cout << ++x << '\n'; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/main.cpp deleted file mode 100644 index fde1a43..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "proxy.hpp" -#include "shared.hpp" - -#include <iostream> - -int main() { - std::cout << shared() << '\n'; - std::cout << proxy() << '\n'; - return 0; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.cpp deleted file mode 100644 index 78e4611..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "proxy.hpp" -#include "shared.hpp" - -int proxy() { - return shared(); -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.hpp deleted file mode 100644 index 7dfc52a..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -int proxy(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/shared.hpp deleted file mode 100644 index 647f49e..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/shared.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -static int shared() { - static int n = 0; - return ++n; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/main.cpp deleted file mode 100644 index fde1a43..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "proxy.hpp" -#include "shared.hpp" - -#include <iostream> - -int main() { - std::cout << shared() << '\n'; - std::cout << proxy() << '\n'; - return 0; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.cpp deleted file mode 100644 index 78e4611..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "proxy.hpp" -#include "shared.hpp" - -int proxy() { - return shared(); -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.hpp deleted file mode 100644 index 7dfc52a..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -int proxy(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/shared.hpp deleted file mode 100644 index 28de441..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/shared.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -static inline int shared() { - static int x = 0; - return ++x; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/main.cpp deleted file mode 100644 index fde1a43..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/main.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "proxy.hpp" -#include "shared.hpp" - -#include <iostream> - -int main() { - std::cout << shared() << '\n'; - std::cout << proxy() << '\n'; - return 0; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.cpp deleted file mode 100644 index 78e4611..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "proxy.hpp" -#include "shared.hpp" - -int proxy() { - return shared(); -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.hpp deleted file mode 100644 index 7dfc52a..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -int proxy(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/shared.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/shared.hpp deleted file mode 100644 index e21a00c..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/shared.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -namespace { - -inline int shared() { - static int x = 0; - return ++x; -} - -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.cpp deleted file mode 100644 index cc7556d..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "another.hpp" - -#include <iostream> - -namespace { - -struct Test { - Test() { - std::cout << "another.cpp: Test::Test()\n"; - } - - float y = 1.; -}; - -} - -void another() { - Test test; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.hpp deleted file mode 100644 index 9c26d3f..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void another(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/main.cpp deleted file mode 100644 index e383ded..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/main.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "another.hpp" - -#include <iostream> - -namespace { - -struct Test { - Test() { - std::cout << "main.cpp: Test::Test()\n"; - } - - int x = 1; -}; - -} - -int main() { - Test test; - std::cout << test.x << '\n'; - another(); - return 0; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.cpp deleted file mode 100644 index 0e0bff9..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "another.hpp" - -#include <iostream> - -struct Test { - Test() { - std::cout << "another.cpp: Test::Test()\n"; - } - - float y = 1.; -}; - -void another() { - Test test; -} diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.hpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.hpp deleted file mode 100644 index 9c26d3f..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void another(); diff --git a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/main.cpp b/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/main.cpp deleted file mode 100644 index abd42b7..0000000 --- a/_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/main.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "another.hpp" - -#include <iostream> - -struct Test { - Test() { - std::cout << "main.cpp: Test::Test()\n"; - } - - int x = 1; -}; - -int main() { - Test test; - std::cout << test.x << '\n'; - another(); - return 0; -} diff --git a/all/index.html b/all/index.html deleted file mode 100644 index 71e24f2..0000000 --- a/all/index.html +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: All posts -groups: - - navbar -navbar_link: <span class="glyphicon glyphicon-th-list"></span> Posts -navbar_priority: 2 ---- -{% if site.categories.size != 0 %} - {% for category in site.categories %} - <h1><a class="category" href="{{ site.baseurl }}/categories/{{ category[0] | slugify: 'pretty' }}">{{ category[0] }}</a></h1> - <hr/> - <ul> - {% for post in category[1] %} - <li><a href="{{ site.baseurl }}{{ post.url }}">{{ post.date | date: "%Y-%m-%d" }} — {{ post.title }}</a></li> - {% endfor %} - </ul> - {% endfor %} -{% else %} - <p>Sorry, no posts have been added yet.</p> - <hr/> -{% endif %} diff --git a/css/common/footer.css b/assets/css/common/footer.css index 1e05c57..1e05c57 100644 --- a/css/common/footer.css +++ b/assets/css/common/footer.css diff --git a/css/common/misc.css b/assets/css/common/misc.css index 4bf362b..4bf362b 100644 --- a/css/common/misc.css +++ b/assets/css/common/misc.css diff --git a/css/snippets.css b/assets/css/snippets.css index 78fa9e9..78fa9e9 100644 --- a/css/snippets.css +++ b/assets/css/snippets.css diff --git a/css/syntax.css b/assets/css/syntax.css index 855ae2c..855ae2c 100644 --- a/css/syntax.css +++ b/assets/css/syntax.css diff --git a/build.sh b/build.sh deleted file mode 100755 index 249700b..0000000 --- a/build.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -o nounset -o pipefail - -script_name="$( basename -- "${BASH_SOURCE[0]}" )" - -case "$#" in - 0) ;; - 1) - dest_dir="$1" - ;; - *) - echo "usage: $script_name [DEST_DIR]" >&2 - exit 1 -esac - -bundle exec jekyll build \ - --config _config.yml,_config_dev.yml \ - ${dest_dir+--destination "$dest_dir"} \ - --drafts diff --git a/categories/c++/index.html b/categories/c++/index.html deleted file mode 100644 index 05a5f3f..0000000 --- a/categories/c++/index.html +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: C++ -category: C++ ---- diff --git a/categories/haskell/index.html b/categories/haskell/index.html deleted file mode 100644 index 1f19919..0000000 --- a/categories/haskell/index.html +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Haskell -category: Haskell ---- diff --git a/categories/math/index.html b/categories/math/index.html deleted file mode 100644 index 9019971..0000000 --- a/categories/math/index.html +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Math -category: Math ---- diff --git a/img/ssh_tunnel_services.png b/img/ssh_tunnel_services.png Binary files differdeleted file mode 100644 index 163cb24..0000000 --- a/img/ssh_tunnel_services.png +++ /dev/null diff --git a/index.html b/index.html deleted file mode 100644 index 69c22ad..0000000 --- a/index.html +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: Main page -groups: - - navbar -navbar_link: <span class="glyphicon glyphicon-home"></span> Main page -navbar_priority: 1 -root_page: true ---- -{% if site.posts.size == 0 %} - <p class="h3">Sorry, no posts have been added yet.</p> - <hr/> -{% else %} - {% for post in paginator.posts %} - <h2><a href="{{ site.baseurl }}{{ post.url }}">{{ post.title }}</a></h2> - <p class="text-muted"> - <span class="glyphicon glyphicon-time"></span> Posted on {{ post.date | date: '%-d %B %Y' }} - {%- if post.category %} in <span class="glyphicon glyphicon-folder-open"></span> <a class="category" href="{{ site.baseurl }}/categories/{{ post.category | slugify: 'pretty' }}/">{{ post.category }}</a>{% endif %} - </p> - {{ post.excerpt | markdownify }} - <hr/> - {% endfor %} - <div class="text-center"> - {% include common/paginator.html %} - </div> -{% endif %} diff --git a/notes/index.html b/notes/index.html deleted file mode 100644 index 0ceb78c..0000000 --- a/notes/index.html +++ /dev/null @@ -1,21 +0,0 @@ ---- -layout: default -title: Notes -groups: - - navbar -navbar_link: <span class="glyphicon glyphicon-search"></span> Notes -navbar_priority: 3 ---- -<h1>{{ page.title }}</h1> -<hr/> -{% if site.notes.size != 0 %} - <p>This is a complete list of notes I maintain for my personal usage.</p> - <ul> - {% assign note_list = site.notes | sort: 'title' %} - {% for note in note_list %} - <li><a href="{{ site.baseurl }}{{ note.url }}">{{ note.title }}</a></li> - {% endfor %} - </ul> -{% else %} - <p>Sorry, no notes have been added yet.</p> -{% endif %} diff --git a/serve.bat b/serve.bat deleted file mode 100644 index c4dcd0c..0000000 --- a/serve.bat +++ /dev/null @@ -1 +0,0 @@ -bundle exec jekyll serve --watch --force_polling --host 0.0.0.0 --drafts --config _config.yml,_config_dev.yml diff --git a/serve.sh b/serve.sh deleted file mode 100755 index 933f365..0000000 --- a/serve.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -o nounset -o pipefail - -script_name="$( basename -- "${BASH_SOURCE[0]}" )" - -case "$#" in - 0) ;; - 1) - dest_dir="$1" - ;; - *) - echo "usage: $script_name [DEST_DIR]" >&2 - exit 1 -esac - -bundle exec jekyll serve \ - --config _config.yml,_config_dev.yml \ - ${dest_dir+--destination "${dest_dir}"} \ - --drafts \ - --force_polling \ - --host 0.0.0.0 \ - --watch |