Blog on Victor Kropphttps://victor.kropp.name/blog/
Recent content in Blog on Victor KroppHugo -- gohugo.ioUnless otherwise noted, content on this site is licensed under a <a href="http://creativecommons.org/licenses/by-nc-sa/4.0">CC BY-NC-SA 4.0</a> license. <a href="https://victor.kropp.name/disclaimer">Disclaimer</a>Fri, 01 Jan 2016 00:00:00 +0000Ubuntu Theme for IntelliJ IDEAhttps://victor.kropp.name/blog/intellij-theme-ubuntu/
Fri, 15 Mar 2019 14:49:14 +0100https://victor.kropp.name/blog/intellij-theme-ubuntu/<p>Following yesterday’s <a href="https://blog.jetbrains.com/idea/2019/03/brighten-up-your-day-add-color-to-intellij-idea/">announcement</a> of custom themes support for IntelliJ IDEA, I’m excited to release a preview of <a href="https://plugins.jetbrains.com/plugin/12105-ubuntu-theme">Ubuntu theme</a>. It is based on awesome Darcula theme, but is tuned to match Yaru color scheme introduced in Ubuntu 18.10.</p>
<figure>
<img src="https://victor.kropp.name/projects/intellij-theme-ubuntu/screenshot.png"
alt="Ubuntu theme for IntelliJ IDEA" width="1000" height="700"/> <figcaption>
<p>Ubuntu theme for IntelliJ IDEA</p>
</figcaption>
</figure>
<p>Creating a new visual theme for JetBrains’ IDEs is now <a href="https://blog.jetbrains.com/platform/2019/03/creating-custom-themes-for-intellij-platform-ides/">easier than ever</a>, check out the documentation and try it yourself. You can tweak colors and apply changes instantly right in the editor!</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2019/intellij-theme-apply.gif"
alt="Applying theme from the editor" width="800" height="600"/> <figcaption>
<p>Applying theme from the editor</p>
</figcaption>
</figure>
<p>The source code of this theme is available on <i class="fa fa-github" style="color: rgb(23,21,21)"></i> <a href="https://github.com/kropp/intellij-theme-ubuntu">GitHub</a>. It is work in progress and Pull Requests are welcome!</p>
<p><a href="https://plugins.jetbrains.com/plugin/12105-ubuntu-theme">Give it a try</a> and let me know what you think.</p>
X11 app in Kotlin/Nativehttps://victor.kropp.name/blog/x11-app-in-kotlin-native/
Tue, 19 Feb 2019 13:20:41 +0300https://victor.kropp.name/blog/x11-app-in-kotlin-native/
<p>In this blog post, we will go step by step through a process of creation of a simple full-screen always on top Linux application. It will dim the screen and only highlight area around mouse cursor like in a stage light. I won’t be using any UI framework, but stick to bare essentials provided by <a href="https://www.x.org/releases/current/doc/libX11/libX11/libX11.html">Xlib</a>. There are two reasons to do this: first, all frameworks have a huge toolkit of UI elements, such as buttons or menus, but they are not very well suited to just show a semi-transparent window and paint on it. Second, it makes a lot of fun to dig into a low-level technology and learn how it works.</p>
<blockquote>
<p>X Server is an application that manages graphics displays and input devices (keyboards, mice, etc.) on Linux. It is also known as X11 because it implements the eleventh version of the X protocol. The most widely used implementation now is <a href="https://x.org">X.org</a>. X server uses a client-server model. GUI applications usually run on the same computer, but it may also work over the network. It is possible to write a GUI application using only Xlib—a X11 client library, but usually, high-level UI frameworks are used, like <a href="https://victor.kropp.name/blog/kotlin-native-0.2-and-gtk/">GTK+</a> or Qt.</p>
</blockquote>
<p>I will be using <a href="https://kotlinlang.org/docs/reference/native-overview.html">Kotlin/Native</a>, so you&rsquo;ll also learn how interoperability with native C libraries works in Kotlin/Native.</p>
<p>Here is what I will be implementing tonight.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2019/x11-demo-beam.gif"
alt="My homepage in spotlight" width="800"/> <figcaption>
<p>My homepage in spotlight</p>
</figcaption>
</figure>
<h3 id="interoperability-with-c-libraries">Interoperability with C libraries</h3>
<p>So, let’s start! To begin with we need to teach Kotlin/Native how to use Xlib. Kotlin/Native compiler includes a tool called <code>cinterop</code>. It generates bindings to native libraries defined in <code>.def</code> file. Here’s the definition for Xlib:</p>
<div class="highlight"><pre class="chroma"><code class="language-make" data-lang="make"><span class="nv">package</span> <span class="o">=</span> x11
<span class="nv">headers</span> <span class="o">=</span> X11/Xlib.h X11/Xutil.h X11/Xatom.h
<span class="nv">headerFilter</span> <span class="o">=</span> X11/*
<span class="nv">compilerOpts</span> <span class="o">=</span> -I/usr/include/ -I/usr/include/x86_64-linux-gnu
<span class="nv">linkerOpts</span> <span class="o">=</span> -lX11 -L/usr/lib/x86_64-linux-gnu/
</code></pre></div>
<p>Here, we give the generated package a name, <code>x11</code> in our case. We tell <strong>cinterop</strong> to generate bindings to all functions and structs defined in <code>Xlib.h</code>, <code>Xutil.h</code> and <code>Xatom.h</code> (we’ll see later why we need these header files) and transitively included from them, but filtered by path mask <code>X11/*</code>. This prevents us from accidentally generating bindings for the whole <em>world</em>.</p>
<p><code>compilerOpts</code> set the base path to search for header files and <code>linkerOpts</code> tell compiler to link to <code>libX11.so</code> and where to find it. You can find complete reference for the tool in the <a href="https://kotlinlang.org/docs/reference/native/c_interop.html">official documentation</a>.</p>
<h3 id="basic-app">Basic app</h3>
<h4 id="initialization">Initialization</h4>
<p>To connect to a X Server we open a display connection.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">val</span> <span class="py">display</span> <span class="p">=</span> <span class="n">XOpenDisplay</span><span class="p">()</span> <span class="o">?:</span> <span class="n">error</span><span class="p">(</span><span class="s">&#34;Can&#39;t open display&#34;</span><span class="p">)</span>
<span class="k">val</span> <span class="py">screen</span> <span class="p">=</span> <span class="n">XDefaultScreenOfDisplay</span><span class="p">(</span><span class="n">display</span><span class="p">)</span> <span class="o">?:</span> <span class="n">error</span><span class="p">(</span><span class="s">&#34;Can&#39;t detect default screen&#34;</span><span class="p">)</span>
<span class="k">val</span> <span class="py">screenWidth</span> <span class="p">=</span> <span class="n">screen</span><span class="p">.</span><span class="n">pointed</span><span class="p">.</span><span class="n">width</span><span class="p">.</span><span class="n">toUInt</span><span class="p">()</span>
<span class="k">val</span> <span class="py">screenHeight</span> <span class="p">=</span> <span class="n">screen</span><span class="p">.</span><span class="n">pointed</span><span class="p">.</span><span class="n">height</span><span class="p">.</span><span class="n">toUInt</span><span class="p">()</span>
<span class="n">XFree</span><span class="p">(</span><span class="n">screen</span><span class="p">)</span></code></pre></div>
<p>Kotlin’s <code>cinterop</code> usually does a good job, so this code looks pretty much like its C analogue, just with a little mix of Kotlin flavor.</p>
<p>To dereference a pointer there is an extension property <code>CPointer.pointed</code>. It works as expected, even though it requires more typing compared to <code>*</code> or <code>-&gt;</code> in C/C++.
Despite <code>width</code> and <code>height</code> are signed integers in <code>Screen</code> subsequent APIs will require unsigned integers, so we also convert them immediately. In C such conversions are implicit, so in many places like this, types are inconsistent. Kotlin is much stricter, which results in more verbose, but hopefully safer code.</p>
<h4 id="create-and-show-window">Create and show window</h4>
<p>Next step is to create a window. We want our window to be semi-transparent, so we need to set some custom window attributes. C structs are mapped to Kotliln classes, but in order to be able to pass them later to native code, we need to allocate them in native memory. We create <code>XVisualInfo</code> struct by calling <code>alloc</code> inside a <code>memScoped</code> block. To prevent memory leaks everything allocated inside this block will be freed on exit.</p>
<p>Created object will have <code>.ptr</code> extension property which works like <code>&amp;</code> operator in C. It returns a pointer to a local variable.</p>
<p>Similarly <code>XSetWindowAttributes</code> struct is created. The important thing here is to set 32-bit depth to allow transparency. Finally, a window is created with all the attributes specified.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">val</span> <span class="py">window</span> <span class="p">=</span> <span class="n">memScoped</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">visualInfo</span> <span class="p">=</span> <span class="n">alloc</span><span class="p">&lt;</span><span class="n">XVisualInfo</span><span class="p">&gt;()</span>
<span class="n">XMatchVisualInfo</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">screenNumber</span><span class="p">,</span> <span class="m">32</span><span class="p">,</span> <span class="n">TrueColor</span><span class="p">,</span> <span class="n">visualInfo</span><span class="p">.</span><span class="n">ptr</span><span class="p">)</span>
<span class="k">val</span> <span class="py">attrs</span> <span class="p">=</span> <span class="n">alloc</span><span class="p">&lt;</span><span class="n">XSetWindowAttributes</span><span class="p">&gt;</span> <span class="p">{</span>
<span class="n">override_redirect</span> <span class="p">=</span> <span class="m">1</span>
<span class="n">colormap</span> <span class="p">=</span> <span class="n">XCreateColormap</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">XDefaultRootWindow</span><span class="p">(</span><span class="n">display</span><span class="p">),</span> <span class="n">visualInfo</span><span class="p">.</span><span class="n">visual</span><span class="p">,</span> <span class="n">AllocNone</span><span class="p">)</span>
<span class="n">border_pixel</span> <span class="p">=</span> <span class="m">0UL</span>
<span class="n">background_pixel</span> <span class="p">=</span> <span class="m">0xffffffUL</span>
<span class="p">}.</span><span class="n">ptr</span>
<span class="n">XCreateWindow</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">XRootWindow</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">screenNumber</span><span class="p">),</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">screen</span><span class="p">.</span><span class="n">width</span><span class="p">,</span> <span class="n">screen</span><span class="p">.</span><span class="n">height</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">visualInfo</span><span class="p">.</span><span class="n">depth</span><span class="p">,</span> <span class="n">CopyFromParent</span><span class="p">.</span><span class="n">toUInt</span><span class="p">(),</span>
<span class="n">visualInfo</span><span class="p">.</span><span class="n">visual</span><span class="p">,</span> <span class="p">(</span><span class="n">CWColormap</span> <span class="n">or</span> <span class="n">CWBorderPixel</span> <span class="n">or</span> <span class="n">CWBackPixel</span> <span class="n">or</span> <span class="n">CWOverrideRedirect</span><span class="p">).</span><span class="n">toULong</span><span class="p">(),</span> <span class="n">attrs</span><span class="p">)</span>
<span class="p">}</span></code></pre></div>
<p>We don’t need <code>visualInfo</code> and <code>attrs</code> after window is created and <code>memScoped</code> takes care of them.</p>
<p>The window can be shown as easy as</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="n">XMapWindow</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">window</span><span class="p">)</span>
<span class="n">XRaiseWindow</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">window</span><span class="p">)</span>
<span class="n">XFlush</span><span class="p">(</span><span class="n">display</span><span class="p">)</span></code></pre></div>
<p>This code snippet puts the window on a given display, brings it to front and forces repaint. And again it doesn&rsquo;t differ at all from its C counterpart.</p>
<h4 id="auxillary-settings">Auxillary settings</h4>
<p>It is unnecessary for this particular application, but we can set the window name, which will be displayed in window switcher and window class name which will be used to match window and application icon. I only include this snippet to demonstrate a small inconsistency in C-interop.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">const</span> <span class="k">val</span> <span class="py">APPLICATION_NAME</span> <span class="p">=</span> <span class="s">&#34;spotlight&#34;</span>
<span class="n">XStoreName</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">window</span><span class="p">,</span> <span class="n">APPLICATION_NAME</span><span class="p">)</span>
<span class="n">memScoped</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">hint</span> <span class="p">=</span> <span class="n">alloc</span><span class="p">&lt;</span><span class="n">XClassHint</span><span class="p">&gt;</span> <span class="p">{</span>
<span class="n">res_name</span> <span class="p">=</span> <span class="n">APPLICATION_NAME</span><span class="p">.</span><span class="n">cstr</span><span class="p">.</span><span class="n">ptr</span>
<span class="n">res_class</span> <span class="p">=</span> <span class="n">APPLICATION_NAME</span><span class="p">.</span><span class="n">cstr</span><span class="p">.</span><span class="n">ptr</span>
<span class="p">}</span>
<span class="n">XSetClassHint</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">window</span><span class="p">,</span> <span class="n">hint</span><span class="p">.</span><span class="n">ptr</span><span class="p">)</span>
<span class="p">}</span></code></pre></div>
<p>When calling a C function <code>char*</code> parameter is translated to Kotlin’s <code>String</code>, so the function call is absolutely transparent. However, if we need to pass the very same string in a struct field the things get complicated: we need first to convert it to a C-string (effectively array of bytes) and then get a pointer to it. Thus, this <code>.cstr.ptr</code> calls inside a <code>memScoped</code>.</p>
<h4 id="always-on-top">Always on top</h4>
<p>To keep the window always on top, we need to ask a window manager to do it for us by sending it an event.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">val</span> <span class="py">e</span> <span class="p">=</span> <span class="n">alloc</span><span class="p">&lt;</span><span class="n">XEvent</span><span class="p">&gt;</span> <span class="p">{</span>
<span class="n">xclient</span><span class="p">.</span><span class="n">apply</span> <span class="p">{</span>
<span class="n">type</span> <span class="p">=</span> <span class="n">ClientMessage</span>
<span class="n">message_type</span> <span class="p">=</span> <span class="n">XInternAtom</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="s">&#34;_NET_WM_STATE&#34;</span><span class="p">,</span> <span class="n">False</span><span class="p">)</span>
<span class="k">this</span><span class="p">.</span><span class="n">display</span> <span class="p">=</span> <span class="n">display</span>
<span class="k">this</span><span class="p">.</span><span class="n">window</span> <span class="p">=</span> <span class="n">window</span>
<span class="n">format</span> <span class="p">=</span> <span class="m">32</span>
<span class="n">serial</span> <span class="p">=</span> <span class="m">0UL</span>
<span class="k">data</span><span class="p">.</span><span class="n">l</span><span class="na">[0]</span> <span class="p">=</span> <span class="m">1</span>
<span class="k">data</span><span class="p">.</span><span class="n">l</span><span class="na">[1]</span> <span class="p">=</span> <span class="n">XInternAtom</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="s">&#34;_NET_WM_STATE_STAYS_ON_TOP&#34;</span><span class="p">,</span> <span class="n">False</span><span class="p">).</span><span class="n">toLong</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">XSendEvent</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">XRootWindow</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">screenNumber</span><span class="p">),</span> <span class="n">False</span><span class="p">,</span> <span class="n">SubstructureRedirectMask</span><span class="p">,</span> <span class="n">e</span><span class="p">.</span><span class="n">ptr</span><span class="p">)</span></code></pre></div>
<p><code>XEvent</code> is a union in C, which combines all event types in a single structure by mapping the same memory area to different fields depending on a way you access it. You cannot define such data type in Kotlin, but accessing native union types works as expected. Each possible variant is represented by a property.</p>
<h4 id="hiding-and-showing-mouse-cursor">Hiding and showing mouse cursor</h4>
<p>To hide mouse pointer we create an empty cursor out of an empty bitmap with empty mask and default color both for foreground and background. Since both the shape and the mask of the cursor are empty it doesn’t really matter what color we use. This method only hides the pointer, all the associated events, like hovering or clicks still work.</p>
<p>To show the cursor back we revert the change by call to <code>XUndefineCursor</code>.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="n">@kotlin</span><span class="p">.</span><span class="n">ExperimentalUnsignedTypes</span>
<span class="k">class</span> <span class="nc">MousePointer</span><span class="p">(</span><span class="k">private</span> <span class="k">val</span> <span class="py">display</span><span class="p">:</span> <span class="n">CPointer</span><span class="p">&lt;</span><span class="n">Display</span><span class="p">&gt;,</span> <span class="k">private</span> <span class="k">val</span> <span class="py">window</span><span class="p">:</span> <span class="n">Window</span><span class="p">)</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">hide</span><span class="p">()</span> <span class="p">=</span> <span class="n">memScoped</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">bitmap</span> <span class="p">=</span> <span class="n">XCreateBitmapFromData</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">window</span><span class="p">,</span> <span class="s">&#34;\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000&#34;</span><span class="p">,</span> <span class="m">8</span><span class="p">,</span> <span class="m">8</span><span class="p">)</span>
<span class="k">val</span> <span class="py">black</span> <span class="p">=</span> <span class="n">alloc</span><span class="p">&lt;</span><span class="n">XColor</span><span class="p">&gt;</span> <span class="p">{</span>
<span class="n">red</span> <span class="p">=</span> <span class="m">0U</span>
<span class="n">green</span> <span class="p">=</span> <span class="m">0U</span>
<span class="n">blue</span> <span class="p">=</span> <span class="m">0U</span>
<span class="p">}</span>
<span class="k">val</span> <span class="py">cursor</span> <span class="p">=</span> <span class="n">XCreatePixmapCursor</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">bitmap</span><span class="p">,</span> <span class="n">bitmap</span><span class="p">,</span> <span class="n">black</span><span class="p">.</span><span class="n">ptr</span><span class="p">,</span> <span class="n">black</span><span class="p">.</span><span class="n">ptr</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">)</span>
<span class="n">XDefineCursor</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">window</span><span class="p">,</span> <span class="n">cursor</span><span class="p">)</span>
<span class="n">XFreeCursor</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">cursor</span><span class="p">)</span>
<span class="n">XFreePixmap</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">bitmap</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">fun</span> <span class="nf">show</span><span class="p">()</span> <span class="p">{</span>
<span class="n">XUndefineCursor</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">window</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>In this case, automatic <code>char*</code> to String conversion by cinterop is unnecessary. It is possible to <a href="https://github.com/JetBrains/kotlin-native/blob/master/INTEROP.md#working-with-the-strings">disable it for a specific function</a> by adding <code>noStringConversion = XCreateBitmapFromData</code> to <code>x11.def</code></p>
<p><em>We may improve performance of this snippet by allocating <code>cursor</code> in a <code>nativeHeap</code>, which is a global scope, and saving it to a field.</em></p>
<h3 id="event-loop">Event loop</h3>
<p>We’ve finally come to a core part of the program, the event loop. In an infinite loop, we will listen to <a href="https://tronche.com/gui/x/xlib/events/processing-overview.html#PointerMotionMask">input events</a>, like mouse motion and redraw the window accordingly.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="n">XSelectInput</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">window</span><span class="p">,</span> <span class="n">PointerMotionMask</span> <span class="n">or</span> <span class="n">ButtonPressMask</span> <span class="n">or</span> <span class="n">ButtonReleaseMask</span> <span class="n">or</span> <span class="n">KeyPressMask</span> <span class="n">or</span> <span class="n">KeyReleaseMask</span><span class="p">)</span>
<span class="k">val</span> <span class="py">gc</span> <span class="p">=</span> <span class="n">memScoped</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">values</span> <span class="p">=</span> <span class="n">alloc</span><span class="p">&lt;</span><span class="n">XGCValues</span><span class="p">&gt;</span> <span class="p">{</span> <span class="n">graphics_exposures</span> <span class="p">=</span> <span class="n">False</span> <span class="p">}.</span><span class="n">ptr</span>
<span class="n">XCreateGC</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">window</span><span class="p">,</span> <span class="m">0UL</span><span class="p">,</span> <span class="n">values</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">val</span> <span class="py">event</span> <span class="p">=</span> <span class="n">alloc</span><span class="p">&lt;</span><span class="n">XEvent</span><span class="p">&gt;()</span>
<span class="k">while</span> <span class="p">(</span><span class="k">true</span><span class="p">)</span> <span class="p">{</span>
<span class="n">XNextEvent</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">event</span><span class="p">.</span><span class="n">ptr</span><span class="p">)</span>
<span class="n">XSetForeground</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">gc</span><span class="p">,</span> <span class="m">0xdd000000UL</span><span class="p">)</span>
<span class="n">XFillRectangle</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">window</span><span class="p">,</span> <span class="n">gc</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">screen</span><span class="p">.</span><span class="n">width</span><span class="p">,</span> <span class="n">screen</span><span class="p">.</span><span class="n">height</span><span class="p">)</span>
<span class="k">if</span> <span class="p">(</span><span class="n">event</span><span class="p">.</span><span class="n">type</span> <span class="p">==</span> <span class="n">MotionNotify</span><span class="p">)</span> <span class="p">{</span>
<span class="n">XSetForeground</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">gc</span><span class="p">,</span> <span class="m">0x00000000UL</span><span class="p">)</span>
<span class="n">XFillArc</span><span class="p">(</span><span class="n">display</span><span class="p">,</span> <span class="n">window</span><span class="p">,</span> <span class="n">gc</span><span class="p">,</span> <span class="n">event</span><span class="p">.</span><span class="n">xmotion</span><span class="p">.</span><span class="n">x</span> <span class="p">-</span> <span class="n">SIZE</span> <span class="p">/</span> <span class="m">2</span><span class="p">,</span> <span class="n">event</span><span class="p">.</span><span class="n">xmotion</span><span class="p">.</span><span class="n">y</span> <span class="p">-</span> <span class="n">SIZE</span> <span class="p">/</span> <span class="m">2</span><span class="p">,</span> <span class="n">SIZE</span><span class="p">.</span><span class="n">toUInt</span><span class="p">(),</span> <span class="n">SIZE</span><span class="p">.</span><span class="n">toUInt</span><span class="p">(),</span> <span class="m">0</span><span class="p">,</span> <span class="m">360</span> <span class="p">*</span> <span class="m">64</span><span class="p">)</span>
<span class="n">XFlush</span><span class="p">(</span><span class="n">display</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>This is pretty simple, we choose the event types we are interested in and process them one by one. The program will block until next event.</p>
<p>To draw a spotlight we fill the window with semi-transparent black. <code>XFillRectangle</code> does the job, the first component of the foreground color <code>dd000000</code> is alpha-channel. And then draw a fully transparent circle above.</p>
<p>That’s it.</p>
<p>Check out the <a href="https://gist.github.com/kropp/bd8628cce07c81a0c458be565bad4801">full source code</a> of this example!</p>
<h3 id="lessons-learned">Lessons learned</h3>
<p>In this article, we’ve seen how to generate Kotlin/Native <strong>bindings</strong> for native libraries, how clever string bindings are implemented, but also the shortcomings in current implementation, how to create and pass <strong>structs</strong> to native functions from Kotlin code, and how <strong>unions</strong> are mapped to Kotlin.</p>
<p>Overall, Kotlin version of the program is only a little bit verbose compared to the C code, but the resulting code is much safer. And I believe this is a fair price.</p>
Setting up IntelliJ IDEA on Ubuntu 18.10https://victor.kropp.name/blog/intellij-ubuntu-18.10/
Mon, 28 Jan 2019 10:39:42 +0100https://victor.kropp.name/blog/intellij-ubuntu-18.10/
<p>I’ve refreshed my computer recently and installed Ubuntu 18.10 from scratch. It doesn’t require much effort and from my experience is much quicker than installing any other OS. Setting up all the software takes much more time.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2019/ubuntu-intellij.png"
alt="IntelliJ IDEA 2019.1 EAP running on Ubuntu 18.10" width="1000" height="562"/> <figcaption>
<p>IntelliJ IDEA 2019.1 EAP running on Ubuntu 18.10</p>
</figcaption>
</figure>
<p>But first, you need to install your favorite IDE and the best way to do it is, of course, <a href="https://jetbrains.com/toolbox/app/">JetBrains Toolbox App</a>. And not because I’m one of the <a href="https://victor.kropp.name/blog/jetbrains-toolbox/">developers of this application</a>, but because you download it once and then it updates itself and all your IDEs automatically. One less thing to care about.</p>
<h4 id="inotify">inotify</h4>
<p>Before you start the IDE, there is one important system setting to tune. <a href="https://confluence.jetbrains.com/display/IDEADEV/Inotify+Watches+Limit">IntelliJ-based IDEs use inotify</a> to watch project files for changes. This subsystem has very low default watches limit but it&rsquo;s very easy to alter it: just put the following line in <code>/etc/sysctl.d/90-intellij-inotify.conf</code></p>
<div class="highlight"><pre class="chroma"><code class="language-conf" data-lang="conf">fs.inotify.max_user_watches = 524288</code></pre></div>
<p>And run this command in a terminal to apply the change:</p>
<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash">sudo sysctl -p --system</code></pre></div>
<h4 id="keyboard-shortcuts-conflicts">Keyboard shortcuts conflicts</h4>
<p>Don’t close the terminal yet, you’ll need it to resolve keyboard shortcuts conflicts. There are many of them and unfortunately, some are not listed in System Settings → Devices → Keyboard dialog.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2019/settings-keyboard.png"
alt="System keyboard shortucts in Ubuntu/GNOME control center" width="1020" height="750"/> <figcaption>
<p>System keyboard shortucts in Ubuntu/GNOME control center</p>
</figcaption>
</figure>
<p>Most of the conflicts come from workspaces section. If you don’t use workspaces at all you may want to disable these shortcuts completely, like I do. Just run these commands from the terminal.</p>
<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash">gsettings <span class="nb">set</span> org.gnome.desktop.wm.keybindings switch-group <span class="s2">&#34;[&#39;disabled&#39;]&#34;</span>
gsettings <span class="nb">set</span> org.gnome.desktop.wm.keybindings switch-group-backward <span class="s2">&#34;[&#39;disabled&#39;]&#34;</span>
gsettings <span class="nb">set</span> org.gnome.desktop.wm.keybindings toggle-maximized <span class="s2">&#34;[&#39;disabled&#39;]&#34;</span>
gsettings <span class="nb">set</span> org.gnome.desktop.wm.keybindings switch-to-workspace-down <span class="s2">&#34;[&#39;&lt;Super&gt;Page_Down&#39;]&#34;</span>
gsettings <span class="nb">set</span> org.gnome.desktop.wm.keybindings move-to-workspace-down <span class="s2">&#34;[&#39;&lt;Super&gt;&lt;Shift&gt;Page_Down&#39;]&#34;</span>
gsettings <span class="nb">set</span> org.gnome.desktop.wm.keybindings move-to-workspace-up <span class="s2">&#34;[&#39;&lt;Super&gt;&lt;Shift&gt;Page_Up&#39;]&#34;</span>
gsettings <span class="nb">set</span> org.gnome.desktop.wm.keybindings switch-to-workspace-up <span class="s2">&#34;[&#39;&lt;Super&gt;Page_Up&#39;]&#34;</span>
gsettings <span class="nb">set</span> org.gnome.desktop.wm.keybindings switch-to-workspace-left <span class="s2">&#34;[&#39;disabled&#39;]&#34;</span>
gsettings <span class="nb">set</span> org.gnome.desktop.wm.keybindings switch-to-workspace-right <span class="s2">&#34;[&#39;disabled&#39;]&#34;</span>
gsettings <span class="nb">set</span> org.gnome.desktop.wm.keybindings begin-resize <span class="s2">&#34;[&#39;disabled&#39;]&#34;</span>
gsettings <span class="nb">set</span> org.gnome.desktop.interface menubar-accel <span class="s1">&#39;&#39;</span></code></pre></div>
<p>Alt+` shortcut which I use many times daily also conflicts with the system shortcut to switch application window. Since I prefer Alt+Tab to switch between all windows (and use <a href="https://extensions.gnome.org/extension/15/alternatetab/">Alternate Tab</a> GNOME Shell extension to have a better overview), I disabled it too.
I never use Alt+F8 to resize windows, but do use this shortcut in debugger to evaluate expressions. And the last one is F10 absolutely unnecessary reserved for menubar access when fewer and fewer GNOME apps have one.</p>
<h4 id="hidpi-font-scaling">HiDPI font scaling</h4>
<p>If you’re a happy owner of 4K (HiDPI) screen, then you also need to install <code>libgtk2.0-0</code> package, otherwise all text will be rendered in tiny font.</p>
<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash">sudo apt install libgtk2.0-0</code></pre></div>
<p>Here is <a href="https://youtrack.jetbrains.com/issue/JRE-1040">the related issue</a> in the bug tracker, this step will be not be required as soon as it is fixed.</p>
<h4 id="ide-cloud-settings">IDE Cloud Settings</h4>
<p>Now we can finally start the IDE. If you’ve already used it you can skip all initial setup and have your code editor settings, plugins, etc. <a href="https://www.jetbrains.com/help/idea/sharing-your-ide-settings.html">synced from the cloud</a>. This is my preferred option now. And if you’re using Toolbox App as I already suggested, you can sign in into your JetBrains Account there and have all your settings from the cloud with no additional effort.</p>
<h4 id="plugins">Plugins</h4>
<p>There are several <a href="http://plugins.jetbrains.com/">thousand plugins in the repository</a> including <a href="http://plugins.jetbrains.com/author/449d4b59-fc7f-4c81-877a-9d82eacdc737">some by yours truly</a>. I’d like to highlight one here. One of the features of Unity desktop I miss in GNOME Shell is global menu integration because it saved some precious vertical screen space. I know many shortcuts by heart and even if I don’t know the one I use Ctrl+Shift+A to find and invoke needed action. Given all this, I prefer to completely remove the main menu with <a href="http://plugins.jetbrains.com/plugin/7297-main-menu-toggler">Main Menu toggler</a> plugin.</p>
<p>That’s it, happy coding!</p>
2018 Conference Reporthttps://victor.kropp.name/blog/2018-trip-report/
Mon, 24 Dec 2018 13:38:39 +0100https://victor.kropp.name/blog/2018-trip-report/
<p>I&rsquo;ve been at 9 IT events worldwide this year. The topic I&rsquo;ve been speaking most is unsurprisingly Kotlin. You can find complete list of my public appearances in <a href="https://victor.kropp.name/talks">Talks</a> section, but now I want to share only my experience about events themselves.</p>
<h3 id="gdg-nuremberg-android-meetup-https-www-meetup-com-gdg-nuremberg-android-january-10-nuremberg-i-class-flag-flag-de-i"><a href="https://www.meetup.com/GDG-Nuremberg-Android/">GDG Nuremberg Android Meetup</a>, January 10, Nuremberg <i class="flag flag-de"></i></h3>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Enjoyed yesterday&#39;s <a href="https://twitter.com/GDGNbgAndroid?ref_src=twsrc%5Etfw">@GDGNbgAndroid</a> meetup. Thanks for having me! The slides from my talk are here: <a href="https://t.co/IWDwJAxWuZ">https://t.co/IWDwJAxWuZ</a> <a href="https://t.co/VRNzUIX3aP">pic.twitter.com/VRNzUIX3aP</a></p>&mdash; Victor Kropp (@kropp) <a href="https://twitter.com/kropp/status/951447206086828032?ref_src=twsrc%5Etfw">January 11, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>The year has started at a local meetup in Nuremberg. The city is just shy 170 km away from Munich, so I was able to quickly travel there for just a few hours in the evening. The meetup group is way smaller than in Munich, but it doesn&rsquo;t affect the quality of meetups or discussions. Highly recommend visiting them if you&rsquo;re in the area.</p>
<h3 id="codemotion-rome-https-rome2018-codemotionworld-com-april-14-15-rome-i-class-flag-flag-it-i"><a href="https://rome2018.codemotionworld.com/">Codemotion Rome</a>, April 14–15, Rome <i class="flag flag-it"></i></h3>
<p>With three days, multiple tracks and thousands of attendees it’s a relatively big conference which is a part of Codemotion series. I’ve been to their Berlin edition many years before. Nothing has changed much since then, most of the participants are students (the event takes place in a University). The most successful talks in such setting are detailed, but not too deep technical presentations, where the speaker uncovers a particular technology, framework or library. I’ve given two talks there, first got a very positive rating and feedback, the second one was different and unfortunately was aimed at a different audience.</p>
<h3 id="javaday-istanbul-https-2018-javaday-istanbul-may-5-istanbul-i-class-flag-flag-tr-i"><a href="https://2018.javaday.istanbul/">JavaDay Istanbul</a>, May 5, Istanbul <i class="flag flag-tr"></i></h3>
<p>I have mixed feelings about this one: on the one hand, all attendees seemed to be genuinely interested in programming and were thriving to learn. On the other hand, I only spoke with only one guy (except my colleagues of course), because others prefer only to speak Turkish. Nevertheless, I enjoyed the event and the warm welcome.</p>
<h3 id="riga-dev-days-https-2018-rigadevdays-lv-may-29-31-riga-i-class-flag-flag-lv-i"><a href="https://2018.rigadevdays.lv/">Riga Dev Days</a>, May 29-31, Riga <i class="flag flag-lv"></i></h3>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Fantastic performance from laser-cyborg-dancers, who opens <a href="https://twitter.com/hashtag/RigaDevDays?src=hash&amp;ref_src=twsrc%5Etfw">#RigaDevDays</a> today! <a href="https://t.co/F9KmI5EQLq">pic.twitter.com/F9KmI5EQLq</a></p>&mdash; Riga Dev Days (@RigaDevDays) <a href="https://twitter.com/RigaDevDays/status/1001736928520212481?ref_src=twsrc%5Etfw">May 30, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>A remarkable event in the capital of Latvia! Highly recommend it to everyone. The city is charming in May, I’ve only been there in winter before. The conference features two full days of many talks on different topics delivered by experienced speakers. I&rsquo;ve had a lot of inspiring conversations there, and the party after the conference was a success. The highlight of the evening was the drummer <a href="https://www.instagram.com/nellibub/">Nelli Bubujanca</a> and the live drum music she played.</p>
<h3 id="jbcnconf-http-jbcnconf-com-2018-june-11-13-barcelona-i-class-flag-flag-es-i"><a href="http://jbcnconf.com/2018/">JBCNConf</a>, June 11–13, Barcelona <i class="flag flag-es"></i></h3>
<p>JBCNConf is a Community Java Conference, which invited me to talk about Kotlin. It’s nice to see a rising interest in Kotlin among Java developers. The event is fun and the community there is thriving. Sadly I was only able to spend just half a day there.</p>
<h3 id="milan-kotlin-community-conf-https-milan-kotlincommunityconf-com-june-14-milan-i-class-flag-flag-it-i"><a href="https://milan.kotlincommunityconf.com/">Milan Kotlin Community Conf</a>, June 14, Milan <i class="flag flag-it"></i></h3>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Deep purple Milan Kotlin Community Conf dinner! 🤣 <a href="https://twitter.com/kropp?ref_src=twsrc%5Etfw">@kropp</a> <a href="https://twitter.com/PiDayDev?ref_src=twsrc%5Etfw">@PiDayDev</a> <a href="https://twitter.com/jesuswasrasta?ref_src=twsrc%5Etfw">@jesuswasrasta</a> <a href="https://twitter.com/_tiwiz?ref_src=twsrc%5Etfw">@_tiwiz</a> <a href="https://twitter.com/crucio14?ref_src=twsrc%5Etfw">@crucio14</a> <a href="https://twitter.com/TechIsFun?ref_src=twsrc%5Etfw">@TechIsFun</a> <a href="https://twitter.com/mfalcier?ref_src=twsrc%5Etfw">@mfalcier</a> <a href="https://twitter.com/c_bellone?ref_src=twsrc%5Etfw">@c_bellone</a> <a href="https://twitter.com/hashtag/kcc18?src=hash&amp;ref_src=twsrc%5Etfw">#kcc18</a> <a href="https://t.co/nDeFc8GdI6">pic.twitter.com/nDeFc8GdI6</a></p>&mdash; Milan Kotlin Community Conf (@KotlinCommConf) <a href="https://twitter.com/KotlinCommConf/status/1007002441190125569?ref_src=twsrc%5Etfw">June 13, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>After <a href="https://victor.kropp.name/blog/november-2017-trip-report/">NoSlidesConf</a> last year, <a href="https://twitter.com/jesuswasrasta">Ferdinando Santacroce</a> approached me to help organize first Italian community event dedicated entirely to Kotlin. I forwarded organizational inquires to a responsible manager at JetBrains, so I don’t have much detail about this aspect of the conference. But I’ve seen myself, that those folks were able to build a great whole-day two-track event, which was entirely free for the attendees. It was a pleasure to deliver the keynote there; it was very well accepted. I’ve enjoyed Milan and am looking forward to coming back there sometime.</p>
<h3 id="oracle-codeone-https-www-oracle-com-code-one-october-22-25-san-francisco-i-class-flag-flag-us-i"><a href="https://www.oracle.com/code-one/">Oracle CodeOne</a>, October 22–25, San Francisco <i class="flag flag-us"></i></h3>
<p>The biggest Java Conference has been rebranded, but it didn’t change much. Many attendees were still saying JavaOne. And confusing these two names was the most popular joke on stage. Rebranding, however, didn’t help the event. It’s getting smaller and less attractive since I’ve been there last time. Attempt to attract talks about languages other than Java failed. There were far too many talks comparing different languages (on JVM, or Java vs. Go for example). And JavaOne CodeOne remains the main Java conference, with most of the presentations about it and most prominent speakers coming from Java developers and community.</p>
<p>Despite all of this, I was excited to be speaking there; my talk went well. Unfortunately, there is no recording. I haven’t visited other sessions, because I was busy at JetBrains booth most of the time.</p>
<h3 id="devfest-toulouse-https-devfesttoulouse-fr-november-8-toulouse-i-class-flag-flag-fr-i"><a href="https://devfesttoulouse.fr">DevFest Toulouse</a>, November 8, Toulouse <i class="flag flag-fr"></i></h3>
<p>DevFest series of events organized by GDG communities all over the world is mostly dedicated to Android and Google Cloud technologies, but not necessarily. I don’t remember exactly how I’ve found this one, but I liked the diversity of talks. Only a few of them were in English, but organizers aim to have half of the presentations in English in next year.</p>
<p>It’s the city of Airbus, so most of IT people there work directly or indirectly in aero industry. Young people don’t have any problem to speak English. The speakers’ dinner in a bar was also the best I’ve been to. To cut it short, it was a five stars event.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I&#39;ve enjoyed <a href="https://twitter.com/DevFestToulouse?ref_src=twsrc%5Etfw">@DevFestToulouse</a> a lot, but it is now time to go back home. Thanks <a href="https://twitter.com/GDGToulouse?ref_src=twsrc%5Etfw">@GDGToulouse</a> <a href="https://twitter.com/julienrenaux?ref_src=twsrc%5Etfw">@julienrenaux</a> and everyone involved. See you next time! <a href="https://t.co/70hYo8aaI6">pic.twitter.com/70hYo8aaI6</a></p>&mdash; Victor Kropp (@kropp) <a href="https://twitter.com/kropp/status/1060561204769382400?ref_src=twsrc%5Etfw">November 8, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<h3 id="hackatum-https-hack-tum-de-november-16-18-munich-i-class-flag-flag-de-i"><a href="https://hack.tum.de/">hackaTUM</a>, November 16–18, Munich <i class="flag flag-de"></i></h3>
<p>And finally, I gave a workshop during a Hackathon at the local University. I graduated a little less than ten years ago and hadn’t been teaching students for quite a while, so I misjudged the level of the attendees. I was able to change the topic and the structure of my presentation quickly, but it would be much better if I had prepared it differently in the first place. We’ve participated in the Hackathon to promote internships in JetBrains’ Munich office. We’ll see how it goes.</p>
<h3 id="that-s-a-wrap">That’s a wrap!</h3>
<p>It&rsquo;s been a pretty intense year, I&rsquo;ve learned a lot and hope some people learned from me as well. Next year I’d like to prepare new content and travel less, so I haven’t submitted any talks yet. But I already have many ideas, stay tuned!</p>
Makefile support plugin 1.5https://victor.kropp.name/blog/makefile-plugin-1.5/
Thu, 27 Sep 2018 09:18:55 +0200https://victor.kropp.name/blog/makefile-plugin-1.5/<p>I’m very happy to announce the release 1.5 of <a href="https://victor.kropp.name/projects/makefile/">Makefile support plugin</a> for IntelliJ based IDEs, which adds a Make tool window to quickly browse and execute Makefile targets.</p>
<figure>
<img src="https://victor.kropp.name/projects/makefile/makefile-toolwindow.png"
alt="Makefile tool window" width="477" height="318"/> <figcaption>
<p>Makefile tool window</p>
</figcaption>
</figure>
<p>Since I first wrote about the plugin even before its release, I’ve been getting lots of feedback, including many samples when it failed to parse some special directives. Did you know how complex <a href="https://www.gnu.org/software/make/manual/">Makefile syntax</a> is? I know now. And what upsets me the most is that plugin still fails in some rare cases. If you encounter faulty behavior please don’t hesitate to submit an issue on <i class="fa fa-github" style="color: rgb(23,21,21)"></i> <a href="https://github.com/kropp/intellij-makefile">GitHub</a>.</p>
<p>Recently the plugin was <a href="https://blog.jetbrains.com/clion/2018/08/working-with-makefiles-in-clion-using-compilation-db/">featured in CLion blog</a>. I’ve got a lot of positive reviews after that. Thanks to everyone for your feedback and 5-star ratings in the plugin repository. If you haven’t yet put your 5 stars, do it now! This and downloads stats motivate me to continue working on this project.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2018/makefile-plugin-stats.png" width="590" height="170"/>
</figure>
<p>I’ve been preparing this update for quite some time. To efficiently show all Makefiles and target in a tool window, the plugin must first index all of them. So there is now an index, which contributes to an Indexing phase of IntelliJ startup. I tried to keep at as minimal and as simple as possible. As a “side effect,” it also brings performance improvements in different analyses like “Unresolved target” for example.</p>
<p>If you use Makefiles in your project, <a href="https://plugins.jetbrains.com/idea/plugin/9333-makefile-support">install the plugin</a> now!</p>
Unexpected GIF animation issueshttps://victor.kropp.name/blog/unexpected-gif-animation-issues/
Wed, 29 Aug 2018 15:50:33 +0200https://victor.kropp.name/blog/unexpected-gif-animation-issues/<p>Last week I helped to create an animated GIF from a short screencast for a <a href="https://blog.jetbrains.com/blog/2018/08/23/toolbox-app-1-11-whats-new/">blog post</a> announcing Toolbox App 1.11 release. The solution for this task on Ubuntu is pretty straightforward with <code>ffmpeg</code> and <code>ImageMagick</code>:</p>
<pre class="shell nohighlight"><code><b>$</b> ffmpeg -i screencast.mov -r 25 'screencast/frame-%03d.png'
<b>$</b> convert -delay 4 -loop 0 -layers optimize-transparency screencast/*.png screencast.gif
</code></pre>
<p><code>ffmpeg</code> creates a sequence of frames in a given format (defined by the file extension in the pattern) with the given frame rate of 25 fps.</p>
<p><code>convert</code> combines all the frames into an animated GIF. This command sets the delay between frames to 4 hundredths of a second (25 fps × 0.04 delay = 1 second), makes it loop infinitely (non-zero argument makes it repeat a given number of times and then stop), and optimizes file by saving only the difference between frames.</p>
<p>You may optionally also play with <code>-fuzz 1%</code> parameter, I don&rsquo;t recommend it for screencasts where you&rsquo;d better have bigger but crispier image, but if you&rsquo;re working with video, than treating similar colors as the same may significantly reduce each layer and thus the size of the whole file.</p>
<p><em>I intentionally don&rsquo;t make it a one-liner. Usually, GIF animations are short, so you can quickly check out all frames and edit them as necessary. For example, shorten intro and outro, remove unwanted intermediate mouse movements to produce precise and accurate motion.</em></p>
<p>There were few issues though.</p>
<p>First, it didn&rsquo;t work. Well, it worked blazing fast when I didn&rsquo;t want any optimizations but produced 30 MB GIF file, which is… too large even for current download speeds. And when I applied optimizations, it either entered an infinite memory leaking loop or failed with some exceptions shortly after the start. It appeared that the problem was in <a href="https://www.imagemagick.org/discourse-server/viewtopic.php?f=1&amp;t=34044&amp;p=156413#p156413">very low default resource limits</a> (<code>/etc/ImageMagick-6/policy.xml</code>). When I increased them everything worked as expected, it was just a little bit slower than in the first run.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2018/toolbox111-bad.gif"
alt="The image above appears broken in Safari" width="584" height="740"/> <figcaption>
<p>The image above appears broken in Safari</p>
</figcaption>
</figure>
<p>The second problem was that suddenly the resulting GIF didn&rsquo;t display in Safari and Preview on macOS. I spend nearly an hour trying to understand what&rsquo;s wrong with the image, and the answer surprised me. It turned out that cropping I applied to each frame before converting them into a GIF was breaking things. I applied the following command to each image:</p>
<pre class="shell nohighlight"><code><b>$</b> convert -crop 800x600+100+200 image.png
</code></pre>
<p>But this command only crops a visible layer but leaves the original image (Virtual Canvas) size intact. In many image formats, like JPEG, it is unsupported, but GIF supports files in which image size is different from any its layers sizes. And it worked in any browser and app I tried but confused Safari which I didn&rsquo;t try. Alas. Good for me the fix was trivial:</p>
<pre class="shell nohighlight"><code><b>$</b> convert -crop 800x600+100+200 +repage image.png
</code></pre>
<p>It is explained in the <a href="http://www.imagemagick.org/Usage/crop/">documentation</a>, but who reads it? ¯\_(ツ)_/¯</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2018/toolbox111.gif"
alt="Final animation" width="441" height="700"/> <figcaption>
<p>Final animation</p>
</figcaption>
</figure>
Black navigation bar on Galaxy S9https://victor.kropp.name/blog/galaxy-s9-black-navigation-bar/
Sat, 21 Jul 2018 15:08:29 +0200https://victor.kropp.name/blog/galaxy-s9-black-navigation-bar/
<p>I&rsquo;ve been using Galaxy S9 since it&rsquo;s official release. I liked my previous Nexus 6, but unfortunately, it fell off my pocket shortly before. And also I got a good trade-in deal for one of my old phones. Samsung hardware is and has always been great, but their software… meh. It has improved recently, and it&rsquo;s possible to tune or disable most of the &ldquo;features.&rdquo; One thing bothered me though: the navigation bar at the bottom was always bright white. Using apps with a dark theme in the twilight was very uncomfortable.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2018/galaxy-s9-wnb.jpg" width="270" height="555"/>
</figure>
<p>There is an easy solution. It only requires <code>adb</code> tool from <a href="https://developer.android.com/studio/#command-tools">Android SDK</a>.</p>
<p>❗ Do it on your own risk. I&rsquo;m not responsible for any damage caused to your phone or computer by any of these actions.</p>
<p><a href="https://developer.android.com/studio/debug/dev-options#enable">Enable USB debugging</a>. Connect the phone to a computer via a USB cable. Open Terminal and open a remote shell on your phone:</p>
<pre class="shell nohighlight"><code><b>$</b> adb shell
</code></pre>
<p>To check current settings run the following command:</p>
<div class="highlight"><pre class="chroma"><code class="language-nohighlight" data-lang="nohighlight">gsettings list global</code></pre></div>
<p>If you&rsquo;ve set up white navigation bar in System Settings, then among other preferences you&rsquo;ll see:</p>
<div class="highlight"><pre class="chroma"><code class="language-nohighlight" data-lang="nohighlight">navigationbar_color=-986896
navigationbar_current_color=-986896</code></pre></div>
<p>You don&rsquo;t need to remember these since you can always revert to original color in Settings.</p>
<p>And now update the color by issuing two following commands:</p>
<div class="highlight"><pre class="chroma"><code class="language-nohighlight" data-lang="nohighlight">settings put global navigationbar_color=-16777216
settings put global navigationbar_current_color=-16777216</code></pre></div>
<p>Congratulations, you now have a black navigation bar which doesn&rsquo;t hurt your eyes in the dark!</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2018/galaxy-s9-bnb.jpg" width="270" height="555"/>
</figure>
<p>❗ You may want to try other colors; here&rsquo;s a <a href="https://codepen.io/anon/pen/mwQjEZ">color picker</a>. Be careful and do not try to guess colors, if you put an incorrect value, the phone may refuse to boot and need a factory reset. It happened to me, unfortunately. Don&rsquo;t repeat my mistakes.</p>
<h4 id="bonus">Bonus</h4>
<p>When I applied this change, I noticed another option available there: <code>airplane_mode_radios</code>. Its default value is <code>cell,bluetooth,wifi,nfc,wimax</code>. A quick check verified my guess: this is the list of the connections disabled when the phone is in airplane mode. I always use my Bluetooth noise-canceling headphones when I travel, and I do it quite often. I hate to re-enable Bluetooth after I switch the phone to airplane mode before takeoff.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Lufthansa now explicitly allows using Bluetooth during the whole flight. Nice!</p>&mdash; Victor Kropp (@kropp) <a href="https://twitter.com/kropp/status/900310705630580737?ref_src=twsrc%5Etfw">August 23, 2017</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>So now I know how to fix this problem, all I need is to remove <code>bluetooth</code> from the list:</p>
<div class="highlight"><pre class="chroma"><code class="language-nohighlight" data-lang="nohighlight">settings put global airplane_mode_radios=cell,wifi,nfc,wimax</code></pre></div>
<p>It takes just a few seconds to improve your experience from using the phone. It took me much longer to restore the phone after factory reset. And it took me even longer to finish this post.</p>
Thanks plugin for Gradlehttps://victor.kropp.name/blog/gradle-thanks-plugin/
Mon, 15 Jan 2018 15:24:26 +0100https://victor.kropp.name/blog/gradle-thanks-plugin/<p>Please welcome <a href="https://plugins.gradle.org/plugin/com.github.kropp.thanks">Thanks plugin</a> for <a href="https://gradle.org/">Gradle</a>: the simplest way to thank opensource projects you depend upon. When invoked it enumerates all projects dependencies, finds out their Github projects (if source control URL is set in .pom file) and stars all those projects.</p>
<p>The usage is pretty simple, just add the plugin to <code>plugins</code> section:</p>
<div class="highlight"><pre class="chroma"><code class="language-gradle" data-lang="gradle"><span class="n">plugins</span> <span class="o">{</span>
<span class="n">id</span> <span class="s2">&#34;com.github.kropp.thanks&#34;</span> <span class="n">version</span> <span class="s2">&#34;0.3&#34;</span>
<span class="o">}</span></code></pre></div>
<p>Plugin is only compatible with Gradle 4.2 or newer. By default it does nothing, so it is safe to commit this change to your repository. To invoke the plugin, just call Gradle with <code>thanks</code> parameter.</p>
<pre class="shell nohighlight"><code><b>$</b> ./gradlew -q thanks
</code></pre>
<p><em><code>-q</code> disables auxiliary output</em></p>
<p>To access <a href="https://developer.github.com/v3/">GitHub API</a> the plugin needs a valid token. You can get one <a href="https://github.com/settings/tokens/new">here</a>. Only <code>public_repo</code> scope is required.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2018/github-new-token.png" width="1000" height="540"/>
</figure>
<p>Then either set it to an environment variable <code>GITHUB_TOKEN</code> or pass to Gradle with <code>-PGithubToken=…</code> command line parameter.</p>
<p>Here is how it works on a sample project:</p>
<script src="https://asciinema.org/a/UJpnS2sfTioUQ60h37WsagWcu.js" id="asciicast-UJpnS2sfTioUQ60h37WsagWcu" async></script>
<p>Thanks plugin also stars Gradle and known plugins. To add a plugin to a known plugins list, submit <a href="https://github.com/kropp/gradle-plugin-thanks/issues">issue</a> or pull request on <i class="fa fa-github" style="color: rgb(23,21,21)"></i> <a href="https://github.com/kropp/gradle-plugin-thanks">GitHub</a>.</p>
<p>Don&rsquo;t forget to say thanks regularly, because new dependencies are added over time and ask your team colleagues to do the same.</p>
<p>PS. This plugin was inspired by PHP <a href="https://symfony.com/blog/say-thanks-to-the-libraries-you-depend-on">Composer Thanks plugin</a>, which in turn was inspired by Rust&rsquo;s <a href="https://github.com/softprops/cargo-thanks">cargo Thanks plugin</a>. Thanks <a href="https://twitter.com/artspb">@artspb</a> for a link.</p>
2017: Year in Reviewhttps://victor.kropp.name/blog/2017-year-in-review/
Sun, 31 Dec 2017 11:51:47 +0100https://victor.kropp.name/blog/2017-year-in-review/<p>Another year is over. It&rsquo;s time to look back and reminisce.</p>
<p>The most prominent event of the year is, of course, the birth of my son Alex. Being a parent is sometimes exhaustive, but it is always great fun.</p>
<blockquote class="instagram-media" data-instgrm-captioned data-instgrm-permalink="https://www.instagram.com/p/BW13SlzlUVf/?utm_source=ig_embed&amp;utm_medium=loading" data-instgrm-version="12" style=" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; min-width:326px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);"><div style="padding:16px;"> <a href="https://www.instagram.com/p/BW13SlzlUVf/?utm_source=ig_embed&amp;utm_medium=loading" style=" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;" target="_blank"> <div style=" display: flex; flex-direction: row; align-items: center;"> <div style="background-color: #F4F4F4; border-radius: 50%; flex-grow: 0; height: 40px; margin-right: 14px; width: 40px;"></div> <div style="display: flex; flex-direction: column; flex-grow: 1; justify-content: center;"> <div style=" background-color: #F4F4F4; border-radius: 4px; flex-grow: 0; height: 14px; margin-bottom: 6px; width: 100px;"></div> <div style=" background-color: #F4F4F4; border-radius: 4px; flex-grow: 0; height: 14px; width: 60px;"></div></div></div><div style="padding: 19% 0;"></div><div style="display:block; height:50px; margin:0 auto 12px; width:50px;"><svg width="50px" height="50px" viewBox="0 0 60 60" version="1.1" xmlns="https://www.w3.org/2000/svg" xmlns:xlink="https://www.w3.org/1999/xlink"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g transform="translate(-511.000000, -20.000000)" fill="#000000"><g><path d="M556.869,30.41 C554.814,30.41 553.148,32.076 553.148,34.131 C553.148,36.186 554.814,37.852 556.869,37.852 C558.924,37.852 560.59,36.186 560.59,34.131 C560.59,32.076 558.924,30.41 556.869,30.41 M541,60.657 C535.114,60.657 530.342,55.887 530.342,50 C530.342,44.114 535.114,39.342 541,39.342 C546.887,39.342 551.658,44.114 551.658,50 C551.658,55.887 546.887,60.657 541,60.657 M541,33.886 C532.1,33.886 524.886,41.1 524.886,50 C524.886,58.899 532.1,66.113 541,66.113 C549.9,66.113 557.115,58.899 557.115,50 C557.115,41.1 549.9,33.886 541,33.886 M565.378,62.101 C565.244,65.022 564.756,66.606 564.346,67.663 C563.803,69.06 563.154,70.057 562.106,71.106 C561.058,72.155 560.06,72.803 558.662,73.347 C557.607,73.757 556.021,74.244 553.102,74.378 C549.944,74.521 548.997,74.552 541,74.552 C533.003,74.552 532.056,74.521 528.898,74.378 C525.979,74.244 524.393,73.757 523.338,73.347 C521.94,72.803 520.942,72.155 519.894,71.106 C518.846,70.057 518.197,69.06 517.654,67.663 C517.244,66.606 516.755,65.022 516.623,62.101 C516.479,58.943 516.448,57.996 516.448,50 C516.448,42.003 516.479,41.056 516.623,37.899 C516.755,34.978 517.244,33.391 517.654,32.338 C518.197,30.938 518.846,29.942 519.894,28.894 C520.942,27.846 521.94,27.196 523.338,26.654 C524.393,26.244 525.979,25.756 528.898,25.623 C532.057,25.479 533.004,25.448 541,25.448 C548.997,25.448 549.943,25.479 553.102,25.623 C556.021,25.756 557.607,26.244 558.662,26.654 C560.06,27.196 561.058,27.846 562.106,28.894 C563.154,29.942 563.803,30.938 564.346,32.338 C564.756,33.391 565.244,34.978 565.378,37.899 C565.522,41.056 565.552,42.003 565.552,50 C565.552,57.996 565.522,58.943 565.378,62.101 M570.82,37.631 C570.674,34.438 570.167,32.258 569.425,30.349 C568.659,28.377 567.633,26.702 565.965,25.035 C564.297,23.368 562.623,22.342 560.652,21.575 C558.743,20.834 556.562,20.326 553.369,20.18 C550.169,20.033 549.148,20 541,20 C532.853,20 531.831,20.033 528.631,20.18 C525.438,20.326 523.257,20.834 521.349,21.575 C519.376,22.342 517.703,23.368 516.035,25.035 C514.368,26.702 513.342,28.377 512.574,30.349 C511.834,32.258 511.326,34.438 511.181,37.631 C511.035,40.831 511,41.851 511,50 C511,58.147 511.035,59.17 511.181,62.369 C511.326,65.562 511.834,67.743 512.574,69.651 C513.342,71.625 514.368,73.296 516.035,74.965 C517.703,76.634 519.376,77.658 521.349,78.425 C523.257,79.167 525.438,79.673 528.631,79.82 C531.831,79.965 532.853,80.001 541,80.001 C549.148,80.001 550.169,79.965 553.369,79.82 C556.562,79.673 558.743,79.167 560.652,78.425 C562.623,77.658 564.297,76.634 565.965,74.965 C567.633,73.296 568.659,71.625 569.425,69.651 C570.167,67.743 570.674,65.562 570.82,62.369 C570.966,59.17 571,58.147 571,50 C571,41.851 570.966,40.831 570.82,37.631"></path></g></g></g></svg></div><div style="padding-top: 8px;"> <div style=" color:#3897f0; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:550; line-height:18px;"> View this post on Instagram</div></div><div style="padding: 12.5% 0;"></div> <div style="display: flex; flex-direction: row; margin-bottom: 14px; align-items: center;"><div> <div style="background-color: #F4F4F4; border-radius: 50%; height: 12.5px; width: 12.5px; transform: translateX(0px) translateY(7px);"></div> <div style="background-color: #F4F4F4; height: 12.5px; transform: rotate(-45deg) translateX(3px) translateY(1px); width: 12.5px; flex-grow: 0; margin-right: 14px; margin-left: 2px;"></div> <div style="background-color: #F4F4F4; border-radius: 50%; height: 12.5px; width: 12.5px; transform: translateX(9px) translateY(-18px);"></div></div><div style="margin-left: 8px;"> <div style=" background-color: #F4F4F4; border-radius: 50%; flex-grow: 0; height: 20px; width: 20px;"></div> <div style=" width: 0; height: 0; border-top: 2px solid transparent; border-left: 6px solid #f4f4f4; border-bottom: 2px solid transparent; transform: translateX(16px) translateY(-4px) rotate(30deg)"></div></div><div style="margin-left: auto;"> <div style=" width: 0px; border-top: 8px solid #F4F4F4; border-right: 8px solid transparent; transform: translateY(16px);"></div> <div style=" background-color: #F4F4F4; flex-grow: 0; height: 12px; width: 16px; transform: translateY(-4px);"></div> <div style=" width: 0; height: 0; border-top: 8px solid #F4F4F4; border-left: 8px solid transparent; transform: translateY(-4px) translateX(8px);"></div></div></div></a> <p style=" margin:8px 0 0 0; padding:0 4px;"> <a href="https://www.instagram.com/p/BW13SlzlUVf/?utm_source=ig_embed&amp;utm_medium=loading" style=" color:#000; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px; text-decoration:none; word-wrap:break-word;" target="_blank">Like father, like son</a></p> <p style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin-bottom:0; margin-top:8px; overflow:hidden; padding:8px 0 7px; text-align:center; text-overflow:ellipsis; white-space:nowrap;">A post shared by <a href="https://www.instagram.com/victorkropp/?utm_source=ig_embed&amp;utm_medium=loading" style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px;" target="_blank"> Victor Kropp</a> (@victorkropp) on <time style=" font-family:Arial,sans-serif; font-size:14px; line-height:17px;" datetime="2017-07-22T08:09:48+00:00">Jul 22, 2017 at 1:09am PDT</time></p></div></blockquote>
<script async src="//www.instagram.com/embed.js"></script>
<p>Since I became a father, I don&rsquo;t have much free time for running or cycling. Only recently I started jogging with a stroller. But I did my second IRONMAN in September in Italy despite total lack of training. It was <strong>very</strong> hard but I didn&rsquo;t give up. As they say: Pain is temporary, pride is forever.</p>
<p>I did some cool things in the office too. Together with the <a href="https://victor.kropp.name/blog/jetbrains-toolbox/">awesome team</a> behind the JetBrains Toolbox App, we prepared several <a href="https://blog.jetbrains.com/blog/2017/05/22/jetbrains-toolbox-app-1-3-is-here/">feature-packed</a> <a href="https://blog.jetbrains.com/blog/2017/10/26/toolbox-app-1-5-staying-up-to-date-has-never-been-easier/">releases</a>. Later in the year, almost half of our team changed for different reasons, but we continue going strong and have a lot of cool features waiting for release.</p>
<p>On the other news, I discontinued one unannounced project and joined another unannounced project. I still believe in the ideas I wanted to implement in the first one and think they will fit the new one as well. (Sorry, I know it may sound cryptic, I will share all the details as soon as we announce the product)</p>
<p>For the second time in my life this summer I became a mentor for an intern in my project. This time it was a very positive experience, both for the student and for me. She continued working with us after the internship, and this is the best possible outcome.</p>
<p>Also, I hope that my advice to those who didn&rsquo;t get to the interview was helpful as well.</p>
<div class="covers-line">
<img src="https://victor.kropp.name/talks/2017/Zen Habits of using IntelliJ IDEA.png" width="250" /><img src="https://victor.kropp.name/talks/2017/From Hackathon to Production in a Year.jpg" width="250" /><img src="https://victor.kropp.name/talks/2017/Create your own DSL in Kotlin.png" width="250" /><img src="https://victor.kropp.name/talks/2017/Asynchronous programming in Kotlin with coroutines.png" width="250" />
</div>
<p>This year I&rsquo;ve visited four conferences and gave there five <a href="https://victor.kropp.name/talks">talks</a> in total. Together with meetups and internal company events, it&rsquo;s more than I&rsquo;ve ever done before. I&rsquo;ve enjoyed the experience and want to continue presenting at the conferences. It&rsquo;s great to share the knowledge, and I always learn something new when preparing for the talks.</p>
<p>I also continued to write in this blog. This year I focused on <a href="https://victor.kropp.name/tags/kotlin" class="tag-kotlin">Kotlin</a>, but I have other topics on my mind to cover next year.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2017/github.png"
alt="My Github contributions chart says for itself" width="758"/> <figcaption>
<p>My Github contributions chart says for itself</p>
</figcaption>
</figure>
<p>Earlier this year I&rsquo;ve <a href="https://victor.kropp.name/blog/makefile-plugin/">announced</a> <a href="https://victor.kropp.name/projects/makefile">Makefile plugin for IntelliJ</a>. It has matured and has a good userbase. Other pet projects I started this year are not yet ready to be published. Stay tuned!</p>
<p>I have a lot of plans for the coming year but want to keep them secret for now. We&rsquo;ll see in 365 days what I will have managed to achieve.</p>
<p>I wish you Happy New Year! 🎉 Dare to try something new in 2018!</p>
Expressive code with DSLs in Kotlin. Part 2https://victor.kropp.name/blog/expressive-code-with-dsls-in-kotlin-2/
Sun, 24 Dec 2017 17:40:51 +0100https://victor.kropp.name/blog/expressive-code-with-dsls-in-kotlin-2/
<figure>
<img src="https://victor.kropp.name/blog/img/2017/christmas2.jpg" width="1000" height="550"/>
</figure>
<p>In the <a href="https://victor.kropp.name/blog/expressive-code-with-dsls-in-kotlin/">first part</a> of this tutorial, I’ve shown how to create custom internal DSL, which helps to convert an unstructured imperative code to expressive structured and declarative. In this blog post, I&rsquo;ll improve it further.</p>
<h3 id="dates-manipulation">Dates manipulation</h3>
<p>I know well that the Christmas is on December 25, but the question I always ask myself at the beginning of December when is the first Advent Sunday. There are four of them, and the last one is on Sunday before Christmas. So the first one can be anytime between November 27 and December 3. Let&rsquo;s find it out:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">val</span> <span class="err">`4</span><span class="py">th</span> <span class="n">Advent</span><span class="err">`</span> <span class="p">=</span> <span class="n">Sunday</span> <span class="n">before</span> <span class="n">Christmas</span></code></pre></div>
<p><em>Variable names can neither start with a digit nor contain a space, in Kotlin you can escape them with backticks. Do not overuse this feature, though.</em></p>
<p>Looks nice, isn&rsquo;t it? It doesn&rsquo;t work out of the box, though. To help compiler figure it out, let&rsquo;s declare the variable <code>Sunday</code> and infix function <code>before</code> (we&rsquo;ve seen this trick before):</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">val</span> <span class="py">Sunday</span> <span class="p">=</span> <span class="n">DayOfWeek</span><span class="p">.</span><span class="n">SUNDAY</span>
<span class="k">infix</span> <span class="k">fun</span> <span class="nf">DayOfWeek</span><span class="p">.</span><span class="n">before</span><span class="p">(</span><span class="n">date</span><span class="p">:</span> <span class="n">LocalDate</span><span class="p">):</span> <span class="n">LocalDate</span> <span class="p">=</span> <span class="n">date</span><span class="p">.</span><span class="n">with</span><span class="p">(</span><span class="n">TemporalAdjusters</span><span class="p">.</span><span class="n">previous</span><span class="p">(</span><span class="k">this</span><span class="p">))</span></code></pre></div>
<p>To create events in our calendar for all Advent Sundays we need to find the first one (3 weeks earlier) and iterate over them. It can be done in the following way:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="p">(</span><span class="err">`</span><span class="m">4</span><span class="n">th</span> <span class="n">Advent</span><span class="err">`</span> <span class="p">-</span> <span class="m">3</span> <span class="p">*</span> <span class="n">week</span> <span class="p">..</span> <span class="err">`</span><span class="m">4</span><span class="n">th</span> <span class="n">Advent</span><span class="err">`</span> <span class="n">every</span> <span class="n">week</span><span class="p">).</span><span class="n">forEachIndexed</span> <span class="p">{</span> <span class="n">i</span><span class="p">,</span> <span class="n">Advent</span> <span class="p">-&gt;</span>
<span class="n">event</span> <span class="p">{</span>
<span class="n">title</span> <span class="p">=</span> <span class="s">&#34;$i Advent&#34;</span>
<span class="n">date</span> <span class="p">=</span> <span class="n">Advent</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>The most interesting is the first line, which is packed with neat tricks, following lines just repeat the creation process of an event for Christmas. First, with the help of <a href="https://kotlinlang.org/docs/reference/operator-overloading.html">overloaded multiplication operator</a>, we create an object, representing three weeks:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">val</span> <span class="py">week</span><span class="p">:</span> <span class="n">Period</span> <span class="p">=</span> <span class="n">Period</span><span class="p">.</span><span class="n">ofDays</span><span class="p">(</span><span class="m">7</span><span class="p">)</span>
<span class="k">operator</span> <span class="k">fun</span> <span class="nf">Int</span><span class="p">.</span><span class="n">times</span><span class="p">(</span><span class="n">p</span><span class="p">:</span> <span class="n">Period</span><span class="p">):</span> <span class="n">Period</span> <span class="p">=</span> <span class="n">p</span><span class="p">.</span><span class="n">multipliedBy</span><span class="p">(</span><span class="k">this</span><span class="p">)</span></code></pre></div>
<p><code>operator</code> keyword allows us to call extension function <code>times</code> with an asterisk, like any ordinary multiplication. <code>LocalDate</code> class is defined in Java and already has <code>minus</code> function, Kotlin allows to call it with a <code>-</code> sign without any additional modifications, so that
<code>4th Advent - 3 * week</code> compiles to <code>4th Advent.minus(3 * week)</code></p>
<h3 id="ranges">Ranges</h3>
<p>Two dots denote a <a href="https://kotlinlang.org/docs/reference/ranges.html">range</a> in Kotlin. And since its a regular class we can define an extension function <code>every</code> on it:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">infix</span> <span class="k">fun</span> <span class="nf">ClosedRange</span><span class="p">&lt;</span><span class="n">LocalDate</span><span class="p">&gt;.</span><span class="n">every</span><span class="p">(</span><span class="n">period</span><span class="p">:</span> <span class="n">Period</span><span class="p">)</span> <span class="p">=</span> <span class="n">buildSequence</span> <span class="p">{</span>
<span class="k">var</span> <span class="py">current</span> <span class="p">=</span> <span class="n">start</span>
<span class="k">do</span> <span class="p">{</span>
<span class="n">yield</span><span class="p">(</span><span class="n">current</span><span class="p">)</span>
<span class="n">current</span> <span class="p">+=</span> <span class="n">period</span>
<span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">current</span> <span class="p">&lt;=</span> <span class="n">endInclusive</span><span class="p">)</span>
<span class="p">}</span></code></pre></div>
<p>Without going into much detail here, it creates a sequence of dates with a given period in-between, which we can then iterate with <code>forEachIndexed</code>, or standard <code>for</code> loop, of course.</p>
<h3 id="invoke-convention"><code>invoke</code> convention</h3>
<p>This code will look much better if we can avoid this <code>.forEachIndexed</code> call altogether:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="p">(</span><span class="err">`</span><span class="m">4</span><span class="n">th</span> <span class="n">Advent</span><span class="err">`</span> <span class="p">-</span> <span class="m">3</span> <span class="p">*</span> <span class="n">week</span> <span class="p">..</span> <span class="err">`</span><span class="m">4</span><span class="n">th</span> <span class="n">Advent</span><span class="err">`</span> <span class="n">every</span> <span class="n">week</span><span class="p">)</span> <span class="p">{</span> <span class="n">i</span><span class="p">,</span> <span class="n">Advent</span> <span class="p">-&gt;</span>
<span class="n">event</span> <span class="p">{</span>
<span class="n">title</span> <span class="p">=</span> <span class="s">&#34;$i Advent&#34;</span>
<span class="n">date</span> <span class="p">=</span> <span class="n">Advent</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>And we can! <a href="https://kotlinlang.org/docs/reference/operator-overloading.html#invoke"><code>invoke</code></a> operator allows us to call an object or an expression as a method. In our case it will just delegate to <code>forEachIndexed</code>:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">operator</span> <span class="k">fun</span> &lt;T&gt; <span class="nf">Sequence</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;.</span><span class="n">invoke</span><span class="p">(</span><span class="n">body</span><span class="p">:</span> <span class="p">(</span><span class="n">Int</span><span class="p">,</span> <span class="n">T</span><span class="p">)</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">=</span> <span class="n">forEachIndexed</span><span class="p">(</span><span class="n">body</span><span class="p">)</span></code></pre></div>
<h3 id="performance">Performance</h3>
<p>DSLs in Kotlin are statically compiled code; they do not require any dynamic resolution whatsoever. They do not use reflection either. Everything we&rsquo;ve seen here is just function calls. However, passing lambda functions here and there can be a performance problem because each of them requires creating a closure. To solve this problem, we can mark DSL functions with <code>inline</code> keyword. They will be inlined at the call site together with a lambda function they take as a parameter.</p>
<h3 id="scopes">Scopes</h3>
<p>As I said before the whole DSL is based on simple functions, which can be called from everywhere, for example, such code is allowed by default:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="n">calendar</span> <span class="p">{</span>
<span class="n">event</span> <span class="p">{</span>
<span class="n">event</span> <span class="p">{}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>Nesting events don&rsquo;t make much sense. Since Kotlin 1.1 we can <a href="https://kotlinlang.org/docs/reference/whatsnew11.html#scope-control-for-implicit-receivers-in-dsls">control scope of the implicit receivers</a>.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="n">@DslMarker</span>
<span class="n">@Target</span><span class="p">(</span><span class="n">AnnotationTarget</span><span class="p">.</span><span class="n">TYPE</span><span class="p">)</span>
<span class="k">annotation</span> <span class="k">class</span> <span class="nc">CalendarDsl</span>
<span class="k">fun</span> <span class="nf">calendar</span><span class="p">(</span><span class="n">builder</span><span class="p">:</span> <span class="p">(</span><span class="n">@CalendarDsl</span> <span class="n">ICalendar</span><span class="p">).()</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">=</span> <span class="n">ICalendar</span><span class="p">().</span><span class="n">apply</span><span class="p">(</span><span class="n">builder</span><span class="p">)</span>
<span class="k">fun</span> <span class="nf">ICalendar</span><span class="p">.</span><span class="n">event</span><span class="p">(</span><span class="n">builder</span><span class="p">:</span> <span class="p">(</span><span class="n">@CalendarDsl</span> <span class="n">VEvent</span><span class="p">).()</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">=</span> <span class="n">addEvent</span><span class="p">(</span><span class="n">VEvent</span><span class="p">().</span><span class="n">apply</span><span class="p">(</span><span class="n">builder</span><span class="p">))</span></code></pre></div>
<p>To disallow such calls, we define an annotation, mark it with <code>@DslMarker</code> annotation, and then apply it types which define logical scopes in our DSL. After that nested <code>event</code> may be called only with an implicit receiver.</p>
<p>And that&rsquo;s it! Our DSL is finished. You can find the full source code of this example <i class="fa fa-github" style="color: rgb(23,21,21)"></i> <a href="https://github.com/kropp/noslidesconf2017-kotlin-dsl">GitHub</a>. The recording of my talk about this DSL is available on <i class="fa fa-youtube-play" style="color: #ff0000"></i> <a href="https://www.youtube.com/watch?v=tZIRovCbYM8">YouTube</a>.</p>
<p>Thanks for reading! I wish you Merry Christmas and Happy New Year!</p>
Expressive code with DSLs in Kotlinhttps://victor.kropp.name/blog/expressive-code-with-dsls-in-kotlin/
Mon, 11 Dec 2017 13:43:30 +0100https://victor.kropp.name/blog/expressive-code-with-dsls-in-kotlin/
<figure>
<img src="https://victor.kropp.name/blog/img/2017/christmas.jpg" width="1000"/>
</figure>
<p>In this tutorial I&rsquo;ll show how to create your own DSL from scratch in Kotlin. It is mostly based on my talk I presented few weeks ago at <a href="http://noslidesconf.net/">NoSlidesConf</a>.</p>
<p>As an example I will create a calendar for upcoming holidays. I will use <a href="https://github.com/mangstadt/biweekly">Biweekly</a> library for that:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">val</span> <span class="py">ical</span> <span class="p">=</span> <span class="n">ICalendar</span><span class="p">()</span>
<span class="k">val</span> <span class="py">event</span> <span class="p">=</span> <span class="n">VEvent</span><span class="p">()</span>
<span class="n">event</span><span class="p">.</span><span class="n">setSummary</span><span class="p">(</span><span class="s">&#34;Christmas&#34;</span><span class="p">)</span>
<span class="k">val</span> <span class="py">date</span> <span class="p">=</span> <span class="n">GregorianCalendar</span><span class="p">(</span><span class="m">2017</span><span class="p">,</span> <span class="m">11</span><span class="p">,</span> <span class="m">25</span><span class="p">).</span><span class="n">time</span>
<span class="n">event</span><span class="p">.</span><span class="n">setDateStart</span><span class="p">(</span><span class="n">date</span><span class="p">)</span>
<span class="n">event</span><span class="p">.</span><span class="n">setDateEnd</span><span class="p">(</span><span class="n">date</span><span class="p">)</span>
<span class="n">ical</span><span class="p">.</span><span class="n">addEvent</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
<span class="n">println</span><span class="p">(</span><span class="n">Biweekly</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">ical</span><span class="p">).</span><span class="n">go</span><span class="p">())</span></code></pre></div>
<p>The code looks exactly as you may expect it. We create a calendar object, then an object, representing an event, set its properties, add the event to the calendar, and finally serialize it to string and print. You&rsquo;ve seen similar code billion times before, and there is nothing bad about it. Stop. Bullshit! There are a lot of flaws in this code.</p>
<p>Firstly, it&rsquo;s utterly unstructured. You can move statements back and forth, and in some cases, it will work as before while in some other cases it may suddenly fail even if the code will remain compilable. For example, if you modify <code>event</code> object after adding it to a calendar, the result depends on the implementation details of the library: it may save a copy of the event and then all subsequent changes are lost.</p>
<p>Secondly, it&rsquo;s very easy to mess everything up by copy-pasting. I know, one should never copy-paste any code, but still, people do this and then suffer from weird side-effects. If some references are not properly updated, a whole lot of different errors may arise, like missing or duplicate events, wrong event data, etc.</p>
<p>We can avoid most of this errors by changing code style from imperative to declarative. Let&rsquo;s see how.</p>
<h3 id="declarative-builders">Declarative builders</h3>
<p>Let&rsquo;s start with a one-line helper function to create a calendar:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">fun</span> <span class="nf">calendar</span><span class="p">(</span><span class="n">builder</span><span class="p">:</span> <span class="n">ICalendar</span><span class="p">.()</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">=</span> <span class="n">ICalendar</span><span class="p">().</span><span class="n">apply</span><span class="p">(</span><span class="n">builder</span><span class="p">)</span></code></pre></div>
<p>Kotlin supports <a href="https://kotlinlang.org/docs/reference/functions.html#function-scope">top-level functions</a>, so we can put it anywhere in our file and then create and initialize calendar object with it. <code>builder</code> parameter, in this case, is <a href="https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver">a lambda function with a receiver</a> of type <code>ICalendar</code> which means that it behaves like if it was a member function of the given type, i. e. <code>this</code> is available in the lambda body (and can be omitted as in regular instance methods).</p>
<p>The same can be applied to an event:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">fun</span> <span class="nf">ICalendar</span><span class="p">.</span><span class="n">event</span><span class="p">(</span><span class="n">builder</span><span class="p">:</span> <span class="n">VEvent</span><span class="p">.()</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">=</span> <span class="n">addEvent</span><span class="p">(</span><span class="n">VEvent</span><span class="p">().</span><span class="n">apply</span><span class="p">(</span><span class="n">builder</span><span class="p">))</span></code></pre></div>
<p>Here we not only create and initialize a <code>VEvent</code> object but also add it to an enclosing calendar. <code>event()</code> is an <a href="https://kotlinlang.org/docs/reference/extensions.html">extension function</a> which behaves as a member function, like the lambda we&rsquo;ve just discussed. Together with a previous one, they make a skeleton of our DSL:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">val</span> <span class="py">ical</span> <span class="p">=</span> <span class="n">calendar</span> <span class="p">{</span>
<span class="n">event</span> <span class="p">{</span>
<span class="n">setSummary</span><span class="p">(</span><span class="s">&#34;Christmas&#34;</span><span class="p">)</span>
<span class="k">val</span> <span class="py">date</span> <span class="p">=</span> <span class="n">GregorianCalendar</span><span class="p">(</span><span class="m">2017</span><span class="p">,</span> <span class="m">11</span><span class="p">,</span> <span class="m">25</span><span class="p">).</span><span class="n">time</span>
<span class="n">setDateStart</span><span class="p">(</span><span class="n">date</span><span class="p">)</span>
<span class="n">setDateEnd</span><span class="p">(</span><span class="n">date</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">println</span><span class="p">(</span><span class="n">Biweekly</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">ical</span><span class="p">).</span><span class="n">go</span><span class="p">())</span></code></pre></div>
<h3 id="more-extension-methods-and-properties">More extension methods and properties</h3>
<p>We now clearly see how the code is structured, but it is still a mix of imperative and declarative approach. With the help of extension functions and properties, we can improve it further.</p>
<p>First, if we need to print calendars often, it&rsquo;s worth to hide serialization code in a helper extension function.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">fun</span> <span class="nf">ICalendar</span><span class="p">.</span><span class="n">print</span><span class="p">()</span> <span class="p">=</span> <span class="n">println</span><span class="p">(</span><span class="n">Biweekly</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="n">go</span><span class="p">())</span></code></pre></div>
<p>Second, an idiomatic way of setting summary and date in Kotlin is by assign values to properties. Luckily, we can declare extension properties similar to extension functions:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">var</span> <span class="py">VEvent</span><span class="p">.</span><span class="n">title</span><span class="p">:</span> <span class="n">String</span>
<span class="k">set</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span>
<span class="n">setSummary</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">get</span><span class="p">()</span> <span class="p">=</span> <span class="n">TODO</span><span class="p">()</span>
<span class="k">var</span> <span class="py">VEvent</span><span class="p">.</span><span class="n">date</span><span class="p">:</span> <span class="n">LocalDate</span>
<span class="k">set</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">date</span> <span class="p">=</span> <span class="n">java</span><span class="p">.</span><span class="n">sql</span><span class="p">.</span><span class="n">Date</span><span class="p">.</span><span class="n">valueOf</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="n">setDateStart</span><span class="p">(</span><span class="n">date</span><span class="p">)</span>
<span class="n">setDateEnd</span><span class="p">(</span><span class="n">date</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">get</span><span class="p">()</span> <span class="p">=</span> <span class="n">TODO</span><span class="p">()</span></code></pre></div>
<p><em>Setter-only properties are not (yet) allowed in Kotlin, so we must define dummy getters here.</em></p>
<p>After this step the calendar creation code now looks like this:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="n">calendar</span> <span class="p">{</span>
<span class="n">event</span> <span class="p">{</span>
<span class="n">title</span> <span class="p">=</span> <span class="s">&#34;Christmas&#34;</span>
<span class="n">date</span> <span class="p">=</span> <span class="n">LocalDate</span><span class="p">.</span><span class="n">of</span><span class="p">(</span><span class="m">2017</span><span class="p">,</span> <span class="m">11</span><span class="p">,</span> <span class="m">25</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}.</span><span class="n">print</span><span class="p">()</span></code></pre></div>
<p>It is now much shorter and cleaner!</p>
<h3 id="mini-dsl-for-dates">Mini-DSL for dates</h3>
<p>The last thing that stands out in this example is a <code>LocalDate</code> object. What I especially dislike here are zero-numbered months, so that December is 11th month of the year. There is another factory method on <code>LocalDate</code> class accepting <code>Month</code> enum: <code>LocalDate.of(2017, Month.DECEMBER, 25)</code> However, in this particular case, my solution would be the following:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">private</span> <span class="k">infix</span> <span class="k">fun</span> <span class="nf">Int</span><span class="p">.</span><span class="n">December</span><span class="p">(</span><span class="n">year</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="p">=</span> <span class="n">LocalDate</span><span class="p">.</span><span class="n">of</span><span class="p">(</span><span class="n">year</span><span class="p">,</span> <span class="n">Month</span><span class="p">.</span><span class="n">DECEMBER</span><span class="p">,</span> <span class="k">this</span><span class="p">)</span>
<span class="c1">// and similar methods for all months</span></code></pre></div>
<p><code>infix</code> modifier allows invoking function without dot and parenthesis. So the final example would then be:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="n">calendar</span> <span class="p">{</span>
<span class="n">event</span> <span class="p">{</span>
<span class="n">title</span> <span class="p">=</span> <span class="s">&#34;Christmas&#34;</span>
<span class="n">date</span> <span class="p">=</span> <span class="m">25</span> <span class="n">December</span> <span class="m">2017</span>
<span class="p">}</span>
<span class="p">}.</span><span class="n">print</span><span class="p">()</span></code></pre></div>
<p>Warning! Do not declare extension functions on standard types such as <code>Int</code> public. Especially in top-level package. They will spoil completion list and can lead to mysterious errors if they clash with other similar functions with slightly different implementations.</p>
<h3 id="conclusion">Conclusion</h3>
<p>In this tutorial, I&rsquo;ve shown how to create custom internal DSL, using simple language features, such as extension functions and properties and lambdas with a receiver. With its help, an unstructured imperative code can be converted to expressive structured and declarative.</p>
<p>The source code of the complete example is available on <i class="fa fa-github" style="color: rgb(23,21,21)"></i> <a href="https://github.com/kropp/noslidesconf2017-kotlin-dsl">GitHub</a>.</p>
<p>In the second part, I&rsquo;ll show some advanced tricks to make DSL even more powerful. Stay tuned.</p>
November 2017 Conference Reporthttps://victor.kropp.name/blog/november-2017-trip-report/
Wed, 29 Nov 2017 16:13:55 +0100https://victor.kropp.name/blog/november-2017-trip-report/
<p>I had a chance to visit three conferences during the last month and gave talks at each event. It was a unique experience for me. I enjoyed it and learned a lot.</p>
<h3 id="mobile-unplugged-http-www-iquestgroup-com-en-event-mobile-unplugged-2017-november-2-cluj-napoca-i-class-flag-flag-ro-i"><a href="http://www.iquestgroup.com/en/event/mobile-unplugged-2017/">Mobile Unplugged</a>, November 2, Cluj-Napoca <i class="flag flag-ro"></i></h3>
<p>I was invited to give two talks about Kotlin at the first edition of the mobile-focused conference. Not a surprise that the whole Android track was dedicated to Kotlin, after Google I/O in May, every Android developer is talking about Kotlin.</p>
<figure>
<img src="//c1.staticflickr.com/5/4583/38181901336_b3eb37b1c2_k.jpg"
alt="Mobile Unplugged 2017" width="1000"/> <figcaption>
<p>Mobile Unplugged 2017</p>
</figcaption>
</figure>
<p>I&rsquo;ve started with an introduction to Kotlin and continued later with live coding session showing how to use Kotlin coroutines in Android apps. As it often happens at the end of the session Internet connection went down (and it was required for the demo).</p>
<p>The event was relatively small, but it has a great potential, I&rsquo;ve seen passionate and motivated developers and will return there next year with pleasure.</p>
<h3 id="devoxx-https-devoxx-be-november-6-10-antwerpen-i-class-flag-flag-be-i"><a href="https://devoxx.be/">Devoxx</a>, November 6–10, Antwerpen <i class="flag flag-be"></i></h3>
<figure>
<img src="//c1.staticflickr.com/5/4548/38226313726_61828dd87a_k.jpg"
alt="Devoxx Belgium 2017" width="1000"/> <figcaption>
<p>Devoxx Belgium 2017</p>
</figcaption>
</figure>
<p>It was my first time at the best Java Conference, and it was awesome. Over 4000 attendees, eight tracks, and all events streamed live—this is impressive. I did a tips &amp; tricks session on IntelliJ IDEA there. Even though I&rsquo;ve been showing things I&rsquo;m using daily and know very well, I was nervous standing in front of bright lights and few hundreds of spectators. Thanks to all submitted their feedback—I&rsquo;ve learned a lot in this session and will improve next time.</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe src="//www.youtube.com/embed/MZge92bbU7E" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>
<p>The event itself was a blast, I&rsquo;ve attended some great talks and going to watch those I missed on <a href="https://www.youtube.com/watch?v=YXDm3WHZT5g&amp;list=PLRsbF2sD7JVqZ4RpHYkqSuCNhxumGP5eo">YouTube</a>.</p>
<h3 id="noslidesconf-http-www-noslidesconf-net-november-25-bologna-i-class-flag-flag-it-i"><a href="http://www.noslidesconf.net/">NoSlidesConf</a>, November 25, Bologna <i class="flag flag-it"></i></h3>
<p>I liked the idea of the event immediately after I discovered it. The whole day without any slides, only code, only live demos. And sessions are not limited to any language or technology, so I&rsquo;ve not only discovered two new languages but also have learned something new about cloud applications.</p>
<p>My session about DSLs in Kotlin was a success. I&rsquo;ve unveiled the power of the language, and people have left the audience impressed. I&rsquo;m going to write down my talk as a blog post a bit later, but you can already study the source code.</p>
<p>I recommend the event and am looking forward to the next year.</p>
<p>P.S. Some talk recordings are not yet ready, I will update this post as soon as they are available.</p>
Inbox Zero and Getting Things Donehttps://victor.kropp.name/blog/getting-things-done/
Thu, 19 Oct 2017 16:51:51 +0200https://victor.kropp.name/blog/getting-things-done/
<blockquote>
<p><img src="https://victor.kropp.name/blog/img/2017/MarkTwain.jpg" class="photo" width="120" />
The secret of getting ahead is getting started.</p>
<p>The secret of getting started is breaking your complex overwhelming tasks into small manageable tasks, and then starting on the first one.</p>
<p><cite>— Mark Twain</cite></p>
</blockquote>
<p>The most valuable resource we have is attention. Every email, every push notification from all your favorite social networks distract you. And often it needs your reaction. We, humans, have limited willpower to make decisions throughout the day. So applying some routine to process email saves you mental energy for more important things.</p>
<p>The well-known <a href="http://gettingthingsdone.com/">Getting Things Done</a> technique improves daily task management tremendously. However, it’s not easy at all to implement it in real life. <a href="https://www.youtube.com/watch?v=z9UjeTMb3Yk">Inbox Zero</a> is a simplified version of this workflow chosen by many people, who drowned in an ocean of information coming from everywhere. I’d like to describe both workflows and shows benefits they provide.</p>
<h3 id="inbox-zero">Inbox Zero</h3>
<figure>
<img src="https://victor.kropp.name/blog/img/2017/inboxzero.png"
alt="Google Inbox" width="1000"/> <figcaption>
<p>Google Inbox</p>
</figcaption>
</figure>
<p>Suggested initially for Gmail it heavily uses its Archive button. In Gmail archived messages are not deleted, they can be searched and viewed in All mail folder, but they don’t show up in your Inbox.</p>
<p>To start using this workflow, you archive all emails in your Inbox. Simply as that you got empty inbox or zero messages in the inbox, hence the name of the technique.</p>
<p>Next step is to turn off automatic email checker and notifications and read incoming messages only when you want and have time.</p>
<p>And most important, you never leave messages as unread in your mailbox, once you’ve seen them. Trash messages mercilessly if they don’t make any sense to you. If you can take action in less than 5 minutes, then do it immediately. It includes making an appointment, giving a call, filing an issue in a bug tracker, etc. If you need someone else to take a look, forward and delegate. If an email doesn’t require any actions from you, Archive it. If it does, then Star and Archive it.</p>
<p>Process messages one by one, don’t skip, all of them should have the same priority. Thus you will keep your inbox always empty.
Powerful and easy to implement this workflow have some drawbacks still: it applies to email only, it requires other tools for reminders and tasks (though Google Inbox together with Calendar and Keep solve this issue); it uses single Starred items folder to keep track on all open items.</p>
<p>Let’s see how these problems are addressed in Getting Things Done.</p>
<h3 id="getting-thing-done">Getting Thing Done</h3>
<p>Getting Thing Done workflow consists of 5 parts:</p>
<ol>
<li>Collect (Capture)</li>
<li>Process (Clarify)</li>
<li>Organize</li>
<li>Review (Reflect)</li>
<li>Do (Engage)</li>
</ol>
<p>Let&rsquo;s take a closer look on each of these steps.</p>
<h4 id="collect-capture">Collect (Capture)</h4>
<p>To work efficiently, you need to collect all work items in one place. For a software developer, this would be: issues in a bug tracker, build or test failure responsibilities, pending code reviews, recent messages from team or company mailing list or internal forum and personal todos as well.</p>
<h4 id="process-clarify">Process (Clarify)</h4>
<blockquote>
<p><img src="https://victor.kropp.name/blog/img/2017/AlbertEinstein.jpg" class="photo" width="120" />
Everything should be made as simple as possible, but not simpler.</p>
<p><cite>— Albert Einstein</cite></p>
</blockquote>
<p>Once you collect all incoming notifications in a single view, you need to deal with them. Inbox Zero focuses on this matter. And it works here as well. You either respond, forward, defer, or classify it for a future reference.</p>
<h4 id="organize">Organize</h4>
<p>Inbox Zero has a significant drawback of having a single folder for all open items. It is important to create several meaningful buckets for work items to overcome this problem. Some of them already exist: like Projects you’re working on with their issue tracker and wiki. You probably already have a calendar with all meetings and important dates. What naturally complements these are personal notes or todo items that to small yet for an issue in a company-wide system. Most often people use post-it notes for this purpose.</p>
<p>You also need some structure in the list of assigned requests. Either they are already in your system as Projects, Subsystems, Versions, Priorities, etc. or you create personal tags to distinguish issues.
But the primary focus here should be put on making all things actionable: it must be clear what to do for each particular task. If you don’t know yet, it means that the next step would be to make a research on a given topic and this should be put on your list as the next action as well.</p>
<h4 id="review-reflect">Review (Reflect)</h4>
<p>You should revisit all items in your backlog on a regular basis. Weekly reviews on Fridays are great to keep attention on what’s going on. But some open items placed on &ldquo;Wait for reply&rdquo; or &ldquo;Someday/Maybe&rdquo; lists are also necessary to be reviewed periodically.
When you have nothing to do with your current list, it’s a good time
to check next actions on some blocked items.</p>
<h4 id="do-engage">Do (Engage)</h4>
<p>Keeping things organized and in actionable items, helps you to find what to do next.</p>
<h3 id="conclusion">Conclusion</h3>
<p>These simple routine helps me avoid much stress caused by endless stream of incoming information. Start with Inbox Zero and apply as much as possible of Getting Things Done and see how it will change your life.</p>
<blockquote>
<p>I&rsquo;m an old man and have known a great many troubles, but most of them never happen.</p>
<p><cite>— Mark Twain</cite></p>
</blockquote>
Brazil Trip Reporthttps://victor.kropp.name/blog/brazil-2017-trip-report/
Thu, 14 Sep 2017 17:44:25 +0200https://victor.kropp.name/blog/brazil-2017-trip-report/<p>In August I flew to Brazil to give a keynote talk at <a href="https://br.qtcon.org/">QtCon Brazil</a>. Here is my trip report.</p>
<figure>
<img src="https://farm5.staticflickr.com/4333/37189688095_4b86946277_h.jpg"
alt="QtCon Brazil 2017" width="1000"/> <figcaption>
<p>QtCon Brazil 2017</p>
</figcaption>
</figure>
<p>I arrived just a few hours before the start of the conference. Fortunately, the traffic was calm on early Saturday morning in São Paulo, and I made it on time to salute attendees on behalf of JetBrains at the QtCon&rsquo;s opening session.</p>
<p>What was less fortunate, is that all conference sessions (except mine and one other) were presented in Portuguese. That meant I wasn&rsquo;t able to follow all talks in full, only read slides. Judging from them the level of talks was very wide spread: from very basic overviews of existing APIs to a deep technical dive into how to build a custom Linux distribution for an embedded device.</p>
<div class="fotorama" data-allow-full-screen="native" data-keyboard="true" data-loop="true" data-width="100%">
<img src="https://farm5.staticflickr.com/4339/37189671935_c7f04f4d82_h.jpg" data-full="https://farm5.staticflickr.com/4339/37189671935_28e506a9fa_o.jpg" data-caption="QtCon Brazil 2017" />
<img src="https://farm5.staticflickr.com/4354/36352839284_3ca7e85548_h.jpg" data-full="https://farm5.staticflickr.com/4354/36352839284_8bdbeba842_o.jpg" data-caption="QtCon Brazil 2017" />
<img src="https://farm5.staticflickr.com/4419/37017995152_9c3cd807c7_h.jpg" data-full="https://farm5.staticflickr.com/4419/37017995152_e45df2edec_o.jpg" data-caption="QtCon Brazil 2017" />
<img src="https://farm5.staticflickr.com/4348/36352839044_6a9d2720c2_h.jpg" data-full="https://farm5.staticflickr.com/4348/36352839044_ccf5b977ce_o.jpg" data-caption="QtCon Brazil 2017" />
</div>
<p>The audience was very welcoming. I enjoyed my talk and had some meaningful conversations afterward. It was also cool to meet other developers, who independently chose similar approach to application architecture as we did. We all left the conference with more confidence in our decisions.</p>
<blockquote class="twitter-tweet"><p lang="pt" dir="ltr">At <a href="https://twitter.com/hashtag/Kotlin?src=hash&amp;ref_src=twsrc%5Etfw">#Kotlin</a> meetup in São Paulo <a href="https://t.co/v9XyBxPdbU">pic.twitter.com/v9XyBxPdbU</a></p>&mdash; Victor Kropp (@kropp) <a href="https://twitter.com/kropp/status/899758585936302083?ref_src=twsrc%5Etfw">August 21, 2017</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>I stayed in São Paulo for an additional day to attend a local <a href="https://www.meetup.com/kotlin-meetup-sp/events/242365014/">Kotlin meetup</a>, where I gave an introductory talk to DSLs in Kotlin. All 80 spots at the meetup were taken long before the event; I was surprised by the interest in the language. It was nice to meet Rodrigo from Gradle there, and we had an awesome chat and dinner after the event with him and organizers.</p>
<p>With such a tight schedule and inclement weather (it was late winter, and it was raining most of the time) I didn&rsquo;t have a chance to see the country. I only had a short walk along Paulista Avenue and spent an hour in <a href="http://masp.art.br/">Museum of Art</a>, which was small but enjoyable and worth visiting.</p>
<p>Looking forward to revisiting Brazil in summer and seeing other cities and incredible nature.</p>
🎉 Emoji on 🐧 Linuxhttps://victor.kropp.name/blog/emoji-on-linux/
Mon, 28 Aug 2017 18:11:16 +0200https://victor.kropp.name/blog/emoji-on-linux/
<figure>
<img src="https://victor.kropp.name/blog/img/2017/emoji.png" width="749"/>
</figure>
<p>I should have prepared this blog post on World Emoji Day when Google <a href="https://www.blog.google/products/android/world-emoji-day-since-u-been-blob/">said farewell</a> to its iconic &lsquo;blob&rsquo; emoji typeface. Better late than never.</p>
<p>I&rsquo;m not the biggest emoji fun, but even if I only use them rarely, I still want to see web pages as they were intended to be seen. By default on Linux one only sees a small number of black-and-white smileys. However, it is easy to setup your system to display all emojis in color.</p>
<p>During my short research, I stumbled upon <a href="https://github.com/notwaldorf/ama/issues/53">few</a> <a href="http://probablement.net/txt/emojilinux">posts</a> on how to set up emoji on Linux, but all of them were lengthy and suggested some incorrect setups. So I decided to sum up my experience in this super quick tutorial.</p>
<h3 id="choose-font">Choose font</h3>
<p>First of all, you need to choose a font. I prefer <a href="https://www.google.com/get/noto/#emoji-zsye-color">Noto Color Emoji</a>, which is a font used to display emojis on Android. The font was <a href="https://github.com/googlei18n/noto-emoji/commit/91dc393ca4f4a924f4f6b06bf8e4407b30c7bdd9">recently updated</a> with <a href="https://medium.com/google-design/redesigning-android-emoji-cb22e3b51cc6">normal faces</a> instead of old controversial blobs. But if you&rsquo;ve been using Android since ages and like those, you always can install an older version of the same font. An alternative option would be an <a href="https://www.emojione.com/">Emoji One font</a>, which is also good, especially its third version.</p>
<p>Independently of which font you&rsquo;ve chosen, put it in <code>~/.fonts</code>.</p>
<h3 id="tell-system-you-prefer-this-font-to-render-emoji">Tell system you prefer this font to render emoji</h3>
<p>Next, you need to create a file <code>~/.config/fontconfig/fonts.conf</code> with following content:</p>
<div class="highlight"><pre class="chroma"><code class="language-xml" data-lang="xml"><span class="cp">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
<span class="cp">&lt;!DOCTYPE fontconfig SYSTEM &#34;fonts.dtd&#34;&gt;</span>
<span class="nt">&lt;fontconfig&gt;</span>
<span class="nt">&lt;alias&gt;</span>
<span class="nt">&lt;family&gt;</span>serif<span class="nt">&lt;/family&gt;</span>
<span class="nt">&lt;prefer&gt;</span>
<span class="nt">&lt;family&gt;</span>Noto Color Emoji<span class="nt">&lt;/family&gt;</span>
<span class="nt">&lt;/prefer&gt;</span>
<span class="nt">&lt;/alias&gt;</span>
<span class="nt">&lt;alias&gt;</span>
<span class="nt">&lt;family&gt;</span>sans-serif<span class="nt">&lt;/family&gt;</span>
<span class="nt">&lt;prefer&gt;</span>
<span class="nt">&lt;family&gt;</span>Noto Color Emoji<span class="nt">&lt;/family&gt;</span>
<span class="nt">&lt;/prefer&gt;</span>
<span class="nt">&lt;/alias&gt;</span>
<span class="nt">&lt;alias&gt;</span>
<span class="nt">&lt;family&gt;</span>monospace<span class="nt">&lt;/family&gt;</span>
<span class="nt">&lt;prefer&gt;</span>
<span class="nt">&lt;family&gt;</span>Noto Color Emoji<span class="nt">&lt;/family&gt;</span>
<span class="nt">&lt;/prefer&gt;</span>
<span class="nt">&lt;/alias&gt;</span>
<span class="nt">&lt;/fontconfig&gt;</span></code></pre></div>
<p>To apply new configuration, run <code>fc-cache -f -v</code> in Terminal.</p>
<p>After you restart a browser (or any other app), you&rsquo;ll see new emojis everywhere. If everything looks good, congratulations, you&rsquo;re done! If you see new emojis, but still in black-and-white, read further.</p>
<h3 id="optionally-install-modified-font-rendering-library"><em>(Optionally)</em> Install modified font rendering library</h3>
<p>On Ubuntu, most applications are built with <a href="https://www.gtk.org/">GTK</a> framework, which uses <a href="https://cairographics.org/"><code>cairo</code></a> library to render text. It supports multi-color fonts, but this support is for some reason disabled by default. I uncommented the related line of code and <a href="https://launchpad.net/~kropp/+archive/ubuntu/cairo-coloremoji">published a package in a PPA</a>. To install it run the following commands:</p>
<pre class="shell"><code><b>$</b> sudo add-apt-repository ppa:kropp/cairo-coloremoji
<b>$</b> sudo apt update && sudo apt upgrade</code></pre>
<p>Restart your computer to apply changes.</p>
<p>Voilá! 🎉</p>
Weekend project: Proselint plugin for IntelliJ IDEAhttps://victor.kropp.name/blog/weekend-project-proselint-plugin/
Mon, 24 Jul 2017 16:13:21 +0200https://victor.kropp.name/blog/weekend-project-proselint-plugin/<p>Last weekend I was listening to <a href="http://cppcast.com/2017/06/richel-bilderbeek/">CppCast</a>—a podcast for C++ developers and heard about <a href="http://proselint.com/">Proselint</a>—a linter for prose.</p>
<p>I usually use <a href="https://grammarly.com/">Grammarly</a> for grammar and stylistic checks of my writings, but I also like to put finishing touches after I import the text into a blog codebase. IntelliJ IDEA already has a <a href="https://www.jetbrains.com/help/idea/spellchecking.html">spell checker built-in</a>, but it&rsquo;d be good to have some style checker there too. Of course, I immediately decided to create a plugin for that. I&rsquo;ve already had <a href="https://victor.kropp.name/blog/makefile-plugin/">some experience</a> writing plugins, and given that it&rsquo;s not the first linter to be supported by IntelliJ, I didn&rsquo;t take me much time to integrate Proselint into the editor.</p>
<p>So, please welcome <a href="https://plugins.jetbrains.com/plugin/9854-proselint">Proselint plugin</a> for IntelliJ IDEA. The plugin depends on <a href="https://plugins.jetbrains.com/plugin/7793-markdown-support">Markdown support plugin</a> and requires Python and <a href="https://github.com/amperser/proselint">Proselint to be installed</a> on your computer. The only thing you need to do is to configure the path to proselint executable if it was not guessed correctly.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2017/proselint.png"
alt="Proselint plugin in action" width="453" height="73"/> <figcaption>
<p>Proselint plugin in action</p>
</figcaption>
</figure>
<p>If there is a replacement suggested by Proselint, a quick-fix appears to apply it via <code>Alt+Enter</code>.</p>
<p>Feel free to check out the <a href="https://github.com/kropp/intellij-proselint">source code</a> and contribute by filing a feature request or bug report or submit a pull request.</p>
<p>P.S. This post was written in Intellij IDEA and checked by Proselint.</p>
Building culture of gratitudehttps://victor.kropp.name/blog/building-culture-of-gratitude/
Thu, 29 Jun 2017 16:05:32 +0200https://victor.kropp.name/blog/building-culture-of-gratitude/<p>Since five years JetBrains holds an annual Hackathon. It gives all employees a perfect opportunity to implement their <a href="https://blog.jetbrains.com/blog/2013/06/04/jetbrains-hackathon-2013-winning-project-weighs-in-at-100-kg/">wildest and craziest ideas</a>. Many cool projects were started as a Hackathon projects and later become <a href="https://www.jetbrains.com/dotmemory/unit/">full</a> <a href="https://blog.jetbrains.com/youtrack/2016/11/introducing-youtrack-mobile/">members</a> of the JetBrains family. I&rsquo;ve already <a href="https://victor.kropp.name/blog/jetbrains-toolbox/">written about Toolbox App</a>, the project we had started two years ago.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Let the annual <a href="https://twitter.com/hashtag/JetBrains?src=hash&amp;ref_src=twsrc%5Etfw">#JetBrains</a> <a href="https://twitter.com/hashtag/hackathon?src=hash&amp;ref_src=twsrc%5Etfw">#hackathon</a> begin! <a href="https://t.co/EsKYmZsDik">pic.twitter.com/EsKYmZsDik</a></p>&mdash; Victor Kropp (@kropp) <a href="https://twitter.com/kropp/status/869855115250978816?ref_src=twsrc%5Etfw">May 31, 2017</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>At this year&rsquo;s Hackathon, I had a dream to help people spread positive vibes inside a company. I introduced an idea of a service I called &ldquo;Thank you.&rdquo; The idea was simple: let every employee thank their colleagues and display the warm words they send each other on a big TV screen we have in each office kitchen. My excellent team and I implemented this idea and presented it to the whole company.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2017/codor.svg" width="300"/>
</figure>
<p>Programmers are introverts by their nature. Some also can be shy or so focused on getting their job done, so they don&rsquo;t pay any attention to what&rsquo;s happening around. They may have difficulties expressing their gratitude. By making it easy and fun, we help people to overcome these small obstacles.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2017/thankometer.png" width="476"/>
</figure>
<p>It is worth mentioning that we don&rsquo;t endorse any competition here, like who is more thankful. Neither do we build any ratings or save history. However, we&rsquo;ve introduced Thank-o-meter, which shows how many thanks in total have been sent in the last 24 hours. When someone sees it goes down, it motivates to cheer someone, so that overall level of happiness in the company stays high.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2017/Flowers.svg" width="300"/>
</figure>
<p>Of course, we still have a lot of free room to improve, but I can already see this simple service has had great success. Not only it won one of the Hackathon&rsquo;s prizes, but people also continue using it a month later. I appreciate very much when I receive warm words from my colleagues sent through this service. What&rsquo;s even better: watching how other people thank their pals.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2017/thks.svg" width="300"/>
</figure>
<p>To be happy one needs to share happiness with people around.</p>
JSON construction DSL in Kotlinhttps://victor.kropp.name/blog/json-dsl-kotlin/
Tue, 30 May 2017 17:26:14 +0200https://victor.kropp.name/blog/json-dsl-kotlin/
<p>In the <a href="https://victor.kropp.name/blog/object-builders-in-idiomatic-kotlin/">previous blog post</a>, I&rsquo;ve suggested an approach to better object builders in Kotlin. That approach involved writing some support code, which is less than ideal solution. Now, I would like to make a step further and automate code generation for such builders.</p>
<p>As an example, I take a small library for creating serializable <a href="http://json.org/">JSON</a> object. It is a common task in many modern server applications: process some data and output response as JSON. Usually, DTOs are used to handle the output. I&rsquo;ll show how to construct answers easily and simplify serialization using code generation.</p>
<h2 id="the-goal">The Goal</h2>
<p>Suppose we have the following data model for our code review application:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">interface</span> <span class="nc">CodeReview</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">id</span><span class="p">:</span> <span class="n">String</span>
<span class="k">val</span> <span class="py">timestamp</span><span class="p">:</span> <span class="n">Date</span>
<span class="k">val</span> <span class="py">finished</span><span class="p">:</span> <span class="n">Boolean</span>
<span class="k">val</span> <span class="py">commits</span><span class="p">:</span> <span class="n">Array</span><span class="p">&lt;</span><span class="k">out</span> <span class="n">Commit</span><span class="p">&gt;</span>
<span class="p">}</span>
<span class="k">interface</span> <span class="nc">Commit</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">id</span><span class="p">:</span> <span class="n">String</span>
<span class="k">val</span> <span class="py">author</span><span class="p">:</span> <span class="n">Person</span>
<span class="p">}</span>
<span class="k">interface</span> <span class="nc">Person</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">name</span><span class="p">:</span> <span class="n">String</span>
<span class="p">}</span></code></pre></div>
<p>Note that all properties are immutable. Wouldn&rsquo;t it be great if we can have mutable interfaces generated during the compilation, as well as implementations for both variants? So that we would be able to write code like this with no additional effort?</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">val</span> <span class="py">review</span> <span class="p">=</span> <span class="n">review</span> <span class="p">{</span>
<span class="n">id</span> <span class="p">=</span> <span class="s">&#34;42&#34;</span>
<span class="n">timestamp</span> <span class="p">=</span> <span class="n">Date</span><span class="p">()</span>
<span class="n">finished</span> <span class="p">=</span> <span class="k">true</span>
<span class="n">commits</span><span class="p">(</span>
<span class="p">{</span> <span class="n">id</span> <span class="p">=</span> <span class="s">&#34;abc123&#34;</span><span class="p">,</span> <span class="n">author</span> <span class="p">{</span> <span class="n">name</span> <span class="p">=</span> <span class="s">&#34;John Doe&#34;</span> <span class="p">}</span> <span class="p">},</span>
<span class="p">{</span> <span class="n">id</span> <span class="p">=</span> <span class="s">&#34;321cba&#34;</span><span class="p">,</span> <span class="n">author</span> <span class="p">{</span> <span class="n">name</span> <span class="p">=</span> <span class="s">&#34;Jane Doe&#34;</span> <span class="p">}</span> <span class="p">}</span>
<span class="p">)</span>
<span class="p">}</span></code></pre></div>
<p>It is easier than you think!</p>
<h2 id="annotation-processing">Annotation Processing</h2>
<p>Let&rsquo;s annotate those interfaces with <code>@Json</code> and write a simple annotation processor. Since Kotlin 1.1.2 it is possible to generate Kotlin code in annotation processors, which allows us to apply all fancy DSL magic there. Of course, the processor itself can be written in Kotlin too.</p>
<p>Its entry point is very simple:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="n">@SupportedAnnotationTypes</span><span class="p">(</span><span class="n">JSON_ANNTOTAION</span><span class="p">)</span>
<span class="n">@SupportedSourceVersion</span><span class="p">(</span><span class="n">SourceVersion</span><span class="p">.</span><span class="n">RELEASE_8</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">JsonAnnotationProcessor</span> <span class="p">:</span> <span class="n">AbstractProcessor</span><span class="p">()</span> <span class="p">{</span>
<span class="k">private</span> <span class="k">val</span> <span class="py">kotlinGenerated</span> <span class="k">by</span> <span class="n">lazy</span> <span class="p">{</span> <span class="n">processingEnv</span><span class="p">.</span><span class="n">options</span><span class="na">[&#34;kapt.kotlin.generated&#34;]</span> <span class="p">}</span>
<span class="k">override</span> <span class="k">fun</span> <span class="nf">process</span><span class="p">(</span><span class="n">annotations</span><span class="p">:</span> <span class="n">Set</span><span class="p">&lt;</span><span class="n">TypeElement</span><span class="p">&gt;,</span> <span class="n">roundEnv</span><span class="p">:</span> <span class="n">RoundEnvironment</span><span class="p">):</span> <span class="n">Boolean</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">elements</span> <span class="p">=</span> <span class="n">annotations</span><span class="p">.</span><span class="n">filter</span> <span class="p">{</span> <span class="n">it</span><span class="p">.</span><span class="n">qualifiedName</span><span class="p">.</span><span class="n">contentEquals</span><span class="p">(</span><span class="n">JSON_ANNTOTAION</span><span class="p">)</span> <span class="p">}</span>
<span class="p">.</span><span class="n">map</span> <span class="p">{</span> <span class="n">roundEnv</span><span class="p">.</span><span class="n">getElementsAnnotatedWith</span><span class="p">(</span><span class="n">it</span><span class="p">)</span> <span class="p">}</span>
<span class="p">.</span><span class="n">flatMap</span> <span class="p">{</span> <span class="n">it</span> <span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">elements</span><span class="p">.</span><span class="n">any</span><span class="p">())</span> <span class="p">{</span>
<span class="n">File</span><span class="p">(</span><span class="n">kotlinGenerated</span><span class="p">).</span><span class="n">mkdirs</span><span class="p">()</span>
<span class="n">elements</span><span class="p">.</span><span class="n">forEach</span> <span class="p">{</span>
<span class="n">generateObjectBuilder</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">true</span>
<span class="p">}</span>
<span class="c1">// code generation skipped
</span><span class="c1"></span><span class="p">}</span></code></pre></div>
<p>That&rsquo;s it. I&rsquo;ve skipped all code generation code for brevity. You can study it <a href="https://github.com/kropp/kotlin-jsonex/blob/0dbba5f/apt/src/main/kotlin/JsonAnnotationProcessor.kt">here</a>.</p>
<h2 id="generated-code">Generated Code</h2>
<p>The annotation processor generates following code for each of the interfaces:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">interface</span> <span class="nc">MutablePerson</span> <span class="p">:</span> <span class="n">Person</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">var</span> <span class="py">name</span><span class="p">:</span> <span class="n">String</span>
<span class="p">}</span>
<span class="k">class</span> <span class="nc">PersonImpl</span><span class="p">(</span><span class="n">map</span><span class="p">:</span> <span class="n">Map</span><span class="p">&lt;</span><span class="n">String</span><span class="p">,</span><span class="n">Any</span><span class="p">&gt;</span> <span class="p">=</span> <span class="n">mapOf</span><span class="p">())</span> <span class="p">:</span> <span class="n">Person</span><span class="p">,</span> <span class="n">JsonObject</span><span class="p">&lt;</span><span class="n">PersonImpl</span><span class="p">&gt;(</span><span class="n">map</span><span class="p">)</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">val</span> <span class="py">name</span> <span class="k">by</span> <span class="n">string</span><span class="p">()</span>
<span class="p">}</span>
<span class="k">class</span> <span class="nc">MutablePersonImpl</span><span class="p">(</span><span class="n">map</span><span class="p">:</span> <span class="n">MutableMap</span><span class="p">&lt;</span><span class="n">String</span><span class="p">,</span><span class="n">Any</span><span class="p">&gt;</span> <span class="p">=</span> <span class="n">mutableMapOf</span><span class="p">())</span> <span class="p">:</span> <span class="n">MutablePerson</span><span class="p">,</span> <span class="n">JsonObjectBuilder</span><span class="p">&lt;</span><span class="n">MutablePersonImpl</span><span class="p">,</span> <span class="n">MutablePerson</span><span class="p">&gt;(</span><span class="n">map</span><span class="p">)</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">var</span> <span class="py">name</span><span class="p">:</span> <span class="n">String</span> <span class="k">by</span> <span class="n">string</span><span class="p">()</span>
<span class="p">}</span>
<span class="k">fun</span> <span class="nf">person</span><span class="p">(</span><span class="n">builder</span><span class="p">:</span> <span class="n">MutablePerson</span><span class="p">.()</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">):</span> <span class="n">Person</span> <span class="p">=</span> <span class="n">PersonImpl</span><span class="p">(</span><span class="n">MutablePersonImpl</span><span class="p">().</span><span class="n">apply</span><span class="p">(</span><span class="n">builder</span><span class="p">).</span><span class="n">_map</span><span class="p">)</span></code></pre></div>
<p>What do we have here?</p>
<ul>
<li>A <strong>mutable interface</strong>, which is absolutely the same as the original, but with <code>var</code> properties instead of <code>val</code></li>
<li><strong>Two implementations</strong> for both mutable and immutable interfaces</li>
<li>An <strong>utility function</strong> to create immutable object by building it from mutable counterpart.</li>
</ul>
<p>The source code of <code>JsonObject</code> base class, which hides all the magic, can be found <a href="https://github.com/kropp/kotlin-jsonex/tree/master/src/main/kotlin">here</a>.</p>
<p>This significantly reduces the boilerplate code you need to write by hand.</p>
<h2 id="usage">Usage</h2>
<p>Annotation processors are very easy to enable in Gradle and Maven builds, please refer to the <a href="https://kotlinlang.org/docs/reference/kapt.html">Kotlin documentation</a>.</p>
<p>Here is a sample Gradle configuration.</p>
<div class="highlight"><pre class="chroma"><code class="language-groovy" data-lang="groovy"><span class="n">apply</span> <span class="nl">plugin:</span> <span class="s1">&#39;kotlin-kapt&#39;</span>
<span class="n">dependencies</span> <span class="o">{</span>
<span class="n">kapt</span> <span class="nf">project</span><span class="o">(</span><span class="s2">&#34;com.github.kropp.jsonex:jsonex:0.1&#34;</span><span class="o">)</span> <span class="c1">// not available yet
</span><span class="c1"></span><span class="o">}</span>
<span class="n">kapt</span> <span class="o">{</span>
<span class="n">arguments</span> <span class="o">{</span>
<span class="n">arg</span><span class="o">(</span><span class="s2">&#34;generate.kotlin.code&#34;</span><span class="o">,</span> <span class="s2">&#34;true&#34;</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></div>
<p>However, I haven&rsquo;t released it yet, due to a small issue in Kotlin plugin for IntelliJ: <a href="https://youtrack.jetbrains.com/issue/KT-18057">Kotlin code generated by annotation processor compiles but is not resolved in IntelliJ</a></p>
<p>This issue kinda defeats all the advantages we can get from this approach. Hopefully, it will be fixed soon.</p>
Kotlin/Native 0.2 + GTKhttps://victor.kropp.name/blog/kotlin-native-0.2-and-gtk/
Tue, 16 May 2017 12:34:55 +0200https://victor.kropp.name/blog/kotlin-native-0.2-and-gtk/
<figure>
<img src="https://victor.kropp.name/blog/img/2017/kotlin&#43;gtk.png" width="225"/>
</figure>
<p>Last week Kotlin/Native saw its <a href="https://blog.jetbrains.com/kotlin/2017/05/kotlinnative-v0-2-is-out/">second preview release</a>. In case you missed it, Kotlin/Native is an another backend for <a href="https://kotlinlang.org/">Kotlin</a> (in addition to JVM and JavaScript), which doesn&rsquo;t require any VM and runs natively on many <a href="https://github.com/JetBrains/kotlin-native/blob/v0.1.0/RELEASE_NOTES.md#supported-platforms">supported platforms</a>.</p>
<p>I played with it over the weekend, and it appeared to be already pretty good and solid for an early tech preview. To start with I took a <a href="https://github.com/JetBrains/kotlin-native/tree/v0.2.0/samples/gtk">sample GTK+ application</a> written in Kotlin and tried to improve it. Let&rsquo;s see what I did (spoiler alert: I rewrote it almost entirely).</p>
<h3 id="demo-application">Demo application</h3>
<p>The original sample code doesn&rsquo;t look very different from its pure C equivalent.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">fun</span> <span class="nf">activate</span><span class="p">(</span><span class="n">app</span><span class="p">:</span> <span class="n">CPointer</span><span class="p">&lt;</span><span class="n">GtkApplication</span><span class="p">&gt;?,</span> <span class="n">user_data</span><span class="p">:</span> <span class="n">gpointer</span><span class="p">?)</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">windowWidget</span> <span class="p">=</span> <span class="n">gtk_application_window_new</span><span class="p">(</span><span class="n">app</span><span class="p">)</span><span class="o">!!</span>
<span class="k">val</span> <span class="py">window</span> <span class="p">=</span> <span class="n">windowWidget</span><span class="p">.</span><span class="n">reinterpret</span><span class="p">&lt;</span><span class="n">GtkWindow</span><span class="p">&gt;()</span>
<span class="n">gtk_window_set_title</span><span class="p">(</span><span class="n">window</span><span class="p">,</span> <span class="s">&#34;Window&#34;</span><span class="p">);</span>
<span class="n">gtk_window_set_default_size</span><span class="p">(</span><span class="n">window</span><span class="p">,</span> <span class="m">200</span><span class="p">,</span> <span class="m">200</span><span class="p">)</span>
<span class="k">val</span> <span class="py">button_box</span> <span class="p">=</span> <span class="n">gtk_button_box_new</span><span class="p">(</span>
<span class="n">GtkOrientation</span><span class="p">.</span><span class="n">GTK_ORIENTATION_HORIZONTAL</span><span class="p">)</span><span class="o">!!</span>
<span class="n">gtk_container_add</span><span class="p">(</span><span class="n">window</span><span class="p">.</span><span class="n">reinterpret</span><span class="p">(),</span> <span class="n">button_box</span><span class="p">);</span>
<span class="k">val</span> <span class="py">button</span> <span class="p">=</span> <span class="n">gtk_button_new_with_label</span><span class="p">(</span><span class="s">&#34;Konan говорит: click me!&#34;</span><span class="p">)</span><span class="o">!!</span>
<span class="n">g_signal_connect</span><span class="p">(</span><span class="n">button</span><span class="p">,</span> <span class="s">&#34;clicked&#34;</span><span class="p">,</span>
<span class="n">staticCFunction</span> <span class="p">{</span> <span class="n">widget</span><span class="p">:</span> <span class="n">CPointer</span><span class="p">&lt;</span><span class="n">GtkApplication</span><span class="p">&gt;?,</span> <span class="k">data</span><span class="p">:</span> <span class="n">gpointer</span><span class="p">?</span> <span class="p">-&gt;</span>
<span class="n">println</span><span class="p">(</span><span class="s">&#34;Hi Kotlin&#34;</span><span class="p">)</span>
<span class="p">});</span>
<span class="n">g_signal_connect</span><span class="p">(</span><span class="n">button</span><span class="p">,</span> <span class="s">&#34;clicked&#34;</span><span class="p">,</span>
<span class="n">staticCFunction</span> <span class="p">{</span> <span class="n">widget</span><span class="p">:</span> <span class="n">CPointer</span><span class="p">&lt;</span><span class="n">GtkWidget</span><span class="p">&gt;?</span> <span class="p">-&gt;</span>
<span class="n">gtk_widget_destroy</span><span class="p">(</span><span class="n">widget</span><span class="p">)</span>
<span class="p">},</span>
<span class="n">window</span><span class="p">,</span> <span class="n">G_CONNECT_SWAPPED</span><span class="p">)</span>
<span class="n">gtk_container_add</span> <span class="p">(</span><span class="n">button_box</span><span class="p">.</span><span class="n">reinterpret</span><span class="p">(),</span> <span class="n">button</span><span class="p">);</span>
<span class="n">gtk_widget_show_all</span><span class="p">(</span><span class="n">windowWidget</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">fun</span> <span class="nf">gtkMain</span><span class="p">(</span><span class="n">args</span><span class="p">:</span> <span class="n">Array</span><span class="p">&lt;</span><span class="n">String</span><span class="p">&gt;):</span> <span class="n">Int</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">app</span> <span class="p">=</span> <span class="n">gtk_application_new</span><span class="p">(</span><span class="s">&#34;org.gtk.example&#34;</span><span class="p">,</span> <span class="n">G_APPLICATION_FLAGS_NONE</span><span class="p">)</span><span class="o">!!</span>
<span class="n">g_signal_connect</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s">&#34;activate&#34;</span><span class="p">,</span> <span class="n">staticCFunction</span><span class="p">(</span><span class="o">::</span><span class="n">activate</span><span class="p">))</span>
<span class="k">val</span> <span class="py">status</span> <span class="p">=</span> <span class="n">memScoped</span> <span class="p">{</span>
<span class="n">g_application_run</span><span class="p">(</span><span class="n">app</span><span class="p">.</span><span class="n">reinterpret</span><span class="p">(),</span>
<span class="n">args</span><span class="p">.</span><span class="n">size</span><span class="p">,</span> <span class="n">args</span><span class="p">.</span><span class="n">map</span> <span class="p">{</span> <span class="n">it</span><span class="p">.</span><span class="n">cstr</span><span class="p">.</span><span class="n">getPointer</span><span class="p">(</span><span class="n">memScope</span><span class="p">)</span> <span class="p">}.</span><span class="n">toCValues</span><span class="p">())</span>
<span class="p">}</span>
<span class="n">g_object_unref</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
<span class="k">return</span> <span class="n">status</span>
<span class="p">}</span></code></pre></div>
<p>You see, it&rsquo;s just a number of C-style function calls. Let&rsquo;s try to convert it to a more pleasantly looking Kotlin code.</p>
<h3 id="object-oriented-version">Object Oriented version</h3>
<p>First of all, Kotlin is an object oriented language. GTK+ framework too, in fact. Let&rsquo;s introduce object hierarchy for widget types used in the example.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">abstract</span> <span class="k">class</span> <span class="nc">Widget</span> <span class="p">{</span>
<span class="k">abstract</span> <span class="k">val</span> <span class="py">widgetPtr</span><span class="p">:</span> <span class="n">CPointer</span><span class="p">&lt;</span><span class="n">GtkWidget</span><span class="p">&gt;</span>
<span class="p">}</span>
<span class="k">abstract</span> <span class="k">class</span> <span class="nc">Container</span><span class="p">:</span> <span class="n">Widget</span><span class="p">()</span> <span class="p">{</span>
<span class="k">fun</span> <span class="nf">add</span><span class="p">(</span><span class="n">widget</span><span class="p">:</span> <span class="n">Widget</span><span class="p">)</span> <span class="p">=</span> <span class="n">gtk_container_add</span><span class="p">(</span><span class="n">widgetPtr</span><span class="p">.</span><span class="n">reinterpret</span><span class="p">(),</span> <span class="n">widget</span><span class="p">.</span><span class="n">widgetPtr</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">class</span> <span class="nc">Window</span><span class="p">(</span><span class="n">app</span><span class="p">:</span> <span class="n">CValuesRef</span><span class="p">&lt;</span><span class="n">GtkApplication</span><span class="p">&gt;):</span> <span class="n">Container</span><span class="p">()</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">val</span> <span class="py">widgetPtr</span> <span class="p">=</span> <span class="n">gtk_application_window_new</span><span class="p">(</span><span class="n">app</span><span class="p">)</span><span class="o">!!</span>
<span class="k">private</span> <span class="k">val</span> <span class="py">window</span> <span class="k">get</span><span class="p">()</span> <span class="p">=</span> <span class="n">widgetPtr</span><span class="p">.</span><span class="n">reinterpret</span><span class="p">&lt;</span><span class="n">GtkWindow</span><span class="p">&gt;()</span>
<span class="k">var</span> <span class="py">title</span><span class="p">:</span> <span class="n">String</span>
<span class="k">get</span><span class="p">()</span> <span class="p">=</span> <span class="n">gtk_window_get_title</span><span class="p">(</span><span class="n">window</span><span class="p">)</span>
<span class="k">set</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span> <span class="n">gtk_window_set_title</span><span class="p">(</span><span class="n">window</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span> <span class="p">}</span>
<span class="k">fun</span> <span class="nf">setDefaultSize</span><span class="p">(</span><span class="n">width</span><span class="p">:</span> <span class="n">Int</span><span class="p">,</span> <span class="n">height</span><span class="p">:</span> <span class="n">Int</span><span class="p">)</span> <span class="p">=</span> <span class="n">gtk_window_set_default_size</span><span class="p">(</span><span class="n">window</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">)</span>
<span class="k">fun</span> <span class="nf">showAll</span><span class="p">()</span> <span class="p">=</span> <span class="n">gtk_widget_show_all</span><span class="p">(</span><span class="n">widgetPtr</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">class</span> <span class="nc">ButtonBox</span><span class="p">(</span><span class="n">orientation</span><span class="p">:</span> <span class="n">GtkOrientation</span><span class="p">):</span> <span class="n">Container</span><span class="p">()</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">val</span> <span class="py">widgetPtr</span> <span class="p">=</span> <span class="n">gtk_button_box_new</span><span class="p">(</span><span class="n">orientation</span><span class="p">)</span><span class="o">!!</span>
<span class="p">}</span>
<span class="k">class</span> <span class="nc">Button</span><span class="p">(</span><span class="n">label</span><span class="p">:</span> <span class="n">String</span><span class="p">):</span> <span class="n">Widget</span><span class="p">()</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">val</span> <span class="py">widgetPtr</span> <span class="p">=</span> <span class="n">gtk_button_new_with_label</span><span class="p">(</span><span class="n">label</span><span class="p">)</span><span class="o">!!</span>
<span class="k">private</span> <span class="k">val</span> <span class="py">button</span> <span class="k">get</span><span class="p">()</span> <span class="p">=</span> <span class="n">widgetPtr</span><span class="p">.</span><span class="n">reinterpret</span><span class="p">&lt;</span><span class="n">GtkButton</span><span class="p">&gt;()</span>
<span class="k">fun</span> <span class="nf">onClicked</span><span class="p">(</span><span class="n">handler</span><span class="p">:</span> <span class="n">GtkButton</span><span class="p">,</span> <span class="n">callback</span><span class="p">:</span> <span class="n">CPointer</span><span class="p">&lt;</span><span class="n">CFunction</span><span class="p">&lt;(</span><span class="n">CPointer</span><span class="p">&lt;</span><span class="n">GtkButton</span><span class="p">&gt;?,</span> <span class="n">gpointer</span><span class="p">?)</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">&gt;&gt;)</span> <span class="p">{</span>
<span class="n">g_signal_connect</span><span class="p">(</span><span class="n">widgetPtr</span><span class="p">,</span> <span class="s">&#34;clicked&#34;</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">fun</span> &lt;T : Widget&gt; <span class="nf">onClicked</span><span class="p">(</span><span class="n">handler</span><span class="p">:</span> <span class="n">T</span><span class="p">,</span> <span class="n">callback</span><span class="p">:</span> <span class="n">CPointer</span><span class="p">&lt;</span><span class="n">CFunction</span><span class="p">&lt;(</span><span class="n">CPointer</span><span class="p">&lt;</span><span class="n">GtkWindow</span><span class="p">&gt;?,</span> <span class="n">gpointer</span><span class="p">?)</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">&gt;&gt;)</span> <span class="p">{</span>
<span class="n">g_signal_connect</span><span class="p">(</span><span class="n">widgetPtr</span><span class="p">,</span> <span class="s">&#34;clicked&#34;</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">handler</span><span class="p">.</span><span class="n">widgetPtr</span><span class="p">,</span> <span class="n">G_CONNECT_SWAPPED</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>Here we have basic hierarchy with <code>Widget</code> as the root, <code>Window</code> and <code>ButtonBox</code> both are <code>Container</code> subclasses and <code>Button</code> derived from <code>Widget</code>. <code>title</code> and <code>setDefaultSize</code> belong now to <code>Window</code> class. Note how naturally <code>gtk_window_get_title</code>/<code>gtk_window_set_title</code> method pair is converted to a <code>title</code> property. <code>Button</code> class also features <code>onClicked</code> method encapsulating signal subscription logic. It hasn&rsquo;t changed much and still doesn&rsquo;t look good, we&rsquo;ll return to it later.</p>
<p>Similarly I&rsquo;ve converted code related to a GtkApplication into an <code>Application</code> class.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">class</span> <span class="nc">Application</span><span class="p">(</span><span class="n">id</span><span class="p">:</span> <span class="n">String</span><span class="p">)</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">app</span> <span class="p">=</span> <span class="n">gtk_application_new</span><span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">G_APPLICATION_FLAGS_NONE</span><span class="p">)</span><span class="o">!!</span>
<span class="k">fun</span> <span class="nf">onActivate</span><span class="p">(</span><span class="n">callback</span><span class="p">:</span> <span class="n">CPointer</span><span class="p">&lt;</span><span class="n">CFunction</span><span class="p">&lt;(</span><span class="n">CPointer</span><span class="p">&lt;</span><span class="n">GtkApplication</span><span class="p">&gt;?,</span> <span class="n">gpointer</span><span class="p">?)</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">&gt;&gt;)</span> <span class="p">{</span>
<span class="n">g_signal_connect</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s">&#34;activate&#34;</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">fun</span> <span class="nf">run</span><span class="p">(</span><span class="n">args</span><span class="p">:</span> <span class="n">Array</span><span class="p">&lt;</span><span class="n">String</span><span class="p">&gt;):</span> <span class="n">Int</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">status</span> <span class="p">=</span> <span class="n">memScoped</span> <span class="p">{</span>
<span class="n">g_application_run</span><span class="p">(</span><span class="n">app</span><span class="p">.</span><span class="n">reinterpret</span><span class="p">(),</span>
<span class="n">args</span><span class="p">.</span><span class="n">size</span><span class="p">,</span> <span class="n">args</span><span class="p">.</span><span class="n">map</span> <span class="p">{</span> <span class="n">it</span><span class="p">.</span><span class="n">cstr</span><span class="p">.</span><span class="n">getPointer</span><span class="p">(</span><span class="n">memScope</span><span class="p">)</span> <span class="p">}.</span><span class="n">toCValues</span><span class="p">())</span>
<span class="p">}</span>
<span class="n">g_object_unref</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
<span class="k">return</span> <span class="n">status</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>This is how the main method now looks like:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">fun</span> <span class="nf">gtkMain</span><span class="p">(</span><span class="n">args</span><span class="p">:</span> <span class="n">Array</span><span class="p">&lt;</span><span class="n">String</span><span class="p">&gt;):</span> <span class="n">Int</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">app</span> <span class="p">=</span> <span class="n">Application</span><span class="p">(</span><span class="s">&#34;org.gtk.example&#34;</span><span class="p">)</span>
<span class="n">app</span><span class="p">.</span><span class="n">onActivate</span><span class="p">(</span><span class="n">staticCFunction</span> <span class="p">{</span> <span class="n">app</span><span class="p">,</span> <span class="n">_</span> <span class="p">-&gt;</span>
<span class="k">val</span> <span class="py">window</span> <span class="p">=</span> <span class="n">Window</span><span class="p">(</span><span class="n">app</span><span class="o">!!</span><span class="p">.</span><span class="n">reinterpret</span><span class="p">())</span>
<span class="n">window</span><span class="p">.</span><span class="n">title</span> <span class="p">=</span> <span class="s">&#34;Kotlin&#34;</span>
<span class="n">window</span><span class="p">.</span><span class="n">setDefaultSize</span><span class="p">(</span><span class="m">200</span><span class="p">,</span> <span class="m">200</span><span class="p">)</span>
<span class="k">val</span> <span class="py">buttonBox</span> <span class="p">=</span> <span class="n">ButtonBox</span><span class="p">(</span><span class="n">GtkOrientation</span><span class="p">.</span><span class="n">GTK_ORIENTATION_HORIZONTAL</span><span class="p">)</span>
<span class="k">val</span> <span class="py">button</span> <span class="p">=</span> <span class="n">Button</span><span class="p">(</span><span class="s">&#34;Hello world!&#34;</span><span class="p">)</span>
<span class="n">button</span><span class="p">.</span><span class="n">onClicked</span><span class="p">(</span><span class="n">staticCFunction</span> <span class="p">{</span> <span class="n">widget</span><span class="p">:</span> <span class="n">CPointer</span><span class="p">&lt;</span><span class="n">GtkButton</span><span class="p">&gt;?,</span> <span class="k">data</span><span class="p">:</span> <span class="n">gpointer</span><span class="p">?</span> <span class="p">-&gt;</span>
<span class="n">println</span><span class="p">(</span><span class="s">&#34;Hello Kotlin!&#34;</span><span class="p">)</span>
<span class="p">})</span>
<span class="n">button</span><span class="p">.</span><span class="n">onClicked</span><span class="p">(</span><span class="n">window</span><span class="p">,</span> <span class="n">staticCFunction</span> <span class="p">{</span> <span class="n">window</span><span class="p">:</span> <span class="n">CPointer</span><span class="p">&lt;</span><span class="n">GtkWindow</span><span class="p">&gt;?,</span> <span class="k">data</span><span class="p">:</span> <span class="n">gpointer</span><span class="p">?</span> <span class="p">-&gt;</span>
<span class="n">gtk_widget_destroy</span><span class="p">(</span><span class="n">window</span><span class="o">!!</span><span class="p">.</span><span class="n">reinterpret</span><span class="p">())</span>
<span class="p">})</span>
<span class="n">buttonBox</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">button</span><span class="p">)</span>
<span class="n">window</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">buttonBox</span><span class="p">)</span>
<span class="n">window</span><span class="p">.</span><span class="n">showAll</span><span class="p">()</span>
<span class="p">})</span>
<span class="k">return</span> <span class="n">app</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
<span class="p">}</span></code></pre></div>
<p>Looks much more readable and object-oriented, isn&rsquo;t it? There are still few things left, however. You have definetely noticed that ugly <code>staticCFunction</code> calls. These are the helpers to pass Kotlin/Native callbacks into C function calls, see <a href="https://github.com/JetBrains/kotlin-native/blob/v0.2.0/INTEROP.md">interoperability guide</a>. Unfortunately, we cannot pass any bound lambda through the boundary, so if we&rsquo;d like our signal subscriptions look better we need to workaround it.</p>
<h3 id="better-callbacks">Better callbacks</h3>
<p>The idea behind the workaround is the following: we will store all handlers in Kotlin and subscribe a static function to an original signal. This callback will then call each handler when invoked. Here is the <code>Signal</code> class which stores handlers. It is a simplified version of <code>Event</code> class from <a href="https://github.com/JetBrains/kotlin-native/blob/v0.2.0/samples/libcurl/src/org/konan/libcurl/Event.kt">libcurl</a> example.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="n">typealias</span> <span class="n">SignalHandler</span> <span class="p">=</span> <span class="p">()</span> <span class="p">-&gt;</span> <span class="n">Unit</span>
<span class="k">class</span> <span class="nc">Signal</span> <span class="p">{</span>
<span class="k">private</span> <span class="k">var</span> <span class="py">handlers</span> <span class="p">=</span> <span class="n">emptyList</span><span class="p">&lt;</span><span class="n">SignalHandler</span><span class="p">&gt;()</span>
<span class="k">operator</span> <span class="k">fun</span> <span class="nf">plusAssign</span><span class="p">(</span><span class="n">handler</span><span class="p">:</span> <span class="n">SignalHandler</span><span class="p">)</span> <span class="p">{</span> <span class="n">handlers</span> <span class="p">+=</span> <span class="n">handler</span> <span class="p">}</span>
<span class="k">operator</span> <span class="k">fun</span> <span class="nf">minusAssign</span><span class="p">(</span><span class="n">handler</span><span class="p">:</span> <span class="n">SignalHandler</span><span class="p">)</span> <span class="p">{</span> <span class="n">handlers</span> <span class="p">-=</span> <span class="n">handler</span> <span class="p">}</span>
<span class="k">operator</span> <span class="k">fun</span> <span class="nf">invoke</span><span class="p">()</span> <span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="n">handler</span> <span class="k">in</span> <span class="n">handlers</span><span class="p">)</span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="n">handler</span><span class="p">()</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">e</span><span class="p">:</span> <span class="n">Throwable</span><span class="p">)</span> <span class="p">{</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>Then we rewrite <code>Button</code> class as follows:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">fun</span> <span class="nf">signalHandler</span><span class="p">(</span><span class="n">sender</span><span class="p">:</span> <span class="n">CPointer</span><span class="p">&lt;*&gt;?,</span> <span class="k">data</span><span class="p">:</span> <span class="n">COpaquePointer</span><span class="p">?)</span> <span class="p">{</span>
<span class="k">val</span> <span class="py">button</span> <span class="p">=</span> <span class="n">StableObjPtr</span><span class="p">.</span><span class="n">fromValue</span><span class="p">(</span><span class="k">data</span><span class="o">!!</span><span class="p">).</span><span class="k">get</span><span class="p">()</span> <span class="k">as</span> <span class="n">Button</span>
<span class="n">button</span><span class="p">.</span><span class="n">clicked</span><span class="p">()</span>
<span class="p">}</span>
<span class="k">class</span> <span class="nc">Button</span><span class="p">(</span><span class="n">label</span><span class="p">:</span> <span class="n">String</span><span class="p">):</span> <span class="n">Widget</span><span class="p">()</span> <span class="p">{</span>
<span class="k">override</span> <span class="k">val</span> <span class="py">widgetPtr</span> <span class="p">=</span> <span class="n">gtk_button_new_with_label</span><span class="p">(</span><span class="n">label</span><span class="p">)</span><span class="o">!!</span>
<span class="n">init</span> <span class="p">{</span>
<span class="n">g_signal_connect</span><span class="p">(</span><span class="n">widgetPtr</span><span class="p">,</span> <span class="s">&#34;clicked&#34;</span><span class="p">,</span> <span class="n">staticCFunction</span><span class="p">(</span><span class="o">::</span><span class="n">signalHandler</span><span class="p">),</span> <span class="n">StableObjPtr</span><span class="p">.</span><span class="n">create</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="n">value</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">val</span> <span class="py">clicked</span> <span class="p">=</span> <span class="n">Signal</span><span class="p">()</span>
<span class="p">}</span></code></pre></div>
<p>Here we&rsquo;ve created a static signal handler for <code>&quot;clicked&quot;</code> signal and used it together with <code>Signal</code> object to handle this signal. Button creation code can now be simplified as well:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="n">button</span><span class="p">.</span><span class="n">clicked</span> <span class="p">+=</span> <span class="p">{</span>
<span class="n">println</span><span class="p">(</span><span class="s">&#34;Hello Kotlin!&#34;</span><span class="p">)</span>
<span class="n">gtk_widget_destroy</span><span class="p">(</span><span class="n">window</span><span class="p">.</span><span class="n">widgetPtr</span><span class="p">)</span>
<span class="p">}</span></code></pre></div>
<p>Lambda provided as a signal handler can now capture local variables, so we don&rsquo;t need to connect <code>&quot;clicked&quot;</code> signal again to handle it in <code>window</code> context. Cool!</p>
<h3 id="ui-builder-dsl">UI builder DSL</h3>
<p>But this is not the end yet! I&rsquo;m a big <a href="https://victor.kropp.name/tag/dsl/">Kotlin DSL lover</a>, so I couldn&rsquo;t resist adding some <a href="https://github.com/Kotlin/anko">Anko</a> style UI builders. They are very simple:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">fun</span> <span class="nf">CPointer</span><span class="p">&lt;</span><span class="n">GtkApplication</span><span class="p">&gt;.</span><span class="n">window</span><span class="p">(</span><span class="n">builder</span><span class="p">:</span> <span class="n">Window</span><span class="p">.()</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">{</span>
<span class="n">Window</span><span class="p">(</span><span class="n">reinterpret</span><span class="p">()).</span><span class="n">apply</span><span class="p">(</span><span class="n">builder</span><span class="p">).</span><span class="n">showAll</span><span class="p">()</span>
<span class="p">}</span>
<span class="k">fun</span> <span class="nf">Container</span><span class="p">.</span><span class="n">buttonBox</span><span class="p">(</span><span class="n">builder</span><span class="p">:</span> <span class="n">ButtonBox</span><span class="p">.()</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">=</span> <span class="n">add</span><span class="p">(</span><span class="n">ButtonBox</span><span class="p">(</span><span class="n">GtkOrientation</span><span class="p">.</span><span class="n">GTK_ORIENTATION_HORIZONTAL</span><span class="p">).</span><span class="n">apply</span><span class="p">(</span><span class="n">builder</span><span class="p">))</span>
<span class="k">fun</span> <span class="nf">ButtonBox</span><span class="p">.</span><span class="n">button</span><span class="p">(</span><span class="n">label</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span> <span class="n">builder</span><span class="p">:</span> <span class="n">Button</span><span class="p">.()</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">=</span> <span class="n">add</span><span class="p">(</span><span class="n">Button</span><span class="p">(</span><span class="n">label</span><span class="p">).</span><span class="n">apply</span><span class="p">(</span><span class="n">builder</span><span class="p">))</span></code></pre></div>
<p>But see how nice and concise is the window creation code now!</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="n">app</span><span class="o">!!</span><span class="p">.</span><span class="n">window</span> <span class="p">{</span>
<span class="n">title</span> <span class="p">=</span> <span class="s">&#34;Kotlin&#34;</span>
<span class="n">setDefaultSize</span><span class="p">(</span><span class="m">200</span><span class="p">,</span> <span class="m">200</span><span class="p">)</span>
<span class="n">buttonBox</span> <span class="p">{</span>
<span class="n">button</span><span class="p">(</span><span class="s">&#34;Hello World!&#34;</span><span class="p">)</span> <span class="p">{</span>
<span class="n">clicked</span> <span class="p">+=</span> <span class="p">{</span>
<span class="n">println</span><span class="p">(</span><span class="s">&#34;Hello Kotlin!&#34;</span><span class="p">)</span>
<span class="k">this</span><span class="n">@window</span><span class="p">.</span><span class="n">destroy</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>Awesome!</p>
<h3 id="result">Result</h3>
<p>I&rsquo;ve uploaded the full working code to <a href="https://gist.github.com/kropp/9b8b9578b9421e932f932bb6aed9598a">a Gist</a>.</p>
<p>The proposed solution has several advantages:</p>
<ul>
<li>it is much more readable</li>
<li>it is statically typed, including signals</li>
<li>it doesn&rsquo;t expose underlying C function calls (thus it is more portable)</li>
</ul>
<h3 id="what-s-next">What&rsquo;s next?</h3>
<p>I&rsquo;m going to create similar <a href="https://github.com/kropp/kotlin-native-gtk">bindings</a> for all GTK+ entities and develop some sample application using it to prove that Kotlin can be a great alternative to <a href="https://wiki.gnome.org/Projects/Vala">Vala</a> for GNOME developers.</p>
<p>Stay tuned!</p>
Bose Headphones spied on listeners (including me)https://victor.kropp.name/blog/bose-headphones-spy-on-listeners/
Wed, 10 May 2017 16:36:16 +0200https://victor.kropp.name/blog/bose-headphones-spy-on-listeners/
<figure>
<img src="https://victor.kropp.name/blog/img/2017/bose-qc35.jpg"
alt="Bose QuietComfort 35 headphones" width="1000"/> <figcaption>
<p>Bose QuietComfort 35 headphones</p>
</figcaption>
</figure>
<p>Bose Quiet Comfort noise canceling headphones are a must have for frequent travelers. Though I don&rsquo;t travel that much, I&rsquo;ve been dreaming about such headphones since a long time. And as soon as they&rsquo;ve announced a new wireless model with Bluetooth connectivity I&rsquo;ve immediately decided to buy one. And I&rsquo;m not disappointed at all; sound quality is superb, noise canceling works as expected, they look beautiful and sit comfortable. They might be a bit overpriced, but I still think they worth it.</p>
<p>I was a satisfied customer until I learned these headphones were spying on listeners via Bose Connect app. On April, 19 it was <a href="http://www.reuters.com/article/us-bose-lawsuit-idUSKBN17L2BT">announced in media</a> after a complaint against Bose Corporation was filed in US.</p>
<p>A few days later Bose started <a href="https://www.bose.com/en_us/landing_pages/bose_corporation_updates.html">communicating this issue</a> with customers on their website (<a href="https://victor.kropp.name/blog/img/2017/Screen Shot 2017-05-08 at 11.59.24-fullpage.png">full-page screenshot</a> as of May 8, 2017, in case they decide to hide this page later). I followed their press releases and noticed one easily recognizable pattern.</p>
<h3 id="the-five-stages-of-grief">The five stages of grief</h3>
<p>To explain what is this, let me just quote a Wikipedia article here:</p>
<blockquote>
<p>The Kübler-Ross model, or the five stages of grief, postulates a series of emotions experienced by terminally ill patients prior to death…
Kübler-Ross later expanded her model to include any form of personal loss, such as … major rejection.</p>
<p><a href="https://en.wikipedia.org/wiki/K%C3%BCbler-Ross_model">Kübler-Ross model</a></p>
</blockquote>
<p>Sounds familiar, right? Let&rsquo;s take a look.</p>
<h4 id="1-denial-and-2-anger">1. Denial and 2. Anger</h4>
<blockquote>
<p><strong>April, 20</strong></p>
<p>We understand the nature of Class Action lawsuits. And we’ll fight the inflammatory, misleading allegations made against us through the legal system.</p>
<p>For now, we want to talk directly to you.</p>
<p>Nothing is more important to us than your trust. We work tirelessly to earn and keep it, and have for over 50 years. That’s never changed, and never will. In the Bose Connect App, we don’t wiretap your communications, we don’t sell your information, and we don’t use anything we collect to identify you—or anyone else—by name.</p>
<p>If there’s anything else we think you should know, you’ll hear it straight from us.</p>
</blockquote>
<p>As expected, their first reaction is to deny all accusations. Of course, such answer doesn&rsquo;t help to restore trust and loyality.</p>
<h4 id="3-bargaining">3. Bargaining</h4>
<blockquote>
<p><strong>April 23, 2017</strong></p>
<p>We told you you’d hear things straight from us. We’ve answered your questions when they’ve come in, but when there’s misleading information being repeated about us, we have to repeat our responses to clarify. So we’re going to share with everyone what we’ve shared with those of you who’ve contacted us directly, and what we’ve shared more broadly to correct the record.</p>
<p>First, our privacy policy can be found on the Connect App. You’ll find that the Connect App collects standard things to make your experience, and our products, better—like device information, app performance, and app and product usage. That includes information about songs playing on the device, volume played, and other usage data.</p>
<p>But you have to be using the Connect App with your Bose product for that to happen. You can use every Bose Bluetooth product without the Connect App.</p>
<p>For as long as we’re hearing from you, you’ll keep hearing from us. And we’ll keep posting additional information that you haven’t asked us about, too.</p>
</blockquote>
<p>Next, they admit collecting a lot of data. But at the same time, they are trying to blame customers for using their app.</p>
<p>This is unfair. I&rsquo;ve installed that app only to receive <a href="https://victor.kropp.name/blog/software-updates-pro-et-contra/">firmware updates</a> which are inevitable with modern gadgets. Yes, I accepted their privacy policy and didn&rsquo;t read it thoroughly. But you don&rsquo;t expect such things too, right?</p>
<h4 id="4-depression">4. Depression</h4>
<blockquote>
<p><strong>April 25, 2017</strong></p>
<p>Everything we’ve shared with you over the last few days still stands—we never sold your data, and we never used it to identify you or anyone else. But we’re now going to take three additional steps to give you more options and assurance.</p>
<p>The Connect App will be updated so you can opt out of having it collect data. Any information collected before the opt out is available will be altered, so it can’t be linked to you or your device by anyone. And the Connect App’s privacy policy will be updated to include even more information.</p>
<p>We’ll let you know when these changes go in to effect. We’re working on them now, and you’ll hear from us soon.</p>
</blockquote>
<p>A week after the news bomb has exploded. Nothing really helps, people keep posting obsessed reviews in app stores. They finally understand they should stop collecting data or at least give an option to opt-out. I hope that they don&rsquo;t lie they never sold any data. But how do I know? We&rsquo;ll wait for a court decision.</p>
<h4 id="5-acceptance">5. Acceptance</h4>
<blockquote>
<p><strong>May 3, 2017</strong></p>
<p>The Bose Connect App update is now available.</p>
<p>After you download the update, go to the app’s main menu, select &ldquo;Privacy Policy and Settings,&rdquo; and use the toggle switch to opt out from data collection.</p>
</blockquote>
<p>It took them two weeks to accept their fault and to understand that privacy still matters. I appreciate they now offer an opt-out and have clarified privacy policy. However, I&rsquo;m still not sure I want to reinstall the app.</p>
<p><strong>Once you lose respect, it&rsquo;s very hard to get it back.</strong></p>
<p>Let it be the lesson for all of us.</p>
Object Builders in idiomatic Kotlinhttps://victor.kropp.name/blog/object-builders-in-idiomatic-kotlin/
Thu, 13 Apr 2017 16:19:03 +0200https://victor.kropp.name/blog/object-builders-in-idiomatic-kotlin/<figure>
<img src="https://victor.kropp.name/blog/img/2017/construction.jpg" width="1000"/> <figcaption>
<p>
<a href="https://www.flickr.com/photos/loozrboy/7218773508/">CC-BY-SA · flickr.com/photos/loozrboy/7218773508/</a></p>
</figcaption>
</figure>
<p>Kotlin supports functions and constructors with named and optional (default) <a href="https://kotlinlang.org/docs/reference/functions.html">arguments</a>. These features help make object construction clear but don&rsquo;t help to avoid huge towers of nested constructors. It is also almost impossible to have any conditionally set properties.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">data</span> <span class="k">class</span> <span class="nc">Article</span><span class="p">(</span>
<span class="k">val</span> <span class="py">name</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
<span class="k">val</span> <span class="py">text</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span>
<span class="k">val</span> <span class="py">author</span><span class="p">:</span> <span class="n">Author</span><span class="p">,</span>
<span class="k">val</span> <span class="py">comment</span><span class="p">:</span> <span class="n">Comment</span>
<span class="p">)</span>
<span class="k">val</span> <span class="py">article</span> <span class="p">=</span> <span class="n">Article</span><span class="p">(</span>
<span class="s">&#34;Kotlin 1.1 released!&#34;</span><span class="p">,</span>
<span class="s">&#34;Lorem ipsum dolor sit amet&#34;</span><span class="p">,</span>
<span class="n">Organization</span><span class="p">(</span><span class="s">&#34;JetBrains&#34;</span><span class="p">),</span>
<span class="n">Comment</span><span class="p">(</span><span class="s">&#34;Hooray!&#34;</span><span class="p">,</span> <span class="n">Person</span><span class="p">(</span><span class="s">&#34;John Doe&#34;</span><span class="p">))</span>
<span class="p">)</span></code></pre></div>
<p>Looks nice, however mixing named and positional arguments is not allowed, which doesn&rsquo;t make construction of complex objects any easier.</p>
<p>Some time ago I created a Java library with a collection of builders for entities defined in <a href="http://schema.org/">Schema.org</a>.
This is how typical object builder looks like:</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="kd">final</span> <span class="n">Article</span> <span class="n">article</span> <span class="o">=</span> <span class="n">SchemaOrg</span><span class="o">.</span><span class="na">article</span><span class="o">()</span>
<span class="o">.</span><span class="na">name</span><span class="o">(</span><span class="s">&#34;Kotlin 1.1 released!&#34;</span><span class="o">)</span>
<span class="o">.</span><span class="na">text</span><span class="o">(</span><span class="s">&#34;Lorem ipsum dolor sit amet&#34;</span><span class="o">)</span>
<span class="o">.</span><span class="na">author</span><span class="o">(</span><span class="n">organization</span><span class="o">().</span><span class="na">name</span><span class="o">(</span><span class="s">&#34;JetBrains&#34;</span><span class="o">).</span><span class="na">build</span><span class="o">())</span>
<span class="o">.</span><span class="na">comment</span><span class="o">(</span>
<span class="n">comment</span><span class="o">().</span><span class="na">text</span><span class="o">(</span><span class="s">&#34;Hooray!&#34;</span><span class="o">).</span><span class="na">author</span><span class="o">(</span><span class="n">person</span><span class="o">().</span><span class="na">name</span><span class="o">(</span><span class="s">&#34;John Doe&#34;</span><span class="o">).</span><span class="na">build</span><span class="o">()).</span><span class="na">build</span><span class="o">()</span>
<span class="o">).</span><span class="na">build</span><span class="o">();</span></code></pre></div>
<p>It is such a common pattern, that there is a <a href="https://github.com/google/FreeBuilder">@FreeBuilder</a> Java library that generates such builders from interfaces. And Groovy has <a href="http://docs.groovy-lang.org/2.4.7/html/gapi/groovy/transform/builder/Builder.html">a similar feature</a> built in.</p>
<p>Everybody is used to this pattern, but it still has some downsides:</p>
<ul>
<li>Fluent interface eliminates an intermediate builder variable, but cannot help when you need to set some properties conditionally.</li>
<li>It is repetitive. When creating nested objects you often need to <code>.build()</code> each of them.</li>
<li>It is verbose. Consider setting comment&rsquo;s author in the code above, you need explicitly create <code>Person</code> object and provide it as an <code>author</code>, but it is clear that an author is a person. You can either have a nice fluent interface or reduce verbosity by making <code>author()</code> return builder for <code>Person</code>.</li>
</ul>
<p>I propose the following syntax in Kotlin to build the same object:</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">val</span> <span class="py">article</span> <span class="p">=</span> <span class="n">article</span> <span class="p">{</span>
<span class="n">name</span> <span class="p">=</span> <span class="s">&#34;Kotlin 1.1 released!&#34;</span>
<span class="n">text</span> <span class="p">=</span> <span class="s">&#34;Lorem ipsum dolor sit amet&#34;</span>
<span class="n">author</span> <span class="p">=</span> <span class="n">organization</span> <span class="p">{</span> <span class="n">name</span> <span class="p">=</span> <span class="s">&#34;JetBrains&#34;</span> <span class="p">}</span>
<span class="n">comment</span> <span class="p">{</span>
<span class="n">text</span> <span class="p">=</span> <span class="s">&#34;Hooray!&#34;</span>
<span class="n">author</span> <span class="p">{</span> <span class="n">name</span> <span class="p">=</span> <span class="s">&#34;John Doe&#34;</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></div>
<p>What advantages does this code have over its Java counterpart?</p>
<ul>
<li>It is possible to have any arbitrary logical constructs inside the builder without any intermediate variables to store it.</li>
<li>Less repetitive. No ubiquitous <code>build()</code> method, fewer braces.</li>
<li>In unambiguous cases it reduces verbosity significantly by providing builders for nested objects in-place.</li>
<li>And it is like <code>data class</code> constructor with benefits!</li>
</ul>
<p>Looks great? Hell yes! What is even better is that it takes only a few lines of code to implement it!</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">class</span> <span class="nc">ArticleBuilder</span> <span class="p">{</span>
<span class="k">var</span> <span class="py">name</span><span class="p">:</span> <span class="n">String</span>
<span class="k">var</span> <span class="py">text</span><span class="p">:</span> <span class="n">String</span>
<span class="k">var</span> <span class="py">author</span><span class="p">:</span> <span class="n">Author</span>
<span class="k">var</span> <span class="py">comment</span><span class="p">:</span> <span class="n">Comment</span>
<span class="k">fun</span> <span class="nf">build</span><span class="p">()</span> <span class="p">=</span> <span class="n">Article</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">text</span><span class="p">,</span> <span class="n">author</span><span class="p">,</span> <span class="n">comment</span><span class="p">)</span>
<span class="p">}</span>
<span class="c1">// and a convenience function to create builder:
</span><span class="c1"></span>
<span class="k">fun</span> <span class="nf">article</span><span class="p">(</span><span class="n">builder</span><span class="p">:</span> <span class="n">ArticleBuilder</span><span class="p">.()</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">=</span> <span class="n">ArticleBuilder</span><span class="p">().</span><span class="n">apply</span><span class="p">(</span><span class="n">builder</span><span class="p">).</span><span class="n">build</span><span class="p">()</span></code></pre></div>
<p>The only problem with the code above is that it doesn&rsquo;t compile unfortunately, because properties must be initialized. There are several possible workarounds:</p>
<ul>
<li>Add <code>lateinit</code> modifier. Accessing uninitialized property in <code>build()</code> will result in <code>UninitializedPropertyAccessException</code> in runtime.</li>
<li>Make properties nullable and initialize them all with <code>null</code>. (We need to deal with unset properties somehow anyway.)</li>
<li>Add private dictionary and <a href="https://kotlinlang.org/docs/reference/delegated-properties.html">delegate</a> it handle all properties</li>
</ul>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">class</span> <span class="nc">ArticleBuilder</span> <span class="p">{</span>
<span class="k">private</span> <span class="k">val</span> <span class="py">values</span> <span class="p">=</span> <span class="n">mutableMapOf</span><span class="p">&lt;</span><span class="n">String</span><span class="p">,</span><span class="n">Any</span><span class="p">&gt;()</span>
<span class="k">var</span> <span class="py">name</span><span class="p">:</span> <span class="n">String</span> <span class="k">by</span> <span class="n">values</span>
<span class="err">…</span>
<span class="k">var</span> <span class="py">comment</span><span class="p">:</span> <span class="n">Comment</span> <span class="k">by</span> <span class="n">values</span>
<span class="p">}</span></code></pre></div>
<p>In this case all type casts are done behind the scenes. This is my preferred approach actually. And if you need this object only to serialize it later to JSON, which basically <strong>is</strong> just a dictionary, it is very efficient.</p>
<blockquote>
<p><em>When Kotlin adds support for <a href="https://youtrack.jetbrains.com/issue/KT-6519">write-only properties</a>, it would be possible to remove getters from <code>var</code> properties making builders another few bytes smaller.</em></p>
</blockquote>
<p>Nested builders are very simple too.</p>
<div class="highlight"><pre class="chroma"><code class="language-kotlin" data-lang="kotlin"><span class="k">var</span> <span class="py">comment</span><span class="p">:</span> <span class="n">Comment</span> <span class="k">by</span> <span class="n">values</span>
<span class="k">fun</span> <span class="nf">comment</span><span class="p">(</span><span class="n">builder</span><span class="p">:</span> <span class="n">CommentBuilder</span><span class="p">.()</span> <span class="p">-&gt;</span> <span class="n">Unit</span><span class="p">)</span> <span class="p">{</span>
<span class="n">comment</span> <span class="p">=</span> <span class="n">CommentBuilder</span><span class="p">().</span><span class="n">apply</span><span class="p">(</span><span class="n">builder</span><span class="p">).</span><span class="n">build</span><span class="p">()</span>
<span class="p">}</span></code></pre></div>
<p>Voilà!</p>
<p>You can try out builders implemented this way in my <a href="https://github.com/kropp/jsonld-metadata">jsonld-metadata</a> library, which implements full <a href="http://schema.org/">Schema.org</a> vocabulary. It is available on BinTray as <a href="https://bintray.com/kropp/org.schema/jsonld-metadata"><code>org.schema:jsonld-metadata</code></a> and <a href="https://bintray.com/kropp/org.schema/jsonld-metadata-kotlin"><code>org.schema:jsonld-metadata-kotlin</code></a>.</p>
<p>To be continued.</p>
100% Code Coveragehttps://victor.kropp.name/blog/100-percent-code-coverage/
Sat, 01 Apr 2017 09:16:25 +0200https://victor.kropp.name/blog/100-percent-code-coverage/<p>If you write unit tests and don&rsquo;t cover all business logic in your project, you are doing it wrong.</p>
<figure>
<img src="http://cs4.pikabu.ru/post_img/big/2014/03/24/7/1395654372_1357302756.jpg" width="1000"/> <figcaption>
<p>
<a href="http://pikabu.ru/story/ne_bud_kak_vse_lomay_sistemu_2103232">pikabu.ru</a></p>
</figcaption>
</figure>
<p>Each untested line of code may contain a bug. Only full coverage can provide confidence in your code.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">&quot;But all the unit tests passed!&quot; <a href="https://twitter.com/hashtag/programming?src=hash&amp;ref_src=twsrc%5Etfw">#programming</a> <a href="https://t.co/8fRToLZdh9">pic.twitter.com/8fRToLZdh9</a></p>&mdash; Jordan Hall (@DivineOmega) <a href="https://twitter.com/DivineOmega/status/807351725006974976?ref_src=twsrc%5Etfw">December 9, 2016</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Integration tests may help to increase this important metric because they cover more lines of code at once.</p>
<p>{{<em>&lt; tweet 829850420948455424 &gt;</em>}}</p>
<p>However, they are harder to write, so don&rsquo;t waste your time.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Unit tests pass, no integration tests were performed. Hold hand under soap dispenser and get soap foam blown all over my body and hair. <a href="https://t.co/6aHV6SC4r1">pic.twitter.com/6aHV6SC4r1</a></p>&mdash; Baron Sc​hwartz (@xaprb) <a href="https://twitter.com/xaprb/status/835995366189326336?ref_src=twsrc%5Etfw">February 26, 2017</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Much, much harder.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">2 unit tests. 0 integration tests. <a href="https://t.co/FpForNhhyi">pic.twitter.com/FpForNhhyi</a></p>&mdash; DEV Community 👩‍💻👨‍💻 (@ThePracticalDev) <a href="https://twitter.com/ThePracticalDev/status/845638950517706752?ref_src=twsrc%5Etfw">March 25, 2017</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>If somebody tells you that some issues may only be discovered in integration testing, don&rsquo;t believe them!</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">2 unit tests. 0 integration tests <a href="https://t.co/V2Z9F4G1sJ">pic.twitter.com/V2Z9F4G1sJ</a></p>&mdash; DEV Community 👩‍💻👨‍💻 (@ThePracticalDev) <a href="https://twitter.com/ThePracticalDev/status/687672086152753152?ref_src=twsrc%5Etfw">January 14, 2016</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>You don&rsquo;t need integration tests.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Two unit tests, no integration tests. <a href="https://t.co/RHWRvzsxnc">pic.twitter.com/RHWRvzsxnc</a></p>&mdash; Tim Bray (@timbray) <a href="https://twitter.com/timbray/status/822470746773409794?ref_src=twsrc%5Etfw">January 20, 2017</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Your code will always be used in the way you expected it to be used.</p>
<figure>
<img src="https://i.giphy.com/l0MYSpvx4pnsoMNz2.gif"/> <figcaption>
<p>
<a href="https://giphy.com/gifs/l0MYSpvx4pnsoMNz2">giphy.com</a></p>
</figcaption>
</figure>
<p>Have other examples? Share links in comments!</p>
<p>And don&rsquo;t take this too serious.</p>
On code formattinghttps://victor.kropp.name/blog/on-code-formatting/
Mon, 20 Mar 2017 19:05:46 +0100https://victor.kropp.name/blog/on-code-formatting/
<figure>
<img src="https://victor.kropp.name/blog/img/2017/code-is-art.jpg" width="1000" height="550"/> <figcaption>
<p>
<a href="https://blog.jetbrains.com/blog/2017/02/20/happy-birthday-jetbrains-how-old-are-you/">“Code is Art” mosaic drawn by JetBrainers</a></p>
</figcaption>
</figure>
<p>Code is text. Like every natural language, programming languages have strict grammar and syntax rules. And like in typography, there are formatting rules. We can read and understand poorly formatted books, but it might be difficult. The same applies to source code as well.</p>
<p>Well-formatted code helps us understand program structure. Of course, different languages have different formatting styles. Wrong or unusual formatting makes code look awkward and dumb.</p>
<figure>
<img src="https://i.imgur.com/wG51k7v.png" width="597" height="255"/> <figcaption>
<p>
<a href="https://www.reddit.com/r/ProgrammerHumor/comments/2wrxyt/a_python_programmer_attempting_java/">A Python programmer attempting Java (via Reddit)</a></p>
</figcaption>
</figure>
<h4 id="tabs-vs-spaces">Tabs vs. Spaces</h4>
<p>Programmers often argue about code formatting. One of the most popular topics is Tabs vs. Spaces. The problem is that you cannot visualy distinguish them and tabs may be displayed differently on different computers and in different code editors: either as 8 or 4 spaces (or any other number of spaces, actually). Besides visual, in some cases they have semantic difference too, like in <a href="https://www.gnu.org/software/make/manual/make.html">Makefile</a> or in <a href="https://www.python.org/">Python</a> code.</p>
<p>A recent <a href="https://medium.com/@hoffa/400-000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd#.h2z315mgw">extensive research</a> should put a stop to it: spaces are far more prevalent in modern programming languages.</p>
<figure>
<img src="https://cdn-images-1.medium.com/max/1680/1*Aaqc9L1Hc62hBg_dpNgBKg.png" width="592" height="389"/> <figcaption>
<p>
<a href="https://medium.com/@hoffa/400-000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd#.h2z315mgw">Tab vs. Spaces (top 400 000 GitHub repos)</a></p>
</figcaption>
</figure>
<p>And take a closer look at Python, in which indentation is crucial for program structure: spaces are used 20 times more frequently. The only language programming language where tabs prevail over spaces is C. Here I would love to see the per year breakdown of newly created files with different indentation styles. Because it might well be the case that recent contributions are using spaces and they may soon take the lead in C language too.</p>
<h4 id="braces">Braces</h4>
<p>Just take a look at this Wikipedia <a href="https://en.wikipedia.org/wiki/Indent_style">article</a> discussing all known brace and indentation styles. Great that all modern programming languages provide style guides and nowdays I see less arguments on where to put a brace. Because what can you object to those, who name their preferred style <strong>1TBS</strong>: One True Brace Style?!</p>
<h4 id="double-and-single-quoted-string">Double and single quoted string</h4>
<p>Ok, done with tabs vs. spaces. What&rsquo;s next? Single or double quotes for strings, of course. There are languages like PHP or JavaScript, which allow both. And some even <a href="http://stackoverflow.com/questions/13620/speed-difference-in-using-inline-strings-vs-concatenation-in-php5">seriously consider performance difference</a> between them! This might sound like bullshit, but many programmers were micro-optimizing their horribly slow and insecure websites by changing how they concatenate strings.</p>
<p>Hopefully, it&rsquo;s not a problem anymore in PHP world, but it is still a real thing in JavaScript. <a href="http://eslint.org">ESLint</a>, a widely used JavaScript linter, has <a href="http://eslint.org/docs/rules/quotes">a rule</a> to force quoting style throughout the codebase. And it is extremely irritating. On the bright side such issues can be fixed automatically by <code>eslint</code>.</p>
<blockquote>
<p>By the way ESLint is a great example of how good idea can be abused by some <a href="http://www.urbandictionary.com/define.php?term=Grammar%20Nazi">Grammar-Nazi</a> style rules, like string quotes one or one forcing proper <a href="http://eslint.org/docs/rules/indent">indentation</a>. And given that it is usually set up to fail CI build in case of <em>any</em> found problem, I feel I sometimes spend more time satisfying <code>eslint</code> than writing any meaningful code.</p>
</blockquote>
<p>The same applies to <a href="https://golang.org/">Go programming language</a>. Its creators even brought it to the next level and made formatter a part of official language tooling. Many open-source projects reject improperly formatted pull requests, so contributors must not forget to execute <code>go fmt</code> before committing.</p>
<h4 id="automation-and-version-control-systems">Automation and version control systems</h4>
<p>When it is all about personal preferences, version control systems might have come to the rescue. <a href="https://git-scm.com/">Git</a> already converts line endings according to the user&rsquo;s OS standard. It has <a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">extensible hooks</a> on push, checkout and commit. If only there was a tool, that can convert formatting back-and-forth between user&rsquo;s preferred style and the style used in the repository; then it could be applied automatically and save billion of hours spent on arguments and reformatting.</p>
<p>A related issue, which is not fully resolved yet, is a semantic diff. Current diff/merge tools are rather dumb and apply changes based on lines of code. This way it is easy to loose a small change in the middle of a method if it was shifted few spaces due to formatting update.</p>
<h4 id="parameters-list-formatting">Parameters list formatting</h4>
<p>Another type of change merge tools usually struggle with is a change in parameters list of a method. Consider following example:</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="kt">void</span> <span class="nf">method</span><span class="o">(</span><span class="kt">int</span> <span class="n">first</span><span class="o">,</span> <span class="n">String</span> <span class="n">second</span><span class="o">,</span> <span class="kt">float</span> <span class="n">third</span><span class="o">)</span> <span class="o">{}</span>
<span class="c1">// New parameter is added in the middle of the line
</span><span class="c1"></span>
<span class="kt">void</span> <span class="nf">method</span><span class="o">(</span><span class="kt">int</span> <span class="n">first</span><span class="o">,</span> <span class="n">String</span> <span class="n">newParam</span><span class="o">,</span> <span class="n">String</span> <span class="n">second</span><span class="o">,</span> <span class="kt">float</span> <span class="n">third</span><span class="o">)</span> <span class="o">{}</span></code></pre></div>
<p>Merge tool will highlight the whole line as changed and it might be hard to spot the difference if there are many parameters. So, the usual solution to this problem (probably invented by those paid per line of code) is to place each parameter on a separate line like this:</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="kt">void</span> <span class="nf">method</span><span class="o">(</span>
<span class="kt">int</span> <span class="n">first</span><span class="o">,</span>
<span class="cm">/* String newParam, ← new parameter inserted here */</span>
<span class="n">String</span> <span class="n">second</span><span class="o">,</span>
<span class="kt">float</span> <span class="n">third</span>
<span class="o">)</span> <span class="o">{}</span></code></pre></div>
<p>Each parameter change will result in line change/insert/deletion, which is easily handled by any diff/merge tool. There is a problem though with the last line, where you put a comma if you&rsquo;d like to add another parameter at the end of the list. A creative solution would be to put a comma always in front of a parameter, but this makes code look so awkward…</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="kt">void</span> <span class="nf">method</span><span class="o">(</span>
<span class="kt">int</span> <span class="n">first</span>
<span class="o">,</span> <span class="n">String</span> <span class="n">second</span>
<span class="o">,</span> <span class="kt">float</span> <span class="n">third</span>
<span class="o">)</span> <span class="o">{}</span></code></pre></div>
<p>WTF?! Please, please never do this.</p>
<blockquote>
<p>There is a tool <a href="https://www.semanticmerge.com/">SemanticMerge</a> which aims to solve this and other merge issues, but I haven&rsquo;t tried it yet.</p>
</blockquote>
<h3 id="conclusion">Conclusion</h3>
<p>I admit that consistent coding style is important for the sustainability of the codebase. Formatting style is an important part of code style, but don&rsquo;t overrate it.</p>
<p>It doesn&rsquo;t worth it to argue a lot on code formatting. If it looks nice—great, but it&rsquo;s far more important that it is correct, maintanable and fast.</p>
<p>Stick to some style across the whole team and just forget it. It is absolutely important to set up automatic code formatting in your IDE of choice. When team IDE preferences vary, <a href="http://editorconfig.org/">EditorConfig</a> may help, it is suppported by all popular code editors.</p>
<p>And let&rsquo;s create better tools that would not force us to apply bad-smelling tricks to our code.</p>
Keeping passwords safehttps://victor.kropp.name/blog/keeping-passwords-safe/
Thu, 09 Mar 2017 21:58:13 +0100https://victor.kropp.name/blog/keeping-passwords-safe/
<p>In Summer 2012 popular professional network Linkedin was <a href="https://en.wikipedia.org/wiki/2012_LinkedIn_hack">hacked</a>, and around 6,5 Mio password were leaked. Though it was just one of <a href="http://www.informationisbeautiful.net/visualizations/worlds-biggest-data-breaches-hacks/">many data breaches</a> in recent years, it urged to me rethink how I protect my private data in many web services I use.</p>
<p>At that time, I&rsquo;ve been using just few strong, unique passwords for most important accounts, like Google or my home bank. While for all other websites I had one pretty simple and short password. Even though primary assets are more or less protected, this is an unacceptable level of digital protection. Just imagine how harmful for your reputation would it be if someone gets access to your accounts on social networks.</p>
<p>I solved a Linkedin issue by just deleting my account there. But for other services, including those that were not yet hacked, I was forced to create new secure and different passwords, because my old universal password was compromised. Given that I needed 30+ new passwords long and random enough I needed software to store and manage them. It doesn&rsquo;t make any sense to remember so many 10 to 20 characters long passwords.</p>
<h4 id="password-managers">Password Managers</h4>
<p>My requirements for password management software were the following:</p>
<ul>
<li>it should be <strong>free and open source</strong>. I want to be able to use it forever and can verify it is correct and doesn&rsquo;t have any backdoors;</li>
<li>it <strong>should not depend on any web service</strong>. I want to decide myself how to synchronize database securely;</li>
<li>it should be <strong>available on all desktop and mobile operating systems</strong>. (Or at least on Linux, Android, and Windows, which I&rsquo;ve been using at that time.)</li>
</ul>
<figure>
<img src="https://victor.kropp.name/blog/img/2017/keepass.png"
alt="KeePass main window on Windows" width="1000"/> <figcaption>
<p>KeePass main window on Windows</p>
</figcaption>
</figure>
<p>I chose <a href="http://keepass.info/">KeePass</a> and its implementations for other operating systems (<a href="https://www.keepassx.org/">KeePassX</a> and <a href="https://play.google.com/store/apps/details?id=com.android.keepass">KeePassDroid</a>). All applications worked well, but were almost unmaintained and I soon stumbled upon some <a href="https://news.ycombinator.com/item?id=9727297">discussions</a> of <a href="http://keepass.info/help/kb/sec_issues.html">possible</a> <a href="http://lifehacker.com/keepass-vulnerability-could-let-attackers-steal-your-pa-1781486764">vulnerabilities</a>. The first thing everybody learns about encryption: do not reinvent the wheel, use well-known and proved algorithms and apply them correctly. I doubt it is the case.</p>
<h4 id="pass"><code>pass</code></h4>
<p>So I started another research and finally found an application that fully satisfied me. It is <code>pass</code> — <a href="https://www.passwordstore.org/">the standard Unix password manager</a>. It follows Unix philosophy: do one thing and do it well. And then combine tools to achieve the goal. Despite the slogan <code>pass</code> is available for all modern operating systems.</p>
<p><code>pass</code> uses <a href="https://www.gnupg.org/">GnuPG</a> to encrypt data and <a href="https://git-scm.com/">git</a> to store and version it. As you may expect it is a command line tool, which is good, because I type faster than can click a mouse. And with completion available for <code>bash</code> and <code>zsh</code> it is even more convenient and fast.</p>
<p>It is possible to encrypt passwords for several GPG keys, either for backup or to share them (or a subdirectory only!)</p>
<p>The only concern in using <code>pass</code> is that it doesn&rsquo;t encrypt password store structure: it is naked set of (encrypted) files. However it isn&rsquo;t a big issue, if you are encrypt your home directory (you should!)</p>
<p>Also it makes sense to sign all changes (call <code>pass git config commit.gpgsign true</code> once to turn it on) to ensure repository integrity and prevent <a href="https://en.wikipedia.org/wiki/Replay_attack">replay attacks</a>.</p>
<h4 id="usage">Usage</h4>
<p>Basic <code>pass</code> commands are easy to remember. To show an entry invoke it without arguments.</p>
<pre><code class="shell nohighlight"><b>$</b> pass my-secret-account
Tieg5Hox7jkas</code></pre>
<p><code>-c</code> key tells <code>pass</code> to copy password to clipboard instead of outputting it in terminal.</p>
<p><code>pass insert</code> creates a new entry, that you can later edit with <code>pass edit</code>, but I prefer using <code>pass generate</code> to have it generate a password for me.</p>
<pre><code class="shell nohighlight"><b>$</b> pass ls dev
dev
├── android
└── plugins.gradle.org</code></pre>
<p><code>pass ls</code>, <code>pass mv</code>, <code>pass cp</code>, <code>pass rm</code> subcommands do exactly what you&rsquo;d expect them to do: list passwords, move/rename individual entries, copy, and delete them respectively. <code>pass find</code> helps to find an entry if you don&rsquo;t remember its exact name or directory where you put it. <code>pass git</code> lets you manipulate storage using familiar git commands. That&rsquo;s it. You can learn more on <a href="https://git.zx2c4.com/password-store/about/">man page</a>.</p>
<p>Pass is powerful but very easy to use tool. I enjoy using it and feel secure and protected.</p>
Software updates: pro et contrahttps://victor.kropp.name/blog/software-updates-pro-et-contra/
Tue, 28 Feb 2017 18:27:05 +0100https://victor.kropp.name/blog/software-updates-pro-et-contra/
<figure>
<img src="https://victor.kropp.name/blog/img/2017/phone-updating.jpg"
alt="Garmin smartwatch downloading new firmware" width="1000"/> <figcaption>
<p>Garmin smartwatch downloading new firmware</p>
</figcaption>
</figure>
<h3 id="pro">Pro</h3>
<p>I love software updates. I always have <strong>latest OS version</strong> on my computer, use <strong>newest releases</strong> of all applications. I use the latest Android version on my smartphone (this was the main reason for choosing Nexus among the wide range of Android phones). I have <strong>up-to-date firmware</strong> on all my sports gadgets (including bike pedals, yay!).</p>
<p>I love updates because they often bring <strong>new exciting features</strong>, improve user experience and simplify my life. Regular maintenance updates keep my computer, phone, and gadgets <strong>secure</strong>. I value privacy a lot, so this is crucial.</p>
<p>I love how modern devices install updates. They find new releases <strong>automatically</strong>, usually download them in the background and require a single click to install them all. No additional actions required. Or even better, many systems have an option to install updates in the background too. All you need is to have good internet connection, and everything else is <strong>magically</strong> done behind the scenes.</p>
<p>Sounds perfect. Heaven on Earth. Well, when it works. When it does not, it is more like hell.</p>
<h3 id="contra">Contra</h3>
<p>I hate software updates. With new features they also bring <strong>bugs</strong>. Sometimes added features are irrelevant to me, but bugs <strong>break functionality</strong> I use often and which has been working flawlessly since years.</p>
<blockquote>
<p>My sports watch has skiing mode in which it can automatically detect ski and lift rides. I&rsquo;ve been using it happily previous years, but when I first time went to the mountains this year, the watch started to reboot every time I took a lift. Soon after many upset watch owners reported the bug (me too), they fixed the bug. But that skiing day was lost.</p>
</blockquote>
<p>I hate software updates because sometimes they are postponed or don&rsquo;t come at all even when promised. This is frustrating. You <strong>wait for a fix</strong> and never get it. Blah!</p>
<blockquote>
<p>It is usual in the Android universe, that manufacturers release new firmware months or even a year later after the announcement. But sometimes Google delay Nexus updates too: compared to other Nexus phones, my Nexus 6 got Android 7.0 almost two months later.</p>
</blockquote>
<p>I hate software updates that arrive in the most <strong>inconvenient</strong> time. Or require a reboot when you are focused on your work (yes, Windows, I&rsquo;m talking about you).</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Preparing for evening bike ride:<br><br>Update bike computer firmware ✔<br>Update left pedal firmware ✔<br>Update right pedal firmware ✔<br>Restart ✔<br>…Ride</p>&mdash; Victor Kropp (@kropp) <a href="https://twitter.com/kropp/status/769093655776886784?ref_src=twsrc%5Etfw">August 26, 2016</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote>
<p>It took me around twenty minutes before the ride to update all the gadgets, even though I had manually initiated a check for updates the day before and there were none.</p>
</blockquote>
<p>I hate software updates because one <strong>can&rsquo;t simply install</strong> them all at once. How often does it happen to you, when you install a bunch of updates, and new update arrives shortly after?</p>
<blockquote>
<p>Have you ever tried to update Windows on a computer you haven&rsquo;t touched several years? It is impossible to update to Windows 10 directly from Windows 8. First you need to install all updates, then Windows 8.1 through Windows Store, another set of critical updates, Windows 10 using special tool and another bunch of fixes. I can&rsquo;t estimate how much time I have spent on it.</p>
</blockquote>
<p>Updated your laptop? Don&rsquo;t forget other computers in your household.</p>
<p>Updated operating system? Don&rsquo;t forget to reboot.</p>
<p>Updated your favorite tool? Don&rsquo;t forget to update its plugins.</p>
<p>Updated mapping software? Don&rsquo;t forget to download new maps.</p>
<p>And because of all this, many people say if it works, don&rsquo;t touch it and resist updating.</p>
<h3 id="so-what">So what?</h3>
<p>I love and hate software updates. Only one thing can be even worse than updating. It is to support users with an outdated version of your software. But aren&rsquo;t we, software developers, <strong>guilty of this</strong>?</p>
Makefile support plugin for IntelliJ IDEAhttps://victor.kropp.name/blog/makefile-plugin/
Mon, 06 Feb 2017 11:40:50 +0100https://victor.kropp.name/blog/makefile-plugin/
<p>I&rsquo;m excited to announce my first ever plugin for IntelliJ IDEA and other IntelliJ platform based IDEs: <a href="https://victor.kropp.name/projects/makefile/">Makefile support</a>.</p>
<p>I&rsquo;ve been developing it since few months, and now it has reached Beta status and is ready for preview. It can be installed from <a href="https://plugins.jetbrains.com/idea/plugin/9333-makefile-support">official plugin repository</a>; the source code is on <i class="fa fa-github" style="color: rgb(23,21,21)"></i> <a href="https://github.com/kropp/intellij-makefile">GitHub</a> (where else?)</p>
<p><em>Disclaimer: I&rsquo;ve been working at JetBrains since many years, but have never contributed to IntelliJ before. This is my pet project, I have developed it following official documentation, investigating source code, searching forums, but I haven&rsquo;t received any direct support from IntelliJ team.</em></p>
<p>My overall impression of the platform and APIs is great. Sometimes it is verbose or unclear, but given the huge experience of IntelliJ developers in supporting hundreds of very different programming languages, I trust them that some verbosity is inevitable.</p>
<h4 id="the-plugin">The plugin</h4>
<p>There are several reasons, why have I developed this plugin. Firstly, I use Makefiles for automation and want to see syntax highlighting in the IDE and be able to run tasks right from there. Secondly, I&rsquo;ve never written a plugin for my favorite IDE before and the last time I wrote a parser was somewhat ten years ago at the University. So, I took a chance to make something useful and usable, refresh some skills and to have fun at the same time.</p>
<figure>
<img src="https://victor.kropp.name/projects/makefile/makefile-example.png"
alt="Syntax highlighting and run actions provided by plugin. Makefile from Hugo static site generator." width="900" height="540"/> <figcaption>
<p>Syntax highlighting and run actions provided by plugin. Makefile from Hugo static site generator.</p>
</figcaption>
</figure>
<p>So well, what does the plugin do? It supports:</p>
<ul>
<li>syntax highlighting for <a href="https://www.gnu.org/software/make/manual/make.html">GNU Makefile</a></li>
<li>rule and multiline variables folding</li>
<li>prerequisites completion (filenames and other targets)</li>
<li>quick fix to create new rule from unresolved prerequisite</li>
<li>run configurations to execute any target in any Makefile</li>
<li>context action and gutter mark icon to run target</li>
</ul>
<p>Pretty much everything you need to start editing and using Makefiles in your project. Plugin is stable and fast.</p>
<p>Even before the announcement, I received a lot of feedback from users. Thanks to everyone who submitted bugs on GitHub for making the plugin better.</p>
<p>If you have any feedback or suggestions, feel free to comment here, file a bug on GitHub or submit a pull request.</p>
Best practices in API designhttps://victor.kropp.name/blog/best-practices-in-api-design/
Tue, 24 Jan 2017 17:12:10 +0100https://victor.kropp.name/blog/best-practices-in-api-design/
<p>Recently I faced some issues with <a href="http://doc.qt.io/qt-5/qurlquery.html"><code>QUrlQuery</code></a> class from <a href="http://qt.io/">Qt Framework</a> which I would like to discuss.</p>
<p>The sole purpose of this class is to provide abstraction over query string part of URL. It converts an array of key-value pairs to a percent-encoded string as required by the standard.</p>
<p>The typical usage example is:</p>
<div class="highlight"><pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="n">QUrlQuery</span> <span class="n">query</span><span class="p">;</span>
<span class="n">query</span><span class="p">.</span><span class="n">addQueryItem</span><span class="p">(</span><span class="s">&#34;firstname&#34;</span><span class="p">,</span> <span class="s">&#34;Victor&#34;</span><span class="p">);</span>
<span class="n">query</span><span class="p">.</span><span class="n">addQueryItem</span><span class="p">(</span><span class="s">&#34;lastname&#34;</span><span class="p">,</span> <span class="s">&#34;Kropp&#34;</span><span class="p">);</span>
<span class="err">…</span>
<span class="n">query</span><span class="p">.</span><span class="n">toString</span><span class="p">(</span><span class="n">QUrl</span><span class="o">::</span><span class="n">FullyEncoded</span><span class="p">);</span>
</code></pre></div>
<p>And the resulting string would be:</p>
<div class="highlight"><pre class="chroma"><code class="language-http" data-lang="http"><span class="err">firstname=Victor&amp;lastname=Kropp</span></code></pre></div>
<p>What can possibly go wrong here?</p>
<h3 id="design-api-for-the-real-world-not-for-specifications">Design API for the real world, not for specifications</h3>
<p>I like specifications. They help a lot if you want to know every detail of a particular system, library or protocol. However, actual implementations often differ from specifications. Sometimes these differences become standards <em>de facto</em>.</p>
<p>For example, spaces in query strings are encoded with <code>+</code> signs. And <code>+</code> itself is encoded with <code>%2B</code> (which is its hexadecimal ASCII value obviously). Every browser and every web server do this. But it was not required by <a href="https://tools.ietf.org/html/rfc1738"><strong>RFC 1738</strong> Uniform Resource Locators (URL)</a>! This RFC is dated back to December 1994—the very early days of the World Wide Web.</p>
<p>A lot has changed since then, and the newer <a href="https://tools.ietf.org/html/rfc3986"><strong>RFC 3986</strong> Uniform Resource Identifier (URI): Generic Syntax</a> was released in January 2005. Apparently, This RFC reflected how all implementations interpreted the specification. <code>+</code> sign was added to the list of reserved characters that must be percent-encoded (section 2.2).</p>
<p><code>QUrlQuery</code> still doesn&rsquo;t encode <code>+</code> even in the latest version. To say I was surprised is to say nothing. And it isn&rsquo;t a bug; it&rsquo;s a feature. This peculiarity even has its own section in <a href="http://doc.qt.io/qt-5/qurlquery.html#handling-of-spaces-and-plus">documentation</a>. Should I have read it? Probably. But do you read <em>all</em> documentation, especially in such obvious cases?</p>
<p>A good solution would be to add an option to enforce the old or the new standard.</p>
<p>Here comes the first rule in designing APIs for people: API should reflect the real world, not a specification.</p>
<h3 id="explicit-is-better-than-implicit">Explicit is better than implicit</h3>
<p>Let&rsquo;s continue our journey with <code>QUrlQuery</code>. The case of <code>+</code> is solved, now it is time to find out what happens if query parameter contains <code>%</code> sign. As with many programming questions, the correct answer is: &ldquo;It depends.&rdquo;</p>
<p>Not the answer you want to hear? Sorry. Let&rsquo;s investigate what happens here. In the following snippent, I provide two strings (<code>%ab</code> and <code>%xy</code>) to <code>QUrlQuery</code> and check the result.</p>
<div class="highlight"><pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="n">query</span><span class="p">.</span><span class="n">addQueryItem</span><span class="p">(</span><span class="s">&#34;encoded&#34;</span><span class="p">,</span> <span class="s">&#34;%abc&amp;&#34;</span><span class="p">);</span>
<span class="n">query</span><span class="p">.</span><span class="n">addQueryItem</span><span class="p">(</span><span class="s">&#34;plain&#34;</span><span class="p">,</span> <span class="s">&#34;%xyz&amp;&#34;</span><span class="p">);</span>
</code></pre></div><div class="highlight"><pre class="chroma"><code class="language-http" data-lang="http"><span class="err">encoded=%ABc%26&amp;plain=%25xyz%26</span></code></pre></div>
<p>Surprised? Me too. And again, public API is not the best place for surprises. Well, what has happened here?</p>
<ul>
<li>String <code>%ab</code> was treated as encoded and was outputted unaltered.</li>
<li><code>%</code> in string <code>%xy</code> was encoded, because it didn&rsquo;t represent a hexadecimal number.</li>
</ul>
<p>It is great that <code>addQueryItem</code> can handle both types of arguments. What is disappointing here, is the lack of control. I&rsquo;d prefer to have two methods or a method with a parameter. This way I, as a user of the library, can decide how it should to interpret each particular string.</p>
<p>The second rule of designing APIs is: explicit is better than implicit.</p>
<h3 id="legacy-api">Legacy API</h3>
<p>Somebody may argue that these rules are inapplicable to old libraries, that must remain backward compatible. A good solution would be to add interfaces, implementations, new methods or overloaded methods. New entities could then provide updated behavior while original ones remain for compatibility. To keep the public API surface clean and tidy old variants may be marked as deprecated and eventually removed.</p>
<p>I appreciate the work of Qt Framework developers and maintainers. Keeping such a big and famous library up and running is a demanding task. They are doing a great job! But there is always room to improve.</p>
DSLs in Kotlin: The Good, the Bad and the Uglyhttps://victor.kropp.name/blog/kotlin-dsls-good-bad-and-ugly/
Wed, 11 Jan 2017 15:10:18 +0100https://victor.kropp.name/blog/kotlin-dsls-good-bad-and-ugly/
<p><a href="https://en.wikipedia.org/wiki/Domain-specific_language"><abbr title="Domain-specific Language">DSLs</abbr></a> are a very hot topic among Kotlin developers. No surprise, language designers take it seriously and are adding <a href="https://github.com/Kotlin/KEEP/blob/master/proposals/scope-control-for-implicit-receivers.md">specific features directly into the language</a> to improve DSL behavior. In this post, I&rsquo;d like to share and discuss 3 examples of DSLs written in Kotlin.</p>
<figure>
<img src="https://victor.kropp.name/blog/img/2017/the-good-the-bad-and-the-ugly.jpg"
alt="The Good, the Bad and the Ugly (1966)" width="1000"/> <figcaption>
<p>The Good, the Bad and the Ugly (1966)</p>
</figcaption>
</figure>
<h3 id="the-good">The Good</h3>
<p><a href="https://github.com/Kotlin/anko">Anko</a> is a great DSL for building Android views. Here is an example from official documentation:</p>
<pre><code class="kotlin">verticalLayout {
val name = editText()
button("Say Hello") {
onClick { toast("Hello, ${name.text}!") }
}
}
</code></pre>
<p>Anko uses Kotlin&rsquo;s builder functions not only to create nested views but also to add listeners. Still, it is absolutely clear in both cases what is meant to be here. This language is extensible and covers all use cases.</p>
<p><a href="https://github.com/Kotlin/kotlinx.html">kotlinx.html</a> is very similar language to build HTML. It would be the perfect example as well if only it doesn&rsquo;t use <code>+</code> operator to append raw text. Why? I&rsquo;ll explain it in the next section.</p>
<h3 id="the-bad">The Bad</h3>
<p>Here is the whole DSL in just one line of code:
<pre><code class="kotlin">operator fun String.div(path: String) = this + &ldquo;/&rdquo; + path
val logFile = home / &ldquo;logs&rdquo; / &ldquo;log.txt&rdquo;</code></pre></p>
<p>It allows using <code>/</code> operator on strings for file system path concatenation. I&rsquo;ve seen it many times before (for example, in C# and C++ where operator overloading is possible too).</p>
<p>On the first sight, it looks like a smart and clever idea. However you soon discover its limits:</p>
<ul>
<li>you cannot start path with <code>/</code> (there is no unary division). You should either start with an empty string or put root slash into first path component.</li>
<li>on Windows path components separated by backslashes (<code>\</code>) and there is a notion of &ldquo;disks&rdquo; which are denoted by a colon (<code>:</code>). You cannot extend this DSL to support this options and need to find other solutions.</li>
<li>you cannot extend this DSLs to manage file extensions, because <code>.</code> (dot) operator has very different meaning in Kotlin</li>
<li>it is confusing. This operator may become available in different contexts, where it is not applicable or should behave differently. For example, if there are numbers stored in strings, somebody can think that this operator implements mathematical division of such numbers.</li>
</ul>
<p>Don&rsquo;t abuse operator overloading, it is usually unclear and can lead to unpredictable errors. Still not convinced? Read further.</p>
<h3 id="the-ugly">The Ugly</h3>
<script type="application/javascript" src="//gist.github.com/naixx/9d94c1498c4d45ffda3a.js"></script>
<p>Just don&rsquo;t do this. Never.</p>
<p>It is a very quirky way to add missing ternary operator. Reasons, why it is not implemented in Kotlin, are explained in the <a href="https://kotlinlang.org/docs/reference/control-flow.html">documentation</a>. One of them is the lack of extensibility, nested ternary operators look ugly and it might be very difficult to find out what&rsquo;s going on there. Use <code>when</code> instead.</p>
<p>This DSL does not resolve the aforementioned problem but adds another one: without looking in the source code, it is absolutely unclear what does these <code>%</code> and <code>/</code> symbols mean in this context. I bet, even the author of this snippet will forget their meaning in a year.</p>
<p>If only it was not enough already, this particular code adds an object instantiation on every call, which may lead to performance problems if it is on a critical path.</p>
<p>So let me repeat it once again: <strong>don&rsquo;t do this</strong>.</p>
<h3 id="conclusion">Conclusion</h3>
<p>Kotlin is very flexible general purpose language. It offers great extensibility and power of type-safe builders and extension functions to library creators. Please, don&rsquo;t abuse it. With great power comes great responsibility.</p>
<p>Do you know other DSLs written in Kotlin? Share and discuss in comments!</p>
Videos to watch on holidayshttps://victor.kropp.name/blog/videos-to-watch-2016/
Sat, 24 Dec 2016 18:39:58 +0100https://victor.kropp.name/blog/videos-to-watch-2016/
<p>The festive season has begun. This is the most wonderful time of the year! But it is cold and gray in the Northern Hemisphere now and many people will spend forthcoming holidays on a sofa in the living room. What will you be doing? Instead of watching yet another TV series or Christmas movie, I&rsquo;d like to suggest you choosing something different this time.</p>
<p>For example, there is a huge collection of great educational videos from <a href="https://www.ted.com/">TED</a> conferences. They are usually short, but always very inspiring. To start with, check <a href="https://www.ted.com/playlists/171/the_most_popular_talks_of_all">25 most popular talks</a> or try these, which are my favorites:</p>
<ul>
<li><a href="https://www.ted.com/talks/amy_cuddy_your_body_language_shapes_who_you_are">Your body language shapes who you are</a> by Amy Cuddy</li>
<li><a href="https://www.ted.com/talks/michael_shellenberger_how_fear_of_nuclear_power_is_hurting_the_environment">How fear of nuclear power is hurting the environment</a> by Michael Shellenberger</li>
<li><a href="https://www.ted.com/talks/nilofer_merchant_got_a_meeting_take_a_walk">Got a meeting? Take a walk</a> by Nilofer Merchant</li>
</ul>
<p>If you are into programming, you can&rsquo;t miss this famous talk by <a href="http://worrydream.com/">Bret Victor</a>:
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe src="//www.youtube.com/embed/PUv66718DII" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>
</p>
<p>Check out his other talks too.</p>
<p>Many big software development conferences publish videos, including <a href="https://www.youtube.com/channel/UCCBVCTuk6uJrN3iFV_3vurg">Devoxx</a>, <a href="https://www.youtube.com/user/GotoConferences">GoTo</a>, <a href="https://www.youtube.com/channel/UCTdw38Cw6jcm0atBPA39a0Q">NDC</a> and many others. If you don&rsquo;t know where to start, look for prominent speakers, like <a href="http://www.agiledeveloper.com/">Venkat Subramaniam</a>, <a href="http://curbralan.com/">Kevlin Henney</a> or my JetBrains colleagues <a href="http://hadihariri.com/">Hadi Hariri</a> and <a href="https://trishagee.github.io/">Trisha Gee</a>. Choose any of their talks and you wouldn&rsquo;t be disappointed.</p>
<p>Also try searching YouTube on a topic you&rsquo;re interested in, and you&rsquo;ll find lots of interesting content there. It is also a great opportunity to learn something new: watch some introductory video and decide whether you need to learn that technology or framework deeper.</p>
<p>Speaking of education, you can replace weekly TV series with online courses. Free courses are available on many platforms, including <a href="https://www.coursera.org/">Coursera</a>, <a href="https://www.udacity.com/">Udacity</a>, and <a href="https://www.edx.org/">edX</a>. I recently attended courses about <a href="https://www.coursera.org/learn/machine-learning">Machine Learning</a> and <a href="https://www.coursera.org/learn/crypto/">Cryptography</a> there and can definitely recommend these. Udacity offers many courses in collaboration with leading vendors. For example, there is <a href="https://www.udacity.com/course/android-basics-nanodegree-by-google--nd803">Android Basics</a> course co-created by Google. And on edX I&rsquo;ve seen good language courses.</p>
<p>There is one more thing I&rsquo;d like to share:</p>
<blockquote>
<h4 id="if-you-want-something-you-ve-never-had-then-you-ve-got-to-do-something-you-ve-never-done">If you want something you&rsquo;ve never had, then you&rsquo;ve got to do something you&rsquo;ve never done.</h4>
</blockquote>
<p>I cannot agree more. If you do New Year Resolutions take this one.</p>
<p>Merry Christmas and Happy New Year! See you in 2017.</p>
Encrypted USB stickhttps://victor.kropp.name/blog/encrypted-usb-stick/
Mon, 12 Dec 2016 14:54:10 +0100https://victor.kropp.name/blog/encrypted-usb-stick/<p>I sometimes need access to different private documents. I want them to be always easily accessible. At the moment they are stored in the cloud. However, I can never be sure that when I need them I&rsquo;ll be able to go online. On the other hand, I can&rsquo;t store them on any memory stick because I don&rsquo;t want to expose sensitive information if I loose the medium.</p>
<p>I&rsquo;ve recently got a small 8GB USB stick, which I decided to turn into multipurpose solution: it should be at the same time unencrypted drive accessible from every OS, bootable (I put live Ubuntu distribution on it) and has a secure encrypted partition. Here&rsquo;s how I achieved that.</p>
<p>Like any other storage, USB stick may be partitioned into several parts. Luckily, Windows detects only the first one, so it will be universally accessible FAT32 partition. So, if I lose the drive, chances are high nobody even notices there is anything else.</p>
<figure><img src="https://victor.kropp.name/blog/img/2016/gnome-disks.png" width="873" /></figure>
<p>USB stick can be partitioned in any utility of choice, like <code>parted</code> or <a href="http://unix.stackexchange.com/questions/30322/how-do-i-partition-a-usb-drive-so-that-its-bootable-and-has-a-windows-compatibl"><code>fdisk</code></a>. I&rsquo;ve used GUI-based Disks (<code>gnome-disks</code>). I&rsquo;ve created 3 partitions:</p>
<ul>
<li>2 GB FAT32 partition, unencrypted and visible everywhere</li>
<li>2 GB ext4 for Ubuntu Live installation</li>
<li>4 GB LUKS+ext4 encrypted partition (if you prefer command line approach, here is the excellent <a href="https://help.ubuntu.com/community/EncryptedFilesystemsOnRemovableStorage">guide on creating encrypted partition</a>)</li>
</ul>
<figure><img src="https://victor.kropp.name/blog/img/2016/usb-creator-gtk.png" width="764" /></figure>
<p>Creating data partitions is pretty straight-forward. But default Ubuntu Startup Disk Creator (<code>usb-creator-gtk</code>) utility can&rsquo;t put live install in a partition and erases the whole disk instead. The solution is to do it manually, it is really easy:</p>
<pre class="shell"><code><b>$</b> sudo dd bs=4M if=~/Downloads/ubuntu-16.10-desktop-amd64.iso of=/dev/sdb2 && sync</code></pre>
<p>So far so good, I tested newly prepared USB stick on several computers and OS and it works great. Apart from a small problem with file ownership on encrypted partition: all files will be created there with your UID (to find it out type <code>id</code> in terminal). But on a different computer, your UID may be different. This is, for example, the case with Ubuntu Live distribution where default user has UID 999, while on a real Ubuntu installation first user usually has UID 1000. To access files you then need first to change their ownership with <code>chown username * -R</code></p>
No prefix, please!https://victor.kropp.name/blog/no-prefix-please/
Mon, 05 Dec 2016 09:49:05 +0100https://victor.kropp.name/blog/no-prefix-please/<p>For many years developers have been adding prefixes to instance fields: <code>my</code>, <code>m</code>, <code>_</code> and whatever else. I’ve seen many coding style guides requiring one of these prefixes. But nowadays it looks like a rudiment of a previous century.</p>
<p>Like ill-famed <a href="https://en.wikipedia.org/wiki/Hungarian_notation">Hungarian notation</a> they are used to give programmer a hint on some properties of entity. With powerful IDEs, it is not necessary anymore. You can have much more powerful hints and easily navigate code to discover much more.</p>
<p>Modern software development practices almost eliminate situations, where the confusion between instance fields and methods parameters can arise. If your objects are immutable, then you don’t have setters and only deal with parameters in the constructor. Here C++ has a nice syntax for fields initializers:</p>
<pre><code class="cpp">class Point {
private:
const int x, y;
public:
Point(int x, int y) : x(x), y(y) {}
};
</code></pre>
<p><del>Note also, that you can declare methods with the same as fields. And again there is no confusion!</del> No, actually, you can&rsquo;t.</p>
<p><a href="https://kotlinlang.org/">Kotlin</a> went further and completely eliminated getters and setters and merged them with fields and constructor parameters into a single entity.</p>
<pre><code class="kotlin">class Point(public val x: Int, public val y: Int)</code></pre>
<p>Similarly, properties are implemented in Objective-C. And in C# many people prefer properties to fields because in most cases one can leave them auto-implemented while retaining an ability to assign getter and setter different access rights.</p>
<p>So the last case where confusion may arise is a method that has a parameter with the same name as a field, but it is neither a setter nor the constructor or there is similarly named variable. This sounds suspicious. Probably some fields or variables must be renamed to better reflect their purpose.</p>
<p>And there is one more aid in this situation: <a href="https://medium.com/@evnbr/coding-in-color-3a6db2743a1e#.37hfeyrw4">color coding</a>. I&rsquo;ve been using it for quite some time already in <a href="https://www.youtube.com/watch?v=8WRH59PQ5Dk">IntelliJ IDEA 2016.3</a> and am absolutely impressed. I used to use highlight usages on a variable to see data flow in a method. Now it is immediately visible at a glance. And you&rsquo;ll never mix up different variables anymore.</p>
<p>Don’t add prefixes to fields names! They are unnecessary.</p>
BuildStuff 2016 Reporthttps://victor.kropp.name/blog/build-stuff-2016/
Wed, 23 Nov 2016 15:08:49 +0100https://victor.kropp.name/blog/build-stuff-2016/
<p>Last week I attended <a href="http://buildstuff.lt/">BuildStuff</a> conference in Vilnius. I was there to work (to chat with our users mostly) at the JetBrains booth, but I also had a chance to listen to many talks during all three conference days. Here is my report.</p>
<h3 id="day-1">Day 1</h3>
<h4 id="new-adventures-in-responsive-design-by-vitaly-friedman-https-twitter-com-smashingmag">New Adventures in Responsive design <em>by</em> <a href="https://twitter.com/smashingmag">Vitaly Friedman</a></h4>
<p>Vitaly is chief editor of well known <a href="https://smashingmagazine.com/">Smashing Magazine</a>. I couldn&rsquo;t miss a chance to see him live. He was talking about evolution in responsive design, building blocks and tools, showing parallels to teletext development few decades ago. In the second part of this talk he explained how one can be built statically generated, but dynamic web site with API services or generated JSON files and <a href="https://developer.mozilla.org/en/docs/Web/API/Service_Worker_API">Service Workers</a>. I chose similar approach for my personal web site.</p>
<h4 id="metrics-driven-development-by-sam-elamin-https-twitter-com-samelamin">Metrics Driven Development <em>by</em> <a href="https://twitter.com/Samelamin">Sam Elamin</a></h4>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe src="//www.youtube.com/embed/re9AE4r27Ng" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>
<p>To understand what your application is doing you need to measure it: on business level (number of requests served, purchases done, etc.) and application level (these are mainly performance timers). Choose core metric — the most important one and don&rsquo;t measure everything. Follow the money to choose what to measure.</p>
<p>There was also an interesting idea to DDOS your own application in order to prove it can handle future load. For example, put the application under constant load of 50% additional fake requests and when your real load increases, you can turn off these fake requests and serve real ones safely.</p>
<h3 id="day-2">Day 2</h3>
<h4 id="how-shit-works-the-cpu-by-tomer-gabel-https-twitter-com-tomerg">How shit works: the CPU <em>by</em> <a href="https://twitter.com/tomerg">Tomer Gabel</a></h4>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe src="//www.youtube.com/embed/rPBjjI60c7w" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>
<p>Tomer talked about basic things every developer should know, even if he/she work with higher level programing languages. 30 year old processor is already very complex, but CPUs didn&rsquo;t change fundamentally since then. He showed that RAM access is slow (like 30× time to access registers).
If you are working on performance critical parts of application, you should be aware of branch (mis)prediction and develop cache-friendly algorithms. There is one popular technique, <strong>tiling</strong>: split workload into blocks to limit number of hot cache lines.</p>
<h4 id="work-on-wrong-things-first-by-amye-scavarda">Work on wrong things first <em>by</em> Amye Scavarda</h4>
<p>This talk was a flop. Reading text on slides is not how one does a good talk. (<a href="https://www.youtube.com/watch?v=-9VflSaXUIo">Video</a>)</p>
<h4 id="lean-requirements-by-bill-cronin-https-twitter-com-agilebandit">Lean requirements <em>by</em> <a href="https://twitter.com/AgileBandit">Bill Cronin</a></h4>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe src="//www.youtube.com/embed/dl3jAJgPbgk" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>
<p>Bill showed interesting numbers on failed projects and wasted budgets and provided some examples, like Myspace (which was once a most popular social network in the world) or Kodak, who invented digital photography, but didn&rsquo;t embrace new technology because of fear it destroy their current business.
There are 3 major reasons projects fail:
1. Lack of executive support
2. No end user involvement
3. Unclear requirements</p>
<p>In order to succeed team should achieve shared understanding of their goal.</p>
<h4 id="secret-sauce-of-successful-teams-by-sven-peters-https-twitter-com-svenpet">Secret sauce of successful teams <em>by</em> <a href="https://twitter.com/svenpet">Sven Peters</a></h4>
<p>Sven was talking about good practices in building successful teams and shared lots of examples how they achieve this in Atlassian. Here are they:</p>
<ul>
<li>Successful teams are built of successful persons. Rockstars are great, but it&rsquo;s a team who builds project.</li>
<li>High performance teams speak to each other, listen to each other, respect each other. Make team a safe place.</li>
<li>They share the same mindset, follow the same line and have the same vision.</li>
<li>How do you measure success? Stretch goals, quarterly, transparent.</li>
<li>Cross-functional teams.</li>
<li>Conference video Fridays—watch and discuss together some relevant recent talk.</li>
<li>Team is made of individuals, give kudos to each other</li>
<li>Intranet should be open by default</li>
<li>How healthy is the team?</li>
<li>Be the change you seek</li>
</ul>
<p>He also recommended a book to read on this topic: <a href="https://www.amazon.de/Creativity-Inc-Overcoming-Unseen-Inspiration/dp/0593070097/ref=tmm_hrd_swatch_0?_encoding=UTF8&amp;qid=1479814692&amp;sr=8-1">Creativity Inc.</a></p>
<h3 id="day-3">Day 3</h3>
<h4 id="understanding-and-building-your-own-docker-by-motiejus-jakštys-https-twitter-com-mo-kelione">Understanding and building your own Docker <em>by</em> <a href="https://twitter.com/mo_kelione">Motiejus Jakštys</a></h4>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe src="//www.youtube.com/embed/vYZKxVkUMvQ" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>
<p>Motiejus did an awesome talk on building your own Docker in 20 lines of Bash. However, the devil is in the details, so he warned not to use it in production, because there are tons of issues, you should be aware of.</p>
<p>So, basic building blocks are:</p>
<ol>
<li><code>fork</code>/<code>exec</code></li>
<li>Copy-on-write filesystem, like <code>zfs</code>, <code>btrfs</code> or <code>lvm</code> (for effective container images)</li>
<li><code>cgroups</code> for fairness</li>
<li>Namespaces for isolation
<ul>
<li><code>unshare --map-root-user</code> → pretend to be root</li>
<li><code>unshare --mount</code> → isolate mounts</li>
<li><code>unshare --pid --mount-proc --fork</code> → isolate processes</li>
<li><code>ip netns add t1</code> → adds network namespace t1</li>
</ul></li>
</ol>
<p>Here are <a href="https://github.com/Motiejus/buildstuff2016">the materials for Motiejus&rsquo; talk</a> if you&rsquo;re interested in more details.</p>
<h4 id="modern-linux-tracing-landscape-by-sasha-goldshtein-https-twitter-com-goldstn">Modern Linux Tracing Landscape <em>by</em> <a href="https://twitter.com/goldstn">Sasha Goldshtein</a></h4>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe src="//www.youtube.com/embed/-09mptUISV0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>
<p>During his talk Sasha listed so many usefull commands, tools and extension points, that I need some more time to review them all. Firstly, there are tracepoints (<code>/sys/kernel/debug/tracing/available_events</code>) There are also tracepoints in VMs for higher level languages. This is employed by <code>ftrace</code> reads events from <code>debugfs</code> file, not really suitable for a huge number of events.
Secondly, there are <code>kprobes</code> and <code>uprobes</code> for kernel and user code. They are used by <code>BPF</code> — emering kernel tracing technology. BCC (BPF Compiler Collection) simplifies using it.</p>
<p>Very useful talk, here are the <a href="https://s.sashag.net/buildstuff1">slides</a>. You find lots of links there.</p>
<h4 id="how-do-you-know-when-your-product-is-ready-to-be-shipped-by-yegor-bugayenko-https-twitter-com-yegor256">How Do You Know When Your Product is Ready to be Shipped? <em>by</em> <a href="https://twitter.com/yegor256">Yegor Bugayenko</a></h4>
<p>Actually, the talk was renamed to &ldquo;Test Exit Criteria&rdquo;, but I haven&rsquo;t heard exact criteria suggested. And there were also some points I strongly disagree, like &ldquo;Developers and QA should be in (productive) conflict&rdquo;. However, Yegor has speaking talent and it was interesting to listen to him. (<a href="https://www.youtube.com/watch?v=zhNGxemnCIU">Video</a>)</p>
<h4 id="functional-c-by-kevlin-henney-https-twitter-com-kevlinhenney">Functional C++ <em>by</em> <a href="https://twitter.com/KevlinHenney">Kevlin Henney</a></h4>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe src="//www.youtube.com/embed/CIg6eyJv4dk" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>
<p>I did only few notes during this talk, because it was so interesting and packed, that I almost had no time. Kevlin is an excellent speaker and I definetely recommend to watch this talk when recording is available. Some key takeaways are:</p>
<ul>
<li><p>Functional approach provides benefits in any language</p></li>
<li><p>Cast is ugly thing, so it should look ugly</p></li>
<li><p>Mutex should have been called bottleneck (I put a bottleneck in this code)</p></li>
</ul>
<p>And, surprisingly, I even learned a new russian word (остранение) during the talk!</p>
<h3 id="conclusion">Conclusion</h3>
<p>The conference overall was great organized, there were many entertaining things around: VR &amp; Old Games rooms, I enjoyed both. I would love to come back next year!</p>
<p>P. S. One very important note about this conference:</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Love the fact that <a href="https://twitter.com/gregyoung?ref_src=twsrc%5Etfw">@gregyoung</a> and <a href="https://twitter.com/NeringaYoung?ref_src=twsrc%5Etfw">@NeringaYoung</a> run <a href="https://twitter.com/BuildStuffLT?ref_src=twsrc%5Etfw">@BuildStuffLT</a> stuff as a non-profit, donating money to charity to help children. Kudos.</p>&mdash; Hadi Hariri (@hhariri) <a href="https://twitter.com/hhariri/status/798784908353097728?ref_src=twsrc%5Etfw">November 16, 2016</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Dell XPS 15https://victor.kropp.name/blog/dell-xps-15/
Sun, 06 Nov 2016 17:59:00 +0200https://victor.kropp.name/blog/dell-xps-15/<p>I&rsquo;ve been on a hunt for a decent laptop for developer for quite some time. I&rsquo;ve even tried a MacBook for a few weeks, but wasn&rsquo;t impressed at all. It could never convince me that it has enough advantages over Windows and, primarily, Linux to adjust high price tag.</p>
<p>Finally, I&rsquo;ve found the ideal solution for me: <a href="http://www.dell.com/en-us/shop/productdetails/xps-15-9550-laptop">Dell XPS 15</a>. I&rsquo;ve been using it for quite some time already and totally happy with it.</p>
<figure><img src="https://victor.kropp.name/blog/img/2016/dell-xps-15-ubuntu.jpg" width="1000" /></figure>
<p>First, let&rsquo;s check specs. It is powered by <a href="http://ark.intel.com/products/88967/Intel-Core-i7-6700HQ-Processor-6M-Cache-up-to-3_50-GHz">Intel Core i7-6700HQ</a>, one of the most performant mobile CPUs in Skylake lineup. It is not yet clear what exact unit is used in new MacBooks, probably the same. My configuration features 16 GB DDR4 memory, which is exapandable to 32 GB (and probably to 64 GB, when such 32 GB units will be available). This is a clear advantage for me. Lack of RAM was biggest struggle with my previous laptop. Unfortunately, we are living in the age when some team communication software can eat up to several gigs of memory…</p>
<p>For storage it has high-speed 512 GB <a href="https://en.wikipedia.org/wiki/M.2">m.2</a> <a href="https://en.wikipedia.org/wiki/NVM_Express">NVMe</a> SSD, which is replaceable as well, however I don&rsquo;t need to expand it yet. I&rsquo;d only warn everybody not to buy configurations with additional HDD, cause it shrinks the battery significantly. HDDs will pass away soon, like CDs and floppy disks already are.</p>
<p>XPS also has dedicated <a href="http://www.geforce.com/hardware/notebook-gpus/geforce-gtx-960m">NVIDIA GeForce GTX 960M</a> video card in addition to integrated Intel HD530. It&rsquo;s a nice bonus if you&rsquo;d like to play some video games on Friday night.</p>
<p>And the hightlight is, of course, the gorgeous edge-to-edge 4K screen. There are only few millimeters bezels around it, fitting 15&rdquo; display into 14&rdquo; chassis. And MacBook Pro Retina owners will definetly confirm, that once you used to use high resolution display, you can not go back.</p>
<p>New MacBook Pro might be a laptop of tomorrow with its 4 USB-C ports, but this one is more of a laptop of today: it has just one USB-C (Thunderbolt 3 with power delivery and external 4K monitor support), but it also features 2 USB 3.0 ports, HDMI and card reader. I don&rsquo;t yet have any USB-C devices, while there are numerous phones, drives, watches, lights I own and use with my laptop on the go.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">If you don&#39;t understand the difference between USB-C and Thunderbolt. (Like i did) <a href="https://t.co/mFftm6i2ZU">https://t.co/mFftm6i2ZU</a></p>&mdash; Victor Kropp (@kropp) <a href="https://twitter.com/kropp/status/793893778989916160?ref_src=twsrc%5Etfw">November 2, 2016</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>These outstanding specs are packed into a great looking body. Touchpad feels and works great. In size and weight it is smaller and lighter than old MacBook and on par with recently announced one. I had no problems running Ubuntu on this hardware.</p>
<p>There are some not so good things, though: display is glossy and is touch. So you&rsquo;ll be force to clean it often. And the webcam is in awkward position below the screen. But that&rsquo;s mostly it.</p>
<p>I definetely recommend this laptop to anyone looking for a mobile powerhorse today. If you are frustrated by recent Apple unveiling, you should seriously consider this laptop.</p>
JetBrains Toolbox App 1.0https://victor.kropp.name/blog/jetbrains-toolbox/
Wed, 19 Oct 2016 21:43:00 +0200https://victor.kropp.name/blog/jetbrains-toolbox/<p>Yesterday we&rsquo;ve released <a href="https://jetbrains.com/toolbox/app/">JetBrains Toolbox App 1.0</a>! This is a very important milestone for me. We started this project in July 2015 as a <a href="https://blog.jetbrains.com/blog/2015/08/31/jetbrains-3rd-annual-hackathon-new-generation-debugger-grabs-1st-place/">Hackathon project</a>. And now, some one and a half years later, we reached first public release.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">JetBrains Toolbox App 1.0: A Control Panel for your Coding Tools and Projects! <a href="https://t.co/EzzBCHEIcu">https://t.co/EzzBCHEIcu</a> <a href="https://t.co/rsTaA7zjzo">pic.twitter.com/rsTaA7zjzo</a></p>&mdash; JetBrains Toolbox (@JBToolbox) <a href="https://twitter.com/JBToolbox/status/788313753158881280?ref_src=twsrc%5Etfw">October 18, 2016</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>This is the result of a work of great team, consisting of 6 passionate people with different specialities, which perfectly blend into a single unit capable of producing slick and fast app, providing great user experience. What is also great with this team, is that we have successfully solved all the conflicts, that are inevitable in any collaborative project.</p>
<figure><img src="https://victor.kropp.name/blog/img/2016/toolbox-title.png" width="970" /></figure>
<p>It is not only the coolest thing I&rsquo;ve built, but also helped me to grow professionaly. I gave my first ever <a href="https://victor.kropp.name/talks#qtcon-2016-berlin">public talk</a> sharing our experience in building this app. With the whole bunch of modern technologies and languages (I wrote C++ 10 years ago last time!), Toolbox App is a greatly engineered tool. I&rsquo;m very proud to be a part of this project.</p>
<p>P. S. If you&rsquo;re using any JetBrains&rsquo; IDE and haven&rsquo;t yet seen this app, <a href="https://jetbrains.com/toolbox/app/">try it now</a>!</p>
Skypehttps://victor.kropp.name/blog/skype/
Mon, 10 Oct 2016 21:53:00 +0200https://victor.kropp.name/blog/skype/<p>I&rsquo;ve been using Skype since ages, but it was never my wish. But back in 2000s, it was probably the first and only video communication solution. This helped Skype to grow so big. And this is how I always treated Skype: live video chat.</p>
<p>Because other functionality never worked really well for me. Let&rsquo;s take offline messages for example. For a long time they were delivered only when both participants were back online. Which completely defeats the purpose of <em>offline</em> messages.</p>
<p>And speaking of messaging, there were always lots of alternatives, that were way better than Skype. When we discovered Slack my usage of Skype reduced dramatically.</p>
<p>When Skype was bought by Microsoft it didn&rsquo;t change much. Okay, they fixed something, but the amount of advertisments and senseless user interface changes in Windows version of software became unbearable. I was very happy, when I switched to Ubuntu and started using abandoned Linux Skype client, which just works. And there are no ads, because they&rsquo;ve never been implemented there.</p>
<p>Sometime ago new version of Skype for Linux has been finally <a href="https://community.skype.com/t5/Linux/Skype-for-Linux-Alpha-and-calling-on-Chrome-amp-Chromebooks/td-p/4434299">announced</a>. I was a bit sceptical when I first heared about it. I was worried that first thing they would do is to add ads. But that was not the case. The alpha version of fully reworked app was clean, simple and was not spoiled with any useless functionality, like video calling.</p>
<p>Yes, you read it right, the world&rsquo;s most famous video calling software was released <em>without</em> video calling capabilities.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">New <a href="https://twitter.com/hashtag/Skype?src=hash&amp;ref_src=twsrc%5Etfw">#Skype</a> for Linux doesn&#39;t support video calls. Sounds like a bad joke even if it is just alpha version.</p>&mdash; Victor Kropp (@kropp) <a href="https://twitter.com/kropp/status/753335796246142976?ref_src=twsrc%5Etfw">July 13, 2016</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>Well, maybe there was something extraordinary in this alpha build to be announced so early, that can justify lack of video chat support? Let&rsquo;s check <a href="https://support.skype.com/en/faq/FA34656/more-information-about-skype-for-linux-alpha">feature list</a>:</p>
<figure><img src="https://victor.kropp.name/blog/img/2016/skype-features.png" width="656" /></figure>
<p>Nothing. Oh, wait, new emoticons! This definetely is worth upgrading!</p>
<p>Fast forward to today. 10 bi-weekly builds later Skype for Linux Alpha 1.10 <a href="https://community.skype.com/t5/Linux/What-s-New-in-Skype-1-10-for-Linux-Alpha/m-p/4495850">now supports video calling</a>. But only between users of this particular build. This is not funny anymore, Skype.</p>
<p>I am a big fan of &ldquo;release early, release often&rdquo; philosophy. But to show product to users you first need to have <abbr title="Minimum Viable Product"><a href="https://en.wikipedia.org/wiki/Minimum_viable_product">MVP</a></abbr>. And in this case it is easy video calling. Anything else makes absolutely no sense.</p>
Java Preferences APIhttps://victor.kropp.name/blog/java-preferences-api/
Wed, 28 Sep 2016 22:05:00 +0200https://victor.kropp.name/blog/java-preferences-api/
<p><a href="https://docs.oracle.com/javase/8/docs/api/java/util/prefs/Preferences.html"><code>java.util.prefs.Preferences</code></a> API is available in Java since 1.4. Here is an example:</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="kn">import</span> <span class="nn">java.util.prefs.Preferences</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Example</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Preferences</span> <span class="n">root</span> <span class="o">=</span> <span class="n">Preferences</span><span class="o">.</span><span class="na">userRoot</span><span class="o">().</span><span class="na">node</span><span class="o">(</span><span class="s">&#34;name&#34;</span><span class="o">).</span><span class="na">node</span><span class="o">(</span><span class="s">&#34;kropp&#34;</span><span class="o">);</span>
<span class="n">root</span><span class="o">.</span><span class="na">putInt</span><span class="o">(</span><span class="s">&#34;birth_year&#34;</span><span class="o">,</span> <span class="n">1986</span><span class="o">);</span>
<span class="n">root</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">&#34;camelCase&#34;</span><span class="o">,</span> <span class="s">&#34;String/Value&#34;</span><span class="o">);</span>
<span class="n">root</span><span class="o">.</span><span class="na">node</span><span class="o">(</span><span class="s">&#34;sub_node&#34;</span><span class="o">).</span><span class="na">putBoolean</span><span class="o">(</span><span class="s">&#34;enabled&#34;</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">root</span><span class="o">.</span><span class="na">getInt</span><span class="o">(</span><span class="s">&#34;birth_year&#34;</span><span class="o">,</span> <span class="n">0</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></div>
<p>Java somehow stores given key-value pairs organized in a tree structure on a user&rsquo;s computer. On every operating system, it uses native APIs to do this. So values are stored in <a href="https://en.wikipedia.org/wiki/Windows_Registry">Registry</a> on Windows, in <a href="https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man5/plist.5.html"><code>.plist</code></a> on Mac and in XML files on others systems (primarily, Linux). Although, you shouldn&rsquo;t really care about it, because it just works.</p>
<p>But only until you need to access these settings from outside Java Virtual Machine. In my case, I needed to read/write these values from C++. So I started to investigate how it is implemented in JRE and reimplement the same in C++. Here is what I&rsquo;ve found.</p>
<h4 id="mac-os">Mac OS</h4>
<p>Let&rsquo;s start with the simplest case. On Mac OS X preferences are stored in dictionaries in <code>.plist</code> you can list them quite easily:</p>
<pre class="shell"><code><b>$</b> defaults read ~/Library/Preferences/com.apple.java.util.prefs.plist /</code></pre>
<pre class="highlight"><code>{
"name/" = {
"kropp/" = {
"birth_year" = 1986;
camelCase = "String/Value";
"sub_node/" = {
};
};
};
}
</code></pre>
<p>Have you noticed slashes at the end of each key? For some reason Mac implementation doesn&rsquo;t remove node separator even though nodes are already nested. However the biggest problem is that <a href="https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man8/cfprefsd.8.html">Preferences daemon</a> caches these values and you&rsquo;re in trouble if you read/write them not using standard APIs. <a href="http://manytricks.com/blog/?p=3049">The best advice</a> on how to overcome this issue was: <code>killall cfprefsd</code></p>
<p>Ouch.</p>
<h4 id="windows">Windows</h4>
<p>Registry keys are nested too, but Windows JRE developers have removed unnecessary slashes. Right before they would apply some fancy encoding to both keys and values.</p>
<figure><img src="https://victor.kropp.name/blog/img/2016/java-preferences-registry.png" width="695" height="160" alt="" /></figure>
<p><a href="http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/windows/classes/java/util/prefs/WindowsPreferences.java#l1030">Comment in Javadoc</a> explains why do they did this.</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="cm">/**
</span><span class="cm"> * Converts value string to it Windows representation.
</span><span class="cm"> * as a byte-encoded string.
</span><span class="cm"> * Encoding algorithm adds &#34;/&#34; character to capital letters, i.e.
</span><span class="cm"> * &#34;A&#34; is encoded as &#34;/A&#34;. Character &#39;\&#39; is encoded as &#39;//&#39;,
</span><span class="cm"> * &#39;/&#39; is encoded as &#39;\&#39;.
</span><span class="cm"> * Then encoding scheme similar to jdk&#39;s native2ascii converter is used
</span><span class="cm"> * to convert java string to a byte array of ASCII characters.
</span><span class="cm"> */</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">toWindowsValueString</span><span class="o">(</span><span class="n">String</span> <span class="n">javaName</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// …
</span><span class="c1"></span><span class="o">}</span></code></pre></div>
<p>Do you understand? Me neither.</p>
<h4 id="linux">Linux</h4>
<p>But my favorite implementation is on Linux. At first sight it is the cleanest and the most obvious one:</p>
<pre class="shell"><code><b>$</b> cat ~/.java/.userPrefs/name/kropp/site/prefs.xml</code></pre>
<pre class="highlight"><code>&lt;?xml version="1.0" encoding="UTF-8" standalone="no"?&gt;
&lt;!DOCTYPE map SYSTEM "http://java.sun.com/dtd/preferences.dtd"&gt;
&lt;map MAP_XML_VERSION="1.0"&gt;
&lt;entry key="birth_year" value="1986"/&gt;
&lt;entry key="camelCase" value="String/Value"/&gt;
&lt;/map&gt;
</code></pre>
<p>Up until you store a key in a node with underscore in its name. Then something really awkward happens:</p>
<pre class="shell"><code><b>$</b> ls ~/.java/.userPrefs/name/kropp/
<b>_!(:!d@"i!&8!bg"v!'@!~@==</b> prefs.xml
</code></pre>
<p>This cryptic <strong>_!(:!d@&ldquo;i!&amp;8!bg&rdquo;v!&lsquo;@!~@==</strong> is actually &ldquo;birth_year&rdquo;. What happened to it? Let&rsquo;s again take a look into <a href="http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/solaris/classes/java/util/prefs/FileSystemPreferences.java#l847">Java sources</a>:</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java"><span class="cm">/**
</span><span class="cm"> * Returns true if the specified character is appropriate for use in
</span><span class="cm"> * Unix directory names. A character is appropriate if it&#39;s a printable
</span><span class="cm"> * ASCII character (&gt; 0x1f &amp;&amp; &lt; 0x7f) and unequal to slash (&#39;/&#39;, 0x2f),
</span><span class="cm"> * dot (&#39;.&#39;, 0x2e), or underscore (&#39;_&#39;, 0x5f).
</span><span class="cm"> */</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">isDirChar</span><span class="o">(</span><span class="kt">char</span> <span class="n">ch</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">ch</span> <span class="o">&gt;</span> <span class="n">0x1f</span> <span class="o">&amp;&amp;</span> <span class="n">ch</span> <span class="o">&lt;</span> <span class="n">0x7f</span> <span class="o">&amp;&amp;</span> <span class="n">ch</span> <span class="o">!=</span> <span class="sc">&#39;/&#39;</span> <span class="o">&amp;&amp;</span> <span class="n">ch</span> <span class="o">!=</span> <span class="sc">&#39;.&#39;</span> <span class="o">&amp;&amp;</span> <span class="n">ch</span> <span class="o">!=</span> <span class="sc">&#39;_&#39;</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
</span><span class="cm"> * Returns the directory name corresponding to the specified node name.
</span><span class="cm"> * Generally, this is just the node name. If the node name includes
</span><span class="cm"> * inappropriate characters (as per isDirChar) it is translated to Base64.
</span><span class="cm"> * with the underscore character (&#39;_&#39;, 0x5f) prepended.
</span><span class="cm"> */</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="n">String</span> <span class="nf">dirName</span><span class="o">(</span><span class="n">String</span> <span class="n">nodeName</span><span class="o">)</span> <span class="o">{</span>
<span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">0</span><span class="o">,</span> <span class="n">n</span><span class="o">=</span><span class="n">nodeName</span><span class="o">.</span><span class="na">length</span><span class="o">();</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">isDirChar</span><span class="o">(</span><span class="n">nodeName</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">i</span><span class="o">)))</span>
<span class="k">return</span> <span class="s">&#34;_&#34;</span> <span class="o">+</span> <span class="n">Base64</span><span class="o">.</span><span class="na">byteArrayToAltBase64</span><span class="o">(</span><span class="n">byteArray</span><span class="o">(</span><span class="n">nodeName</span><span class="o">));</span>
<span class="k">return</span> <span class="n">nodeName</span><span class="o">;</span>
<span class="o">}</span></code></pre></div>
<p>The encoding used appears to be Base64, but some <em>alternative</em> one. This is because in original Base64 there are both lower and upper case characters, which are indistinguishable on some file systems.</p>
<p>When you look at it again, this is really crazy: if there is an underscore in a node name, it is encoded and as a final step underscore is prepended. What?!</p>
<h4 id="conclusion">Conclusion</h4>
<p>Cross platform programming is hard.</p>
Hello World!https://victor.kropp.name/blog/hello-world/
Wed, 21 Sep 2016 22:06:00 +0200https://victor.kropp.name/blog/hello-world/<p>This isn&rsquo;t my first attempt to start blog, and probably not the last. But this time I feel I have something to say and share. Mostly I will be writing here about programming and other software development related topics.</p>
<p>I&rsquo;d rather post here a good content, but unregularly, not vice versa. So <a href="https://twitter.com/kropp">follow me on <i class="fa fa-fw fa-twitter" style="color: rgb(70,192,251);"></i>@kropp</a> and stay tuned!</p>