<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mika Feiler</title>
    <description>The latest articles on DEV Community by Mika Feiler (@mkf).</description>
    <link>https://dev.to/mkf</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F29550%2F386a57c8-2b28-49a9-944d-a196d55a7191.jpg</url>
      <title>DEV Community: Mika Feiler</title>
      <link>https://dev.to/mkf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mkf"/>
    <language>en</language>
    <item>
      <title>Checking remote authorized_keys without entering key passphrase, done more neatly — and against .ssh/config</title>
      <dc:creator>Mika Feiler</dc:creator>
      <pubDate>Tue, 27 Feb 2024 21:50:33 +0000</pubDate>
      <link>https://dev.to/mkf/checking-remote-authorizedkeys-without-entering-key-passphrase-done-neatly-2nnj</link>
      <guid>https://dev.to/mkf/checking-remote-authorizedkeys-without-entering-key-passphrase-done-neatly-2nnj</guid>
      <description>&lt;p&gt;You have a bunch of client machines with private keys set up to access a bunch of destination hosts. How do you check which of them has them to access which? &lt;em&gt;Maybe you wish for &lt;code&gt;ssh-copy-id&lt;/code&gt; to not ask for key password when you can first check that quicker with &lt;code&gt;ssh&lt;/code&gt; and &lt;code&gt;^C&lt;/code&gt;?&lt;/em&gt;&lt;br&gt;
How does ssh act out&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Enter passphrase for key '/path/to/key': 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;as opposed to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Permission denied (publickey).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While &lt;code&gt;-vvv&lt;/code&gt; (&lt;code&gt;debug3&lt;/code&gt;) shows more, let's see just &lt;code&gt;debug1&lt;/code&gt; (&lt;code&gt;-v&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;debug1: Authentications that can continue: publickey,password,keyboard-interactive
debug1: Next authentication method: publickey
debug1: Will attempt key: /path/to/key ED25519 SHA256:... explicit
debug1: Offering public key: /path/to/key ED25519 SHA256:... explicit
debug1: Server accepts key: /path/to/key ED25519 SHA256:... explicit
Enter passphrase for key '/path/to/key': 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we can clearly just scrape that stderr, seek the debug1 accept or the passphrase prompt, regex the path to key out of the thing.&lt;/p&gt;

&lt;p&gt;Or we can do it neater.&lt;br&gt;
Cockpit Project happened to make a contribution enabling us to use libssh for that: &lt;a href="https://gitlab.com/libssh/libssh-mirror/-/merge_requests/134"&gt;https://gitlab.com/libssh/libssh-mirror/-/merge_requests/134&lt;/a&gt;&lt;br&gt;
— they happened to want to be able to prompt the user for key passphrase only when needed. We've only been having that available in libssh for two years.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ssh_userauth_publickey_auto_get_current_identity&lt;/code&gt; function has to be called in an &lt;code&gt;auth_function&lt;/code&gt; callback, and the value it obtains is the key file path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Besides the &lt;code&gt;auto&lt;/code&gt; mode, even without that it was already possible to check a single key — with the result of the &lt;code&gt;ssh_userauth_try_publickey&lt;/code&gt; function.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Attached is the quick-and-dirty source code for such a utility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// LGPL (c) 2024-02-27 Mika Feiler &amp;lt;m@mikf.pl&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// BUILD: cc -lssh&lt;/span&gt;

&lt;span class="cm"&gt;/*
      This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;
*/&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;libssh/libssh.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;libssh/callbacks.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;ssh_session&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;leave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;_echo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;_verify&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="n"&gt;rc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssh_userauth_publickey_auto_get_current_identity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Thanks, Cockpit Project!&lt;/span&gt;
  &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;leave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;a0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Usage: %s hostname [port [keypath|'' [keyuser [disregardunknownhost]]]]&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;a0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;"This little program uses ssh_userauth_publickey_auto_get_current_identity,"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;"thanks to Cockpit, to offer keys (per config) to host and print out path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;"of one that gets accepted by the host, even if it has a passphrase."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;"This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handle_host_verification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;pass_unknown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;ssh_known_hosts_e&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssh_session_is_known_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;SSH_KNOWN_HOSTS_UNKNOWN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pass_unknown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;SSH_KNOWN_HOSTS_OK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;default:&lt;/span&gt;
    &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssh_new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;verbosity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SSH_LOG_WARNING&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;ssh_options_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SSH_OPTIONS_LOG_VERBOSITY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;verbosity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;ssh_options_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SSH_OPTIONS_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="n"&gt;ssh_options_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SSH_OPTIONS_PORT_STR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"22"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;rc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssh_connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;SSH_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;handle_host_verification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// will allow unknown host with one more arg&lt;/span&gt;

  &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ssh_callbacks_struct&lt;/span&gt; &lt;span class="n"&gt;callbacks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth_function&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="c1"&gt;// As per test example for ssh_userauth_publickey_auto_get_current_identity !&lt;/span&gt;

  &lt;span class="n"&gt;ssh_set_blocking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// "User SHOULD be NULL" lol&lt;/span&gt;
  &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// if key path specified&lt;/span&gt;
    &lt;span class="n"&gt;ssh_key&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssh_key_new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;rc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssh_pki_import_pubkey_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;SSH_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;rc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssh_userauth_try_publickey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;leave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// the cool behavior doing .ssh/config :3&lt;/span&gt;
    &lt;span class="n"&gt;ssh_callbacks_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;callbacks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ssh_set_callbacks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;callbacks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;rc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssh_userauth_publickey_auto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;leave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;leave&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;rc&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;leave&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;ssh_disconnect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;ssh_free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;leave&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ssh</category>
      <category>libssh</category>
      <category>devops</category>
      <category>util</category>
    </item>
    <item>
      <title>Manual export from Bard, ChatGPT, MS Copilot</title>
      <dc:creator>Mika Feiler</dc:creator>
      <pubDate>Sat, 03 Feb 2024 16:37:33 +0000</pubDate>
      <link>https://dev.to/mkf/manual-export-from-bard-chatgpt-ms-copilot-g23</link>
      <guid>https://dev.to/mkf/manual-export-from-bard-chatgpt-ms-copilot-g23</guid>
      <description>&lt;p&gt;LLM (GPT et al.) chatbots are a thing hard to perceive as what they are and mostly everyone including me fails that.&lt;/p&gt;

&lt;p&gt;When writing things into them and making them proceed with words that resemble conclusions, we put our cognitive capabilities into the chat, sometimes to the benefit of the reasonings and queries, sometimes to waste.&lt;/p&gt;

&lt;p&gt;And of course they are to become a big leap of the Knowledge Graph platforming to centralize and commercialize our access to knowledge, the Internet, and information processing services. &lt;a href="https://jon-e.net/surveillance-graphs/"&gt;https://jon-e.net/surveillance-graphs/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Either way, what goes into chat mostly stays in the chat, at least for the poor human in from of that outlet. Sometimes, it's almost like a notepad, almost like a log post of one's own, only with all the gibberish answers; so even moreso: It is important to have control over that content at least in the area of personally retaining it without navigating to a platform and staying there to keep everything in one place. The "one place" right for your data is &lt;em&gt;your [rented] place&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR: Bing's Word rate-limited me after lots of manual clicks, Bard was ugly after lots of manual clicks but I remove all divs and imgs with &lt;code&gt;sed&lt;/code&gt;, OpenAI had JSON export alright.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Aside from OpenAI's ChatGPT — which provides a link-to-email export of jsons that you then download from proddatamgmtqueue.blob.core.windows.net — neither Google's Bard nor Microsoft's &lt;del&gt;Bing Chat&lt;/del&gt; Copilot, the two other ones that I use, don't.&lt;/p&gt;

&lt;h1&gt;
  
  
  Microsoft's
&lt;/h1&gt;

&lt;p&gt;There are some mention of Visual Studio Code providing Copilot JSON exports (with a mention of a Python tool to transform them easily into neat plaintext), but I didn't want to bother installing Code in hopes of my non-VisualStudio chats being there.&lt;/p&gt;

&lt;p&gt;I first turned to bing.com/chat, which turned out to just not have my history in a sidebar. Data export features allowed me to export just basic CSVs of my Edge browsing history and of Bing searches.&lt;/p&gt;

&lt;p&gt;That was since I have recently turned away from using MS Copilot on a Windows laptop because of it no longer running Windows, and been using it exclusively on my phone — first in Bing app, then in Edge app, because both are really Edge and both work nasty but Edge has the Bing features run a bit better. The chat in Edge for Android allowed me only to export a screenshot of the whole chat.&lt;/p&gt;

&lt;p&gt;So then I figured to navigate to copilot.microsoft.com and there the past chats sidebar was present. It turned out it allowed me to Export a chat: as plain text, as a PDF, and as a Word document.&lt;/p&gt;

&lt;p&gt;The plain text exports lacked links — with the sources feature being an important output of these chats, that was not acceptable. The plain text exports were downloading normally, as txt files downloading immediately with no disruption.&lt;/p&gt;

&lt;p&gt;I haven't tried PDF exports because I meant to process that text, so I don't know if the links in them are working, but I tried the Word exports. Turns out the Word export immediately saves the file to your OneDrive — which sometimes has a warning that editing the document will outright remove some malformed link URIs — and then opens a Word Online popup for that file.&lt;/p&gt;

&lt;p&gt;When my Firefox started disallowing the popups despite my allowing of them after I made more than a dozen happen by clicking Word export on nearly each of my chats, I had to start going into the blocked popups menu and open them — before Microsoft itself rate-limited me, actually making me unable to even look into those old chats of mine anymore, not even on another device, not even on a different IP.&lt;/p&gt;

&lt;p&gt;The files are all saved in the OneDrive with a name BingAnswers-YYYYMMDD-HHMMSS denoting the time of the export. I promptly turned to downloading them all as a zip in fear that I would soon learn that I got banned from Microsoft Live services for suspected/deemed abuse.&lt;/p&gt;

&lt;h1&gt;
  
  
  Google's
&lt;/h1&gt;

&lt;p&gt;Google Bard didn't show any option of exporting the data through Google Takeout, so I took to just making do with the HTML. Two options were to export from the public links preview and from the regular user panel itself.&lt;/p&gt;

&lt;p&gt;The benefit of the public link option is that all the document gets preloaded outright and also nothing will export your profile picture from the chat section because there it's replaced with an anonymous one. The cons are that for each you need to wait and click through the whole public link creation, the public links will clutter up your public links section, and also the links in the documents might be misleading because they will expire in 6 months or if the user deletes them.&lt;/p&gt;

&lt;p&gt;After at first using the Copy Inner HTML on the &lt;code&gt;share-viewer&lt;/code&gt; tag in the browser's Inspector, I figured it's quicker to just carefully scroll through each whole chat to make sure it all preloads, then take the inner HTML content of the &lt;code&gt;infinite-scroller&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;The results were, of course, cluttered with divs wrappings, and imgs of my profile picture and of a rocket icon. Therefore I turned to some preliminary decluttering of the results through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wl-paste &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; orig.html
pandoc &lt;span class="nt"&gt;-f&lt;/span&gt; html &lt;span class="nt"&gt;-t&lt;/span&gt; html4 orig.html &lt;span class="nt"&gt;-o&lt;/span&gt; result.html
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'/&amp;lt;(div|img)(.*")?$/,/.*&amp;gt;/d'&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'/^&amp;lt;.?(div|img)( [^&amp;gt;]*)?&amp;gt;$/d'&lt;/span&gt; result.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;hatediv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'pandoc -f html -t html4 | sed -E -e '&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;'/&amp;lt;(div|img)(.*")?$/,/.*&amp;gt;/d'&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;' -e '&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;'/^&amp;lt;.?(div|img)( [^&amp;gt;]*)?&amp;gt;$/d'&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;undiv &lt;span class="o"&gt;{&lt;/span&gt;
 wl-paste | hatediv &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  OpenAI's
&lt;/h1&gt;

&lt;p&gt;I have looked into the JSON exports from ChatGPT and they look alright. Haven't yet written myself an XSLT for them, but will sometime soon.&lt;/p&gt;

&lt;p&gt;Apparently one needs to be small enough and focused enough on one product to comply properly with a law.&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>bard</category>
      <category>githubcopilot</category>
      <category>poweruser</category>
    </item>
    <item>
      <title>How I messed up using Git-Annex</title>
      <dc:creator>Mika Feiler</dc:creator>
      <pubDate>Sat, 02 Dec 2023 14:19:23 +0000</pubDate>
      <link>https://dev.to/mkf/how-i-messed-up-using-git-annex-3cm4</link>
      <guid>https://dev.to/mkf/how-i-messed-up-using-git-annex-3cm4</guid>
      <description>&lt;p&gt;I have been using Syncthing for quite a while. There are good reasons for its rapidly gained userbase.&lt;/p&gt;

&lt;p&gt;What ever frustrated me was wanting to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;have it on a Haiku OS machine&lt;/li&gt;
&lt;li&gt;have it easily configurable without the WebUI on older machines where I only had Seamonkey usable&lt;/li&gt;
&lt;li&gt;being able to properly manage the safeguard-versioning&lt;/li&gt;
&lt;li&gt;not have weird conflicts mess things up resulting in there silently being no sync until I'd look at the UI&lt;/li&gt;
&lt;li&gt;be able to easily access even encrypted synchronized-without-trust files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I ended up both creating a repo in my original Syncthing-active directory with all files unlocked and annex.thin set, and adding the directory as a directory importtree&amp;amp;exporttree special remote in Git-annex. I juggled both of these ways trying to achieve what I wanted, synchronizing it with another proper repo as a temporary duplicate.&lt;/p&gt;

&lt;p&gt;That worked for a while, I had a workflow for managing file changes manually post-factum. Until at some point I did something, or not, and suddenly realized all my devices have gotten all files purged from the Syncthing-active directory, and I only have the files in my new proper repo directory.&lt;/p&gt;

&lt;p&gt;And now I am no longer a user of Syncthing. I got migrated. By force — of a mistake of mine.&lt;/p&gt;

&lt;p&gt;I am just still having to figure out the ways of the assistant and the webapp, especially the how to manage the webapp.&lt;/p&gt;

&lt;p&gt;This occurence made me backtrack on some of my prior choices, however. A major problem for me was always not wanting to keep git commiting every small change in a small plaintext-source thing I would be publishing, while wanting it to be in sync as part of a larger bundle of things that I would have. For years already I was resolving to just having such kind of stuff in directories in Syncthing.&lt;/p&gt;

&lt;p&gt;I am now realizing that I should find ways to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;automatically do commits with git, considering I already now let git-annex do that with its assistant (or at least, I intend to). Or at least bundle it up in really properly handy aliases&lt;/li&gt;
&lt;li&gt;start using submodules with git-annex in a way that would have me get that synced between by devices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And let's hope the next time I sit down to a Haiku OS desktop, git-annex will turn out to be packaged or otherwise easy to build.&lt;/p&gt;

</description>
      <category>syncthing</category>
      <category>gitannex</category>
      <category>filesync</category>
      <category>git</category>
    </item>
    <item>
      <title>Once again I wanted to have Emacs be my XML Notepad 2006</title>
      <dc:creator>Mika Feiler</dc:creator>
      <pubDate>Sat, 02 Dec 2023 13:51:38 +0000</pubDate>
      <link>https://dev.to/mkf/once-again-i-wanted-to-have-emacs-be-my-xml-notepad-2006-28hf</link>
      <guid>https://dev.to/mkf/once-again-i-wanted-to-have-emacs-be-my-xml-notepad-2006-28hf</guid>
      <description>&lt;p&gt;XML Notepad from Microsoft, popular since as XML Notepad 2006, and since 2016~2020 having kicked off well as an active MIT-licensed open-source project, is a tool amazing in the simplicity of its basic premise.&lt;/p&gt;

&lt;p&gt;Since I switched back from Windows altogether, I have been seeking to use it again. There is a Wikipedia article titled "Comparison of XML Editors", where Emacs' psgml and xml-mode are mentioned as having Tree editing, and the row mentioning nxml-mode has a question mark.&lt;/p&gt;

&lt;p&gt;Yet nxml-mode has replaced xml-mode in Emacs as a default and not just that, but using the old xml-mode seems hard to do. I had to package-install "psgml" to get that "sgml-show-structure" to be available and it still didn't work.&lt;/p&gt;

&lt;p&gt;I am now trying to write my small XML files with C-c C-i|TAB (nxml-balanced-close-start-tag-inline) and C-c /|C-f (nxml-finish-element), but I got very puzzled as to that C-c C-d bound to nxml-dynamic-markup-word, which doesn't seem to work for me. And M-f keeps moving me just onto the closing tag right angle bracket, from where I have to move with C-M-f or C-f.&lt;/p&gt;

&lt;p&gt;I should probably muscle-memorize the selecting a whole entry, duplicating it before, and removing the content of the content tag. And set nxml-sexp-element-flag to nil.&lt;/p&gt;

&lt;p&gt;A friend has suggested that I use imenu, but it turned out an nxml-mode buffer "cannot use imenu-default-create-index-function".&lt;/p&gt;

</description>
      <category>xml</category>
      <category>emacs</category>
      <category>nonconstructive</category>
      <category>rant</category>
    </item>
    <item>
      <title>'3 Man Chess: In The Round' in APL (NARS2000). Part 1.</title>
      <dc:creator>Mika Feiler</dc:creator>
      <pubDate>Thu, 07 Apr 2022 19:56:32 +0000</pubDate>
      <link>https://dev.to/mkf/3-man-chess-in-the-round-in-apl-nars2000-part-1-1hi6</link>
      <guid>https://dev.to/mkf/3-man-chess-in-the-round-in-apl-nars2000-part-1-1hi6</guid>
      <description>&lt;p&gt;I had previously written a post on getting into APL:&lt;br&gt;
&lt;a href="https://g.mikf.pl/gemlog/2022-03-31-apl.gmi"&gt;https://g.mikf.pl/gemlog/2022-03-31-apl.gmi&lt;/a&gt;&lt;br&gt;
You can find traces of getting started with the below in it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://3manchess.com"&gt;https://3manchess.com&lt;/a&gt;&lt;br&gt;
'3 Man Chess: In The Round' was once created by Clif W. King, the board set used to be US-patented but the patent expired.&lt;br&gt;
Years ago I led a team project for student exhibitions for a Festival of Arts and Science of a computer implementation of it. The project was brought to the attention of Clif King and had his assistance with the rules.&lt;br&gt;
Since the closest-to-finished implementation ended up being very deeply wrongfully designed for some of the bugs to be fixed, the effort failed to produce a working game for the end user.&lt;/p&gt;

&lt;p&gt;His son has since written an iOS implementation that I couldn't try out due to lack of relevant devices. I am left wondering if that rules implementation ended up being restrictive enough.&lt;/p&gt;

&lt;p&gt;The game has since been my goto playtoy for several computer languages along with their paradigms and recommended or interesting Zens and other ways.&lt;/p&gt;

&lt;p&gt;Figure: function 'addvec'&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;result ← from addvec vec; rank
:select
➥{
➥(⍵[1]&amp;gt;⍵[2])∨(⍵[1]=0): ⍵[1] ⍵[2]  ⋄
➥⍵[1]=⍵[2]:            2/⍵[1]≠0   ⋄ 
➥                      ⍵[2] ⍵[1]  } |vec
:case 2 1
 rank←from[1]+vec[1]
 result←{rank&amp;gt;6: 13-rank ⋄ rank} (modfile from[2]+vec[2]+(rank&amp;gt;6)×12)
:case 1 1
 :if from[1]=6
 :andif vec[1]&amp;gt;0
  result←(6 (modfile from[2]-10××vec[2])) ∇ (¯1 1)×(¯1××vec)+vec
 :elseif 7≤vec[1]+from[1]
  result←(6 (modfile from[2]+6-from[1])) ∇ vec-(6-from[1])××vec
 :else
  result←modfile from+vec
 :endif
:case 1 0
 rank←from[1]+vec[1]
 :if rank&amp;gt;6
  result← (13-rank) (modfile from[2]+12)
 :else
  result← rank from[2]
 :endif
:case 0 1
 result←modfile from+vec
:case 0 0
 result←from
:endselect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above function accepts a left argument 'from' and a right argument 'vec'. It has 'rank' marked as a local variable.&lt;/p&gt;

&lt;p&gt;For various types of "vectors" of pieces' movement it is supposed to return the destination coordinates.&lt;/p&gt;

&lt;p&gt;The whole body of the function is a ':SELECT' statement. The denominator of the SELECT is written out multiline, with the Line Continuation characters (➥) inserted by me where the NARS2000 displayed them - that's a so-called 'physical' line-break that is not a 'logical' line-break.&lt;/p&gt;

&lt;p&gt;It is an anonymous function written with 'guards' that has two conditional cases and a default case. It is then ran on the (mapped to absolute values with the Stile - pipe character meaning "Magnitude" function when monadic) 'vec' argument to our function.&lt;/p&gt;

&lt;p&gt;The first conditional case is to if the first element of the vector is greater than the second, or if the first element of the vector is zero, to return the vector's two elements in their original order.&lt;/p&gt;

&lt;p&gt;The second conditional case is to if the elements are equal to return a vector of two ones if the elements are non-zero or else of two zeroes.&lt;/p&gt;

&lt;p&gt;The default case is to return the vector's two elements in reverse order.&lt;/p&gt;

&lt;p&gt;The SELECT statement has no default case, and its cases are "2 1", "1 1", "1 0", "0 1" and "0 0". I expect that due to there being no default case that would assign to the return variable 'result', any wrong 'vec' will result in a "syntax error".&lt;/p&gt;

&lt;p&gt;The first case is "2 1" and it represents a knight move. To the helper variable 'rank' the sum of first coordinates of 'from' and the vector is assigned. Then the result is: first coordinate: if 'rank' is greater than 6 (6th is the innermost rank of the board that is a ring to be precise) then 13 minus the value of it, otherwise just the value of it; second coordinate: the boolean value of "'rank' greater than 6" is multiplied by 12 (i.e. 12 when true (greater), zero when false) and added to the sum of second coordinates of 'from' and the vector, then the modfile function is applied.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modfile ← { 1 + 24| ⍵-1 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The modfile function is substracting one from its argument, having it modulo 24, and then adding one to it and returning. That's because the circular board has 24 files that go in a circle, and since APL uses one-indexing we just have our coordinates from 1 to 24 and not from 0 to 23.&lt;/p&gt;

&lt;p&gt;The way ring-board works is there is an empty center that the pieces can cross and they land on the other side, on still the innermost rank but on the file opposite, that is plus 12.&lt;/p&gt;

&lt;p&gt;The second case is "1 1" which represents a diagonal move. Diagonal moves are made so that the piece could return to its square of origin ('from') if going inwards from the outermost (first) rank.&lt;/p&gt;

&lt;p&gt;It has an IF statement with two conditional cases and a default one.&lt;/p&gt;

&lt;p&gt;The first conditional case is to if the rank of origin is the innermost AND the vector is directed inwards, to have the result be the value of our enclosing function recursively (we can write the Del (delta) as well as the full name 'addvec' but the former makes refactoring easier) with the square of origin argument being on innermost (6th) rank and the file being the file of origin with ten times &lt;em&gt;the sign&lt;/em&gt; of vector's file coordinate (that is, the square that we land after jumping through the center diagonally), and the vector argument being the original vector with a negated unit vector of its original signs substracted, and then the rank coordinate negated.&lt;/p&gt;

&lt;p&gt;The second conditional case is to if the sum of the rank of origin and the vector's rank coordinate is 7 or more (i.e. we cross the center but are not starting from the innermost rank) to have the result be the value of our enclosing function recursively again with the square of origin argument again being on the innermost rank and the file being the file of origin plus the distance between the rank of origin and the innermost rank, and the vector argument being our vector with the unit vector of its original signs multiplied by the same ranks distance substracted from it. That is to move us to the first conditional case in the recursion.&lt;/p&gt;

&lt;p&gt;The default case is when we are not crossing the center and we can just add the coordinates and 'modfile' the file (and the rank too just to write less, because the rank is much less than 24 anyway).&lt;/p&gt;

&lt;p&gt;The third case is "1 0" which represents a rank-wise move vector. It, likewise, assigns to the helper variable 'rank' the sum of first coordinates of 'from' and the vector. If that's greater than 6, it returns the destination square coordinates on the opposite side of the board, and otherwise returns the coordinates with the same file coordinate.&lt;/p&gt;

&lt;p&gt;The fourth case is "0 1" which represents a file-wise move vector. That just adds the coordinates, again putting them through 'modfile' function. That's because we never pass through the center moving filewise.&lt;/p&gt;

&lt;p&gt;The last case is the zero case, that while such move is not legal for no piece, returns the square of origin; just in case.&lt;/p&gt;

&lt;p&gt;Please ask questions (email or wherever) if you were to happen to want to bother yourself asking. I'm eager to answer and to make some sort of FAQ in this post if there were to be any interest.&lt;/p&gt;

&lt;p&gt;I had another one prepared for this part, but it's already long, I will just make this half the first.&lt;/p&gt;

&lt;p&gt;See my gemlog: &lt;a href="https://g.mikf.pl/gemlog/"&gt;https://g.mikf.pl/gemlog/&lt;/a&gt;&lt;br&gt;
Also on gemini: &lt;a href="//gemini://g.mikf.pl/gemlog/"&gt;gemini://g.mikf.pl/gemlog/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>apl</category>
      <category>3manchess</category>
      <category>nars2000</category>
      <category>beginners</category>
    </item>
    <item>
      <title>A first in C# and WinForms: started writing a program for changing screen resolution</title>
      <dc:creator>Mika Feiler</dc:creator>
      <pubDate>Sat, 05 Feb 2022 18:52:59 +0000</pubDate>
      <link>https://dev.to/mkf/a-first-in-c-and-winforms-started-writing-a-program-for-changing-screen-resolution-1450</link>
      <guid>https://dev.to/mkf/a-first-in-c-and-winforms-started-writing-a-program-for-changing-screen-resolution-1450</guid>
      <description>&lt;p&gt;This post mirrors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2022-01-23 &lt;a href="https://g.mikf.pl/gemlog/2022-01-23-winforms.gmi"&gt;A first in C# and WinForms: started writing a program for changing screen resolution&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2022-02-05 &lt;a href="https://g.mikf.pl/gemlog/2022-02-05-winforms.gmi"&gt;An update on my C#/WinForms app that changes screen resolution&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  A first in C# and WinForms: started writing a program for changing screen resolution
&lt;/h1&gt;

&lt;h2&gt;
  
  
  2022-01-23
&lt;/h2&gt;

&lt;p&gt;Since i have recently became a Windows user, some specific needs emerged for specific reasons. I needed a program to change screen resolution for me whenever I would lock my session or login/logoff, or even start my session (change on autostart, yeah maybe i will port it as a Windows Service later) with one screen resolution and then switch to another right before ending session.&lt;/p&gt;

&lt;p&gt;I had no prior experience with WinForms and I don't recall having any meaningful experience witth C#. I had experience with IntelliJ and other JetBrains IDEs, and I dived straight into a fresh install of Visual Studio 2022 with Resharper. Today morning.&lt;/p&gt;

&lt;p&gt;The Designer in VS feels absolutely excellent to me, my first attempt with a GUI designer that went smoothly and led to me actually creating something that works! So far I am lazy and avoid perfectionism so everything is loosely aligned with Drawing class when I look underneath but that allows for incrementalism and unhindered creativity!&lt;/p&gt;

&lt;p&gt;Making an app have a notification icon in taskbar and minimize to it was surprisingly easy! There are problematic quirks but it is so very easy to find answers! Finding out how to get screen resolution or how to distinguish a logoff/shutdown from an Alt-F4 both didn't take long!&lt;/p&gt;

&lt;p&gt;Ok when it now came to actually changng the screen resolution I still haven't figured it out although I'm getting closer to it. That's where be dragons.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mkf/Resolutioner"&gt;https://github.com/mkf/Resolutioner&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mind the date of this post, consider comparing contemporary commits if you're from the future. (inb4 yes i now that future is immediate)&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;a href="https://g.mikf.pl/gemlog/2022-02-05-winforms.gmi"&gt;An update on my C#/WinForms app that changes screen resolution&lt;/a&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  2022-02-05
&lt;/h2&gt;

&lt;p&gt;From the most recent changes to the least recent.&lt;/p&gt;

&lt;p&gt;It would be great if I could finish the .NET app settings config loading&amp;amp;saving, then I would just sit down to add autostart and the program would already be usable.&lt;/p&gt;

&lt;p&gt;Adding Upgrade() to the function that loads config (yeah i know that could have been a handler) seemed to fix earlier issues with Debug builds not saving between executions, but on Release builds loading/saving config not longer works.&lt;/p&gt;

&lt;p&gt;I also added a migration handler in a very-not-advised way as the advised way is handlers in a derived class. My config now has an integer for migration number, I should probably make myself somewhere a table of what migrations will correspond to which releases and commits, maybe make tags for migrations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mkf/Resolutioner/commit/f584ec1f89f77d71ad71515dc612970129206a84.patch"&gt;https://github.com/mkf/Resolutioner/commit/f584ec1f89f77d71ad71515dc612970129206a84.patch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of handling all SessionSwitchReasons in one (actually two) ways I now let the user choose, introducing a rather intuitive two-column UI for which way (my program changes, on events, screen resolution to "the desired one" or "the restored one") the events work (I could make it triple-state dropdowns instead of checkboxes though, or besides checkboxes).&lt;/p&gt;

&lt;p&gt;Wanting to continue that pattern (and make the behavior at all reasonable) with SessionSwitchReason.SessionRemoteControl as well, I ended up needing to PInvoke GetSystemMetrics, where I ended up seemingly needing the type Windows.Win32.UI.WindowsAndMessaging.SYSTEM_METRICS_INDEX to cast to it. What I did was a bad thing as I basically added to my dependencies some random package exposing it called RawInputLight.&lt;/p&gt;

&lt;p&gt;And that was after I learnt of this new thing Microsoft did to ease PInvoke, which is a project called win32metadata that brings it to amongst others Rust, but also to C# and in its case the so-called "language projection" is called CsWin32.&lt;/p&gt;

&lt;p&gt;And the way I did that turned out to cause an override between CsWin32 and RawInputLight, but since in my configuration RawInputLight is winning it, I just had to add pragma to disable warning CS0436 for the line of code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mkf/Resolutioner/commit/88978bf0c8e26cb6c3f776f52e3a56ae5fe5b294.patch"&gt;https://github.com/mkf/Resolutioner/commit/88978bf0c8e26cb6c3f776f52e3a56ae5fe5b294.patch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But I didn't yet mention how did I achieve screen resolution changing, right? Well, back then I used PInvoke without CsWin32, and I followed this guide:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.codeproject.com/Articles/36664/Changing-Display-Settings-Programmatically"&gt;https://www.codeproject.com/Articles/36664/Changing-Display-Settings-Programmatically&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Written by Mohammad Elsheimy in 2009 and licensed with CPL 1.0, it proposed having the DEVMODE struct layed out in one's code, with the dmPosition struct possible to break out into two I4 fields, with [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] on top and a MarshalAs at each field. Then dll imports from User32.dll with an extern declaration all in MarshalAs for each needed function.&lt;/p&gt;

&lt;p&gt;And to change resolution we load the original DEVMODE with EnumDisplaySettings with ENUM_CURRENT_SETTINGS (ENUM_REGISTRY_SETTINGS also available), and without getting a list of all available modes (which is doable with the guide) we just attempt to change to the same DEVMODE with dmPelsWidth and dmPelsHeight set to our other values and see which one of&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SUCCESSFUL = 0, // Indicates that the function succeeded.&lt;/li&gt;
&lt;li&gt;BADMODE = -2, // The graphics mode is not supported.&lt;/li&gt;
&lt;li&gt;_FAILED = -1, // The display driver failed the specified graphics mode.&lt;/li&gt;
&lt;li&gt;RESTART = 1 // The computer must be restarted for the graphics mode to work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;will our ChangeDisplaySettings result in. My function then returns it but presently the value is just ignored.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mkf/Resolutioner/commit/346e922a920a262dcfbf5681b15801cd2a7d209a.patch"&gt;https://github.com/mkf/Resolutioner/commit/346e922a920a262dcfbf5681b15801cd2a7d209a.patch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although now that I accidentally took a glance at&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-changedisplaysettingsa"&gt;https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-changedisplaysettingsa&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;there appears that besides&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DISP_CHANGE_SUCCESSFUL : The settings change was successful.&lt;/li&gt;
&lt;li&gt;DISP_CHANGE_BADMODE : The graphics mode is not supported.&lt;/li&gt;
&lt;li&gt;DISP_CHANGE_FAILED : The display driver failed the specified graphics mode.&lt;/li&gt;
&lt;li&gt;DISP_CHANGE_RESTART : The computer must be restarted for the graphics mode to work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;there are also&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DISP_CHANGE_BADDUALVIEW : The settings change was unsuccessful because the system is DualView capable.&lt;/li&gt;
&lt;li&gt;DISP_CHANGE_BADFLAGS : An invalid set of flags was passed in.&lt;/li&gt;
&lt;li&gt;DISP_CHANGE_BADPARAM : An invalid parameter was passed in. This can include an invalid flag or combination of flags.&lt;/li&gt;
&lt;li&gt;DISP_CHANGE_NOTUPDATED : Unable to write settings to the registry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which I am not handling, I don't know their numeric values and worse, I am casting them into an own four-value (-2..1) enum.&lt;/p&gt;

&lt;p&gt;Back to my configuration though, my actual configuration variables are still my input fields in my WinForms form which is just minimized. All the fields have event handlers to uncheck the "Config Saved" checkbox which can then be re-checked to save the configuration. And initially I tried writing a class deriving from System.Configuration.ConfigurationSection, only later I found out about the settings designer in Visual Studio.&lt;/p&gt;

&lt;p&gt;And I have been asked to write another simple app, where I would use autostart too and configuration saving too. And one of the features of it are to be logging to files, so the last thing I was sitting down to in it was to have a file chooser dialog. Initially I only found out about OpenFileDialog. But it turned out there is also FileDialog but it is not to be used, only it's derivatives including there also being SaveFileDialog. But apparently these are recommended to handle the very writing of a file themselves. I am considering just creating files in a folder so maybe I will just use FolderBrowserDialog. But first, I need to learn how to save app configuration in .NET so that it loads correctly for me, especially between Release releases.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>winforms</category>
      <category>win32</category>
      <category>cswin32</category>
    </item>
    <item>
      <title>2021-08-30 A 6AM dive into PalmOS getting started with use of.</title>
      <dc:creator>Mika Feiler</dc:creator>
      <pubDate>Sat, 05 Feb 2022 18:45:59 +0000</pubDate>
      <link>https://dev.to/mkf/2021-08-30-a-6am-dive-into-palmos-getting-started-with-use-of-45c5</link>
      <guid>https://dev.to/mkf/2021-08-30-a-6am-dive-into-palmos-getting-started-with-use-of-45c5</guid>
      <description>&lt;p&gt;This post mirrors &lt;a href="https://g.mikf.pl/gemlog/2021-08-30--a_6am_palmos.gmi"&gt;https://g.mikf.pl/gemlog/2021-08-30--a_6am_palmos.gmi&lt;/a&gt; and is back from August 30th, 2021.&lt;/p&gt;

&lt;p&gt;This post, in most parts, corresponds to the following fedi&amp;amp;twitter thread&lt;/p&gt;

&lt;p&gt;&lt;a href="https://functional.cafe/web/statuses/106843043909812967"&gt;https://functional.cafe/web/statuses/106843043909812967&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/mika_feiler/status/1432185314051870723"&gt;https://twitter.com/mika_feiler/status/1432185314051870723&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wanted to try using a PalmOS device again, for self-organizing.&lt;/p&gt;

&lt;p&gt;It quickly turned out that freewarepalm.com is dead these days; the domain taken over by some small blog, with the logo seemingly also taken from the original site. Last good snapshots on webarchive are from 2015. Most downloads are not available on webarchive.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://web.archive.org/web/*/http://www.freewarepalm.com/_download/*"&gt;here you can see a listing of all that was archived from the _download/ path of freewarepalm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After getting reminded of a lot of stuff that i used to install, i chose my primary need to be the software for entering Polish characters (ąęśćżńóź) with the Graffiti modifier gesture, and the better clock selector I knew that I once got a license from its author from.&lt;/p&gt;

&lt;p&gt;I quickly found the GMail email back from 2014 where I emailed Szymon Ulatowski and got a license code for ClockSelector corresponding to my HotSync username in an enthusiastic and cordial reply.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://toyspring.com/clock"&gt;Szymon Ulatowski's ToySpring's ClockSelector&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I went to find&lt;/p&gt;

&lt;p&gt;&lt;a href="http://sergem.net/interpilot/"&gt;Interpilot website&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;which referred me to use a new piece of software "PiLoc" instead, for which the duckduckgo finds were&lt;/p&gt;

&lt;p&gt;&lt;a href="https://palm.penreader.com"&gt;https://palm.penreader.com&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;which turned out to only link to defunct parts of Paragon Software website for downloads, and
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="http://palmgear.penreader.com/PalmOS/PiLoc/Polish_PiLoc.html"&gt;http://palmgear.penreader.com/PalmOS/PiLoc/Polish_PiLoc.html&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;which linked to either defunct palmgear website mirror or to a piloc.penreader.com defunct cgi "Download Wizard"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I have a recollection of the names of both Interpilot and PiLoc from my old days.&lt;/p&gt;

&lt;p&gt;The downloads for Interpilot on its website work well so Interpilot is what I will go with.&lt;/p&gt;

&lt;p&gt;Then I went on to learn J-Pilot is available in neither Nixpkgs (Nix/NixOS) nor HaikuOS's Depot but that wasn't that unexpected; the good news is that J-Pilot has reached 2.0 in 2021, with main change being GTK3.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jpilot.org"&gt;https://jpilot.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm somewhat thinking of writing my own utility, maybe native to Haiku, maybe made to be client-server for the cradle to be stationary with a Raspberry Pi in a corner.&lt;/p&gt;

&lt;p&gt;Then I dug up an old "#PalmOS" tweet from an old Twitter account of mine, dating back to August 2012 when I was 13yrs old.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I've just found an old website with some great apps for #PalmOS which I used a long time ago, created by their authors. http://is.gd/AYXVkQ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://mikemccollister.com/"&gt;mikemccollister.com, you need to navigate to "Mike" at least these days&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there was ScreenPrefs among the programs there, a utility that allowed to select the color pallette for the device to operate in, iirc allowing to increase it greatly! A great find!&lt;/p&gt;

&lt;p&gt;Also contains "McNits: Mike’s Palm Programming Nitpicks"&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;McNits is a series of articles that I wrote for the “Handheld Computing Developer” website. They are a compilation of nitpicks that I have concerning those not-so-great Palm OS programs. Some of these are suggestions brought forth by PalmSource, some by me, others are just common sense.

[…] a series of articles to help Palm OS developers create high quality and consistent programs.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And also some tips on increasing productivity with the simple MemoPad utility.&lt;/p&gt;

&lt;p&gt;That stuff, especially the software downloads, especially ScreenPrefs, I need to later make sure web.archive.org/save will grasp well or if it won't want to then I will host at least ScreenPrefs on an own website just in case. 2021 makes me even more sick of PalmOS resources link rot!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/geekculture/howto-using-the-palm-pda-in-2021-3f49ae589bb6"&gt;https://medium.com/geekculture/howto-using-the-palm-pda-in-2021-3f49ae589bb6&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://uxdesign.cc/palm-os-how-does-it-look-today-f1c3c29f2240?gi=a2c77e11aac1"&gt;https://uxdesign.cc/palm-os-how-does-it-look-today-f1c3c29f2240?gi=a2c77e11aac1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These two articles contain a few nice links.&lt;/p&gt;

&lt;p&gt;I'm thinking of writing some software for PalmOS, like an offline Gemini browser, a tool for writing gemlogs and having them published on a HotSync…&lt;/p&gt;

&lt;p&gt;My Tungsten T has dead battery, two Vx surely too but also I don't have the power adapter for their cradle, Zire 71 has the LCD broken once (it was so very delicate!), I started a IIIxe with batteries and that's what im gonna use, but maybe I will also check on that Z22's battery&lt;/p&gt;

&lt;p&gt;Here at parents' I would need to dig a bit to find a miniUSB-B cable but i recall that Z22's battery always used to manage to last for quite a while and even if it will no more it is still a handy although excruciatingly small device that has a neat miniUSB. So imma grab it, and im boarding a train back home tomorrow.&lt;/p&gt;

&lt;p&gt;Also I remembered I had a collection of PalmOS programs on my account ("hamster") on a Polish file hosting site Chomikuj.pl (hamster as a verb, imperative). Everything uploaded there is dated 2010 when I was 11 years old.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://chomikuj.pl/michalekus1998/programy+i+inne+rzeczy+do+system*c3*b3w+operacyjnych+i+OS*27*c3*b3w/PalmOS(TM)"&gt;http://chomikuj.pl/michalekus1998/programy+i+inne+rzeczy+do+system*c3*b3w+operacyjnych+i+OS*27*c3*b3w/PalmOS(TM)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is quite a mess but most of that stuff is no longer findable anywhere else.&lt;/p&gt;

&lt;p&gt;In the parent directories you can also find stuff like a Fluxbox theme that I derived from Debian's and decided to publish at 11yo.&lt;/p&gt;

&lt;p&gt;The reason why i want to use PalmOS for stuff like todos and appointments is because Android phones are a mess, apps on capacitive touchscreen are inferior, notifications are a mess especially as MIUI removes control over notifications' priority once again. I already use paper notebooks and I want something more smart, in pursue of clarity and untediousness. Most input into the pilot gonna be journalled into paper anyway tho lol, can't trust there won't be hardreset-prompting segfault or batteries won't run out.&lt;/p&gt;

</description>
      <category>palmos</category>
    </item>
    <item>
      <title>`-`, &amp;#8209;, &amp;minus; — and Markdown? A rhethorical, and not, question about Markdown renderers.</title>
      <dc:creator>Mika Feiler</dc:creator>
      <pubDate>Sun, 26 Jan 2020 18:23:40 +0000</pubDate>
      <link>https://dev.to/mkf/8209-minus-and-markdown-a-rhethorical-and-not-question-about-markdown-renderers-4a2l</link>
      <guid>https://dev.to/mkf/8209-minus-and-markdown-a-rhethorical-and-not-question-about-markdown-renderers-4a2l</guid>
      <description>&lt;p&gt;In bare HTML, using &lt;code&gt;-&lt;/code&gt; (regular hyphen) causes line-breaks to occur on them. Hence many place non-breaking hyphen Unicode character — which has but a numeric code and afaik no neat html entity code. Hyphen character is also what is used to represent a minus. Turns out that for minus there is HTML entity &lt;code&gt;minus&lt;/code&gt; — &lt;code&gt;&amp;amp;minus;&lt;/code&gt; (« − »).&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://en.wikipedia.org/wiki/Wikipedia:Nonbreaking_hyphen"&gt;https://en.wikipedia.org/wiki/Wikipedia:Nonbreaking_hyphen&lt;/a&gt; for more about the issue.&lt;/p&gt;

&lt;p&gt;But when using Markdown, we rarely think of the resulting HTML. Thus it could be maybe desired from Markdown renderers to take care of it for the user and let them just write the regular hyphen in the source code, by means of some heuristics~extensions — or are there rules in Markdown itself?&lt;/p&gt;

&lt;p&gt;Do they do that, or do they not? Which do, which don't? How?&lt;/p&gt;

&lt;p&gt;P.S. On the end of first paragraph i first wrote the name of entity in code quotes and then the whole entity code in code quotes — bc i don't really know if the Markdown renderer of devto will or will not sanitize code brackets from HTML entities, especially when it comes to a minus. Markdown is wild actually.&lt;/p&gt;

&lt;p&gt;P.P.S. Ok, devto does do it, but idk if someones by-API reader will. (And yes, i know i can click preview, and just did it — this PPS was before publishing.)&lt;/p&gt;

</description>
      <category>markdown</category>
      <category>html</category>
      <category>hyphen</category>
      <category>nonbreaking</category>
    </item>
    <item>
      <title>I just asked: Are .gitignore files from directories above the repository's or from home directory loaded in any versions of Git?</title>
      <dc:creator>Mika Feiler</dc:creator>
      <pubDate>Wed, 22 Jan 2020 19:53:28 +0000</pubDate>
      <link>https://dev.to/mkf/i-just-asked-are-gitignore-files-from-directories-above-the-repository-s-or-from-home-directory-loaded-in-any-versions-of-git-5744</link>
      <guid>https://dev.to/mkf/i-just-asked-are-gitignore-files-from-directories-above-the-repository-s-or-from-home-directory-loaded-in-any-versions-of-git-5744</guid>
      <description>&lt;p&gt;I just &lt;a href="https://superuser.com/questions/1519345/are-gitignore-files-from-directories-above-the-repositorys-or-from-home-direct"&gt;asked on Super User&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;Are &lt;code&gt;.gitignore&lt;/code&gt; files from directories above the repository's or from home directory (&lt;code&gt;~/.gitignore&lt;/code&gt;) loaded in any versions of Git?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;~/.gitignore&lt;/code&gt; is mentioned by some advisory web postings despite not working in the version of Git on my system, and my system manual is unclear about how far up Git will walk looking for a &lt;code&gt;.gitignore&lt;/code&gt;, although only mentions &lt;code&gt;$XDG_CONFIG_HOME/git/ignore&lt;/code&gt; as a home directory global gitignore file location.&lt;/p&gt;

&lt;p&gt;My problem stems from, to manage my home directory dotfiles i have presently chosen to use Git with a custom &lt;code&gt;GIT_DIR&lt;/code&gt; environment variable setting, which does fine with not having Git default to that repository in any subdirectories of my &lt;code&gt;~&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But, as &lt;code&gt;.gitignore&lt;/code&gt; is hardcoded and can't be selected by an environment variable (which i would like to be like &lt;code&gt;"${GIT_DIR%/}ignore"&lt;/code&gt;), being afraid that on some of my systems &lt;code&gt;~/.gitignore&lt;/code&gt; could end up applying either globally or in repositories in the subdirectories of &lt;code&gt;~&lt;/code&gt;, i resorted to adding the below snippet to my &lt;code&gt;${GIT_DIR}/info/exclude&lt;/code&gt; and then staging the &lt;code&gt;${GIT_DIR}/info/exclude&lt;/code&gt; file into the repository, keeping all my gitignore entries that are to apply to my dotfiles management repository in there (and in &lt;code&gt;.gitignore&lt;/code&gt; files in dotfiles-only subdirectories). What i don't like about it is that it's pretty dirty and it might cause minor problems sometimes.&lt;/p&gt;

&lt;p&gt;The snippet mentioned above, with &lt;code&gt;.gd&lt;/code&gt; being my &lt;code&gt;$GIT_DIR&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/.gd/**
!/.gd/info/
!/.gd/info/exclude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>git</category>
      <category>gitignore</category>
    </item>
    <item>
      <title>Want to login to a Bash 5 not in /etc/shells while having your $SHELL, and login shell, set to /bin/bash which stays on v4?</title>
      <dc:creator>Mika Feiler</dc:creator>
      <pubDate>Wed, 04 Sep 2019 11:40:44 +0000</pubDate>
      <link>https://dev.to/mkf/want-to-login-to-a-bash-5-not-in-etc-shells-while-having-your-shell-and-login-shell-set-to-bin-bash-which-stays-on-v4-3k2i</link>
      <guid>https://dev.to/mkf/want-to-login-to-a-bash-5-not-in-etc-shells-while-having-your-shell-and-login-shell-set-to-bin-bash-which-stays-on-v4-3k2i</guid>
      <description>&lt;p&gt;When you run a shell within your login shell, $SHELL is still your login shell. When you run another shell within that shell, $SHELL still stays the same. There are some bad scripts the behavior of which incorrectly depends on $SHELL. If you want to run Bash, you might want $SHELL to stay &lt;code&gt;/bin/bash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And sometimes you want to login to a version of Bash not from &lt;code&gt;/etc/shells&lt;/code&gt; — like, from somewhere else in the system or even from your home directory.&lt;/p&gt;

&lt;p&gt;I'm not sure if there is any non-shell-specific standard way of getting the path of your childmost shell executable. In Bash you can get it from $BASH.&lt;/p&gt;

&lt;p&gt;If you want to land in &lt;code&gt;/bin/bash&lt;/code&gt; only if your own &lt;code&gt;bash&lt;/code&gt; binary doesn't get found in $PATH, put this in your &lt;code&gt;.bashrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$NO_FURTHER_PLEASE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$BASH&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"/bin/bash"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;NO_FURTHER_PLEASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 bash&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might want to replace &lt;code&gt;"/bin/bash"&lt;/code&gt; for &lt;code&gt;$SHELL&lt;/code&gt; in the above if you are not sure if your login shell will stay &lt;code&gt;/bin/bash&lt;/code&gt; since &lt;code&gt;$SHELL&lt;/code&gt; will be always your login shell from /etc/shells.&lt;/p&gt;

&lt;p&gt;If you also want to land in &lt;code&gt;/bin/bash&lt;/code&gt; wherever it is already Bash 5 or newer, put this instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$NO_FURTHER_PLEASE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_VERSINFO&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-le&lt;/span&gt; 4 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;NO_FURTHER_PLEASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 bash&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that in both cases if the &lt;code&gt;bash&lt;/code&gt; from &lt;code&gt;$PATH&lt;/code&gt; ends up being &lt;code&gt;/bin/bash&lt;/code&gt;, you get &lt;code&gt;/bin/bash&lt;/code&gt; inside &lt;code&gt;/bin/bash&lt;/code&gt;. That could be improved on by re-checking against the original condition with something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$NO_FURTHER_PLEASE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; the condition goes there &lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;2&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or instead, even better,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$NO_FURTHER_PLEASE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$SHELL&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$BASH&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;2&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, one could just hardcode the absolute path of their &lt;code&gt;bash&lt;/code&gt; in &lt;code&gt;.bashrc&lt;/code&gt; and then there would be no such problem.&lt;/p&gt;

&lt;p&gt;If someone is wondering, no, &lt;code&gt;$NO_FURTHER_PLEASE&lt;/code&gt; is not inherited by any &lt;code&gt;bash&lt;/code&gt; that you choose to run inside your &lt;code&gt;bash&lt;/code&gt; since &lt;code&gt;NO_FURTHER_PLEASE&lt;/code&gt; is not exported.&lt;/p&gt;

&lt;p&gt;Yes yes i know that there is probably a neater way to test against a variable than returning it from a subshell, i am just too lazy to look for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edit
&lt;/h2&gt;

&lt;p&gt;It seems like all of the above could be replaced with just&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;FURTHER_BASH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; bash&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$SHELL&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nv"&gt;$BASH&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;
&lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;unset &lt;/span&gt;FURTHER_BASH
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$BASH&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nv"&gt;$FURTHER_BASH&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt; 
    &lt;span class="nv"&gt;$FURTHER_BASH&lt;/span&gt;
    &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;unset &lt;/span&gt;FURTHER_BASH
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Staying in login shell."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_VERSINFO&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-le&lt;/span&gt; 4 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Warning: Staying in bash version &lt;/span&gt;&lt;span class="nv"&gt;$BASH_VERSINFO&lt;/span&gt;&lt;span class="s2"&gt; &amp;lt; 5."&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;2&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>bash</category>
    </item>
    <item>
      <title>The *5* 'as well as you can' CS assignments that I failed to submit, on my freshman semester</title>
      <dc:creator>Mika Feiler</dc:creator>
      <pubDate>Sun, 27 Jan 2019 04:37:43 +0000</pubDate>
      <link>https://dev.to/mkf/the-5-as-well-as-you-can-cs-assignments-that-i-failed-to-submit-on-my-freshman-semester-obk</link>
      <guid>https://dev.to/mkf/the-5-as-well-as-you-can-cs-assignments-that-i-failed-to-submit-on-my-freshman-semester-obk</guid>
      <description>&lt;p&gt;&lt;em&gt;I'm failing my freshman semester right now, for the second time (on another uni), and I'm depressed&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I hate when CS assignments have pretty-much-close-to-infinite amount of facultative features for the program/result to have, and doing any of them influences the fundamental design, but greatly increases time needed for it, in a way imprevisible for the students&lt;/p&gt;

&lt;p&gt;&lt;em&gt;-- me, on Twitter and Mastodon&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;(DWIN4) &lt;em&gt;Generate a BMP file, of which the JPEG compression ratio will be the greatest.&lt;/em&gt; I started researching JPEG algorithm and machine learning solutions to this, started trying to code something up, ... in Fortran &lt;em&gt;btw&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(DWIN5) &lt;em&gt;Design a DTD schema for a made up data model for a store, which would have stuff like groceries, stationery, clothing and stuff on shelves and some fields for these products, and types of products&lt;/em&gt; I was late on submitting DWIN4(↑) and still trying, and also it was hard to make that stuff up.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(DWIN7) &lt;em&gt;Find the furthest legit route in the network you can.&lt;/em&gt; A competition who can find the furthest was announced, as in case of the first one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(DWIN8) Not exactly infinite, but the level of detail could be pushed far I think. &lt;em&gt;Host A was connected to local network. It's going to use DHCP config, then with the use of ARP learn the hw addr of host 192.168.0.5 and send to it seeral packets of data with TCP. Describe {exactly, in detail} [this is a translation] the packets the sending and receiving of which should be expected.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(SOP-MS) &lt;em&gt;Write a simple program — shell, in ANSI C. The program should take commands as input, and then execute operations according to them. The shell it supposed to:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(1.0p) &lt;em&gt;print the prompt of &lt;code&gt;[{path}] $&lt;/code&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;(1.0p) &lt;em&gt;support &lt;code&gt;cd&lt;/code&gt;, analogous to the one from bash&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;(0.5p) &lt;em&gt;support &lt;code&gt;exit&lt;/code&gt; command, ending the operation of the shell program&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;(0.5p) &lt;em&gt;support &lt;code&gt;help&lt;/code&gt; command, displaying info about the author and supported features&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;(2.0p) &lt;em&gt;support two other, &lt;strong&gt;arbitrarily selected&lt;/strong&gt; commands of a shell (it's about an own, simple implementation of two commands, for example &lt;code&gt;cp&lt;/code&gt;, sources for which where not provided on the classes)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;(2.0p) &lt;em&gt;take commands referring by name to scripts and programs present in directories describes by the envirinmental variable &lt;code&gt;PATH&lt;/code&gt; and allow for execution of these scripts with arguments (i.e. &lt;code&gt;fork&lt;/code&gt;+&lt;code&gt;exec*&lt;/code&gt;)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;(1.0p) &lt;em&gt;print error message, when correct command interpretation is impossible&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;(2.0p) &lt;em&gt;having some so-called additional &lt;strong&gt;frills&lt;/strong&gt; (depending on the level of complexity of the problem), for example displaying the login of a currently logged in user, color support, quoted arguments support, [reasonable] support of signals (for example, &lt;code&gt;Ctrl+Z&lt;/code&gt;), command history support, syntax autocompletion, etc.&lt;/em&gt; I started digging deep into &lt;code&gt;libedit&lt;/code&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While I understand how these assignments are encouraging creativity and may really provide great learning experience, these are pretty much flawed, at least in cases like me. I really love these teachers, their attitude and everything, but it's just these assignments being like "there is no such thing as «done»". Obviously they were only a minor contribution to me failing this semester, but still... (*failing — I still might pass)&lt;/p&gt;

</description>
      <category>university</category>
      <category>student</category>
      <category>education</category>
      <category>rant</category>
    </item>
    <item>
      <title>Implementing the rules of 3 Man Chess: Variant “In The Round”. Part 1, Fundamental Types</title>
      <dc:creator>Mika Feiler</dc:creator>
      <pubDate>Sun, 22 Apr 2018 03:49:28 +0000</pubDate>
      <link>https://dev.to/mkf/implementing-the-rules-of-3-man-chess-variant-in-the-round-part-1-fundamental-types-3hap</link>
      <guid>https://dev.to/mkf/implementing-the-rules-of-3-man-chess-variant-in-the-round-part-1-fundamental-types-3hap</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally published in April 2018 on Medium. The project described in it is &lt;strong&gt;temporarily&lt;/strong&gt; discontinued. This post is not even up-to-date with the project. I'm just trying out the Medium→Dev.To migration feature.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;For the past three years, my go-to project for learning new programming languages and paradigms was the implementation of the rules of &lt;a href="http://3manchess.com"&gt;3 Man Chess: Variant “In The Round”&lt;/a&gt;. I have used it to learn much about Go, Dart, Java, Clojure and Haskell. All the implementation attempts are available on my Github profile. So what’s the matter with the “attempts” word, why none of them is working, what’s so difficult? This is what this series is going to be about. But these it this “pilot” article, in this part, will be just fundamental data types because I don’t have much time. I have festival presentation deadlines for this project. One of them is &lt;strong&gt;today, in four hours.&lt;/strong&gt; So, if you could look at the entirety of the code and help me, please do. &lt;a href="https://github.com/ArchieT/ThreeManChess"&gt;https://github.com/ArchieT/ThreeManChess&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, the board. It is a circular board, consisting of six rings, later called Ranks, numbered from 0 (MostOuter) to 5 (MostInner).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data Rank = MostOuter | SecondOuter | MiddleOuter 
 | MiddleInner | SecondInner | MostInner 
 deriving (Eq, Ord, Read, Show)
ranks :: [Rank]
inw :: Rank -&amp;gt; Rank
out :: Rank -&amp;gt; Maybe Rank
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Each of those ranks consists of 24 Files.&lt;/p&gt;

&lt;p&gt;The board is divided in three, one for each of the players. Opponents’ rooks are next to each other, but they cannot capture each other because of a feature called “moats”. Neither can pawns, because of a feature called “creeks”. If you want to know how it looks or have other questions, &lt;a href="http://www.3manchess.com"&gt;www.3manchess.com&lt;/a&gt; may answer them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Set all Kings on white. White goes first, then clockwise to gray, then black.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data Color = White | Gray | Black
 deriving (Eq, Ord, Read)
next :: Color -&amp;gt; Color
prev :: Color -&amp;gt; Color
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So now we also need some data type that would correspond to number from 0 to 7, why not just use an Integer type? Because we want to be protected with our Haskellish type system, and another way we do this data type of ours may turn beneficial to us in some ways. So. Say hello to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data SegmentHalf = FirstHalf | SecondHalf 
 deriving (Eq, Ord, Read, Show)
data SegmentQuarter = SegmentQuarter 
 { half :: SegmentHalf
 , halfQuarter :: SegmentHalf }
 deriving (Eq, Ord, Read, Show)
data SegmentEight = SegmentEight 
 { segmentQuarter :: SegmentQuarter
 , quarterHalf :: SegmentHalf } 
 deriving (Eq, Ord, Read, Show)
type ColorSegment = Color
data File = File { segmColor :: ColorSegment
 , colorSegmFile :: SegmentEight }
 deriving (Eq, Ord, Read, Show)
opposite :: File -&amp;gt; File
plus :: File -&amp;gt; File
minus :: File -&amp;gt; File

-- and finally
type Pos = (Rank, File)
rank :: Pos -&amp;gt; Rank
file :: Pos -&amp;gt; File

-- |'kfm' is where the King stands
kfm :: SegmentEight
kfm = (SegmentEight (SegmentQuarter SecondHalf FirstHalf) FirstHalf)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Okay, enough about the board coordinates data structures.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;The center of the board may be passed through, but has no square to be occupied.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;a. Adjoining vertical squares, through the center, maintain the same color.&lt;/p&gt;

&lt;p&gt;i. Queen, King, Rook, or Pawn, advancing 1 square through center, retains same color.&lt;/p&gt;

&lt;p&gt;ii. Knight also will retain same color.&lt;/p&gt;

&lt;p&gt;iii. This phenomenon is necessary to maintain ‘round board’ integrity. As players should be aware of this, conventional Chess strategy is not compromised.&lt;/p&gt;

&lt;p&gt;[…]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;VERTICAL MOVES (Queen, King, Rook, Pawn)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;a. Follows straight, (and if necessary, through the center), along the checkerboard file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And a Pawn can go only forward. So, we do not want to prove that it is not possible for a Pawn to perform so many captures as to it become unsure if it’s directed inwards or outwards, and am unsure if I had proven it to be impossible sometime ago already, but anyway such distinction helps. Therefore,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data FigType = InwardPawn | OutwardPawn | Rook | Knight
 | Bishop | King | Queen
 deriving (Eq, Read)

--for promotion purposes, we will also define
data Promotion = RookPromotion | KnightPromotion |
 | BishopPromotion | QueenPromotion
 deriving (Eq, Show)
desiredType :: Promotion -&amp;gt; FigType
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;HORIZONTAL MOVES (Queen, King, Rook)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;a. Rotate about the center on the same row (rank).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the moves are, like, modulo 24.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;DIAGONAL MOVES (Queen, King, Bishop, or Pawn capturing)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;a. Follow 1 of the 2 trajectory lines out from the square it rest on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On the board, there are 48 diagonal &lt;em&gt;trajectory lines&lt;/em&gt;, pairs of them crossing over each one of the squares. On the MostOuter rank, on each of the files a pair of &lt;em&gt;trajectory lines&lt;/em&gt; forms a corner. Each of those pairs forms a loop over the center.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;b. May rotate through the center.&lt;/p&gt;

&lt;p&gt;c. Can not ‘turn the corner’ at the outer rank, in 1 move.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also, what is not included in the rules but what was stated to be the right thing by Mr Clif King, the owner of 3 Man Chess, and I guess their creator, in our correspondence when I asked for this specifically and argumented for it, and which is not yet included in the rules, the figure must not go diagonally through the center or filewise(horizontally) around the center back to the square it went from — it would cause oft something like a lack of zugzwang (compulsion to move), an important feature of chess, and would have serious consequences in gameplay, especially in case of computer gameplay.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;KNIGHT MOVES&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;a. 2 squares vertically then 1 square horizontally, or&lt;/p&gt;

&lt;p&gt;b. 1 square vertically then 2 horizontally.&lt;/p&gt;

&lt;p&gt;c. Use 1 of the 2 methods above (i.e., do not follow a trajectory line through the center). Also, these 2 methods are necessary for BORDER CONTROL described below.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These are just about the same, until when it comes to “border control”, i.e. “moats”.&lt;/p&gt;

&lt;p&gt;So, there are multiple ways to perform a single from→to move, which we need to handle separately to avoid unnecessary computations. Therefore, we need data structures for that&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data Orientation = Rankwise | Filewise deriving (Eq, Read, Show)
data RankwiseDirection = Inwards | Outwards
 deriving (Eq, Show)
data FilewiseDirection = Pluswards | Minuswards
 deriving (Eq, Show)
filewiseInc :: FilewiseDirection -&amp;gt; File -&amp;gt; File

data DiagonalDirection = DiagonalDirection
 RankwiseDirection
 FilewiseDirection
 deriving (Eq, Show)
data Count = Once | OnceMore Count deriving (Eq, Read, Show)

class (Eq a) =&amp;gt; LinearDirection a where
 addOne :: a -&amp;gt; Pos -&amp;gt; Maybe Pos
instance LinearDirection RankwiseDirection where
 addOne Inwards (MostInner, file) = 
 Just (MostInner, opposite file)
 addOne Inwards (rank, file) = 
 Just (inw rank, file)
 addOne Outwards (rank, file) =
 do { o &amp;lt;- out rank;
 return (o, file) }
instance LinearDirection FilewiseDirection where
 addOne w (rank, file) = Just (rank, filewiseInc w file)
instance LinearDirection DiagonalDirection where
 addOne (DiagonalDirection Inwards p)
 (MostInner, file) = ... --long case expressions here
 addOne (DiagonalDirection Inwards p) (rank, file) = 
 Just (inw rank, filewiseInc p file)
 addOne (DiagonalDirection Outwards p) (rank, file) = 
 do { o &amp;lt;- out rank; return (o, filewiseInc p file) }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I have to go back to work now, and I am not sure if I have good reasons not to publish this beginning. There were almost no difficulties so far in this post, though even those few caveats took me many man-days of thinking back in the days. I am writing this post to motivate myself and to clarify the fundamentals of my code. Aaaand I’m &lt;strong&gt;hoping for collaborators&lt;/strong&gt;. Really. &lt;strong&gt;Any.&lt;/strong&gt; Any &lt;strong&gt;collaborators.&lt;/strong&gt; You don’t need to know Haskell for more than a few hours, &lt;strong&gt;you will learn Haskell along the way&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So. &lt;a href="https://github.com/ArchieT/ThreeManChess"&gt;&lt;strong&gt;https://github.com/ArchieT/ThreeManChess&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want more information about something like “why don’t the rooks capture each other” or “what does it all look like”, look at &lt;a href="http://www.3manchess.com"&gt;www.3manchess.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Should I update this post later or just post next parts? Maybe posting next parts will be better.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>chess</category>
      <category>haskell</category>
      <category>3manchess</category>
    </item>
  </channel>
</rss>
