aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/_posts
diff options
context:
space:
mode:
authorEgor Tensin <Egor.Tensin@gmail.com>2020-05-07 01:48:11 +0000
committerEgor Tensin <Egor.Tensin@gmail.com>2020-05-07 01:48:11 +0000
commitadb9b3fe169a92ea2da7b8c804c8b91f966c21a4 (patch)
treefe340f4de0afa6763e220194d2e6bea3366b4c71 /_posts
parentbind-mounts: rename the file (diff)
downloadjekyll-theme-adb9b3fe169a92ea2da7b8c804c8b91f966c21a4.tar.gz
jekyll-theme-adb9b3fe169a92ea2da7b8c804c8b91f966c21a4.zip
remove everything except Jekyll theme stuff
I tagged the previous commit to explain what's going on.
Diffstat (limited to '_posts')
-rw-r--r--_posts/2015-07-03-std-call-once-bug.md258
-rw-r--r--_posts/2017-01-07-building-boost.md248
-rw-r--r--_posts/2017-06-24-static-vs-inline-vs-unnamed-namespaces.md279
-rw-r--r--_posts/2018-02-18-peculiar-indentation.md106
-rw-r--r--_posts/2019-09-30-recurring-decimals.md93
-rw-r--r--_posts/2020-02-24-ssh-tunnel-windows.md154
-rw-r--r--_posts/2020-05-06-docker-bind-mounts.md176
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/shared.hpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.cpp11
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/another.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/inline/weird/main.cpp13
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.cpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/another.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/main.cpp8
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/separate_method_definitions/shared.hpp12
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/main.cpp10
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.cpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/proxy.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static/shared.hpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/main.cpp10
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.cpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/proxy.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/static_and_inline/shared.hpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/main.cpp10
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.cpp6
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/proxy.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespace_and_inline/shared.hpp10
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.cpp19
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/another.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/ok/main.cpp22
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.cpp15
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/another.hpp3
-rw-r--r--_posts/snippets/static_vs_inline_vs_unnamed_namespaces/unnamed_namespaces/weird/main.cpp18
33 files changed, 0 insertions, 1535 deletions
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 &mdash; 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&nbsp;{
-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** &mdash; Is it a class or a function?
- * **Class** &mdash; There's no need to do anything.
- * **Function** &mdash; Do you want it to behave differently for each
-translation unit (may be useful, for example, for logging)?
- * **Yes** &mdash; Use `static`.
- * **No** &mdash; Use `inline`.
-* **In a .cpp file** &mdash; 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;
-}