<?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: Nick | OneThingWell.dev</title>
    <description>The latest articles on DEV Community by Nick | OneThingWell.dev (@onethingwell).</description>
    <link>https://dev.to/onethingwell</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%2F660347%2F6cb4da50-706f-40fb-8b25-f10f61cbbff6.png</url>
      <title>DEV Community: Nick | OneThingWell.dev</title>
      <link>https://dev.to/onethingwell</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/onethingwell"/>
    <language>en</language>
    <item>
      <title>Linux: Finding ASCII code of a key</title>
      <dc:creator>Nick | OneThingWell.dev</dc:creator>
      <pubDate>Fri, 05 Apr 2024 11:54:16 +0000</pubDate>
      <link>https://dev.to/onethingwell/linux-finding-ascii-code-of-a-key-8jo</link>
      <guid>https://dev.to/onethingwell/linux-finding-ascii-code-of-a-key-8jo</guid>
      <description>&lt;p&gt;You can use &lt;code&gt;showkey&lt;/code&gt; command from &lt;code&gt;kbd&lt;/code&gt; package to quickly find out an ASCII code of a key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;showkey -a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that you you can press any number of keys to find out their ASCII codes (you can press CTRL+d to terminate the program).&lt;/p&gt;

&lt;p&gt;Note: &lt;code&gt;kbd&lt;/code&gt; package should be installed out-of-the-box on most Linux distributions, if you don't have it for some reason, you can install it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# deb-based (Debian, Ubuntu, Mint, Raspbian, Kali, etc.)
apt install kbd

# rpm-based (Fedora, CentOS, etc.)
dnf install kbd

# Arch
pacman -S kbd

# Alpine
apk add kbd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Alternatives
&lt;/h2&gt;

&lt;p&gt;Alternatively, you can use the man page of &lt;code&gt;ascii&lt;/code&gt; command (this should work both on Linux on BSD):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;man ascii
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'll include the tables here for convenience:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       Oct   Dec   Hex   Char                      │ Oct   Dec   Hex   Char
       ────────────────────────────────────────────┼───────────────────────────
       000   0     00    NUL '\0' (null character) │ 100   64    40    @
       001   1     01    SOH (start of heading)    │ 101   65    41    A
       002   2     02    STX (start of text)       │ 102   66    42    B
       003   3     03    ETX (end of text)         │ 103   67    43    C
       004   4     04    EOT (end of transmission) │ 104   68    44    D
       005   5     05    ENQ (enquiry)             │ 105   69    45    E
       006   6     06    ACK (acknowledge)         │ 106   70    46    F
       007   7     07    BEL '\a' (bell)           │ 107   71    47    G
       010   8     08    BS  '\b' (backspace)      │ 110   72    48    H
       011   9     09    HT  '\t' (horizontal tab) │ 111   73    49    I
       012   10    0A    LF  '\n' (new line)       │ 112   74    4A    J
       013   11    0B    VT  '\v' (vertical tab)   │ 113   75    4B    K
       014   12    0C    FF  '\f' (form feed)      │ 114   76    4C    L
       015   13    0D    CR  '\r' (carriage ret)   │ 115   77    4D    M
       016   14    0E    SO  (shift out)           │ 116   78    4E    N
       017   15    0F    SI  (shift in)            │ 117   79    4F    O
       020   16    10    DLE (data link escape)    │ 120   80    50    P
       021   17    11    DC1 (device control 1)    │ 121   81    51    Q
       022   18    12    DC2 (device control 2)    │ 122   82    52    R
       023   19    13    DC3 (device control 3)    │ 123   83    53    S
       024   20    14    DC4 (device control 4)    │ 124   84    54    T
       025   21    15    NAK (negative ack.)       │ 125   85    55    U
       026   22    16    SYN (synchronous idle)    │ 126   86    56    V
       027   23    17    ETB (end of trans. blk)   │ 127   87    57    W
       030   24    18    CAN (cancel)              │ 130   88    58    X
       031   25    19    EM  (end of medium)       │ 131   89    59    Y
       032   26    1A    SUB (substitute)          │ 132   90    5A    Z
       033   27    1B    ESC (escape)              │ 133   91    5B    [
       034   28    1C    FS  (file separator)      │ 134   92    5C    \  '\\'
       035   29    1D    GS  (group separator)     │ 135   93    5D    ]
       036   30    1E    RS  (record separator)    │ 136   94    5E    ^
       037   31    1F    US  (unit separator)      │ 137   95    5F    _
       040   32    20    SPACE                     │ 140   96    60    `
       041   33    21    !                         │ 141   97    61    a
       042   34    22    "                         │ 142   98    62    b
       043   35    23    #                         │ 143   99    63    c
       044   36    24    $                         │ 144   100   64    d
       045   37    25    %                         │ 145   101   65    e
       046   38    26    &amp;amp;                         │ 146   102   66    f
       047   39    27    '                         │ 147   103   67    g
       050   40    28    (                         │ 150   104   68    h
       051   41    29    )                         │ 151   105   69    i
       052   42    2A    *                         │ 152   106   6A    j
       053   43    2B    +                         │ 153   107   6B    k
       054   44    2C    ,                         │ 154   108   6C    l
       055   45    2D    -                         │ 155   109   6D    m
       056   46    2E    .                         │ 156   110   6E    n
       057   47    2F    /                         │ 157   111   6F    o
       060   48    30    0                         │ 160   112   70    p
       061   49    31    1                         │ 161   113   71    q
       062   50    32    2                         │ 162   114   72    r
       063   51    33    3                         │ 163   115   73    s
       064   52    34    4                         │ 164   116   74    t
       065   53    35    5                         │ 165   117   75    u
       066   54    36    6                         │ 166   118   76    v
       067   55    37    7                         │ 167   119   77    w
       070   56    38    8                         │ 170   120   78    x
       071   57    39    9                         │ 171   121   79    y
       072   58    3A    :                         │ 172   122   7A    z
       073   59    3B    ;                         │ 173   123   7B    {
       074   60    3C    &amp;lt;                         │ 174   124   7C    |
       075   61    3D    =                         │ 175   125   7D    }
       076   62    3E    &amp;gt;                         │ 176   126   7E    ~
       077   63    3F    ?                         │ 177   127   7F    DEL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compact tables in hex and decimal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          2 3 4 5 6 7       30 40 50 60 70 80 90 100 110 120
        -------------      ---------------------------------
       0:   0 @ P ` p     0:    (  2  &amp;lt;  F  P  Z  d   n   x
       1: ! 1 A Q a q     1:    )  3  =  G  Q  [  e   o   y
       2: " 2 B R b r     2:    *  4  &amp;gt;  H  R  \  f   p   z
       3: # 3 C S c s     3: !  +  5  ?  I  S  ]  g   q   {
       4: $ 4 D T d t     4: "  ,  6  @  J  T  ^  h   r   |
       5: % 5 E U e u     5: #  -  7  A  K  U  _  i   s   }
       6: &amp;amp; 6 F V f v     6: $  .  8  B  L  V  `  j   t   ~
       7: ' 7 G W g w     7: %  /  9  C  M  W  a  k   u  DEL
       8: ( 8 H X h x     8: &amp;amp;  0  :  D  N  X  b  l   v
       9: ) 9 I Y i y     9: '  1  ;  E  O  Y  c  m   w
       A: * : J Z j z
       B: + ; K [ k {
       C: , &amp;lt; L \ l |
       D: - = M ] m }
       E: . &amp;gt; N ^ n ~
       F: / ? O _ o DEL              
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;small&gt;&lt;br&gt;&lt;br&gt;
Note: This is a snapshot of the wiki page from &lt;a href="https://onethingwell.dev"&gt;OneThingWell.dev wiki&lt;/a&gt;, you can find the latest, fully formatted version here: &lt;a href="https://onethingwell.dev/linux-finding-ascii-code-of-a-key"&gt;onethingwell.dev/linux-finding-ascii-code-of-a-key&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
&lt;/small&gt;

</description>
      <category>linux</category>
      <category>cli</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Three great virtues of a programmer</title>
      <dc:creator>Nick | OneThingWell.dev</dc:creator>
      <pubDate>Wed, 21 Dec 2022 16:14:52 +0000</pubDate>
      <link>https://dev.to/onethingwell/three-great-virtues-of-a-programmer-1oh3</link>
      <guid>https://dev.to/onethingwell/three-great-virtues-of-a-programmer-1oh3</guid>
      <description>&lt;p&gt;In his book "Programming Perl" (also known as "Camel Book"), Larry Wall encourages us to develop these three great virtues of a programmer: laziness, impatience, and hubris.&lt;/p&gt;

&lt;p&gt;There are many ways to interpret this, but in the second edition of the book, we have a glossary with definitions of these terms:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Laziness&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The quality that makes you go to great effort to reduce overall energy expenditure. It makes you write labor-saving programs that other people will find useful, and document what you wrote so you don't have to answer so many questions about it. Hence, the first great virtue of a programmer. Also hence, this book. See also impatience and hubris. (page 609)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impatience&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The anger you feel when the computer is being lazy. This makes you write programs that don't just react to your needs, but actually anticipate them. Or at least pretend to. Hence, the second great virtue of a programmer. See also laziness and hubris. (page 608)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hubris&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Excessive pride, the sort of thing Zeus zaps you for. Also the quality that makes you write (and maintain) programs that other people won't want to say bad things about. Hence, the third great virtue of a programmer. See also laziness and impatience. (page 607)&lt;/p&gt;




&lt;p&gt;I've seen a lot of criticism of this, especially in the context of the author and his design of Perl, but leaving that aside, I think there's some truth to this.&lt;/p&gt;

&lt;p&gt;Almost all great programmers I've met had these virtues, at least to some degree (and in some sense of these words). A sort of pride or hubris is a huge motivator to improve things, to come up with something better. And the combination of impatience and laziness can help you to force yourself to find less wasteful, less broken ways.&lt;/p&gt;

&lt;p&gt;That being said, I've also seen lousy programmers with these virtues, so I'm not sure I'd recommend actively developing them; but if you already do have them, maybe you can use them to your advantage.&lt;/p&gt;




&lt;small&gt;&lt;br&gt;&lt;br&gt;
Note: This is a snapshot of the wiki page from the &lt;a href="https://betterways.dev"&gt;BetterWays.dev wiki&lt;/a&gt;, you can find the latest, fully formatted version here: &lt;a href="https://betterways.dev/three-great-virtues-of-a-programmer"&gt;betterways.dev/three-great-virtues-of-a-programmer&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
&lt;/small&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>discuss</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Finding out environment variables of the process on Linux</title>
      <dc:creator>Nick | OneThingWell.dev</dc:creator>
      <pubDate>Fri, 21 Oct 2022 10:04:00 +0000</pubDate>
      <link>https://dev.to/onethingwell/finding-out-environment-variables-of-the-process-on-linux-4ibg</link>
      <guid>https://dev.to/onethingwell/finding-out-environment-variables-of-the-process-on-linux-4ibg</guid>
      <description>&lt;p&gt;As you probably know, each process on Linux can define its own environment variables (which are by default inherited by child processes).&lt;/p&gt;

&lt;p&gt;Let's create an example process and pass it two environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a=1 b=2 sleep 120 &amp;amp;
PID=$!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we're creating a process that will sleep for 120 seconds, then we're saving its process id (PID) in a variable named &lt;code&gt;$PID&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can read the initial variables from the &lt;code&gt;/proc/$PID/environ&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat /proc/$PID/environ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;b=2a=1SHELL=/bin/bashWINDOWID=16831489QT_ACCESSIBILITY=1COLORTERM=rxvt-xpm ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since entries are separated by the null byte character ('\0'), the output is not very readable, so let's try to fix that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sed -z 's/$/\n/' /proc/$PID/environ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-z&lt;/code&gt; option tells &lt;code&gt;sed&lt;/code&gt; that new lines are separated by the null byte character, instead of the usual newline character - exactly what we need here.&lt;/p&gt;

&lt;p&gt;That output is now more readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;b=2
a=1
SHELL=/bin/bash
WINDOWID=16831489
QT_ACCESSIBILITY=1
COLORTERM=rxvt-xpm
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: use this only for display purposes, entries are separated by the null byte character for a good reason - it's the only character that can't be part of the value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives
&lt;/h2&gt;

&lt;p&gt;Alternatively, we could also use &lt;code&gt;ps&lt;/code&gt; for this purpose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ps e -p $PID -ww
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're using &lt;code&gt;e&lt;/code&gt; option to tell &lt;code&gt;ps&lt;/code&gt; to show the environment variables after the command, &lt;code&gt;-p&lt;/code&gt; to specify the process id, and &lt;code&gt;-ww&lt;/code&gt; for wide output (unlimited width).&lt;/p&gt;

&lt;p&gt;Example output (entries are separated by spaces):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; 657114 pts/47   S      0:00 sleep 120 b=2 a=1 SHELL=/bin/bash WINDOWID=16831489 QT_ACCESSIBILITY=1 COLORTERM=rxvt-xpm ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Updated values
&lt;/h2&gt;

&lt;p&gt;As I mentioned earlier, &lt;code&gt;/proc/$PID/environ&lt;/code&gt; contains only initial variables. If the process changes its environment, and you want to read updated variables, you'll need to do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 'p (char *) getenv("a")' | gdb -q -p $PID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value should be included in the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) $1 = 0x7ffeddf781d4 "1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;small&gt;&lt;br&gt;&lt;br&gt;
Note: This is a snapshot of the wiki page from the &lt;a href="https://betterways.dev"&gt;BetterWays.dev wiki&lt;/a&gt;, you can find the latest, fully formatted version here: &lt;a href="https://betterways.dev/finding-out-environment-variables-of-the-process-on-linux"&gt;betterways.dev/finding-out-environment-variables-of-the-process-on-linux&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
&lt;/small&gt;

</description>
      <category>linux</category>
      <category>tutorial</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Creating a whole directory tree at once in Linux/Unix</title>
      <dc:creator>Nick | OneThingWell.dev</dc:creator>
      <pubDate>Wed, 19 Oct 2022 15:22:00 +0000</pubDate>
      <link>https://dev.to/onethingwell/creating-a-directory-tree-at-once-in-linuxunix-1bo2</link>
      <guid>https://dev.to/onethingwell/creating-a-directory-tree-at-once-in-linuxunix-1bo2</guid>
      <description>&lt;p&gt;Instead of creating each directory in the tree separately, you can use brace expansion to do this in a single line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p testdir/{subdir1/subdir11/{subdir111,subdir112},subdir2,subdir3}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we check the result with &lt;code&gt;tree testdir&lt;/code&gt;, the result should be as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;testdir
├── subdir1
│   └── subdir11
│       ├── subdir111
│       └── subdir112
├── subdir2
└── subdir3

6 directories, 0 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works in most shells today, including &lt;code&gt;bash&lt;/code&gt; and &lt;code&gt;zsh&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;Brace expansion is a similar mechanism to filename expansion, but the generated filenames don't need to exist. For example, if we put echo in front of the above command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo mkdir -p testdir/{subdir1/subdir11/{subdir111,subdir112},subdir2,subdir3}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll see the expanded command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p testdir/subdir1/subdir11/subdir111 testdir/subdir1/subdir11/subdir112 testdir/subdir2 testdir/subdir3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: we have to use the mkdir's &lt;code&gt;-p&lt;/code&gt; option to make the parent directories automatically, otherwise the command would fail.&lt;/p&gt;




&lt;small&gt;&lt;br&gt;&lt;br&gt;
Note: This is a snapshot of the wiki page from the &lt;a href="https://betterways.dev"&gt;BetterWays.dev wiki&lt;/a&gt;, you can find the latest, fully formatted version here: &lt;a href="https://betterways.dev/creating-a-directory-tree-at-once-in-linux-unix"&gt;betterways.dev/creating-a-directory-tree-at-once-in-linux-unix&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
&lt;/small&gt;

</description>
      <category>linux</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>CLI: Backing up and restoring file modification times</title>
      <dc:creator>Nick | OneThingWell.dev</dc:creator>
      <pubDate>Tue, 27 Sep 2022 11:08:13 +0000</pubDate>
      <link>https://dev.to/onethingwell/cli-backing-up-and-restoring-file-modification-times-2dn9</link>
      <guid>https://dev.to/onethingwell/cli-backing-up-and-restoring-file-modification-times-2dn9</guid>
      <description>&lt;p&gt;I recently needed to keep the exact file modification times as a part of a git repository. Since git doesn't support such functionality out of the box, I used a simple combination of &lt;code&gt;find&lt;/code&gt; and &lt;code&gt;touch&lt;/code&gt; commands as a part of the pre-commit hook.&lt;/p&gt;

&lt;p&gt;Here are two versions of this approach, one with the &lt;code&gt;stat&lt;/code&gt; command, and the other one with just the combination of &lt;code&gt;find&lt;/code&gt; and &lt;code&gt;touch&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1st version (stat)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;find . -type f -exec stat -c 'touch -d "%y" "%n"' {} \; &amp;gt; restore_mtimes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using the &lt;code&gt;find&lt;/code&gt; command, we're recursively iterating over all files (-type f) in all subdirectories, starting from the current directory (&lt;code&gt;.&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;for each file, we're executing (-exec flag) the &lt;code&gt;stat ...&lt;/code&gt; command (The string &lt;code&gt;{}&lt;/code&gt; is replaced by the current file name)&lt;/li&gt;
&lt;li&gt;we're using the formatted output of &lt;code&gt;stat&lt;/code&gt; command (-c flag) to generate &lt;code&gt;touch -d "%y" "%n"&lt;/code&gt; lines as a part of our restore script ("%y" is modification time, "%n" is file name).&lt;/li&gt;
&lt;li&gt;we're redirecting the whole output of the &lt;code&gt;find&lt;/code&gt; command to the &lt;code&gt;restore_mtimes&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The resulting &lt;code&gt;restore_mtimes&lt;/code&gt; file looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch -d "2022-09-26 15:55:10.127898032 +0200" "./f2"
touch -d "2022-09-26 15:55:11.651909078 +0200" "./f3"
touch -d "2022-09-26 15:55:06.751873534 +0200" "./f1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can execute this file to restore the original modification times (either by making it executable with &lt;code&gt;chmod +x restore_mtimes&lt;/code&gt; or sourcing it directly with &lt;code&gt;. restore_mtimes&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  2nd version (find &amp;amp; touch)
&lt;/h2&gt;

&lt;p&gt;Since we only need the file modification time, we could optimize things by removing the unnecessary call to the &lt;code&gt;stat&lt;/code&gt; command, and simply use the modification time provided by &lt;code&gt;find&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;find . -type f -printf 'touch -d "%t" "%p"\n' &amp;gt; restore_mtimes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;"%t" is modification time, "%p" is file name&lt;/li&gt;
&lt;li&gt;unlike with &lt;code&gt;stat -c&lt;/code&gt;, we also need to explicitly add a newline character at the end&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The time format returned by find is a bit different (but it should be also parsed correctly by &lt;code&gt;touch&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;touch -d "Mon Sep 26 15:55:10.1278980320 2022" "./f2"
touch -d "Mon Sep 26 15:55:11.6519090780 2022" "./f3"
touch -d "Mon Sep 26 15:55:06.7518735340 2022" "./f1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Alternatives and additional things to consider:&lt;/p&gt;

&lt;h2&gt;
  
  
  VCS commit times
&lt;/h2&gt;

&lt;p&gt;One alternative to backing up file modification times is reusing the last commit time from your versioning control system, e.g.: &lt;a href="/restoring-file-mtimes-with-git"&gt;restoring file mtimes with git&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  touch --no-create
&lt;/h2&gt;

&lt;p&gt;In cases where you're planning to restore the modification times to a tree where some files may be deleted, it may be useful to add the &lt;code&gt;--no-create&lt;/code&gt; flag (which will prevent &lt;code&gt;touch&lt;/code&gt; from creating any new files).&lt;/p&gt;




&lt;small&gt;&lt;br&gt;&lt;br&gt;
Note: This is a snapshot of the wiki page from the &lt;a href="https://betterways.dev"&gt;BetterWays.dev wiki&lt;/a&gt;, you can find the latest, better formatted version here: &lt;a href="https://betterways.dev/cli-backing-up-and-restoring-file-modification-times"&gt;betterways.dev/cli-backing-up-and-restoring-file-modification-times&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
&lt;/small&gt;

</description>
      <category>linux</category>
      <category>tutorial</category>
      <category>devops</category>
      <category>programming</category>
    </item>
    <item>
      <title>"Copy to Clipboard" functionality in plain JavaScript</title>
      <dc:creator>Nick | OneThingWell.dev</dc:creator>
      <pubDate>Sun, 18 Sep 2022 14:20:27 +0000</pubDate>
      <link>https://dev.to/onethingwell/copy-to-clipboard-functionality-in-plain-javascript-8fk</link>
      <guid>https://dev.to/onethingwell/copy-to-clipboard-functionality-in-plain-javascript-8fk</guid>
      <description>&lt;p&gt;In modern browsers, you can use Clipboard API to read and write to the system clipboard.&lt;/p&gt;

&lt;p&gt;Clipboard API consists of four asynchronous methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;navigator.clipboard.read()&lt;/code&gt; - reading arbitrary data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;navigator.clipboard.readText()&lt;/code&gt; - reading text&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;navigator.clipboard.write()&lt;/code&gt; - writing arbitrary data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;navigator.clipboard.writeText()&lt;/code&gt; - writing text&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's very easy to use the &lt;code&gt;writeText()&lt;/code&gt; method to implement a simple "Copy to Clipboard" functionality.&lt;/p&gt;

&lt;p&gt;HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"copy-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"copy-btn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Copy to Clipboard&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;copy-btn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clipboard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Clipboard API is not available&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;copy-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clipboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Copied to clipboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you try to run this code, you should see "Copied to clipboard" text in the console after clicking the copy button.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explanation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;copy-btn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clipboard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Clipboard API is not available&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&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;



&lt;p&gt;First, we're attaching onclick event handler to our "#copy-btn" button, and checking &lt;code&gt;navigator.clipboard&lt;/code&gt; is available. We don't want our code to break if it's not, so we will just log an error and return.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;copy-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clipboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Copied to clipboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;



&lt;p&gt;Then we're getting the text value from our "copy-text" input element, and using &lt;code&gt;navigator.clipboard.writeText&lt;/code&gt; method to write it to the system clipboard. Keep in mind that &lt;code&gt;writeText&lt;/code&gt; is an async method that returns a promise, and you need to use the promise API directly (like the above), or use async/await.&lt;/p&gt;

&lt;p&gt;Common mistake I've seen often is to do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clipboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Copied to clipboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which will log "Copied to clipboard" immediately after calling &lt;code&gt;writeText&lt;/code&gt; (regardless if the operation was successful or not).&lt;/p&gt;

&lt;h2&gt;
  
  
  Permissions API
&lt;/h2&gt;

&lt;p&gt;"clipboard-write" permission is automatically granted to pages when they are in the active tab, but if you need to explicitly check for the permission, you can use something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clipboard-write&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;small&gt;&lt;br&gt;&lt;br&gt;
Note: This is a snapshot of the wiki page from the &lt;a href="https://betterways.dev"&gt;BetterWays.dev wiki&lt;/a&gt;, you can find the latest, better formatted version here: &lt;a href="https://betterways.dev/copy-to-clipboard-in-plain-javascript"&gt;betterways.dev/copy-to-clipboard-in-plain-javascript&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
&lt;/small&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Simple, reliable, fast (in that order)</title>
      <dc:creator>Nick | OneThingWell.dev</dc:creator>
      <pubDate>Thu, 15 Sep 2022 10:43:15 +0000</pubDate>
      <link>https://dev.to/onethingwell/simple-reliable-fast-in-that-order-51ae</link>
      <guid>https://dev.to/onethingwell/simple-reliable-fast-in-that-order-51ae</guid>
      <description>&lt;p&gt;If I had to summarize my approach to software development in three words, the words "simple, reliable, fast" come to mind.&lt;/p&gt;

&lt;p&gt;This phrase is my variation of Drew DeValut's "Simple, correct, fast: in that order" phrase. While "correct" is definitely a relevant word here, I think "robust" and "reliable" are more relevant.&lt;/p&gt;

&lt;p&gt;So, let's try to first define the words "correctness", "robustness" and "reliability".&lt;/p&gt;

&lt;p&gt;I'll use Matthew Wilson's definitions (from his "Quality Matters: Correctness, Robustness and Reliability" article), because I think they make the most sense in this context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Correctness: The degree to which a software entity's behavior matches its specification.&lt;/li&gt;
&lt;li&gt;Robustness: The adjudged ability of a software entity to behave according to the expectations of its stakeholders.&lt;/li&gt;
&lt;li&gt;Reliability: The degree to which a software system behaves robustly over time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While all three words are relevant in this context, in the practical sense robustness is more relevant than correctness, and reliability implies robustness over time.&lt;/p&gt;

&lt;p&gt;The question is - how do we achieve these characteristics, and more importantly, how do we maintain them in the long term? Obviously, these characteristics are important for all software projects, but the vast majority of them end up having almost the opposite characteristics.&lt;/p&gt;

&lt;p&gt;So, why do so many software projects fail in that regard? Complexity has a lot to do with it.&lt;/p&gt;

&lt;p&gt;Complexity kills, and it's extremely easy to introduce additional complexity on every step of the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplicity first
&lt;/h2&gt;

&lt;p&gt;"Simplicity is a great virtue but it requires hard work to achieve it and education to appreciate it. And to make matters worse: complexity sells better." (Edsger W. Dijkstra)&lt;/p&gt;

&lt;p&gt;Simplicity-first approach definitely requires a lot of hard work, but it's almost a prerequisite for these characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;robustness and reliability ("Simplicity is prerequisite for reliability" - Dijkstra)&lt;/li&gt;
&lt;li&gt;performance (simple code is much easier to profile and optimize)&lt;/li&gt;
&lt;li&gt;composability (try to make your design composable - when you have a complex problem, try to split it into smaller, simpler composable parts)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the other hand, with more complex/intertwined solutions, even if you manage to temporary achieve those characteristics, it will be extremely hard (or impossible) to maintain them in the long term.&lt;/p&gt;




&lt;small&gt;&lt;br&gt;&lt;br&gt;
Note: This is a snapshot of the wiki page from the &lt;a href="https://betterways.dev"&gt;BetterWays.dev wiki&lt;/a&gt;, you can find the latest (better formatted) version here: &lt;a href="https://betterways.dev/simple-reliable-fast"&gt;betterways.dev/simple-reliable-fast&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
&lt;/small&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Simple JavaScript template engine by (ab)using template literals</title>
      <dc:creator>Nick | OneThingWell.dev</dc:creator>
      <pubDate>Mon, 12 Sep 2022 13:37:05 +0000</pubDate>
      <link>https://dev.to/onethingwell/simple-javascript-template-engine-by-abusing-template-literals-2md</link>
      <guid>https://dev.to/onethingwell/simple-javascript-template-engine-by-abusing-template-literals-2md</guid>
      <description>&lt;p&gt;Templating inline strings is simple using ES6 template literals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const a = "hello"
const b = "world"

console.log(`${a} ${b}`)
//hello world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what if you have a string that can't be inlined (i.e. it comes from an external source)?&lt;/p&gt;

&lt;p&gt;Here's the gist of the function I recently used for this purpose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function tpl(str, props) {
    let names = Object.keys(props);
    let vals = Object.values(props);
    return new Function(...names, `return \`${str}\`;`)(...vals);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, (a slightly less readable) one-liner version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const tpl = (str, props) =&amp;gt; new Function(...Object.keys(props), `return \`${str}\`;`)(...Object.values(props))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(tpl('${a} ${b}', {a: 'hello', b: 'world'}))
//hello world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Explanation
&lt;/h2&gt;

&lt;p&gt;So, we are defining a function called &lt;code&gt;tpl&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;function tpl(str, props) {
    let names = Object.keys(props);
    let vals = Object.values(props);
    return new Function(...names, `return \`${str}\`;`)(...vals);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first two lines are self-explanatory - we are just extracting keys and values from the passed-in &lt;code&gt;props&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;In the last line, we are dynamically creating a function from a string. Instead of doing &lt;code&gt;eval&lt;/code&gt;, we are using the &lt;code&gt;Function&lt;/code&gt; constructor, which is a much safer alternative.&lt;/p&gt;

&lt;p&gt;Our new (dynamically generated) function receives a list of names of our props keys, and returns the same passed-in &lt;code&gt;str&lt;/code&gt; string but delimited with backtick characters (basically, we are turning our "external" string into an inline template string). &lt;/p&gt;

&lt;p&gt;After that, we just need to call our new function with a list of values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Function.call alternative
&lt;/h2&gt;

&lt;p&gt;We could simplify things by doing something like this instead of extracting names and values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new Function(`return \`${str}\`;`).call(props)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But then we would need to use &lt;code&gt;${this.a}&lt;/code&gt; instead of just &lt;code&gt;${a}&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching
&lt;/h2&gt;

&lt;p&gt;Each time you're calling the &lt;code&gt;Function&lt;/code&gt; constructor, the function body needs to be parsed (some overhead), but it would be very easy to do some caching based on the value of &lt;code&gt;str&lt;/code&gt;.&lt;/p&gt;




&lt;small&gt;&lt;br&gt;&lt;br&gt;
Note: This is a snapshot of the wiki page from the &lt;a href="https://betterways.dev"&gt;BetterWays.dev wiki&lt;/a&gt;, you can find the latest (better formatted) version here: &lt;a href="https://betterways.dev/simple-javascript-template-engine-by-ab-using-template-literals"&gt;betterways.dev/simple-javascript-template-engine-by-ab-using-template-literals&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
&lt;/small&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Setting up a simple SOCKS proxy tunnel over SSH</title>
      <dc:creator>Nick | OneThingWell.dev</dc:creator>
      <pubDate>Sat, 10 Sep 2022 14:58:27 +0000</pubDate>
      <link>https://dev.to/onethingwell/setting-up-a-simple-socks-proxy-tunnel-over-ssh-224</link>
      <guid>https://dev.to/onethingwell/setting-up-a-simple-socks-proxy-tunnel-over-ssh-224</guid>
      <description>&lt;p&gt;If you have any kind of Linux/Unix server accessible over SSH, it's very easy to use it as a simple proxy server. This can be useful to bypass content filters and other restrictions on your local Internet connection. Even the cheapest Linux/BSD VPS options will be more than enough for this.&lt;/p&gt;

&lt;p&gt;This feature is built into OpenSSH, and you don't need to install any additional software, or do any additional configuration.&lt;/p&gt;

&lt;p&gt;All you need to do is open an ssh connection from the client side with a dynamic port forwarding option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -D 1080 myserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-D&lt;/code&gt; option tells ssh to use the local 1080 port for dynamic, application-level port forwarding. In a practical sense, this means that your ssh client will act as a SOCKS 4/5 server on that port.&lt;/p&gt;

&lt;p&gt;Depending on your configuration, you may also need to specify an SSH port and user (i.e. &lt;code&gt;ssh -p 2222 myuser@myserver&lt;/code&gt;, but in that case, you may want to consider setting up a host profile in your ~/.ssh/config file instead).&lt;/p&gt;

&lt;p&gt;After that, all you need to do is tell your browser to use a SOCKS proxy on localhost:1080.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browser setup
&lt;/h2&gt;

&lt;p&gt;In Firefox, you can set SOCKS proxy in Settings / Network Settings / Configure Proxy Access to the Internet - Manual proxy configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SOCKS Host: localhost&lt;/li&gt;
&lt;li&gt;Port: 1080&lt;/li&gt;
&lt;li&gt;SOCKS v5&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Google Chrome/Chromium, you need to start the browser with &lt;code&gt;--proxy-server&lt;/code&gt; argument:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chromium --proxy-server="socks5://localhost:1080"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Non-interactive / scripting use
&lt;/h2&gt;

&lt;p&gt;If you don't want the SSH client to open an interactive session, you can prevent it from executing the shell with &lt;code&gt;-N&lt;/code&gt; flag, and &lt;code&gt;-f&lt;/code&gt; flag to put it into the background, i.e.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -N -f -D 1080 myserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to automatically restart the connection when necessary, you can use &lt;code&gt;autossh&lt;/code&gt; tool (the syntax is the same):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;autossh -N -f -D 1080 myserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Putty
&lt;/h2&gt;

&lt;p&gt;If you're using Putty instead of CLI ssh client, you need to add 1080 as a source port and select Dynamic as a forwarding option under Connection / SSH / Tunnels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant ssh options
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     -D [bind_address:]port
             Specifies a local “dynamic” application-level port forwarding.
             This works by allocating a socket to listen to port on the local
             side, optionally bound to the specified bind_address.  Whenever a
             connection is made to this port, the connection is forwarded over
             the secure channel, and the application protocol is then used to
             determine where to connect to from the remote machine.  Currently
             the SOCKS4 and SOCKS5 protocols are supported, and ssh will act
             as a SOCKS server.  Only root can forward privileged ports.  Dy‐
             namic port forwardings can also be specified in the configuration
             file.

             IPv6 addresses can be specified by enclosing the address in
             square brackets.  Only the superuser can forward privileged
             ports.  By default, the local port is bound in accordance with
             the GatewayPorts setting.  However, an explicit bind_address may
             be used to bind the connection to a specific address.  The
             bind_address of “localhost” indicates that the listening port be
             bound for local use only, while an empty address or ‘*’ indicates
             that the port should be available from all interfaces.

     -N      Do not execute a remote command.  This is useful for just for‐
             warding ports.

     -f      Requests ssh to go to background just before command execution.
             This is useful if ssh is going to ask for passwords or
             passphrases, but the user wants it in the background.  This im‐
             plies -n.  The recommended way to start X11 programs at a remote
             site is with something like ssh -f host xterm.

             If the ExitOnForwardFailure configuration option is set to “yes”,
             then a client started with -f will wait for all remote port for‐
             wards to be successfully established before placing itself in the
             background.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;small&gt;&lt;br&gt;&lt;br&gt;
Note: This is a snapshot of the wiki page from the &lt;a href="https://betterways.dev"&gt;BetterWays.dev wiki&lt;/a&gt;, you can find the latest (better formatted) version here: &lt;a href="https://betterways.dev/setting-up-a-simple-socks-proxy-tunnel-over-ssh"&gt;betterways.dev/setting-up-a-simple-socks-proxy-tunnel-over-ssh&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
&lt;/small&gt;

</description>
      <category>linux</category>
      <category>tutorial</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Inxi - Finding out hardware configuration on Linux</title>
      <dc:creator>Nick | OneThingWell.dev</dc:creator>
      <pubDate>Thu, 08 Sep 2022 11:42:01 +0000</pubDate>
      <link>https://dev.to/onethingwell/inxi-finding-out-hardware-configuration-on-linux-4cib</link>
      <guid>https://dev.to/onethingwell/inxi-finding-out-hardware-configuration-on-linux-4cib</guid>
      <description>&lt;p&gt;Inxi is a great tool you can use to find out the system and hardware information on a Linux system.&lt;/p&gt;

&lt;p&gt;If you're using Debian/Ubuntu-based distribution, you can install it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;inxi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On rpm-based distros, you can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dnf &lt;span class="nb"&gt;install &lt;/span&gt;inxi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Arch Linux, you can install &lt;code&gt;inxi&lt;/code&gt; package from AUR.&lt;/p&gt;

&lt;p&gt;You can use &lt;code&gt;inxi --recommends&lt;/code&gt; to check if you need to install additional dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic use
&lt;/h2&gt;

&lt;p&gt;If you run just the &lt;code&gt;inxi&lt;/code&gt; command, you'll get a quick summary like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CPU: Single Core Intel Xeon (Skylake IBRS) (-MCP-) speed: 2100 MHz 
Kernel: 4.19.0-12-amd64 x86_64 Up: 649d 1h 15m Mem: 350.9/1947.2 MiB (18.0%) 
Storage: 19.07 GiB (11.9% used) Procs: 87 Shell: bash 5.0.3 inxi: 3.0.32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get a full summary, you can use &lt;code&gt;-F&lt;/code&gt; or &lt;code&gt;--full&lt;/code&gt; flag, i.e. &lt;code&gt;inxi -F&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;System:    Host: s Kernel: 4.19.0-12-amd64 x86_64 bits: 64 Console: tty 0 Distro: Debian GNU/Linux 10 (buster) 
Machine:   Type: Kvm System: BetterWays product: vServer v: 20171111 serial: 8711068 
           Mobo: N/A model: N/A serial: N/A BIOS: BetterWays v: 20171111 date: 11/11/2017 
CPU:       Topology: Single Core model: Intel Xeon (Skylake IBRS) bits: 64 type: MCP L2 cache: 16.0 MiB 
           Speed: 2100 MHz min/max: N/A Core speed (MHz): 1: 2100 
Graphics:  Device-1: driver: bochs-drm v: N/A 
           Display: server: No display server data found. Headless machine? tty: 237x63 
           Message: Unable to show advanced data. Required tool glxinfo missing. 
Audio:     Message: No Device data found. 
Network:   Device-1: Intel 82371AB/EB/MB PIIX4 ACPI type: network bridge driver: piix4_smbus 
           Device-2: Red Hat Virtio network driver: virtio-pci 
           IF: eth0 state: up speed: -1 duplex: unknown mac: 96:00:00:80:bb:5e 
Drives:    Local Storage: total: 19.07 GiB used: 2.27 GiB (11.9%) 
           ID-1: /dev/sda vendor: QEMU model: HARDDISK size: 19.07 GiB 
Partition: ID-1: / size: 18.60 GiB used: 2.27 GiB (12.2%) fs: ext4 dev: /dev/sda1 
Sensors:   Missing: Required tool sensors not installed. Check --recommends 
Info:      Processes: 88 Uptime: 649d 1h 19m Memory: 1.90 GiB used: 351.8 MiB (18.1%) Init: systemd runlevel: 5 Shell: bash 
           inxi: 3.0.32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If for some reason you get weird output, you can turn off colors with &lt;code&gt;-c 0&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Output
&lt;/h2&gt;

&lt;p&gt;The default behavior is to just output the information to the screen (&lt;code&gt;--output screen&lt;/code&gt; is implied).&lt;/p&gt;

&lt;p&gt;But we also can output the information to json/xml files, which can be very useful for scripting/programming purposes.&lt;/p&gt;

&lt;p&gt;You can use &lt;code&gt;inxi -F --output json --output-file /tmp/inxi.json&lt;/code&gt; to get a json file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "001#Partition": [
    {
      "001#ID": "/",
      "007#uuid": "4236cc65-d07b-4264-8ae6-ff71b870d7cc",
      "006#label": "N/A",
      "003#used": "2.27 GiB (12.2%)",
      "005#dev": "/dev/sda1",
      "002#size": "18.60 GiB",
      "004#fs": "ext4"
    }
  ],
  "000#CPU": [
    {
      "000#Topology": "Single Core",
      "002#bits": 64,
      "001#model": "Intel Xeon (Skylake IBRS)",
      "004#L2 cache": "16.0 MiB",
      "003#type": "MCP"
    },
    {
      "008#1": "2100",
      "005#Speed": "2100 MHz",
      "006#min/max": "N/A",
      "007#Core speed (MHz)": ""
    },
    {
      "009#Flags": "3dnowprefetch abm adx aes apic arat avx avx2 avx512bw avx512cd avx512dq avx512f avx512vl bmi1 bmi2 clflush clwb cmov constant_tsc cpuid cpuid_fault cx16 cx8 de erms f16c fma fpu fsgsbase fxsr hle hypervisor ibpb ibrs invpcid invpcid_single lahf_lm lm mca mce md_clear mmx movbe msr mtrr nopl nx ospke pae pat pcid pclmulqdq pdpe1gb pge pku pni popcnt pse pse36 pti rdrand rdseed rdtscp rep_good rtm sep smap smep ssbd sse sse2 sse4_1 sse4_2 ssse3 syscall tsc tsc_deadline_timer tsc_known_freq vme x2apic xgetbv1 xsave xsavec xsaveopt xtopology"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get an error message like &lt;code&gt;Error 80: The required json Perl module is not installed: Cpanel::JSON::XS OR JSON::XS&lt;/code&gt;, you need to install &lt;code&gt;libjson-xs-perl&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;xml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inxi -F --output xml --output-file /tmp/inxi.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case you see something like &lt;code&gt;Error 80: The required xml Perl module is not installed: XML::Dumper&lt;/code&gt;, you need to install &lt;code&gt;libxml-dumper-perl&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;If you need to just export textual info, you use normal output redirection (you can disable colors with &lt;code&gt;-c 0&lt;/code&gt;, but inxi will usually do that automatically if the connected output is not interactive terminal):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inxi -c 0 -F &amp;gt; /tmp/inxi.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Specific categories
&lt;/h2&gt;

&lt;p&gt;If you're interested only in specific categories, you can limit the output with the following flags (the same works for json/xml output):&lt;/p&gt;

&lt;p&gt;Audio info - &lt;code&gt;inxi -A&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;Audio:     Message: No Device data found.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CPU info - &lt;code&gt;inxi -C&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;CPU:       Topology: Single Core model: Intel Xeon (Skylake IBRS) bits: 64 type: MCP L2 cache: 16.0 MiB 
           Speed: 2100 MHz min/max: N/A Core speed (MHz): 1: 2100 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drives info - &lt;code&gt;inxi -D&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;Drives:    Local Storage: total: 19.07 GiB used: 2.27 GiB (11.9%) 
           ID-1: /dev/sda vendor: QEMU model: HARDDISK size: 19.07 GiB 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Graphics info - &lt;code&gt;inxi -G&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;Graphics:  Device-1: driver: bochs-drm v: N/A 
           Display: server: No display server data found. Headless machine? tty: 237x63 
           Message: Unable to show advanced data. Required tool glxinfo missing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Machine info - &lt;code&gt;inxi -M&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;Machine:   Type: Kvm System: BetterWays product: vServer v: 20171111 serial: 8711068 
           Mobo: N/A model: N/A serial: N/A BIOS: BetterWays v: 20171111 date: 11/11/2017 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Network info - &lt;code&gt;inxi -N&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;Network:   Device-1: Intel 82371AB/EB/MB PIIX4 ACPI type: network bridge driver: piix4_smbus 
           Device-2: Red Hat Virtio network driver: virtio-pci 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, of course, you can combine multiple categories - &lt;code&gt;inxi -C -D&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;CPU:       Topology: Single Core model: Intel Xeon (Skylake IBRS) bits: 64 type: MCP L2 cache: 16.0 MiB 
           Speed: 2100 MHz min/max: N/A Core speed (MHz): 1: 2100 
Drives:    Local Storage: total: 19.07 GiB used: 2.27 GiB (11.9%) 
           ID-1: /dev/sda vendor: QEMU model: HARDDISK size: 19.07 GiB 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Weather
&lt;/h2&gt;

&lt;p&gt;If that's not enough, &lt;code&gt;inxi&lt;/code&gt; can also show you the weather info with &lt;code&gt;inxi -w&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;Weather:
  Report: temperature: 29.4 C (85 F) conditions: Scattered clouds 
  Locale: current time: Sun 04 Sep 2022 02:40:34 PM CEST (Europe/Berlin) 
  Source: WeatherBit.io 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(you can specify the location with &lt;code&gt;-W&lt;/code&gt; switch)&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives
&lt;/h2&gt;

&lt;p&gt;A lot of this information can be found in /proc, which doesn't require any additional tool.&lt;/p&gt;

&lt;p&gt;Another popular script you may want to check is called &lt;code&gt;neofetch&lt;/code&gt;.&lt;/p&gt;




&lt;small&gt;&lt;br&gt;&lt;br&gt;
Note: This is a snapshot of the wiki page from the &lt;a href="https://betterways.dev"&gt;BetterWays.dev wiki&lt;/a&gt;, you can find the latest (better formatted) version here: &lt;a href="https://betterways.dev/inxi-finding-out-hardware-configuration-on-linux"&gt;betterways.dev/inxi-finding-out-hardware-configuration-on-linux&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
&lt;/small&gt;

</description>
      <category>linux</category>
      <category>tutorial</category>
      <category>productivity</category>
      <category>cli</category>
    </item>
    <item>
      <title>Functional core, imperative shell</title>
      <dc:creator>Nick | OneThingWell.dev</dc:creator>
      <pubDate>Mon, 29 Aug 2022 10:17:00 +0000</pubDate>
      <link>https://dev.to/onethingwell/functional-core-imperative-shell-4fde</link>
      <guid>https://dev.to/onethingwell/functional-core-imperative-shell-4fde</guid>
      <description>&lt;p&gt;I'm going to assume that you're at least somewhat familiar with basic functional programming concepts, but as a quick reminder:&lt;/p&gt;

&lt;p&gt;A pure function is a function that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;is referentially transparent - it will always return the same output for the same input&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;have no side effects - it doesn't affect the outside world&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This brings us a lot of benefits (referential transparency, unit testing, they are easier to reason about) and we should split as much functionality as possible into pure functions, but how do we get there?&lt;/p&gt;

&lt;p&gt;One technique that can help us get there is called the "Functional core, imperative shell". As the name says, the idea is to separate the effectful, imperative code into the outer shell and keep the inner core pure (functional core).&lt;/p&gt;

&lt;p&gt;Purely functional languages will nudge you in that direction due to their design (i.e. IO monads), but you can use and benefit from this technique in pretty much every programming language.&lt;/p&gt;

&lt;p&gt;If you're reading this guide, there's a good chance that you know at least some JavaScript. So, we're going to go with that.&lt;/p&gt;

&lt;p&gt;In some ways, JavaScript is also kind of nudging us in this direction. You've probably used async functions. While they are generally nicer to use than callbacks or promises directly, you soon realize that they don't really play nicely with the rest of your codebase - values inside promises are a very different beast from normal values, and functions which return promises are very different from normal functions.&lt;/p&gt;

&lt;p&gt;This is the important part. Instead of trying to mix those two concepts throughout our codebase (and infect almost everything in the process), the idea is that we take and isolate those async (and impure) stuff into the outer shell, so we can keep our core nice and clean.&lt;/p&gt;

&lt;p&gt;Here's a very simple example that should look familiar if you ever used something similar to express.js:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// imperative shell
async function handler(req, res) {
    var users = await fetchUsers()
    var projects = await fetchProjects()

    var result = render(transformData(users, projects))

    res.send(result)
}

// functional core
function transformData(users, projects) {}

function render(model) {}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, we have two parts:&lt;/p&gt;

&lt;h2 id="imperative-shell"&gt;Imperative shell&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;handler&lt;/code&gt; is an express-like request handler function, which represents our outer imperative shell. You can do pretty much what you want here - usually, you need to first get the data from somewhere (impure part), then transform data (pure part), then send the result (impure part).&lt;/p&gt;

&lt;h2 id="functional-core"&gt;Functional core&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;transformData&lt;/code&gt; and &lt;code&gt;render&lt;/code&gt; are pure functions - you should have all the needed data ready before calling into the functional core, as these functions will use only what they'll get in the parameters.&lt;/p&gt;

&lt;p&gt;This example is arbitrary, but here are a few points which may help you to understand it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;transformData&lt;/code&gt; function transforms (normalizes and prepares) the fetched data for rendering - you can see the returned data as a form of ViewModel - the data is organized in a way that we need for our view and if the outside data format ever changes, we just need to change the mapping function&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;render&lt;/code&gt; function takes that model and returns rendered html string - it can call other pure functions which return html parts (i.e. similar to the concepts of components or partial views)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, the idea itself is very simple, but it can take some effort (depending on the nature of the problem you're solving - i.e. IO-heavy code is harder to organize this way).&lt;/p&gt;




&lt;small&gt;&lt;br&gt;&lt;br&gt;
Note: This is a snapshot of the wiki page from the &lt;a href="https://betterways.dev"&gt;BetterWays.dev wiki&lt;/a&gt;, you can find the latest (better formatted) version here: &lt;a href="https://betterways.dev/functional-core-imperative-shell"&gt;betterways.dev/functional-core-imperative-shell&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
&lt;/small&gt;

</description>
      <category>programming</category>
      <category>functional</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Forcing a browser to download a file (HTML and server side)</title>
      <dc:creator>Nick | OneThingWell.dev</dc:creator>
      <pubDate>Fri, 26 Aug 2022 15:21:00 +0000</pubDate>
      <link>https://dev.to/onethingwell/forcing-a-browser-to-download-a-file-html-and-server-side-3hp3</link>
      <guid>https://dev.to/onethingwell/forcing-a-browser-to-download-a-file-html-and-server-side-3hp3</guid>
      <description>&lt;p&gt;When a user clicks a normal HTML link to a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="path/to/file.ext"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browsers will usually try to open the file directly (inline) instead of opening the file download dialog. &lt;/p&gt;

&lt;p&gt;You can use HTML5 &lt;code&gt;download&lt;/code&gt; attribute to tell modern browsers to open the download dialog instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="path/to/file.ext" download&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also specify the suggested filename the user will see in the download dialog:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="path/to/file.ext" download="myfile.ext"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you specify just the file name (without the extension), the extension will usually be inferred from the original filename (this example will still suggest "myfile.ext" in most browsers):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="path/to/file.ext" download="myfile"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Limitations and workarounds
&lt;/h2&gt;

&lt;p&gt;Nowadays, &lt;code&gt;download&lt;/code&gt; attribute is supported in all mainstream browsers, but there's an important limitation: this attribute only works for same-origin URLs (protocol, port, and host have to match), and the &lt;code&gt;blob:&lt;/code&gt; and &lt;code&gt;data:&lt;/code&gt; schemes.&lt;/p&gt;

&lt;p&gt;Besides the &lt;code&gt;download&lt;/code&gt; attribute, there's not much else you can do to force this behavior from the client side, but you can on the server side.&lt;/p&gt;

&lt;p&gt;Including the &lt;code&gt;Content-Disposition&lt;/code&gt; header in the HTTP response will have a similar effect to &lt;code&gt;download&lt;/code&gt; attribute (but without this limitation):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Content-Disposition: attachment; filename=file.ext
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll also need to send the &lt;code&gt;Content-type&lt;/code&gt; header and the actual file contents. &lt;/p&gt;

&lt;p&gt;In PHP, that would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Content-Disposition: attachment; filename="downloaded.pdf"'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Content-type: application/pdf'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;readfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'test.pdf'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But to avoid the performance overhead, I recommend doing that on the webserver level instead of the app level. &lt;/p&gt;

&lt;h3&gt;
  
  
  nginx
&lt;/h3&gt;

&lt;p&gt;For &lt;code&gt;nginx&lt;/code&gt; this could be as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;add_header Content-Disposition 'attachment; filename="file.ext"';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: nginx will usually send the correct &lt;code&gt;Content-type&lt;/code&gt; header automatically, but you can override that if needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;add_header Content-Type 'application/pdf'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a more general case, you could send a generic &lt;code&gt;application/octet-stream&lt;/code&gt; header and &lt;code&gt;Content-Disposition&lt;/code&gt; without a filename:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;location /myloc {
        if ($request_filename ~* ^.*?\.(pdf|zip|docx)$) {
            add_header Content-Disposition attachment;
            add_header Content-Type application/octet-stream;
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Combination of download attribute and Content-Disposition header
&lt;/h2&gt;

&lt;p&gt;If both the download attribute and Content-Disposition header are present and both define the filename, the filename defined in the header will have priority.&lt;/p&gt;

&lt;p&gt;In the case of &lt;code&gt;Content-Disposition: inline&lt;/code&gt; header (which tells the browser to display the contents &lt;code&gt;inline&lt;/code&gt; - as a part of the page), the download attribute will have the priority (for the same-origin URLs).&lt;/p&gt;




&lt;small&gt;&lt;br&gt;&lt;br&gt;
Note: This is a snapshot of the page from the &lt;a href="https://betterways.dev"&gt;BetterWays.dev&lt;/a&gt; wiki, you can find the latest (better formatted) version here: &lt;a href="https://betterways.dev/forcing-a-browser-to-download-a-file"&gt;betterways.dev/forcing-a-browser-to-download-a-file&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
&lt;/small&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>html</category>
      <category>php</category>
    </item>
  </channel>
</rss>
