<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Yuri Zamyatin: Posts</title><description>List of posts on Yuri Zamyatin</description><link>https://yrz.am/posts/</link><language>en</language><managingEditor>yuri@yrz.am</managingEditor><lastBuildDate>Thu, 02 Oct 2025 17:04:20 +0000</lastBuildDate><atom:link href="https://yrz.am/posts/rss.xml" rel="self" type="application/rss+xml"/><item><title>Sticky dotfiles</title><link>https://yrz.am/posts/wscompat/</link><pubDate>Thu, 02 Oct 2025 17:04:20 +0000</pubDate><author>yuri@yrz.am</author><guid>https://yrz.am/posts/wscompat/</guid><description>&lt;h2 id="idea"&gt;Idea&lt;/h2&gt;
&lt;p&gt;Managing configuration files for essential CLI tools such as vim and readline across multiple environments is an interesting challenge. Whether you&amp;rsquo;re running &lt;em&gt;sudo vim&lt;/em&gt; to edit system files or SSH-ing into a new server, configs get lost. It&amp;rsquo;s a common headache to keep them in sync and avoid conflicts, especially on shared accounts like root. I&amp;rsquo;ve created a solution that is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Transparent and fast&lt;/strong&gt;. Just use the commands normally - configs will be migrated where needed. No slow file transfers or double authentication will occur. Absolutely minimal requirements are imposed on the destination.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Works recursively&lt;/strong&gt;. If destinations are chained, dotfiles propagate accordingly. For example, you can: ssh host1 -&amp;gt; sudo su -&amp;gt; ssh host2 -&amp;gt; su user -&amp;gt; &amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session-only&lt;/strong&gt;. Other persons will not be affected by your configs on the remote, even if the remote user is shared.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-user&lt;/strong&gt;. Multiple users can utilize this solution simultaneously, even if the remote user is shared.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Doesn&amp;rsquo;t pollute history&lt;/strong&gt;. Intercepts calls to the affected commands and follows their interface, keeping history compliant with the original version.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatible with scripts&lt;/strong&gt;. Works only on the main interactive session of destination.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source-extensible&lt;/strong&gt;. As a part of my workspace repository, it allows to add custom things to profile without touching source-controlled base files.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="implementation"&gt;Implementation&lt;/h2&gt;
&lt;p&gt;The setup on the destination environment is handled by a single auto-generated file (the &amp;ldquo;remote profile&amp;rdquo;). The easiest way to compose it is to use a template engine.&lt;/p&gt;
&lt;p&gt;I use &lt;a href="https://docs.gomplate.ca/"&gt;gomplate&lt;/a&gt;. It works really well and has everything I need. Importantly, its go template syntax is already familiar to me and has been used to generate the blog you&amp;rsquo;re currently reading. However, I dislike it for being bloated in terms of features and binary size.&lt;/p&gt;
&lt;h3 id="1-remote-profile"&gt;1. Remote profile&lt;/h3&gt;
&lt;p&gt;Remote profile is a self-sufficient bash script that wraps up remote .profile and extends it with our custom stuff. It is static and stores everything inside. To spin up remote configuration, one should export two variables, source it, and source newly generated rcfile. These variables are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$WS_IS_COMPAT&lt;/code&gt; - controls whether we&amp;rsquo;re in compatibility mode, script does nothing if not&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$WSCOMPAT_DIR&lt;/code&gt; - defines the temporary directory where to store populated configuration and scripts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Inside remote profile, we:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Source original &lt;code&gt;.profile&lt;/code&gt;, &lt;code&gt;/etc/profile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Prepend PATH with &lt;code&gt;$WSCOMPAT_DIR&lt;/code&gt; to make transferred executables easily accessible.&lt;/li&gt;
&lt;li&gt;Configure editors. Usually this means making files inside &lt;code&gt;$WSCOMPAT_DIR&lt;/code&gt; directory and instructing programs where to look for them using environment variables.&lt;/li&gt;
&lt;li&gt;Save and chmod executables that will migrate remote profile to the next destination.&lt;/li&gt;
&lt;li&gt;Set arbitrary environment variables according to our preferences.&lt;/li&gt;
&lt;li&gt;Render bashrc wrapper, which
&lt;ol&gt;
&lt;li&gt;Uses aliases or functions to intercept commands that switch environment and calls our wrappers (to make the solution recursive)&lt;/li&gt;
&lt;li&gt;Does arbitrary interactive-only session configuration&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Do other customizations&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Below you can find a template file of the remote profile. It loads and processes other files as templates recursively (dotfiles are also templated). It must be re-rendered when its children change.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;config/workspace-compat/profile.tmpl&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; -z &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$WSCOMPAT_DIR&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$WS_IS_COMPAT&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; !&lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	exit &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt; -f /etc/profile &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; . /etc/profile
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt; -f ~/.profile &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; . ~/.profile
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export EDITOR&lt;span style="color:#f92672"&gt;=&lt;/span&gt;vim
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export SHELL&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$WSCOMPAT_DIR&lt;span style="color:#e6db74"&gt;:&lt;/span&gt;$PATH&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt; &amp;#39;WSCOMPAT_EOF_04tcIQE7&amp;#39; &amp;gt; &amp;#34;$WSCOMPAT_DIR/bashrc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;{{ tmpl.Inline (file.Read &amp;#34;config/workspace-compat/bashrc&amp;#34;) . }}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;WSCOMPAT_EOF_04tcIQE7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export VIMINIT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;source &lt;/span&gt;$WSCOMPAT_DIR&lt;span style="color:#e6db74"&gt;/vimrc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt; &amp;#39;WSCOMPAT_EOF_04tcIQE7&amp;#39; &amp;gt; &amp;#34;$WSCOMPAT_DIR/vimrc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;{{ tmpl.Inline (file.Read &amp;#34;config/vim/vimrc.tmpl&amp;#34;) . }}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;WSCOMPAT_EOF_04tcIQE7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export INPUTRC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$WSCOMPAT_DIR&lt;span style="color:#e6db74"&gt;/inputrc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt; &amp;#39;WSCOMPAT_EOF_04tcIQE7&amp;#39; &amp;gt; &amp;#34;$WSCOMPAT_DIR/inputrc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;{{ tmpl.Inline (file.Read &amp;#34;config/readline/inputrc&amp;#34;) . }}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;WSCOMPAT_EOF_04tcIQE7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export LESSKEYIN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$WSCOMPAT_DIR&lt;span style="color:#e6db74"&gt;/lesskey&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt; &amp;#39;WSCOMPAT_EOF_04tcIQE7&amp;#39; &amp;gt; &amp;#34;$WSCOMPAT_DIR/lesskey&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;{{ tmpl.Inline (file.Read &amp;#34;config/less/lesskey&amp;#34;) . }}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;WSCOMPAT_EOF_04tcIQE7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt; &amp;#39;WSCOMPAT_EOF_04tcIQE7&amp;#39; &amp;gt; &amp;#34;$WSCOMPAT_DIR/wssh&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;{{ tmpl.Inline (file.Read &amp;#34;bin/wssh&amp;#34;) . }}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;WSCOMPAT_EOF_04tcIQE7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod +x &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$WSCOMPAT_DIR&lt;span style="color:#e6db74"&gt;/wssh&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt; &amp;#39;WSCOMPAT_EOF_04tcIQE7&amp;#39; &amp;gt; &amp;#34;$WSCOMPAT_DIR/wsudo&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;{{ tmpl.Inline (file.Read &amp;#34;bin/wsudo&amp;#34;) . }}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;WSCOMPAT_EOF_04tcIQE7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod +x &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$WSCOMPAT_DIR&lt;span style="color:#e6db74"&gt;/wsudo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="2-dotfiles"&gt;2. Dotfiles&lt;/h3&gt;
&lt;p&gt;Dotfiles may need to differ on the master and destination environments. Firstly, they are different in terms of capabilities - the first one is connected to your window manager and has access to a well-defined list of packages and plugins, whereas second one is designed to work anywhere. Secondly, the remote nature of the latter may require some commands to work differently (for example, to make use of your host clipboard, image viewer, etc).&lt;/p&gt;
&lt;p&gt;In order to keep the code reused, they are processed as templates. For the master (native) target, dotfiles should be rendered to their primary location in &lt;code&gt;$XDG_CONFIG_DIRS&lt;/code&gt; or &lt;code&gt;$HOME&lt;/code&gt;. Rendering in compatibility mode is managed by the parent template in the previous section.&lt;/p&gt;
&lt;p&gt;To detect the target, simply check the environment variable &lt;code&gt;IS_COMPAT&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;config/vim/vimrc.tmpl&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;...
{{ if ne .Env.IS_COMPAT &amp;#34;1&amp;#34; }}
...
{{ else }}
...
{{ end }}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If configuration file does not use template engine directives, it will be rendered literally.&lt;/p&gt;
&lt;p&gt;Right now, in compatibility mode, 4 programs are configured separately:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;vim&lt;/strong&gt;: VIMINIT=&amp;ldquo;source /path/to/file&amp;rdquo; method&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;less&lt;/strong&gt;: LESSKEYIN=&amp;quot;/path/to/file&amp;quot; method&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;readline&lt;/strong&gt;: INPUTRC=&amp;quot;/path/to/file&amp;quot; method&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;bash&lt;/strong&gt;: rcfile (supplied by the caller script)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;By the way, I find it useful to render config files as templates besides this task, as it allows to keep generic settings in one place, do inline calculation and adapt to the specs/capabilities of computer I install them on.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="3-command-wrappers"&gt;3. Command wrappers&lt;/h3&gt;
&lt;p&gt;They are special handlers of commands that involve switch of environment, such as &lt;strong&gt;ssh&lt;/strong&gt; and &lt;strong&gt;sudo&lt;/strong&gt;. Interface of these commands must be a subset of the interface of original commands in order to keep them transparent in history.&lt;/p&gt;
&lt;p&gt;Pre-command approach is highly appreciated as it does not lead to double context switching. For now, their names must be unique so they don&amp;rsquo;t pollute &lt;code&gt;PATH&lt;/code&gt; and break programs. I&amp;rsquo;ve chosen &lt;strong&gt;w&lt;/strong&gt; prefix which means &lt;strong&gt;w&lt;/strong&gt;orkspace.&lt;/p&gt;
&lt;p&gt;Basically, every wrapper should do everything that the base command does and achieve the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;On remote, set &lt;code&gt;WS_IS_COMPAT=1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;On remote, set &lt;code&gt;$WSCOMPAT_DIR&lt;/code&gt;. Some implementations use the folder in &lt;code&gt;/tmp&lt;/code&gt;. To avoid conflicts between different users of this solution, variable &lt;code&gt;$WSCOMPAT_MASTER&lt;/code&gt; is passed along the chain of switches to be used as part of &lt;code&gt;$WSCOMPAT_DIR&lt;/code&gt;. It stores the name of the user who initiated the session.&lt;/li&gt;
&lt;li&gt;Merge local &amp;ldquo;remote profile&amp;rdquo; with custom scripts from local &lt;code&gt;$WSCOMPAT_DIR/profile*.sh&lt;/code&gt; and transfer it to remote. Some fancy stuff is done with heredoc separators because wrapper script must transfer itself.&lt;/li&gt;
&lt;li&gt;On remote, source &amp;ldquo;remote profile&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;On the remote, invoke interactive command if it was supplied. If not, invoke shell with generated &lt;code&gt;rcfile&lt;/code&gt; and appropriate parameters&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Wrapper may fall back to the base command if it detects non-interactive use.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;bin/wssh (&lt;strong&gt;ssh&lt;/strong&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;set -e
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; $# -lt &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	echo &lt;span style="color:#e6db74"&gt;&amp;#34;Usage: &lt;/span&gt;$0&lt;span style="color:#e6db74"&gt; &amp;lt;hostname&amp;gt; [ssh-options]&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	exit &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$*&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; *&lt;span style="color:#e6db74"&gt;&amp;#34; -- &amp;#34;&lt;/span&gt;* &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	exec /bin/ssh &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$@&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt; -z &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$WSCOMPAT_MASTER&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; WSCOMPAT_MASTER&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;whoami&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;read -r -d &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt; init_cmd &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt; WSCOMPAT_EOF_9oqn7IVF || true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	export WS_IS_COMPAT=1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	export WSCOMPAT_MASTER=&amp;#34;$WSCOMPAT_MASTER&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	export WSCOMPAT_DIR=&amp;#34;/tmp/wscompat_${WSCOMPAT_MASTER}_\$(whoami)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	rm -rf &amp;#34;\$WSCOMPAT_DIR&amp;#34; &amp;amp;&amp;amp; mkdir -p &amp;#34;\$WSCOMPAT_DIR&amp;#34; &amp;amp;&amp;amp; chmod 700 &amp;#34;\$WSCOMPAT_DIR&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;cat &amp;lt;&amp;lt; &amp;#39;WSCOMPAT_EOF_84EbM3la&amp;#39; &amp;gt; &amp;#34;\$WSCOMPAT_DIR/profile&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;$(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	sed &amp;#39;s/WSCOMPAT_EOF_/WSCOMPAT_EOF__/g&amp;#39; &amp;#34;$WSCOMPAT_DIR/profile&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	for file in &amp;#34;$WSCOMPAT_DIR/profile&amp;#34;*.sh; do
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;		if [ -f &amp;#34;$file&amp;#34; ]; then
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;			sed &amp;#39;s/WSCOMPAT_EOF_/WSCOMPAT_EOF__/g&amp;#39; &amp;#34;$file&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;		fi
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	done
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;WSCOMPAT_EOF_84EbM3la
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	. \$WSCOMPAT_DIR/profile
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	# pam, systemd - wrap in login shell
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	exec /bin/bash --login --norc --noprofile -c &amp;#34;exec /bin/bash --rcfile \&amp;#34;\$WSCOMPAT_DIR/bashrc\&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;WSCOMPAT_EOF_9oqn7IVF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;exec /bin/ssh -t &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$@&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$init_cmd&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When I need to execute remote command, I always use &lt;code&gt;--&lt;/code&gt; syntax because it doesn&amp;rsquo;t require double quotes, so no nesting and extra escaping of quotes occurs. I decided not to implement full argument parsing to handle quoted remote commands.&lt;/p&gt;
&lt;p&gt;As for &lt;code&gt;sudo&lt;/code&gt;, there is a dichotomy between &lt;code&gt;sudo -u&lt;/code&gt; and &lt;code&gt;sudo su&lt;/code&gt;. Dealing with &lt;code&gt;sudo -u&lt;/code&gt; seems a lot easier (no double switching), and this option is more simple. Since we get everything as arguments, it is possible to eliminate &lt;code&gt;su&lt;/code&gt; completely at the parsing stage.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;bin/wsudo (&lt;strong&gt;sudo&lt;/strong&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;parse&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	sudo_user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;root&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	sudo_command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	sudo_login_shell&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	local args&lt;span style="color:#f92672"&gt;=(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$@&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	local i&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	local arg_count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${#&lt;/span&gt;args[@]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	expand_flags&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		local expanded&lt;span style="color:#f92672"&gt;=()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; arg in &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$@&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $arg &lt;span style="color:#f92672"&gt;=&lt;/span&gt;~ ^-&lt;span style="color:#f92672"&gt;[&lt;/span&gt;a-zA-Z&lt;span style="color:#f92672"&gt;]{&lt;/span&gt;2,&lt;span style="color:#f92672"&gt;}&lt;/span&gt;$ &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				local chars&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;arg:1&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#f92672"&gt;((&lt;/span&gt;j&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0; j&amp;lt;&lt;span style="color:#e6db74"&gt;${#&lt;/span&gt;chars&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;; j++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					expanded&lt;span style="color:#f92672"&gt;+=(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;chars:$j:1&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				expanded&lt;span style="color:#f92672"&gt;+=(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$arg&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		args&lt;span style="color:#f92672"&gt;=(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;expanded[@]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		arg_count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${#&lt;/span&gt;args[@]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	expand_flags &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$@&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $i -lt $arg_count &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;args[$i]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; in
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			-u|--user&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#f92672"&gt;((&lt;/span&gt;i++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $i -lt $arg_count &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					sudo_user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;args[$i]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#f92672"&gt;((&lt;/span&gt;i++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			-i|--login&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				sudo_login_shell&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#f92672"&gt;((&lt;/span&gt;i++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			-s|--shell&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#f92672"&gt;((&lt;/span&gt;i++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			--&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#f92672"&gt;((&lt;/span&gt;i++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				sudo_command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;args[*]:$i&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				break;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			-*&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#f92672"&gt;((&lt;/span&gt;i++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			su&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#f92672"&gt;((&lt;/span&gt;i++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				local su_user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				local su_args&lt;span style="color:#f92672"&gt;=()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $i -lt $arg_count &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					su_args&lt;span style="color:#f92672"&gt;+=(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;args[$i]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#f92672"&gt;((&lt;/span&gt;i++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				local su_expanded&lt;span style="color:#f92672"&gt;=()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; arg in &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;su_args[@]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $arg &lt;span style="color:#f92672"&gt;=&lt;/span&gt;~ ^-&lt;span style="color:#f92672"&gt;[&lt;/span&gt;a-zA-Z&lt;span style="color:#f92672"&gt;]{&lt;/span&gt;2,&lt;span style="color:#f92672"&gt;}&lt;/span&gt;$ &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						local chars&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;arg:1&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#f92672"&gt;((&lt;/span&gt;j&lt;span style="color:#f92672"&gt;=&lt;/span&gt;0; j&amp;lt;&lt;span style="color:#e6db74"&gt;${#&lt;/span&gt;chars&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;; j++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							su_expanded&lt;span style="color:#f92672"&gt;+=(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;chars:$j:1&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						su_expanded&lt;span style="color:#f92672"&gt;+=(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$arg&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				local k&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				local su_count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${#&lt;/span&gt;su_expanded[@]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $k -lt $su_count &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;su_expanded[$k]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; in
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						-|-l|--login&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							sudo_login_shell&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#f92672"&gt;((&lt;/span&gt;k++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						-c|--command&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#f92672"&gt;((&lt;/span&gt;k++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $k -lt $su_count &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								sudo_command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;su_expanded[$k]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								&lt;span style="color:#f92672"&gt;((&lt;/span&gt;k++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						--session-command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;*&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							sudo_command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;su_expanded[$k]#*=&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#f92672"&gt;((&lt;/span&gt;k++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						-m|-p|--preserve-environment&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#f92672"&gt;((&lt;/span&gt;k++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						-s|--shell&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#f92672"&gt;((&lt;/span&gt;k++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; $k -lt $su_count &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;su_expanded[$k]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; !&lt;span style="color:#f92672"&gt;=&lt;/span&gt; -* &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								&lt;span style="color:#f92672"&gt;((&lt;/span&gt;k++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						-*&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#f92672"&gt;((&lt;/span&gt;k++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;						*&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; -z &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$su_user&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								su_user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;su_expanded[$k]&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								&lt;span style="color:#f92672"&gt;((&lt;/span&gt;k++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;								&lt;span style="color:#f92672"&gt;((&lt;/span&gt;k++&lt;span style="color:#f92672"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;							&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					&lt;span style="color:#66d9ef"&gt;esac&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[[&lt;/span&gt; -n &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$su_user&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;					sudo_user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$su_user&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				break;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			*&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				sudo_command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;args[*]:$i&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				break;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;esac&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;parse &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$@&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt; -z &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$WSCOMPAT_MASTER&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; WSCOMPAT_MASTER&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;whoami&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;read -r -d &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#39;&lt;/span&gt; init_cmd &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt; WSCOMPAT_EOF_ahkiem3K || true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	export WS_IS_COMPAT=1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	export WSCOMPAT_MASTER=&amp;#34;$WSCOMPAT_MASTER&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	export WSCOMPAT_DIR=&amp;#34;/tmp/wscompat_${WSCOMPAT_MASTER}_\$(whoami)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	rm -rf &amp;#34;\$WSCOMPAT_DIR&amp;#34; &amp;amp;&amp;amp; mkdir -p &amp;#34;\$WSCOMPAT_DIR&amp;#34; &amp;amp;&amp;amp; chmod 700 &amp;#34;\$WSCOMPAT_DIR&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	cat &amp;lt;&amp;lt; &amp;#39;WSCOMPAT_EOF_daePe0Ph&amp;#39; &amp;gt; &amp;#34;\$WSCOMPAT_DIR/profile&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;$(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	sed &amp;#39;s/WSCOMPAT_EOF_/WSCOMPAT_EOF__/g&amp;#39; &amp;#34;$WSCOMPAT_DIR/profile&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	for file in &amp;#34;$WSCOMPAT_DIR/profile&amp;#34;*.sh; do
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;		if [ -f &amp;#34;$file&amp;#34; ]; then
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;			sed &amp;#39;s/WSCOMPAT_EOF_/WSCOMPAT_EOF__/g&amp;#39; &amp;#34;$file&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;		fi
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	done
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;WSCOMPAT_EOF_daePe0Ph
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;	. \$WSCOMPAT_DIR/profile
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;WSCOMPAT_EOF_ahkiem3K&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; -z &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$sudo_command&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	sudo_command&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;exec /bin/bash --rcfile \&amp;#34;\$WSCOMPAT_DIR/bashrc\&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$sudo_login_shell&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	exec /bin/sudo -u &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$sudo_user&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		/bin/bash --login --noprofile --norc -c &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$init_cmd&lt;span style="color:#e6db74"&gt;; cd; &lt;/span&gt;$sudo_command&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	exec /bin/sudo -u &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$sudo_user&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		/bin/bash --noprofile --norc -c &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$init_cmd&lt;span style="color:#e6db74"&gt;; &lt;/span&gt;$sudo_command&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, inject them instead of the basic commands in the interactive shell via aliases in the &lt;code&gt;rcfile&lt;/code&gt; below, which is transferred through remote profile and invoked as &lt;code&gt;--rcfile&lt;/code&gt;. It sources the default &lt;code&gt;rcfile&lt;/code&gt; aka &lt;code&gt;.bashrc&lt;/code&gt; and adds customizations.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;config/workspace-compat/bashrc&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt; -f ~/.bashrc &lt;span style="color:#f92672"&gt;]&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; . ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alias ssh&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;wssh&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alias sudo&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;wsudo&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;su&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$1&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;-&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		shift &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; wsudo - -u &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$@&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		wsudo -u &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$@&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;su&lt;/code&gt; from interactive root in the form I use was superseded by &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all the wrappers for today. Next candidates are probably &lt;code&gt;chroot&lt;/code&gt; and &lt;code&gt;docker exec&lt;/code&gt;, which I don&amp;rsquo;t use.&lt;/p&gt;
&lt;h3 id="4-master-environment"&gt;4. Master environment&lt;/h3&gt;
&lt;p&gt;Obviously master (native) environment should not source these scripts, so it needs a bit of configuration - it should know where to look for the remote &lt;code&gt;profile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$WSCOMPAT_DIR&lt;/code&gt; must point to a folder where you rendered &lt;code&gt;profile&lt;/code&gt; template. You can add extra initialization scripts that follow glob &lt;code&gt;profile*.sh&lt;/code&gt; to that folder - they will be merged into the target&amp;rsquo;s &lt;code&gt;profile&lt;/code&gt;. Local &lt;code&gt;$WSCOMPAT_DIR&lt;/code&gt; will not be populated with configs as we&amp;rsquo;re in native mode.&lt;/p&gt;
&lt;p&gt;I recommend setting &lt;code&gt;$WSCOMPAT_DIR&lt;/code&gt; in the local &lt;code&gt;.profile&lt;/code&gt; or its callees. My &lt;code&gt;$WSCOMPAT_DIR&lt;/code&gt; points to &lt;code&gt;.config/workspace-compat&lt;/code&gt; and is exported from &lt;code&gt;.config/workspace-compat/env.sh&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For the better shell experience, &lt;code&gt;wssh&lt;/code&gt; and &lt;code&gt;wsudo&lt;/code&gt; scripts should appear in &lt;code&gt;$PATH&lt;/code&gt; (which is best set in the local &lt;code&gt;.profile&lt;/code&gt; due to its incremental nature). I install them to &lt;code&gt;.local/bin&lt;/code&gt;. To make this truly unified and seamless, I also make &lt;code&gt;sudo&lt;/code&gt; and &lt;code&gt;ssh&lt;/code&gt; aliases, just like in compatibility mode.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alias ssh&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;wssh&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;alias sudo&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;wsudo&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Overriding &lt;code&gt;su&lt;/code&gt; here is useless since native user is not root.&lt;/p&gt;
&lt;h3 id="5-generate"&gt;5. Generate&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;IS_COMPAT=1 gomplate \
 --file config/workspace-compat/profile.tmpl \
 --out $WSCOMPAT_DIR/profile
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;IS_COMPAT&lt;/code&gt; variable is accessible inside template files.&lt;/p&gt;</description></item><item><title>Keyboard layout</title><link>https://yrz.am/posts/keyboard-layout/</link><pubDate>Wed, 09 Jul 2025 06:35:45 +0000</pubDate><author>yuri@yrz.am</author><guid>https://yrz.am/posts/keyboard-layout/</guid><description>&lt;h2 id="how-it-started"&gt;How it started&lt;/h2&gt;
&lt;p&gt;I have been using QWERTY and ЙЦУКЕН for many years while being focused on things other than typing efficiency. The speed was average. I typed using two fingers without looking at the keyboard. At some point, the environment became mature and stable enough for me to deeply invest in skills that provide slow yet steady benefits.&lt;/p&gt;
&lt;p&gt;I decided to learn touch typing - supposedly the most efficient input method where all fingers are utilized. My goal was to improve ergonomics and typing speed and to generally think less about the keyboard. The better you type, the less typing difficulty holds you back. That means less mental overhead, more experiments, and more real-world feedback as opposed to simulations in your mind.&lt;/p&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_qwerty-touch-typing.5c96f9e95838af05ba6844459d9131aef30f44daa9e81328df5a8c9c147d9311.png"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_qwerty-touch-typing.5c96f9e95838af05ba6844459d9131aef30f44daa9e81328df5a8c9c147d9311.png"&gt;&lt;/a&gt;&lt;/figure&gt;

&lt;p&gt;However, it didn&amp;rsquo;t go well with standard layouts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It&amp;rsquo;s like learning a new layout.&lt;/strong&gt; Typing flow is based on muscle memory, not on the location of the keys. That means we&amp;rsquo;re at least at the third layer of abstraction. The first layer is formed by the physics and position of keys, the second layer is introduced by software which maps symbols to keys, and the third layer is entirely made by you - it is how you reach those symbols. People don&amp;rsquo;t interact with QWERTY directly, they use their behavioral model on top of it. Touch typing is a completely new model compared to typing with two fingers, and I am convinced that the reuse of the same keyboard layout gives no advantage. It actually makes learning harder as it creates a conflict between old and new habits, defeating the ability to notice mistakes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But that layout is bad.&lt;/strong&gt; QWERTY is unergonomic by design. Designed in the 1870s (!) to prevent mechanical typewriter jams, it deliberately increases finger movement and places frequent keys in hard-to-reach positions (causing sideways wrist bending, etc). ЙЦУКЕН&amp;rsquo;s main idea is to put all common keys in the center, which is literally the opposite of the touch typing principle. I don&amp;rsquo;t think I need much theory here - feel free to type &amp;ldquo;the right way&amp;rdquo; (illustrated above) and see how inconvenient it is compared to &amp;ldquo;hacking&amp;rdquo; bigrams intuitively via 4 or 6 fingers.&lt;/p&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_qwerty-heatmap.d7e116d22ee5947a3cdf356dc3669fd3fd74d46eafe42507ccfd1f5a4a1275ba.png"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_qwerty-heatmap.d7e116d22ee5947a3cdf356dc3669fd3fd74d46eafe42507ccfd1f5a4a1275ba.png"&gt;&lt;/a&gt;&lt;figcaption&gt;QWERTY heatmap&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;There should be a better alternative. To find it, I must define scope and metrics and try to maximize them while covering all possible use cases.&lt;/p&gt;
&lt;h2 id="scope"&gt;Scope&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;ANSI keyboards.&lt;/strong&gt; Custom hardware looks too time-consuming and fragile. The stability, popularity and affordability of existing keyboards grant much independence from the physical world. Their widespread adoption and production won&amp;rsquo;t let them disappear for decades. An ANSI keyboard can be found easily regardless of the physical location or time of day. No matter what happens - pick one for $5 and you&amp;rsquo;re ready to go. Widely used on laptops, popular as an external option for phones, TVs, they&amp;rsquo;ll likely outlive the form-factor of PCs. The layout can be ported to a European-style or &amp;ldquo;ergonomic&amp;rdquo; keyboard, although I must focus on one option, and the choice is ANSI.

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_ansi-iso.b42acbb9dbac9ed5c09ee72b5c07449af057e51a626a7bc760de6d113f5da804.png"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_ansi-iso.b42acbb9dbac9ed5c09ee72b5c07449af057e51a626a7bc760de6d113f5da804.png"&gt;&lt;/a&gt;&lt;/figure&gt;

&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Two-handed.&lt;/strong&gt; Contrary to popular belief, two-handed typing is not superior to one-handed typing. They have completely different use cases. Two-handed method excels if the best use for the spare hand is to speed up typing (but not to utilize mouse / hold laptop / use phone / etc). Generally, it requires more concentration, less multitasking, stricter physical conditions and keyboard-centered software, but provides obvious benefits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Latin-centric.&lt;/strong&gt; A multilingual environment forces us to make trade-offs between languages. In such cases, English will be prioritized. Other languages must not add context to the key placement.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;General-purpose with modal editing in mind.&lt;/strong&gt; Account for all scenarios, do not over-optimize for specific language dialects. Do not plan continuous recalibration or adjustments; the layout is not a process but a result, try to achieve it once and forever like QWERTY did.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Personal.&lt;/strong&gt; Presumably the keyboard should reflect biological and mental factors which are a bit different among different people. I have no intention to research the significance of that difference or to make the model suboptimal for myself in favor of a larger audience (if such conflict exists).&lt;/p&gt;
&lt;h2 id="result"&gt;Result&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Yurmak-EN layout

 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14
------------------------------------------------------------
AA | * 1 2 3 4 5 6 7 8 9 0 - = \
AB | ` # ~ ! $ ^ % [ ] &amp;lt; &amp;gt; + = @
 |
BA | ESC q w f p b j l u y : ( ) BSP
BB | ESC Q W F P B J L U Y ; { } BSP
 |
CA | CPS a r s t g m n e i o &amp;#34; RET
CB | CPS A R S T G M N E I O &amp;#39; RET
 |
DA | SHF x c d v z k h , . / TAB
DB | X C D V Z K H | &amp;amp; ? TAB
 |
EA | CTL SUP AGR SPC ALT RCT
EB | CTL SUP AGR _ ALT RCT 
--------------------------------------------------------------
column header - horizontal key position 
row header, letter 1 - vertical position, top to bottom
row header, letter 2, A - no modifier
row header, letter 2, B - Shift modifier
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;XKB config may be found &lt;a href="https://git.yrz.am/yrzam/workspace/src/branch/main/arch-user/config/xkb/symbols/us"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="action-keys"&gt;Action keys&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Esc&lt;/code&gt; moved to the left of top alpha row (previously Tab)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Control&lt;/code&gt; moved to the left of middle alpha row (previously Caps)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Shift&lt;/code&gt; stays on the left of bottom alpha row&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This plays well with apps that rely on hotkeys, especially modal programs like vim. It is not a coincidence - just look at the older keyboards they were designed for.&lt;/p&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_old-keyboard.ac5ab5f7921520d05db248fd6d6de072fc7387354ebdda45ffc9ebeb4275fb21.jpg"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_old-keyboard.ac5ab5f7921520d05db248fd6d6de072fc7387354ebdda45ffc9ebeb4275fb21.jpg"&gt;&lt;/a&gt;&lt;/figure&gt;

&lt;p&gt;You may notice that even modern programs have not recalibrated and use the same keys. Surely &lt;strong&gt;Control&lt;/strong&gt; is more useful than &lt;strong&gt;Caps lock&lt;/strong&gt; for most people.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Backspace&lt;/code&gt; goes to the right of top alpha row (previously backslash)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Enter&lt;/code&gt; stays on its original position - right of the middle alpha row.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Tab&lt;/code&gt; is placed on the right of bottom alpha row (previously Right Shift)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Backspace&lt;/strong&gt; is used more than backslash, so I move it to the more reachable position. However, it should not be used as frequently as one may think, because character deletion is also covered by case-specific combos like &lt;strong&gt;ctrl+w&lt;/strong&gt;, &lt;strong&gt;ctrl+n&lt;/strong&gt;, &lt;strong&gt;x&lt;/strong&gt;, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tab&lt;/strong&gt; is widely used for auto-completion and indentation. Tab is not a modifier key, it is pressed sequentially and involves some semantic pause - it is either a gap itself or it introduces unpredictable branching. Combinations with tab do not include right-side modifier and action keys. I find this position perfect for Tab as it requires some movement, yet that movement is very convenient and frequent. Right shift is superseded completely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enter&lt;/strong&gt; follows similar rules: used frequently, pause is assumed, no common bigrams with the right pinky.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Window manager key&lt;/code&gt; introduced. It takes the left place on the thumb row (previously Control)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Layout switch key&lt;/code&gt; introduced and placed as the second to the left key of space. (previously OS key)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Window manager (OS) key&lt;/strong&gt; is for window arrangement, app launcher, device management (brightness, volume) and other inter-application stuff such as clipboard. This, by design, requires some distraction, so the key is farther than other modifiers yet is easy to reach.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Layout switch key&lt;/strong&gt; is used to switch between keyboard layouts. Occupies a spare key, which is reachable yet not suitable for combos due to high concentration of special keys near edge of the keyboard.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AltGr&lt;/code&gt; takes its static place under the left thumb, near Space (previously Left alt)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Left alt&lt;/code&gt; (&lt;code&gt;Meta&lt;/code&gt;) appears under right thumb, near Space (previously Right alt)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Right control&lt;/code&gt; stays on its inconvenient place of 2nd key to the right of Space.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;AltGr&lt;/strong&gt; allows one to type extra characters that do not fit on the base layer, but correspond to some base-layer character, for example, α or á can be mapped to a. Non-English layouts that have more than 26 characters should place extra characters there to keep punctuation keys stable. AltGr can also be used with modifier keys, forming an Alternative modifier combo. If possible, keyboard with a reasonable space length should be chosen in order to make such movement convenient.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alt&lt;/strong&gt; is discouraged and should not be used in applications unless you have a very good reason to do so. We opt for modal flow and already have an application-level modifier key, so, for the sake of simplicity, Control should be used exclusively. Key is deprioritized in its reachability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Right control&lt;/strong&gt; provides compatibility with cheap keyboards that cannot handle certain combos due to hardware limitations, such as Ctrl+Shift+D being impossible to type because manufacturers did not give enough capacity to Caps+Shift prefix. It&amp;rsquo;s quite ironic that our layout is shaped by the same problem as QWERTY was 150 years ago, but, luckily, problem is minor nowadays and does not degrade ergonomics significantly. Discouraged in favor of left control.&lt;/p&gt;
&lt;p&gt;Key meaning summary:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;WM key&lt;/code&gt; - inter-application modifier layer&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AltGr&lt;/code&gt;, &lt;code&gt;Shift&lt;/code&gt; - character modifier layer&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ctrl&lt;/code&gt;, &lt;code&gt;Alt&lt;/code&gt; - application modifier layer&lt;/li&gt;
&lt;li&gt;Keys without modifier pressed are transmitted to the application directly&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="english-keys"&gt;English keys&lt;/h3&gt;
&lt;p&gt;The evolution path is quite rich.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;QWERTY -&amp;gt; Dvorak -&amp;gt; Colemak -&amp;gt; Colemak-DH -&amp;gt; Yurmak&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Alphanumeric characters&lt;/strong&gt; are taken from the &lt;strong&gt;Colemak-DH&lt;/strong&gt; layout.&lt;/p&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_colemak-dh-ansi.cb28741391b87873fda29b84cfe242f0a2e582029d9fb9d5a98a9d5ead9d0931.png"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_colemak-dh-ansi.cb28741391b87873fda29b84cfe242f0a2e582029d9fb9d5a98a9d5ead9d0931.png"&gt;&lt;/a&gt;&lt;figcaption&gt;colemak-dh, ansi variant&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Colemak&lt;/strong&gt; layout family is state-of-the-art in ergonomic layouts, it accumulated lots of efforts, is battle-tested and has a large community.&lt;/p&gt;
&lt;p&gt;One of its main advantages is that it reduces finger movement by placing the most frequently used letters in the English language on the home row, which leads to faster typing speeds and reduced finger strain. This layout also aims to minimize bigrams that are uncomfortable, promotes finger rolls and hand alternation. Additionally, Colemak retains most of the QWERTY key positions for less frequently used letters, making the transition easier for those already familiar with QWERTY.&lt;/p&gt;
&lt;p&gt;Original Colemak was created in 2006 with computational assistance. Colemak Mod-DH is a minor patch to Colemak which discourages lateral movement a bit more, therefore keys &lt;code&gt;D&lt;/code&gt; and &lt;code&gt;H&lt;/code&gt; are moved. I find this to be the right thing to do.&lt;/p&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_colemak-dh-base-effort.7316b9fbf65f86e96901dcec9f18844b07f42fd4f5483d8d8bfa07725a515162.png"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_colemak-dh-base-effort.7316b9fbf65f86e96901dcec9f18844b07f42fd4f5483d8d8bfa07725a515162.png"&gt;&lt;/a&gt;&lt;figcaption&gt;Base effort model, adjusted by colemak-dh&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;This is a short practical review, detailed theory may be found in the &amp;ldquo;Research&amp;rdquo; section.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Punctuation characters&lt;/strong&gt; are derived from Colemak-DH with the following modifications.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[]&lt;/code&gt; swapped with &lt;code&gt;()&lt;/code&gt;, Shift-layered &lt;code&gt;{}&lt;/code&gt; remains untouched&lt;/li&gt;
&lt;li&gt;&lt;code&gt;;&lt;/code&gt; swapped with &lt;code&gt;:&lt;/code&gt; - same key, inverse Shift effect&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;&lt;/code&gt; swapped with &lt;code&gt;'&lt;/code&gt; - same key, inverse Shift effect&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\&lt;/code&gt; moved to former backspace to compensate Action key remap&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am fairly sure in my willingness to promote parentheses, colon and double quotes over their counterparts in all contexts, including programming, casual language and prose. Observations show me that old placement is outdated due to changes in our language - old one really makes sense when you look at texts written a hundred years ago.&lt;/p&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_punctuation-frequency.8f5712e588121a9328daff57af316b94158940a2c147a8096b2ed17e2705c4c0.png"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_punctuation-frequency.8f5712e588121a9328daff57af316b94158940a2c147a8096b2ed17e2705c4c0.png"&gt;&lt;/a&gt;&lt;figcaption&gt;Punctuation character frequency in English&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;Colemak defines the location of Latin alphabetic characters, numbers and a few punctuation signs, nothing more. It is understandable since the layout aims to be universal. I have considered various Colemak modes that cover different locales, special characters and action keys, but they all lack thoroughness and background that makes base Colemak great. That&amp;rsquo;s the reason for me to continue modding further.&lt;/p&gt;
&lt;h3 id="special-symbol-keys"&gt;Special symbol keys&lt;/h3&gt;
&lt;p&gt;At first I wanted to generate the optimized symbol layout programmatically with some genetic algorithm at its core. However, such a layout would lack important properties, such as semantic key grouping and positional meaning of keys. In a typical computer-generated layout position of one specific key is pseudo-random and uncontrollable, it means nothing separated from exact training set and full list of keys. Any correction in the generation process or data rearranges all keys unpredictably.&lt;/p&gt;
&lt;p&gt;I am convinced that symbols, unlike alphabetic characters, &lt;strong&gt;keep some value hidden in their relative position&lt;/strong&gt;, and that value is not limited to learning or memorizing, but lies in usage in general. A certain position fits mental model behind the keys better. For example, &amp;lt;= and =&amp;gt; need movements that look similar, left brace needs to be the left one physically, and such patterns should be consistent across all paired signs. That&amp;rsquo;s why keys should be arranged manually. You may find the result below.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; | 1 2 3 4 5 6 7 8 9 10 11 12 13 14
------------------------------------------------------------
AA | * 1 2 3 4 5 6 7 8 9 0 - = \
AB | ` # ~ ! $ ^ % [ ] &amp;lt; &amp;gt; + = @
BA | : ( )
BB | ; { }
CA | &amp;#34;
CB | &amp;#39;
DA | , . / 
DB | | &amp;amp; ?
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Looks good? Here is how it was made.&lt;/p&gt;
&lt;p&gt;Step 1. &lt;strong&gt;Tokenize - group keys that are used together as one operator.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here is my list of tokens:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generic punctuation: &lt;code&gt;.&lt;/code&gt; &lt;code&gt;,&lt;/code&gt; &lt;code&gt;-&lt;/code&gt; &lt;code&gt;:&lt;/code&gt; &lt;code&gt;;&lt;/code&gt; &lt;code&gt;?&lt;/code&gt; &lt;code&gt;!&lt;/code&gt; &lt;code&gt;#&lt;/code&gt; &lt;code&gt;%&lt;/code&gt; &lt;code&gt;$&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Enclosure: &lt;code&gt;()&lt;/code&gt; &lt;code&gt;[]&lt;/code&gt; &lt;code&gt;{}&lt;/code&gt; &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; &lt;code&gt;''&lt;/code&gt; &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; &lt;code&gt;``&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Logical: &lt;code&gt;!&lt;/code&gt; &lt;code&gt;&amp;lt;&lt;/code&gt; &lt;code&gt;&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;lt;=&lt;/code&gt; &lt;code&gt;&amp;gt;=&lt;/code&gt; &lt;code&gt;==&lt;/code&gt; &lt;code&gt;||&lt;/code&gt; &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; &lt;code&gt;??&lt;/code&gt; &lt;code&gt;|&lt;/code&gt; &lt;code&gt;&amp;amp;&lt;/code&gt; &lt;code&gt;!!&lt;/code&gt; &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Arithmetic: &lt;code&gt;+&lt;/code&gt; &lt;code&gt;-&lt;/code&gt; &lt;code&gt;*&lt;/code&gt; &lt;code&gt;/&lt;/code&gt; &lt;code&gt;.&lt;/code&gt; &lt;code&gt;^&lt;/code&gt; &lt;code&gt;=&lt;/code&gt; &lt;code&gt;+=&lt;/code&gt; &lt;code&gt;-=&lt;/code&gt; &lt;code&gt;*=&lt;/code&gt; &lt;code&gt;/=&lt;/code&gt; &lt;code&gt;++&lt;/code&gt; &lt;code&gt;--&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Figures: &lt;code&gt;=&amp;gt;&lt;/code&gt; &lt;code&gt;-&amp;gt;&lt;/code&gt; &lt;code&gt;:)&lt;/code&gt; &lt;code&gt;:(&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Programming: &lt;code&gt;~/&lt;/code&gt; &lt;code&gt;::&lt;/code&gt; &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; &lt;code&gt;${}&lt;/code&gt; &lt;code&gt;$()&lt;/code&gt; &lt;code&gt;/*&lt;/code&gt; &lt;code&gt;*/&lt;/code&gt; &lt;code&gt;//&lt;/code&gt; &lt;code&gt;&amp;lt;--&lt;/code&gt; &lt;code&gt;&amp;lt;/&lt;/code&gt; &lt;code&gt;@&lt;/code&gt; &lt;code&gt;\&lt;/code&gt; &lt;code&gt;&amp;amp;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Step 2. &lt;strong&gt;Find usage patterns for each token.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;My layout was formed by a trial-and-error method and I do not remember them all, but these observations come to my mind now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Special keys are not so frequent.&lt;/li&gt;
&lt;li&gt;All of them are usually placed near Space. Punctuation keys have space on the right side&lt;/li&gt;
&lt;li&gt;Arithmetic, logical and enclosure sequences reside near numbers&lt;/li&gt;
&lt;li&gt;Number is likely from the left side (our numeric system works in a way that leading digit is likely to be small)&lt;/li&gt;
&lt;li&gt;Semicolon seldom follows space. In computer contexts, it often follows enclosure&lt;/li&gt;
&lt;li&gt;Logical tokens are often enclosed&lt;/li&gt;
&lt;li&gt;Escape token is usually used with other tokens&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Step 3. &lt;strong&gt;Determine token frequency and arrange keys.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ideally tokens of one group should reside near each other. Token itself must be easy to type. Common combinations with token must be easy to type. In practice,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Base layer is better than Shift layer&lt;/li&gt;
&lt;li&gt;Token should not be on the Shift layer partially&lt;/li&gt;
&lt;li&gt;The close to middle finger on the home row the better&lt;/li&gt;
&lt;li&gt;Inward roll is better than outward roll which is better than no roll at all&lt;/li&gt;
&lt;li&gt;Two-hand movement is better than one hand movement with large distance&lt;/li&gt;
&lt;li&gt;Double-tapped keys should not be assigned to pinky&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Theory above is abstracted from character frequency, you can reuse it with your own data. I recommend running a keylogger to analyze that frequency and then applying trial-and-error method until you find the best placement. It&amp;rsquo;s not so hard since number of good combinations is fairly low. Basically we have very strong bigrams and a few well-accessible keys. The best effect will probably come from keys D9-D11, A2-A4, A7-A13.&lt;/p&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_programming-special-char-frequency.5e46c5a54199e43f4a3d71a7c8c026bd853345e79f16c007cf3eb0dbbbd50d22.png"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_programming-special-char-frequency.5e46c5a54199e43f4a3d71a7c8c026bd853345e79f16c007cf3eb0dbbbd50d22.png"&gt;&lt;/a&gt;&lt;figcaption&gt;Special character frequency in programming languages&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;I would like to emphasize the promotion of characters &lt;code&gt;~&lt;/code&gt; &lt;code&gt;!&lt;/code&gt; &lt;code&gt;|&lt;/code&gt; &lt;code&gt;&amp;amp;&lt;/code&gt; &lt;code&gt;:&lt;/code&gt; &lt;code&gt;&amp;quot;&lt;/code&gt;, making &lt;code&gt;=&lt;/code&gt; independent from Shift, placing &lt;code&gt;_&lt;/code&gt; on Space and moving &lt;code&gt;*&lt;/code&gt; to the base layer on the left for good bigrams. In my opinion, all listed tokens are covered really well and the list itself says enough about key placement.&lt;/p&gt;
&lt;h3 id="russian-keys"&gt;Russian keys&lt;/h3&gt;
&lt;p&gt;The Russian layout matches the English one phonetically whenever possible. It uses the same amount of keys, keeps special character positions constant, and offloads some keys to the &lt;strong&gt;AltGr&lt;/strong&gt; layer.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Yurmak-RU layout

 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14
------------------------------------------------------------
AA | * 1 2 3 4 5 6 7 8 9 0 - = \
AB | ` # ~ ! $ ^ % [ ] &amp;lt; &amp;gt; + = @
 |
BA | ESC ь ы ф п б ж л у я : ( ) BSP
BB | ESC Ь Ы Ф П Б Ж Л У Я ; { } BSP
 |
CA | CPS а р с т Г М Н Е И О &amp;#34; RET
CB | CPS А Р С Т Г М Н Е И О &amp;#39; RET
 |
DA | SHF ч ц д в з к х , . / TAB
DB | Ч Ц Д В З К Х | &amp;amp; ? TAB
 |
EA | CTL SUP AGR SPC ALT RCT 
EB | CTL SUP ARG _ ALT RCT 
--------------------------------------------------------------
column header - horizontal key position 
row header, letter 1 - vertical position, top to bottom
row header, letter 2, A - no modifier
row header, letter 2, B - Shift modifier
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;XKB config may be found &lt;a href="https://git.yrz.am/yrzam/workspace/src/branch/main/arch-user/config/xkb/symbols/ru"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why phonetic layout?&lt;/strong&gt; Well, I think that should always have been the standard for people that use multiple layouts, one of which is primary. Placing letters that produce the same sound, look exactly the same, and have similar usage patterns, in different places, as well as introducing excessive modality of special keys, is pure absurd. It is hard to learn, doesn&amp;rsquo;t scale and gives bad usability for the ordinary user. One fair advantage is that it opens up the possibility to micro-optimize key positions for the target language, but, firstly, such possibility is historically not used (one layout is almost always not-so-optimal QWERTY), and secondly, it can be done only at some constant mental cost, so the entire thing is questionable.&lt;/p&gt;
&lt;p&gt;Mapping summary:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Direct equivalents: &lt;code&gt;ф&lt;/code&gt; &lt;code&gt;п&lt;/code&gt; &lt;code&gt;б&lt;/code&gt; &lt;code&gt;ж&lt;/code&gt; &lt;code&gt;л&lt;/code&gt; &lt;code&gt;у&lt;/code&gt; &lt;code&gt;а&lt;/code&gt; &lt;code&gt;р&lt;/code&gt; &lt;code&gt;с&lt;/code&gt; &lt;code&gt;т&lt;/code&gt; &lt;code&gt;г&lt;/code&gt; &lt;code&gt;м&lt;/code&gt; &lt;code&gt;н&lt;/code&gt; &lt;code&gt;е&lt;/code&gt; &lt;code&gt;и&lt;/code&gt; &lt;code&gt;о&lt;/code&gt; &lt;code&gt;д&lt;/code&gt; &lt;code&gt;в&lt;/code&gt; &lt;code&gt;з&lt;/code&gt; &lt;code&gt;к&lt;/code&gt; &lt;code&gt;х&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Approximations: &lt;code&gt;q&lt;/code&gt;-&amp;gt;&lt;code&gt;ь&lt;/code&gt;, &lt;code&gt;w&lt;/code&gt;-&amp;gt;&lt;code&gt;ы&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;-&amp;gt;&lt;code&gt;я&lt;/code&gt;, &lt;code&gt;x&lt;/code&gt;-&amp;gt;&lt;code&gt;ч&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;-&amp;gt;&lt;code&gt;ц&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Second layer: &lt;code&gt;ь&lt;/code&gt;-&amp;gt;&lt;code&gt;ъ&lt;/code&gt;, &lt;code&gt;:&lt;/code&gt;-&amp;gt;&lt;code&gt;ш&lt;/code&gt;, &lt;code&gt;(&lt;/code&gt;-&amp;gt;&lt;code&gt;щ&lt;/code&gt;, &lt;code&gt;&amp;quot;&lt;/code&gt;-&amp;gt;&lt;code&gt;э&lt;/code&gt;, &lt;code&gt;,&lt;/code&gt;-&amp;gt;&lt;code&gt;ю&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As Yurmak is English-centric, base layout has 26 keys. Almost all of these keys sound the same in English and in Russian. Non-matching and infrequent keys were evicted to the second layer, to the top of either naturally paired character or punctuation sign. One lucky fact is that in Cyrillic and Latin languages similar characters also have similar bigrams and comparable usage frequency, so our phonetical arrangement greatly benefits from optimizations made into Colemak.&lt;/p&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_russian-char-frequency.85b4b4516c9213e2c8642cb1eebd4afd98d2b1b66bf6ec70061f1cc70a84663f.png"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_russian-char-frequency.85b4b4516c9213e2c8642cb1eebd4afd98d2b1b66bf6ec70061f1cc70a84663f.png"&gt;&lt;/a&gt;&lt;figcaption&gt;Russian character frequency in fiction&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code&gt;ш&lt;/code&gt;, &lt;code&gt;щ&lt;/code&gt;, &lt;code&gt;э&lt;/code&gt;, &lt;code&gt;ю&lt;/code&gt; positioning was inspired by ЙЦУКЕН but changed to the edge of the current alpha layer.&lt;/p&gt;
&lt;p&gt;One might say that the entire two-layer system is suboptimal, but that&amp;rsquo;s the trade-off to keep efficiency overall. If Russian layout was more important, I would still keep phonetic principle, but use Cyrillic characters as the base. Moreover, new languages can be rapidly added and adopted - you already know position of their keys since languages share many sounds.&lt;/p&gt;
&lt;h3 id="modal-remapping"&gt;Modal remapping&lt;/h3&gt;
&lt;p&gt;Many programs use standard shortcuts for left-right-up-down paradigm. Since &lt;strong&gt;HJKL&lt;/strong&gt; and &lt;strong&gt;WASD&lt;/strong&gt; are now broken, a new, unified way is proposed:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;N E I O
LEFT DOWN UP RIGHT
index middle ring little
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;NEIO&lt;/strong&gt; are on the home row under fingers by default. &lt;code&gt;E&lt;/code&gt; is down, &lt;code&gt;I&lt;/code&gt; is up - that&amp;rsquo;s because down is more frequent since user usually starts at the top, and &lt;code&gt;E&lt;/code&gt; is easier to press.&lt;/p&gt;
&lt;p&gt;In apps with vim-like keybinds, HJKL keys are now free, so we can do a circle remap in a safe and consistent way, and even create new synonymous mnemonics for known actions on the new positions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;H&lt;/code&gt; (previously &lt;strong&gt;O&lt;/strong&gt; aka Open) - &lt;strong&gt;Hatch&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;J&lt;/code&gt; (previously &lt;strong&gt;E&lt;/strong&gt; aka End) - &lt;strong&gt;Jump&lt;/strong&gt; [forward]&lt;/li&gt;
&lt;li&gt;&lt;code&gt;K&lt;/code&gt; (previously &lt;strong&gt;N&lt;/strong&gt; aka Next) - &lt;strong&gt;Key&lt;/strong&gt; [point]&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L&lt;/code&gt; (previously &lt;strong&gt;I&lt;/strong&gt; aka Insert) - &lt;strong&gt;Lay&lt;/strong&gt;, visual mnemonic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Search and Insert (&lt;code&gt;K&lt;/code&gt; and &lt;code&gt;L&lt;/code&gt;) handle common actions as they&amp;rsquo;re very easy to reach, &lt;code&gt;H&lt;/code&gt; is a bit less loaded, &lt;code&gt;J&lt;/code&gt; is the rest.&lt;/p&gt;
&lt;p&gt;Sometimes, movement is three-dimensional, for such cases, there is an extended version:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;M &amp;#34;
FORWARD/ZOOM-IN BACKWARD/ZOOM-OUT
proxiMity
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="iso-layout"&gt;ISO layout&lt;/h3&gt;
&lt;p&gt;The proposed layout does not have an exact ISO variant, however, I&amp;rsquo;ve used such keyboards enough and am willing to share some ideas. ISO keyboards have an extra key near &lt;strong&gt;Left Shift&lt;/strong&gt; and move one key from the top of &lt;strong&gt;Enter&lt;/strong&gt; to the home row. Here is how authors of Colemak-DH think keys should be arranged:&lt;/p&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_colemak-dh-iso.d7d9725bc01036b82872113ace4e777ddde78dec284d125f786d99dc8393a863.png"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_colemak-dh-iso.d7d9725bc01036b82872113ace4e777ddde78dec284d125f786d99dc8393a863.png"&gt;&lt;/a&gt;&lt;figcaption&gt;ISO variant of Colemak-DH&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;My criticism:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The new key on the home row is ideal for &lt;code&gt;Backspace&lt;/code&gt;, not &lt;code&gt;#&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The extra key should better be dedicated to some modifier (possibly &lt;code&gt;AltGr&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The extra key could be moved to the left, so that &lt;code&gt;Z&lt;/code&gt; keeps its central place (not sure, didn&amp;rsquo;t test much)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="phones"&gt;Phones&lt;/h3&gt;
&lt;p&gt;I use Unexpected Keyboard on my Android phone. It is a free highly-customizable keyboard that replace long taps with swiping keys towards the corners.&lt;/p&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_unexpected-keyboard.a1ca55ed68105e67beb907778ee06fda9a684cca6cfc787bf5fd5b6f923857d5.jpg"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_unexpected-keyboard.a1ca55ed68105e67beb907778ee06fda9a684cca6cfc787bf5fd5b6f923857d5.jpg"&gt;&lt;/a&gt;&lt;figcaption&gt;Unexpected keyboard, YURMAK&lt;/figcaption&gt;&lt;/figure&gt;

&lt;blockquote&gt;
&lt;p&gt;Config files: &lt;a href="https://git.yrz.am/yrzam/workspace/src/branch/main/android/config/unexpected-keyboard/en.xml"&gt;English&lt;/a&gt;, &lt;a href="https://git.yrz.am/yrzam/workspace/src/branch/main/android/config/unexpected-keyboard/ru.xml"&gt;Russian&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;The alphabetic layout is ported literally&lt;/strong&gt; with the base of 26 characters. On phones, typing is different - people type with two fingers and central position is the best one. This contradicts the principles behind Colemak and is suboptimal, but I value this unification more than benefits that separation of layouts could give. If this sounds irrational, imagine what happens if &amp;ldquo;the most optimal&amp;rdquo; layout is chosen every time. By now, we would have 4 completely different layouts (two per language) instead of just one. The effective power of learning and practice would be divided by 4 because we can use only one layout at a time. Situational ergonomics won&amp;rsquo;t outplay the dense practice given by one unified layout.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Keyboard is narrow&lt;/strong&gt; to keep keys larger thus easier to hit, otherwise, the keyboard is really hard to use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Middle row is elevated&lt;/strong&gt; compared to standard phone QWERTY layouts to enhance reachability. Previously, the top row was more convenient, containing 10 characters versus the middle row’s 9. In Yurmak, the home row holds more characters than the top row, requiring fingers to rest closer to it. This is achieved through margins and strategic positioning of the number row.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Digits are moved to the bottom row&lt;/strong&gt; to save precious screen space and elevate other characters. From the ergonomic point of view, this is essentially a boost to content visibility, because alphabetic keys must be positioned high enough, yet screen space is too valuable to place digits at the top of them.&lt;/p&gt;
&lt;p&gt;Introduced &lt;code&gt;Ctrl&lt;/code&gt; and &lt;code&gt;Esc&lt;/code&gt; which are very useful for console applications (yes, I use vim over ssh on the phone). They get not-too-prominent but still convenient positions on the bottom row.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;CTL ESC SPC RET BSP
1 2 3 4 5 6 7 8 9 0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Special keys&lt;/strong&gt; had to be rearranged. I&amp;rsquo;ve tried to do it in a consistent manner, preserving relative grouping as much as possible.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unstable: position of special keys is not perfect and may change in the future.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Keyboard has fewer keys horizontally than before&lt;/strong&gt; -&amp;gt; Excessive keys got their place on the second layer of the top row.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relocation of digits broke bigrams with them&lt;/strong&gt; -&amp;gt; Special keys that are used with numbers frequently have been moved to the bottom.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gestures introduced more space on the home row&lt;/strong&gt; -&amp;gt; Other characters from the top row moved to the home row due to its enhanced reachability.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;For Russian&lt;/strong&gt;, the layout is still based on 26 keys so we can reuse muscle memory, which means that 7 keys get evicted to the second layer. The location of some of them is slightly changed since phone keyboard benefits from reduced width, but their relative position is preserved.&lt;/p&gt;
&lt;h2 id="thoughts-and-observations"&gt;Thoughts and observations&lt;/h2&gt;
&lt;h3 id="learning-process"&gt;Learning process&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Plan.&lt;/strong&gt; Mastering new layout may be complicated and overwhelming at the beginning. One may follow stages below to facilitate the progress.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Evaluate ergonomics, get familiar with new movements&lt;/li&gt;
&lt;li&gt;Memorize the order the of keys verbally&lt;/li&gt;
&lt;li&gt;Train on a website like &lt;a href="https://monkeytype.com/"&gt;monkeytype&lt;/a&gt; until ~15 wpm&lt;/li&gt;
&lt;li&gt;Introduce new layout as another option, use it when ethically and functionally appropriate until you reach some degree of comfort&lt;/li&gt;
&lt;li&gt;Switch fully&lt;/li&gt;
&lt;li&gt;Practice further&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Stage 1 took nearly a month of casual research, stages 2-3 lasted two evenings of active practice, stage 4 was on track for three months (could have been a lot quicker, the purpose was not to do short-term harm to my occupation). After three more months, typing became fluent and unnoticeable. In total, it took me 8-10 months to master the new layout and surpass initial QWERTY experience across all metrics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;More than just a layout.&lt;/strong&gt; It was hard to get used to a new keyboard layout. But that&amp;rsquo;s not the case anymore - now I can adopt new layouts much easier (tested on Dvorak). If you were on the same track but left, you may overestimate future difficulty assuming further progress will be as hard as the first attempt. More importantly, your understanding of ergonomics and physical conditions gets boosted. Mine went from complete ignorance to a firm grasp on comfort of keys, bigrams, movements - what exactly is unergonomic and how to improve it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Diminishing returns.&lt;/strong&gt; Switching has a cost. Firstly, it requires some dedication, secondly, it inevitably slows down typing for some time. Such a pivot in the learning path nullifies further improvements in the current flow and partially invalidates efforts made towards it (so-called Principle of Increasing Marginal Switching Costs). Imagine you were on path A and know that path B is more optimal. However, in order to get onto B you must start from the beginning. From the marginal cost perspective, every step you make on path A decreases the profit you get from switching to path B. Moreover, each subsequent chance by itself is usually less valuable (Optimization Plateau). At some point, there is no more reason to switch paths at all. In our case:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One should change layout only if this leads to a significant improvement.&lt;/li&gt;
&lt;li&gt;One should change layout as early as possible, if they ever will.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_diminishing-returns.cd57ce8773f2b377cfa1fb570a7c7a0933b7b0809f817267fcbeee6b43890c01.png"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_diminishing-returns.cd57ce8773f2b377cfa1fb570a7c7a0933b7b0809f817267fcbeee6b43890c01.png"&gt;&lt;/a&gt;&lt;/figure&gt;

&lt;p&gt;A methodology to estimate this would have to account for lots of variables and marginal factors, producing questionable conclusions. Although the approximation can definitely be done: after initial switch, amount of spent effort is in inverse proportion to the benefits given by the further effort. Surely, transition from QWERTY to an ergonomic layout is beneficial in most cases, but switching between Colemak, Dvorak, Workman, CarpalX layouts in favor of minor ergonomic gains may be suboptimal.&lt;/p&gt;
&lt;h3 id="software-support"&gt;Software support&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Software support is good, but deviation from the standard is still a liability.&lt;/strong&gt; Operating systems have an &amp;lsquo;input layer&amp;rsquo; that abstracts printed symbols from their physical position. Almost all applications take these symbols as their input, leaving key placement up to the user. Such a model works well with both local and remote destinations in a consistent, predictable manner - keys are just moved to the new locations. Shortcuts are remapped too.&lt;/p&gt;
&lt;p&gt;But how do designers assign symbols to actions? Hopefully, they don&amp;rsquo;t roll the dice but express either semantic or positional meaning. Examples of semantic-based assignment are &lt;strong&gt;d&lt;/strong&gt; for delete, &lt;strong&gt;p&lt;/strong&gt; for paste, &lt;strong&gt;go&lt;/strong&gt; for go, etc. Due to the fact that semantics is linked to the language, in our case these keys get even more convenient positions, as the layout is heavily optimized for the general-purpose English. Positional assignment, on the contrary, is problematic, because keys lose the desired placement. WASD and HJKL are great examples. First line of defense is application itself mapping to physical keys (although that&amp;rsquo;s very rare), second is partial compatibility provided by Colemak, and anything further requires key remapping.&lt;/p&gt;
&lt;p&gt;Imagine remapping movement keys over SSH for the root account that is also used by colleagues, mounting configuration files into containers, writing patches for programs that have mappings hardcoded (and compiling them). Imagine hacking this on a proprietary window manager for proprietary software. Fixing conflicts with semantic mapping and other things. My solution is to use good software and minimize remapping as much as possible (I remap only 4 positional keys in a way consistent across programs). In general, this stuff is solvable but requires some deliberation. You can find my approach to configuration roaming &lt;a href="https://yrz.am/posts/wscompat/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="alternatives-considered"&gt;Alternatives considered&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Extra layers.&lt;/strong&gt; Previous versions had a third layer for navigation, numbers and special characters. After lots of attempts to improve it coupled with extensive practice, I am sure it should not be used. A frequently used layer creates massive physical and mental overhead. This overhead grows exponentially with the number of layers. See an example:&lt;/p&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_colemak-mod-ergonomic.02ce1d312a62d85f8e780b9658fc855c22b2da411935c6a2f100877c7c6f677b.png"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_colemak-mod-ergonomic.02ce1d312a62d85f8e780b9658fc855c22b2da411935c6a2f100877c7c6f677b.png"&gt;&lt;/a&gt;&lt;figcaption&gt;Colemak ergonomic mod&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;In my layout it&amp;rsquo;s even worse: the optimal location is under the thumb key, but that key on ANSI keyboard is very uncomfortable for frequent use. No unneeded layers should be introduced. The original ideas come down to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Navigation&lt;/strong&gt; - modal workflow&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Numbers - base layer.&lt;/strong&gt; 1cm finger movement is not worth another key press, especially in combos&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Special characters&lt;/strong&gt; - shift layer. Small movement is a good sacrifice compared to the introduction of another modifier (imagine alternating these keys!).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Shuffling number keys&lt;/strong&gt;. Keys on the number row have different reachability (and that&amp;rsquo;s even baked into our symbol layer), maybe digits should be rearranged in a similar manner, in accordance with Benford&amp;rsquo;s law? Actually, ancestor of Colemak, the original Dvorak layout, did that. The interesting part is that ANSI did not include this aspect in their standard of Dvorak, and when people refer to Dvorak, they usually mean the ANSI version, with sequential number placement. Although a popular mod - &lt;strong&gt;Programmer Dvorak&lt;/strong&gt; - brings this feature back.&lt;/p&gt;

&lt;figure&gt;
 &lt;a href="https://yrz.am/posts/keyboard-layout/_programmer-dvorak.2f72f4cf6bbcfb255140713e7a26925f7043321ba2b1f35a7ff2a8ed865e9f21.png"&gt;&lt;img src="https://yrz.am/posts/keyboard-layout/_programmer-dvorak.2f72f4cf6bbcfb255140713e7a26925f7043321ba2b1f35a7ff2a8ed865e9f21.png"&gt;&lt;/a&gt;&lt;figcaption&gt;Programmer Dvorak layout&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;I&amp;rsquo;ve tried to do the same, but for me it does not feel right. Months of practice did not make it convenient, so the sequential placement is kept unchanged.&lt;/p&gt;
&lt;h3 id="outcome"&gt;Outcome&lt;/h3&gt;
&lt;p&gt;I am pleased with my decision to move from QWERTY / йцукен. Goals were achieved, now the progression path is better than it could be.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No way back.&lt;/strong&gt; Old layouts are forgotten. Locating necessary keys on them requires a lot of effort and is very slow. Punctuation keys that did not have a constant place are particularly difficult to find. However, I am sure I can remember and keep all layouts in my head if needed.&lt;/p&gt;
&lt;h2 id="research"&gt;Research&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;This chapter is unfinished and will be updated over time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;All practical things have been stated above. Feel free to skip this chapter if you&amp;rsquo;re not interested in the theory behind keyboard layouts.&lt;/p&gt;
&lt;h3 id="metrics"&gt;Metrics&lt;/h3&gt;
&lt;p&gt;The key principle in building a layout is to define a &lt;strong&gt;cost function that quantifies typing effort&lt;/strong&gt;. It should reproducibly give an &amp;ldquo;effort score&amp;rdquo; for every provided block of text. After that, a target corpus of texts must be defined. The layout with lowest effort score for that corpus shall be considered the most optimal. Defining such a function is a non-trivial task as it should precisely represent biomechanical factors faced by the user.&lt;/p&gt;
&lt;p&gt;Modern ergonomic models are built upon the core metrics pioneered by &lt;strong&gt;August Dvorak&lt;/strong&gt;. Dvorak was the first to establish formally rigorous principles for evaluating keyboard efficiency based on human factors, targeting speed, accuracy, and fatigue reduction, in his book &amp;ldquo;Typewriting Behavior: Psychology Applied to Teaching and Learning Typewriting&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Below you can find a list of high-level metrics used across popular models.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Character Frequency.&lt;/strong&gt; More frequent characters have a greater impact on the total score because their associated penalties (from other metrics) are incurred more often. The goal is to place high-frequency characters in low-penalty positions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Travel Distance.&lt;/strong&gt; This metric quantifies the total distance fingers travel to press keys. It measures the path length from a finger&amp;rsquo;s resting position (or previous key position) to the target key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Row Penalty.&lt;/strong&gt; Keystrokes on rows other than the home row should incur a penalty. The home row is considered the most comfortable and efficient. The penalty increases based on the distance from the home row.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Column Penalty.&lt;/strong&gt; Some models might incorporate penalties for awkward reaches to certain columns, especially considering the traditional physical stagger of keyboard columns. For example, keys directly above or below the home row position on the same finger might have different penalties than those involving a slight diagonal reach.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Base Finger Penalty.&lt;/strong&gt; This metric assigns different base effort scores to different fingers, expressing that some fingers are stronger and more agile than others. Typically, pinkies and sometimes ring fingers are assigned higher base penalties than index or middle fingers. It also aims to distribute work relatively evenly and avoid overloading any single finger.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Finger Fatigue Penalty.&lt;/strong&gt; Movements are not atomic - there is much &amp;ldquo;inertia&amp;rdquo; in them. In fact, every movement leaves a trace that has an impact on dozens of following keystrokes. This model tries to estimate such a factor - it computes fatigue rate based on movements performed by the affected muscles and their recovery model.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Same-Finger Repetition Penalty in Unigrams and Multigrams.&lt;/strong&gt; This is a significant penalty applied when the same finger is used to type consecutive characters. It is inefficient and fatiguing. Metric is aimed at improving finger alternation and moving repetition to fingers that can handle it better.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hand Alternation:&lt;/strong&gt; This metric evaluates switching between hands for consecutive keystrokes. Typing sequences that alternate hands is generally faster, more rhythmic, and has more potential for parallelization.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Same Finger Unigram Penalty&lt;/strong&gt; is applied for pressing the same key twice or more consecutively with the same finger (unavoidable in alpha layouts, also relevant for special keys and digits).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Same-finger Multigram Penalty&lt;/strong&gt; is applied for pressing two or more different keys consecutively with the same finger. Typically, the problem is caused by the urgent need to reposition that finger.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Inward vs Outward Rolls.&lt;/strong&gt; Certain sequences of finger movements on the same hand are more natural and comfortable. &amp;ldquo;Inward rolls&amp;rdquo; (e.g., typing a sequence from pinky towards index finger on one hand) are generally more preferred than &amp;ldquo;outward rolls&amp;rdquo; (from index towards pinky).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scissors Pattern Penalty.&lt;/strong&gt; Used to express the situation when two adjacent key presses require a twisting motion or cause paths of fingers to cross. Usually this happens because adjacent keys are located on different rows horizontally close to each other (examples in QWERTY: &lt;code&gt;ex&lt;/code&gt;, &lt;code&gt;rc&lt;/code&gt;, combinations with modifiers).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Redirects vs Bad redirects.&lt;/strong&gt; Redirects are trigrams where all keys are pressed by the same hand, but the second key press is in the opposite direction (left/right or up/down) from the first and the third. Bad redirects are instances of redirects that cause even more inefficient and uncomfortable hand movements, typically because they do not use index finger. Bad redirects should be penalized more.&lt;/p&gt;
&lt;p&gt;Uncommon metric, introduced in this post, is &lt;strong&gt;Semantic correlation&lt;/strong&gt;. Layout operates on a stream of characters, and humans perceive this stream differently due to inherent cognitive properties. Unlike simulated outputs, the human brain generates characters at a variable pace and employs specialized grammar-level encoding. A key example is character grouping using well-known separators, such as spaces or dots, accompanied by pauses between groups. This logic extends to word endings, suffixes, and other linguistic units. The core assumption is that layout design must account for the intensity of morphologic and lexical token streams.&lt;/p&gt;
&lt;h3 id="automated-layout-generators"&gt;Automated layout generators&lt;/h3&gt;
&lt;p&gt;To be continued&amp;hellip;&lt;/p&gt;
&lt;h3 id="gathered-dataset"&gt;Gathered dataset&lt;/h3&gt;
&lt;p&gt;To be continued&amp;hellip;&lt;/p&gt;
&lt;h3 id="adjusting-cost-function"&gt;Adjusting cost function&lt;/h3&gt;
&lt;p&gt;To be continued&amp;hellip;&lt;/p&gt;
&lt;h3 id="running-simulation"&gt;Running simulation&lt;/h3&gt;
&lt;p&gt;To be continued&amp;hellip;&lt;/p&gt;
&lt;h3 id="useful-links"&gt;Useful links&lt;/h3&gt;
&lt;p&gt;Papers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://archive.org/stream/in.ernet.dli.2015.74878/2015.74878.Typewriting-Behavior-Psychology-Applied-To-Teaching-And-Learning-Typewriting_djvu.txt"&gt;https://archive.org/stream/in.ernet.dli.2015.74878/2015.74878.Typewriting-Behavior-Psychology-Applied-To-Teaching-And-Learning-Typewriting_djvu.txt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reference layouts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://colemakmods.github.io/mod-dh/"&gt;https://colemakmods.github.io/mod-dh/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://colemakmods.github.io/ergonomic-mods/symbols.html"&gt;https://colemakmods.github.io/ergonomic-mods/symbols.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://forum.colemak.com/"&gt;https://forum.colemak.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Utilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mk.bcgsc.ca/carpalx/"&gt;https://mk.bcgsc.ca/carpalx/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/O-X-E-Y/oxeylyzer"&gt;https://github.com/O-X-E-Y/oxeylyzer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/xsznix/keygen"&gt;https://github.com/xsznix/keygen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/semilin/genkey"&gt;https://github.com/semilin/genkey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pranphy/KeyboardHeatmap"&gt;https://github.com/pranphy/KeyboardHeatmap&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Blog posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://xahlee.info/kbd/keyboard_blog.html"&gt;https://xahlee.info/kbd/keyboard_blog.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://getreuer.info/posts/keyboards/symbol-layer/index.html"&gt;https://getreuer.info/posts/keyboards/symbol-layer/index.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jonashietala.se/blog/2021/06/03/the-t-34-keyboard-layout/"&gt;https://www.jonashietala.se/blog/2021/06/03/the-t-34-keyboard-layout/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/m0rtyn/martynak"&gt;https://github.com/m0rtyn/martynak&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Datasources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.researchgate.net/publication/328512136_Frequency_Distributions_of_Punctuation_Marks_in_English_Evidence_from_Large-scale_Corpora"&gt;https://www.researchgate.net/publication/328512136_Frequency_Distributions_of_Punctuation_Marks_in_English_Evidence_from_Large-scale_Corpora&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://studfile.net/preview/3619128/page:16/"&gt;https://studfile.net/preview/3619128/page:16/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>