From d4ee6684b7d6c8c8e5ff96f6998755c42465ec22 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 18 May 2024 13:24:42 +0300 Subject: Update content for html --- gemfeed/2008-06-26-perl-poetry.html | 148 +-- gemfeed/2010-04-09-standard-ml-and-haskell.html | 166 +-- .../2010-05-09-the-fype-programming-language.html | 78 +- .../2011-05-07-perl-daemon-service-framework.html | 120 +-- .../2014-03-24-the-fibonacci.pl.c-polyglot.html | 188 ++-- ...2-05-run-debian-on-your-phone-with-debroid.html | 184 ++-- ...20-object-oriented-programming-with-ansi-c.html | 66 +- ...021-05-16-personal-bash-coding-style-guide.html | 276 ++--- ...5-gemtexter-one-bash-script-to-rule-it-all.html | 36 +- ...2-08-27-gemtexter-1.1.0-lets-gemtext-again.html | 34 +- ...-tried-emacs-but-i-switched-back-to-neovim.html | 8 +- ...03-25-gemtexter-2.0.0-lets-gemtext-again-2.html | 18 +- ...ithms-and-data-structures-in-golang-part-1.html | 240 ++--- ...iling-guprecords:-uptime-records-with-raku.html | 2 +- ...3-06-01-kiss-server-monitoring-with-gogios.html | 102 +- ...07-21-gemtexter-2.1.0-lets-gemtext-again-3.html | 10 +- gemfeed/2023-09-25-dtail-usage-examples.html | 106 +- ...static-web-photo-albums-with-photoalbum.sh.html | 118 +- gemfeed/2023-12-10-bash-golf-part-3.html | 238 ++--- .../2024-01-13-one-reason-why-i-love-openbsd.html | 10 +- ...-04-01-KISS-high-availability-with-OpenBSD.html | 200 ++-- ...03-projects-i-currently-dont-have-time-for.html | 12 +- .../DRAFT-KISS-high-availability-with-OpenBSD.html | 198 ++-- gemfeed/atom.xml | 1122 ++++++++++---------- index.html | 2 +- testpage.html | 38 +- uptime-stats.html | 2 +- 27 files changed, 1861 insertions(+), 1861 deletions(-) diff --git a/gemfeed/2008-06-26-perl-poetry.html b/gemfeed/2008-06-26-perl-poetry.html index 7d1ce809..7b6130aa 100644 --- a/gemfeed/2008-06-26-perl-poetry.html +++ b/gemfeed/2008-06-26-perl-poetry.html @@ -47,44 +47,44 @@ _~~|~/_|_|__/|~~~~~~~ | / ~~~~~ | | ~~~~~~~~ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
#!/usr/bin/perl
+
#!/usr/bin/perl
 
-# (C) 2006 by Paul C. Buetow
+# (C) 2006 by Paul C. Buetow
 
-goto library for study $math;
-BEGIN { s/earching/ books/ 
-and read $them, $at, $the } library:
+goto library for study $math;
+BEGIN { s/earching/ books/ 
+and read $them, $at, $the } library:
 
-our $topics, cos and tan, 
-require strict; import { of, tied $patience };
+our $topics, cos and tan, 
+require strict; import { of, tied $patience };
 
-do { int'egrate'; sub trade; };
-do { exp'onentize' and abs'olutize' };
-study and study and study and study;
+do { int'egrate'; sub trade; };
+do { exp'onentize' and abs'olutize' };
+study and study and study and study;
 
-foreach $topic ({of, math}) {
-you, m/ay /go, to, limits }
+foreach $topic ({of, math}) {
+you, m/ay /go, to, limits }
 
-do { not qw/erk / unless $success 
-and m/ove /o;$n and study };
+do { not qw/erk / unless $success 
+and m/ove /o;$n and study };
 
-do { int'egrate'; sub trade; };
-do { exp'onentize' and abs'olutize' };
-study and study and study and study;
+do { int'egrate'; sub trade; };
+do { exp'onentize' and abs'olutize' };
+study and study and study and study;
 
-grep /all/, exp'onents' and cos'inuses';
-/seek results/ for @all, log'4rithms';
+grep /all/, exp'onents' and cos'inuses';
+/seek results/ for @all, log'4rithms';
 
-'you' =~ m/ay /go, not home 
-unless each %book ne#ars
-$completion;
+'you' =~ m/ay /go, not home 
+unless each %book ne#ars
+$completion;
 
-do { int'egrate'; sub trade; };
-do { exp'onentize' and abs'olutize' };
+do { int'egrate'; sub trade; };
+do { exp'onentize' and abs'olutize' };
 
-#at
-home: //ig,'nore', time and sleep $very =~ s/tr/on/g;
-__END__
+#at
+home: //ig,'nore', time and sleep $very =~ s/tr/on/g;
+__END__
 
 

@@ -94,47 +94,47 @@ __END__ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
#!/usr/bin/perl
+
#!/usr/bin/perl
 
-# (C) 2006 by Paul C. Buetow
+# (C) 2006 by Paul C. Buetow
 
-Christmas:{time;#!!!
+Christmas:{time;#!!!
 
-Children: do tell $wishes;
+Children: do tell $wishes;
 
-Santa: for $each (@children) { 
-BEGIN { read $each, $their, wishes and study them; use Memoize#ing
+Santa: for $each (@children) { 
+BEGIN { read $each, $their, wishes and study them; use Memoize#ing
 
-} use constant gift, 'wrapping'; 
-package Gifts; pack $each, gift and bless $each and goto deliver
-or do import if not local $available,!!! HO, HO, HO;
+} use constant gift, 'wrapping'; 
+package Gifts; pack $each, gift and bless $each and goto deliver
+or do import if not local $available,!!! HO, HO, HO;
 
-redo Santa, pipe $gifts, to_childs;
-redo Santa and do return if last one, is, delivered; 
+redo Santa, pipe $gifts, to_childs;
+redo Santa and do return if last one, is, delivered; 
 
-deliver: gift and require diagnostics if our $gifts ,not break;
-do{ use NEXT; time; tied $gifts} if broken and dump the, broken, ones;
-The_children: sleep and wait for (each %gift) and try { to => untie $gifts };
+deliver: gift and require diagnostics if our $gifts ,not break;
+do{ use NEXT; time; tied $gifts} if broken and dump the, broken, ones;
+The_children: sleep and wait for (each %gift) and try { to => untie $gifts };
 
-redo Santa, pipe $gifts, to_childs;
-redo Santa and do return if last one, is, delivered; 
+redo Santa, pipe $gifts, to_childs;
+redo Santa and do return if last one, is, delivered; 
 
-The_christmas_tree: formline s/ /childrens/, $gifts;
-alarm and warn if not exists $Christmas{ tree}, @t, $ENV{HOME};  
-write <<EMail
- to the parents to buy a new christmas tree!!!!111
- and send the
-EMail
-;wait and redo deliver until defined local $tree;
+The_christmas_tree: formline s/ /childrens/, $gifts;
+alarm and warn if not exists $Christmas{ tree}, @t, $ENV{HOME};  
+write <<EMail
+ to the parents to buy a new christmas tree!!!!111
+ and send the
+EMail
+;wait and redo deliver until defined local $tree;
 
-redo Santa, pipe $gifts, to_childs;
-redo Santa and do return if last one, is, delivered ;}
+redo Santa, pipe $gifts, to_childs;
+redo Santa and do return if last one, is, delivered ;}
 
-END {} our $mission and do sleep until next Christmas ;}
+END {} our $mission and do sleep until next Christmas ;}
 
-__END__
+__END__
 
-This is perl, v5.8.8 built for i386-freebsd-64int
+This is perl, v5.8.8 built for i386-freebsd-64int
 

shopping.pl


@@ -143,35 +143,35 @@ This is perl, v5. -
#!/usr/bin/perl
+
#!/usr/bin/perl
 
-# (C) 2007 by Paul C. Buetow
+# (C) 2007 by Paul C. Buetow
 
-BEGIN{} goto mall for $shopping; 
+BEGIN{} goto mall for $shopping; 
 
-m/y/; mall: seek$s, cool products(), { to => $sell };
-for $their (@business) { to:; earn:; a:; lot:; of:; money: }
+m/y/; mall: seek$s, cool products(), { to => $sell };
+for $their (@business) { to:; earn:; a:; lot:; of:; money: }
 
-do not goto home and exit mall if exists $new{product};
-foreach $of (q(uality rich products)){} package products; 
+do not goto home and exit mall if exists $new{product};
+foreach $of (q(uality rich products)){} package products; 
 
-our $news; do tell cool products() and do{ sub#tract
-cool{ $products and shift @the, @bad, @ones;
+our $news; do tell cool products() and do{ sub#tract
+cool{ $products and shift @the, @bad, @ones;
 
-do bless [q(uality)], $products 
-and return not undef $stuff if not (local $available) }};
+do bless [q(uality)], $products 
+and return not undef $stuff if not (local $available) }};
 
-do { study and study and study for cool products() }
-and do { seek $all, cool products(), { to => $buy } };
+do { study and study and study for cool products() }
+and do { seek $all, cool products(), { to => $buy } };
 
-do { write $them, $down } and do { order: foreach (@case) { package s } };
-goto home if not exists $more{money} or die q(uerying) ;for( @money){};
+do { write $them, $down } and do { order: foreach (@case) { package s } };
+goto home if not exists $more{money} or die q(uerying) ;for( @money){};
 
-at:;home: do { END{} and:; rest:; a:; bit: exit $shopping } 
-and sleep until unpack$ing, cool products();
+at:;home: do { END{} and:; rest:; a:; bit: exit $shopping } 
+and sleep until unpack$ing, cool products();
 
-__END__
-This is perl, v5.8.8 built for i386-freebsd-64int
+__END__
+This is perl, v5.8.8 built for i386-freebsd-64int
 

More...


diff --git a/gemfeed/2010-04-09-standard-ml-and-haskell.html b/gemfeed/2010-04-09-standard-ml-and-haskell.html index 84ae1fc7..6b3b5e89 100644 --- a/gemfeed/2010-04-09-standard-ml-and-haskell.html +++ b/gemfeed/2010-04-09-standard-ml-and-haskell.html @@ -26,10 +26,10 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
datatype ’a multi
-	= EMPTY
-	| ELEM of ’a
-	| UNION of ’a multi * ’a multi
+
datatype ’a multi
+	= EMPTY
+	| ELEM of ’a
+	| UNION of ’a multi * ’a multi
 

Haskell:
@@ -38,11 +38,11 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
data (Eq a) => Multi a
-    = Empty
-    | Elem a
-    | Union (Multi a) (Multi a)
-    deriving Show
+
data (Eq a) => Multi a
+    = Empty
+    | Elem a
+    | Union (Multi a) (Multi a)
+    deriving Show
 

Processing a multi


@@ -53,12 +53,12 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
fun number (EMPTY) _ = 0
-	| number (ELEM x) w = if x = w then 1 else 0
-	| number (UNION (x,y)) w = (number x w) + (number y w)
-fun test_number w = number (UNION (EMPTY, \
-    UNION (ELEM 4, UNION (ELEM 6, \
-    UNION (UNION (ELEM 4, ELEM 4), EMPTY))))) w 
+
fun number (EMPTY) _ = 0
+	| number (ELEM x) w = if x = w then 1 else 0
+	| number (UNION (x,y)) w = (number x w) + (number y w)
+fun test_number w = number (UNION (EMPTY, \
+    UNION (ELEM 4, UNION (ELEM 6, \
+    UNION (UNION (ELEM 4, ELEM 4), EMPTY))))) w 
 

Haskell:
@@ -67,11 +67,11 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
number Empty _ = 0
-number (Elem x) w = if x == w then 1 else 0
-test_number w = number (Union Empty \
-    (Union (Elem 4) (Union (Elem 6) \
-    (Union (Union (Elem 4) (Elem 4)) Empty)))) w
+
number Empty _ = 0
+number (Elem x) w = if x == w then 1 else 0
+test_number w = number (Union Empty \
+    (Union (Elem 4) (Union (Elem 6) \
+    (Union (Union (Elem 4) (Elem 4)) Empty)))) w
 

Simplify function


@@ -82,19 +82,19 @@ test_number w = number ( -
fun simplify (UNION (x,y)) =
-    let fun is_empty (EMPTY) = true | is_empty _ = false
-        val x’ = simplify x
-        val y’ = simplify y
-    in if (is_empty x’) andalso (is_empty y’)
-            then EMPTY
-       else if (is_empty x’)
-            then y’
-       else if (is_empty y’)
-            then x’
-       else UNION (x’, y’)
-    end
-  | simplify x = x
+
fun simplify (UNION (x,y)) =
+    let fun is_empty (EMPTY) = true | is_empty _ = false
+        val x’ = simplify x
+        val y’ = simplify y
+    in if (is_empty x’) andalso (is_empty y’)
+            then EMPTY
+       else if (is_empty x’)
+            then y’
+       else if (is_empty y’)
+            then x’
+       else UNION (x’, y’)
+    end
+  | simplify x = x
 

Haskell:
@@ -103,17 +103,17 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
simplify (Union x y)
-    | (isEmpty x’) && (isEmpty y’) = Empty
-    | isEmpty x’ = y’
-    | isEmpty y’ = x’
-    | otherwise = Union x’ y’
-    where
-        isEmpty Empty = True
-        isEmpty _ = False
-        x’ = simplify x
-        y’ = simplify y
-simplify x = x
+
simplify (Union x y)
+    | (isEmpty x’) && (isEmpty y’) = Empty
+    | isEmpty x’ = y’
+    | isEmpty y’ = x’
+    | otherwise = Union x’ y’
+    where
+        isEmpty Empty = True
+        isEmpty _ = False
+        x’ = simplify x
+        y’ = simplify y
+simplify x = x
 

Delete all


@@ -124,12 +124,12 @@ simplify x = x by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
fun delete_all m w =
-    let fun delete_all’ (ELEM x) = if x = w then EMPTY else ELEM x
-          | delete_all’ (UNION (x,y)) = UNION (delete_all’ x, delete_all’ y)
-          | delete_all’ x = x
-    in simplify (delete_all’ m)
-    end
+
fun delete_all m w =
+    let fun delete_all’ (ELEM x) = if x = w then EMPTY else ELEM x
+          | delete_all’ (UNION (x,y)) = UNION (delete_all’ x, delete_all’ y)
+          | delete_all’ x = x
+    in simplify (delete_all’ m)
+    end
 

Haskell:
@@ -138,11 +138,11 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
delete_all m w = simplify (delete_all’ m)
-    where
-        delete_all’ (Elem x) = if x == w then Empty else Elem x
-        delete_all’ (Union x y) = Union (delete_all’ x) (delete_all’ y)
-        delete_all’ x = x
+
delete_all m w = simplify (delete_all’ m)
+    where
+        delete_all’ (Elem x) = if x == w then Empty else Elem x
+        delete_all’ (Union x y) = Union (delete_all’ x) (delete_all’ y)
+        delete_all’ x = x
 

Delete one


@@ -153,21 +153,21 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
fun delete_one m w =
-    let fun delete_one’ (UNION (x,y)) =
-            let val (x’, deleted) = delete_one’ x
-                in if deleted
-                   then (UNION (x’, y), deleted)
-                   else let val (y’, deleted) = delete_one’ y
-                       in (UNION (x, y’), deleted)
-                   end
-                end
-          | delete_one’ (ELEM x) =
-            if x = w then (EMPTY, true) else (ELEM x, false)
-          | delete_one’ x = (x, false)
-            val (m’, _) = delete_one’ m
-        in simplify m’
-    end
+
fun delete_one m w =
+    let fun delete_one’ (UNION (x,y)) =
+            let val (x’, deleted) = delete_one’ x
+                in if deleted
+                   then (UNION (x’, y), deleted)
+                   else let val (y’, deleted) = delete_one’ y
+                       in (UNION (x, y’), deleted)
+                   end
+                end
+          | delete_one’ (ELEM x) =
+            if x = w then (EMPTY, true) else (ELEM x, false)
+          | delete_one’ x = (x, false)
+            val (m’, _) = delete_one’ m
+        in simplify m’
+    end
 

Haskell:
@@ -176,19 +176,19 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
delete_one m w = do
-    let (m’, _) = delete_one’ m
-    simplify m’
-    where
-        delete_one’ (Union x y) =
-            let (x’, deleted) = delete_one’ x
-            in if deleted
-                then (Union x’ y, deleted)
-                else let (y’, deleted) = delete_one’ y
-                    in (Union x y’, deleted)
-        delete_one’ (Elem x) =
-            if x == w then (Empty, True) else (Elem x, False)
-        delete_one’ x = (x, False)
+
delete_one m w = do
+    let (m’, _) = delete_one’ m
+    simplify m’
+    where
+        delete_one’ (Union x y) =
+            let (x’, deleted) = delete_one’ x
+            in if deleted
+                then (Union x’ y, deleted)
+                else let (y’, deleted) = delete_one’ y
+                    in (Union x y’, deleted)
+        delete_one’ (Elem x) =
+            if x == w then (Empty, True) else (Elem x, False)
+        delete_one’ x = (x, False)
 

Higher-order functions


diff --git a/gemfeed/2010-05-09-the-fype-programming-language.html b/gemfeed/2010-05-09-the-fype-programming-language.html index 1728107d..4f9ab23c 100644 --- a/gemfeed/2010-05-09-the-fype-programming-language.html +++ b/gemfeed/2010-05-09-the-fype-programming-language.html @@ -37,12 +37,12 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
typedef struct {
-   Tupel *p_tupel_argv; // Contains command line options
-   List *p_list_token; // Initial list of token
-   Hash *p_hash_syms; // Symbol table
-   char *c_basename;
-} Fype;
+
typedef struct {
+   Tupel *p_tupel_argv; // Contains command line options
+   List *p_list_token; // Initial list of token
+   Hash *p_hash_syms; // Symbol table
+   char *c_basename;
+} Fype;
 

And here is a snippet from the primary Fype "class implementation":
@@ -51,53 +51,53 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
Fype*
-fype_new() {
-   Fype *p_fype = malloc(sizeof(Fype));
+
Fype*
+fype_new() {
+   Fype *p_fype = malloc(sizeof(Fype));
 
-   p_fype->p_hash_syms = hash_new(512);
-   p_fype->p_list_token = list_new();
-   p_fype->p_tupel_argv = tupel_new();
-   p_fype->c_basename = NULL;
+   p_fype->p_hash_syms = hash_new(512);
+   p_fype->p_list_token = list_new();
+   p_fype->p_tupel_argv = tupel_new();
+   p_fype->c_basename = NULL;
 
-   garbage_init();
+   garbage_init();
 
-   return (p_fype);
-}
+   return (p_fype);
+}
 
-void
-fype_delete(Fype *p_fype) {
-   argv_tupel_delete(p_fype->p_tupel_argv);
+void
+fype_delete(Fype *p_fype) {
+   argv_tupel_delete(p_fype->p_tupel_argv);
 
-   hash_iterate(p_fype->p_hash_syms, symbol_cleanup_hash_syms_cb);
-   hash_delete(p_fype->p_hash_syms);
+   hash_iterate(p_fype->p_hash_syms, symbol_cleanup_hash_syms_cb);
+   hash_delete(p_fype->p_hash_syms);
 
-   list_iterate(p_fype->p_list_token, token_ref_down_cb);
-   list_delete(p_fype->p_list_token);
+   list_iterate(p_fype->p_list_token, token_ref_down_cb);
+   list_delete(p_fype->p_list_token);
 
-   if (p_fype->c_basename)
-      free(p_fype->c_basename);
+   if (p_fype->c_basename)
+      free(p_fype->c_basename);
 
-   garbage_destroy();
-}
+   garbage_destroy();
+}
 
-int
-fype_run(int i_argc, char **pc_argv) {
-   Fype *p_fype = fype_new();
+int
+fype_run(int i_argc, char **pc_argv) {
+   Fype *p_fype = fype_new();
 
-   // argv: Maintains command line options
-   argv_run(p_fype, i_argc, pc_argv);
+   // argv: Maintains command line options
+   argv_run(p_fype, i_argc, pc_argv);
 
-   // scanner: Creates a list of token
-   scanner_run(p_fype);
+   // scanner: Creates a list of token
+   scanner_run(p_fype);
 
-   // interpret: Interpret the list of token
-   interpret_run(p_fype);
+   // interpret: Interpret the list of token
+   interpret_run(p_fype);
 
-   fype_delete(p_fype);
+   fype_delete(p_fype);
 
-   return (0);
-}
+   return (0);
+}
 

Data types


diff --git a/gemfeed/2011-05-07-perl-daemon-service-framework.html b/gemfeed/2011-05-07-perl-daemon-service-framework.html index 34ee06d9..3e5d08c1 100644 --- a/gemfeed/2011-05-07-perl-daemon-service-framework.html +++ b/gemfeed/2011-05-07-perl-daemon-service-framework.html @@ -41,14 +41,14 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
# Starting
- ./bin/perldaemon start (or shortcut ./control start)
+
# Starting
+ ./bin/perldaemon start (or shortcut ./control start)
 
-# Stopping
- ./bin/perldaemon stop (or shortcut ./control stop)
+# Stopping
+ ./bin/perldaemon stop (or shortcut ./control stop)
 
-# Alternatively: Starting in foreground 
-./bin/perldaemon start daemon.daemonize=no (or shortcut ./control foreground)
+# Alternatively: Starting in foreground 
+./bin/perldaemon start daemon.daemonize=no (or shortcut ./control foreground)
 

To stop a daemon from running in foreground mode, "Ctrl+C" must be hit. To see more available startup options run "./control" without any argument.
@@ -61,30 +61,30 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
pb@titania:~/svn/utils/perldaemon/trunk$ ./control keys
-# Path to the logfile
-daemon.logfile=./log/perldaemon.log
+
pb@titania:~/svn/utils/perldaemon/trunk$ ./control keys
+# Path to the logfile
+daemon.logfile=./log/perldaemon.log
 
-# The amount of seconds until the next event look takes place
-daemon.loopinterval=1
+# The amount of seconds until the next event look takes place
+daemon.loopinterval=1
 
-# Path to the modules dir
-daemon.modules.dir=./lib/PerlDaemonModules
+# Path to the modules dir
+daemon.modules.dir=./lib/PerlDaemonModules
 
-# Specifies either the daemon should run in daemon or foreground mode
-daemon.daemonize=yes
+# Specifies either the daemon should run in daemon or foreground mode
+daemon.daemonize=yes
 
-# Path to the pidfile
-daemon.pidfile=./run/perldaemon.pid
+# Path to the pidfile
+daemon.pidfile=./run/perldaemon.pid
 
-# Each module should run every run interval seconds
-daemon.modules.runinterval=3
+# Each module should run every run interval seconds
+daemon.modules.runinterval=3
 
-# Path to the alive file (is touched every loop interval seconds, usable for monitoring)
-daemon.alivefile=./run/perldaemon.alive
+# Path to the alive file (is touched every loop interval seconds, usable for monitoring)
+daemon.alivefile=./run/perldaemon.alive
 
-# Specifies the working directory
-daemon.wd=./
+# Specifies the working directory
+daemon.wd=./
 

Example


@@ -95,17 +95,17 @@ daemon.wd./control keys | grep daemon.loopinterval -daemon.loopinterval=1 -$ ./control keys daemon.loopinterval=10 | grep daemon.loopinterval -daemon.loopinterval=10 -$ ./control start daemon.loopinterval=10; sleep 10; tail -n 2 log/perldaemon.log -Starting daemon now... -Mon Jun 13 11:29:27 2011 (PID 2838): Triggering PerlDaemonModules::ExampleModule -(last triggered before 10.002106s; carry: 7.002106s; wanted interval: 3s) -Mon Jun 13 11:29:27 2011 (PID 2838): ExampleModule Test 2 -$ ./control stop -Stopping daemon now... +
$ ./control keys | grep daemon.loopinterval
+daemon.loopinterval=1
+$ ./control keys daemon.loopinterval=10 | grep daemon.loopinterval
+daemon.loopinterval=10
+$ ./control start daemon.loopinterval=10; sleep 10; tail -n 2 log/perldaemon.log
+Starting daemon now...
+Mon Jun 13 11:29:27 2011 (PID 2838): Triggering PerlDaemonModules::ExampleModule 
+(last triggered before 10.002106s; carry: 7.002106s; wanted interval: 3s)
+Mon Jun 13 11:29:27 2011 (PID 2838): ExampleModule Test 2
+$ ./control stop
+Stopping daemon now...
 

If you want to change that property forever, either edit perldaemon.conf or do this:
@@ -114,7 +114,7 @@ Stopping daemon now... by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
$ ./control keys daemon.loopinterval=10 > new.conf; mv new.conf conf/perldaemon.conf
+
$ ./control keys daemon.loopinterval=10 > new.conf; mv new.conf conf/perldaemon.conf
 

HiRes event loop


@@ -131,35 +131,35 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
package PerlDaemonModules::ExampleModule;
+
package PerlDaemonModules::ExampleModule;
 
-use strict;
-use warnings;
+use strict;
+use warnings;
 
-sub new ($$$) {
-  my ($class, $conf) = @_;
+sub new ($$$) {
+  my ($class, $conf) = @_;
 
-  my $self = bless { conf => $conf }, $class;
+  my $self = bless { conf => $conf }, $class;
 
-  # Store some private module stuff
-  $self->{counter} = 0;
+  # Store some private module stuff
+  $self->{counter} = 0;
 
-  return $self;
-}
+  return $self;
+}
 
-# Runs periodically in a loop (set interval in perldaemon.conf)
-sub do ($) {
-  my $self = shift;
-  my $conf = $self->{conf};
-  my $logger = $conf->{logger};
+# Runs periodically in a loop (set interval in perldaemon.conf)
+sub do ($) {
+  my $self = shift;
+  my $conf = $self->{conf};
+  my $logger = $conf->{logger};
 
-  # Calculate some private module stuff
-  my $count = ++$self->{counter};
+  # Calculate some private module stuff
+  my $count = ++$self->{counter};
 
-  $logger->logmsg("ExampleModule Test $count");
-}
+  $logger->logmsg("ExampleModule Test $count");
+}
 
-1;
+1;
 

Your own module


@@ -170,11 +170,11 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
 cd ./lib/PerlDaemonModules/
- cp ExampleModule.pm YourModule.pm
- vi YourModule.pm
- cd -
- ./bin/perldaemon restart (or shortcurt ./control restart)
+
 cd ./lib/PerlDaemonModules/
+ cp ExampleModule.pm YourModule.pm
+ vi YourModule.pm
+ cd -
+ ./bin/perldaemon restart (or shortcurt ./control restart)
 

Now watch ./log/perldaemon.log closely. It is a good practice to test your modules in 'foreground mode' (see above how to do that).
diff --git a/gemfeed/2014-03-24-the-fibonacci.pl.c-polyglot.html b/gemfeed/2014-03-24-the-fibonacci.pl.c-polyglot.html index 35725876..dd5e921d 100644 --- a/gemfeed/2014-03-24-the-fibonacci.pl.c-polyglot.html +++ b/gemfeed/2014-03-24-the-fibonacci.pl.c-polyglot.html @@ -24,47 +24,47 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
#include <stdio.h>
+
#include <stdio.h>
 
-#define $arg function_argument
-#define my int
-#define sub int
-#define BEGIN int main(void)
+#define $arg function_argument
+#define my int
+#define sub int
+#define BEGIN int main(void)
 
-my $arg;
+my $arg;
 
-sub hello() {
-    printf("Hello, welcome to the Fibonacci Numbers!\n");
-    printf("This program is all, valid C and C++ and Perl and Raku code!\n");
-    printf("It calculates all fibonacci numbers from 0 to 9!\n\n");
-    return 0;
-}
+sub hello() {
+    printf("Hello, welcome to the Fibonacci Numbers!\n");
+    printf("This program is all, valid C and C++ and Perl and Raku code!\n");
+    printf("It calculates all fibonacci numbers from 0 to 9!\n\n");
+    return 0;
+}
 
-sub fibonacci() {
-    my $n = $arg;
+sub fibonacci() {
+    my $n = $arg;
 
-    if ($n < 2) {
-        return $n;
-    }
+    if ($n < 2) {
+        return $n;
+    }
 
-    $arg = $n - 1;
-    my $fib1 = fibonacci();
-    $arg = $n - 2;
-    my $fib2 = fibonacci();
+    $arg = $n - 1;
+    my $fib1 = fibonacci();
+    $arg = $n - 2;
+    my $fib2 = fibonacci();
 
-    return $fib1 + $fib2;
-}
+    return $fib1 + $fib2;
+}
 
-BEGIN {
-    hello();
-    my $i = 0;
+BEGIN {
+    hello();
+    my $i = 0;
 
-    while ($i <= 10) {
-        $arg = $i;
-        printf("fib(%d) = %d\n", $i, fibonacci());
-        $i++;
-    }
-}
+    while ($i <= 10) {
+        $arg = $i;
+        printf("fib(%d) = %d\n", $i, fibonacci());
+        $i++;
+    }
+}
 

You can find the full source code at GitHub:
@@ -77,41 +77,41 @@ BEGIN { by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
% gcc fibonacci.pl.raku.c -o fibonacci
-% ./fibonacci
-Hello, welcome to the Fibonacci Numbers!
-This program is all, valid C and C++ and Perl and Raku code!
-It calculates all fibonacci numbers from 0 to 9!
+
% gcc fibonacci.pl.raku.c -o fibonacci
+% ./fibonacci
+Hello, welcome to the Fibonacci Numbers!
+This program is all, valid C and C++ and Perl and Raku code!
+It calculates all fibonacci numbers from 0 to 9!
 
-fib(0) = 0
-fib(1) = 1
-fib(2) = 1
-fib(3) = 2
-fib(4) = 3
-fib(5) = 5
-fib(6) = 8
-fib(7) = 13
-fib(8) = 21
-fib(9) = 34
-fib(10) = 55
+fib(0) = 0
+fib(1) = 1
+fib(2) = 1
+fib(3) = 2
+fib(4) = 3
+fib(5) = 5
+fib(6) = 8
+fib(7) = 13
+fib(8) = 21
+fib(9) = 34
+fib(10) = 55
 
-% g++ fibonacci.pl.raku.c -o fibonacci
-% ./fibonacci
-Hello, welcome to the Fibonacci Numbers!
-This program is all, valid C and C++ and Perl and Raku code!
-It calculates all fibonacci numbers from 0 to 9!
+% g++ fibonacci.pl.raku.c -o fibonacci
+% ./fibonacci
+Hello, welcome to the Fibonacci Numbers!
+This program is all, valid C and C++ and Perl and Raku code!
+It calculates all fibonacci numbers from 0 to 9!
 
-fib(0) = 0
-fib(1) = 1
-fib(2) = 1
-fib(3) = 2
-fib(4) = 3
-fib(5) = 5
-fib(6) = 8
-fib(7) = 13
-fib(8) = 21
-fib(9) = 34
-fib(10) = 55
+fib(0) = 0
+fib(1) = 1
+fib(2) = 1
+fib(3) = 2
+fib(4) = 3
+fib(5) = 5
+fib(6) = 8
+fib(7) = 13
+fib(8) = 21
+fib(9) = 34
+fib(10) = 55
 

Let's run it with Perl and Raku


@@ -120,39 +120,39 @@ fib(10% perl fibonacci.pl.raku.c -Hello, welcome to the Fibonacci Numbers! -This program is all, valid C and C++ and Perl and Raku code! -It calculates all fibonacci numbers from 0 to 9! +
% perl fibonacci.pl.raku.c
+Hello, welcome to the Fibonacci Numbers!
+This program is all, valid C and C++ and Perl and Raku code!
+It calculates all fibonacci numbers from 0 to 9!
 
-fib(0) = 0
-fib(1) = 1
-fib(2) = 1
-fib(3) = 2
-fib(4) = 3
-fib(5) = 5
-fib(6) = 8
-fib(7) = 13
-fib(8) = 21
-fib(9) = 34
-fib(10) = 55
+fib(0) = 0
+fib(1) = 1
+fib(2) = 1
+fib(3) = 2
+fib(4) = 3
+fib(5) = 5
+fib(6) = 8
+fib(7) = 13
+fib(8) = 21
+fib(9) = 34
+fib(10) = 55
 
-% raku fibonacci.pl.raku.c
-Hello, welcome to the Fibonacci Numbers!
-This program is all, valid C and C++ and Perl and Raku code!
-It calculates all fibonacci numbers from 0 to 9!
+% raku fibonacci.pl.raku.c
+Hello, welcome to the Fibonacci Numbers!
+This program is all, valid C and C++ and Perl and Raku code!
+It calculates all fibonacci numbers from 0 to 9!
 
-fib(0) = 0
-fib(1) = 1
-fib(2) = 1
-fib(3) = 2
-fib(4) = 3
-fib(5) = 5
-fib(6) = 8
-fib(7) = 13
-fib(8) = 21
-fib(9) = 34
-fib(10) = 55
+fib(0) = 0
+fib(1) = 1
+fib(2) = 1
+fib(3) = 2
+fib(4) = 3
+fib(5) = 5
+fib(6) = 8
+fib(7) = 13
+fib(8) = 21
+fib(9) = 34
+fib(10) = 55
 

It's entertaining to play with :-).
diff --git a/gemfeed/2015-12-05-run-debian-on-your-phone-with-debroid.html b/gemfeed/2015-12-05-run-debian-on-your-phone-with-debroid.html index 7736e050..37989842 100644 --- a/gemfeed/2015-12-05-run-debian-on-your-phone-with-debroid.html +++ b/gemfeed/2015-12-05-run-debian-on-your-phone-with-debroid.html @@ -43,24 +43,24 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
sudo dnf install debootstrap
-# 5g
-dd if=/dev/zero of=jessie.img bs=$[ 1024 * 1024 ] \
-  count=$[ 1024 * 5 ]
+
sudo dnf install debootstrap
+# 5g
+dd if=/dev/zero of=jessie.img bs=$[ 1024 * 1024 ] \
+  count=$[ 1024 * 5 ]
 
-# Show used loop devices
-sudo losetup -f
-# Store the next free one to $loop
-loop=loopN
-sudo losetup /dev/$loop jessie.img
+# Show used loop devices
+sudo losetup -f
+# Store the next free one to $loop
+loop=loopN
+sudo losetup /dev/$loop jessie.img
 
-mkdir jessie
-sudo mkfs.ext4 /dev/$loop
-sudo mount /dev/$loop jessie
-sudo debootstrap --foreign --variant=minbase \
-  --arch armel jessie jessie/ \
-  http://http.debian.net/debian
-sudo umount jessie
+mkdir jessie
+sudo mkfs.ext4 /dev/$loop
+sudo mount /dev/$loop jessie
+sudo debootstrap --foreign --variant=minbase \
+  --arch armel jessie jessie/ \
+  http://http.debian.net/debian
+sudo umount jessie
 

Copy Debian image to the phone


@@ -71,42 +71,42 @@ sudo umount jessie by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
adb root && adb wait-for-device && adb shell
-mkdir -p /storage/sdcard1/Linux/jessie
-exit
+
adb root && adb wait-for-device && adb shell
+mkdir -p /storage/sdcard1/Linux/jessie
+exit
 
-# Sparse image problem, may be too big for copying otherwise
-gzip jessie.img
-# Copy over
-adb push jessie.img.gz /storage/sdcard1/Linux/jessie.img.gz
-adb shell
-cd /storage/sdcard1/Linux
-gunzip jessie.img.gz
+# Sparse image problem, may be too big for copying otherwise
+gzip jessie.img
+# Copy over
+adb push jessie.img.gz /storage/sdcard1/Linux/jessie.img.gz
+adb shell
+cd /storage/sdcard1/Linux
+gunzip jessie.img.gz
 
-# Show used loop devices
-losetup -f
-# Store the next free one to $loop
-loop=loopN
+# Show used loop devices
+losetup -f
+# Store the next free one to $loop
+loop=loopN
 
-# Use the next free one (replace the loop number)
-losetup /dev/block/$loop $(pwd)/jessie.img
-mount -t ext4 /dev/block/$loop $(pwd)/jessie
+# Use the next free one (replace the loop number)
+losetup /dev/block/$loop $(pwd)/jessie.img
+mount -t ext4 /dev/block/$loop $(pwd)/jessie
 
-# Bind-Mound proc, dev, sys`
-busybox mount --bind /proc $(pwd)/jessie/proc
-busybox mount --bind /dev $(pwd)/jessie/dev
-busybox mount --bind /dev/pts $(pwd)/jessie/dev/pts
-busybox mount --bind /sys $(pwd)/jessie/sys
+# Bind-Mound proc, dev, sys`
+busybox mount --bind /proc $(pwd)/jessie/proc
+busybox mount --bind /dev $(pwd)/jessie/dev
+busybox mount --bind /dev/pts $(pwd)/jessie/dev/pts
+busybox mount --bind /sys $(pwd)/jessie/sys
 
-# Bind-Mound the rest of Android
-mkdir -p $(pwd)/jessie/storage/sdcard{0,1}
-busybox mount --bind /storage/emulated \
-  $(pwd)/jessie/storage/sdcard0
-busybox mount --bind /storage/sdcard1 \
-  $(pwd)/jessie/storage/sdcard1
+# Bind-Mound the rest of Android
+mkdir -p $(pwd)/jessie/storage/sdcard{0,1}
+busybox mount --bind /storage/emulated \
+  $(pwd)/jessie/storage/sdcard0
+busybox mount --bind /storage/sdcard1 \
+  $(pwd)/jessie/storage/sdcard1
 
-# Check mounts
-mount | grep jessie
+# Check mounts
+mount | grep jessie
 

Second debootstrap stage


@@ -117,11 +117,11 @@ mount | grep jessie by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
chroot $(pwd)/jessie /bin/bash -l
-export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin
-/debootstrap/debootstrap --second-stage
-exit # Leave chroot
-exit # Leave adb shell
+
chroot $(pwd)/jessie /bin/bash -l
+export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin
+/debootstrap/debootstrap --second-stage
+exit # Leave chroot
+exit # Leave adb shell
 

Setup of various scripts


@@ -132,36 +132,36 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
# Install script jessie.sh
-adb push storage/sdcard1/Linux/jessie.sh /storage/sdcard/Linux/jessie.sh
-adb shell
-cd /storage/sdcard1/Linux
-sh jessie.sh enter
+
# Install script jessie.sh
+adb push storage/sdcard1/Linux/jessie.sh /storage/sdcard/Linux/jessie.sh
+adb shell
+cd /storage/sdcard1/Linux
+sh jessie.sh enter
 
-# Bashrc
-cat <<END >~/.bashrc
-export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
-export EDITOR=vim
-hostname $(cat /etc/hostname)
-END
+# Bashrc
+cat <<END >~/.bashrc
+export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
+export EDITOR=vim
+hostname $(cat /etc/hostname)
+END
 
-# Fixing an error message while loading the profile
-sed -i s#id#/usr/bin/id# /etc/profile
+# Fixing an error message while loading the profile
+sed -i s#id#/usr/bin/id# /etc/profile
 
-# Setting the hostname
-echo phobos > /etc/hostname
-echo 127.0.0.1 phobos > /etc/hosts
-hostname phobos
+# Setting the hostname
+echo phobos > /etc/hostname
+echo 127.0.0.1 phobos > /etc/hosts
+hostname phobos
 
-# Apt-sources
-cat <<END > sources.list
-deb http://ftp.uk.debian.org/debian/ jessie main contrib non-free
-deb-src http://ftp.uk.debian.org/debian/ jessie main contrib non-free
-END
-apt-get update
-apt-get upgrade
-apt-get dist-upgrade
-exit # Exit chroot
+# Apt-sources
+cat <<END > sources.list
+deb http://ftp.uk.debian.org/debian/ jessie main contrib non-free
+deb-src http://ftp.uk.debian.org/debian/ jessie main contrib non-free
+END
+apt-get update
+apt-get upgrade
+apt-get dist-upgrade
+exit # Exit chroot
 

Entering Debroid and enable a service


@@ -172,19 +172,19 @@ apt-get dist-upgrade by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
sh jessie.sh enter
+
sh jessie.sh enter
 
-# Setup example serice uptimed
-apt-get install uptimed
-cat <<END > /etc/rc.debroid
-export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
-service uptimed status &>/dev/null || service uptimed start
-exit 0
-END
+# Setup example serice uptimed
+apt-get install uptimed
+cat <<END > /etc/rc.debroid
+export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
+service uptimed status &>/dev/null || service uptimed start
+exit 0
+END
 
-chmod 0755 /etc/rc.debroid
-exit # Exit chroot
-exit # Exit adb shell
+chmod 0755 /etc/rc.debroid
+exit # Exit chroot
+exit # Exit adb shell
 

Include to Android startup:


@@ -195,10 +195,10 @@ chmod 0755 /etc/rc.deb by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
adb push data/local/userinit.sh /data/local/userinit.sh
-adb shell
-chmod +x /data/local/userinit.sh
-exit
+
adb push data/local/userinit.sh /data/local/userinit.sh
+adb shell
+chmod +x /data/local/userinit.sh
+exit
 

Reboot & test! Enjoy!
diff --git a/gemfeed/2016-11-20-object-oriented-programming-with-ansi-c.html b/gemfeed/2016-11-20-object-oriented-programming-with-ansi-c.html index 3c8e6fad..82302e43 100644 --- a/gemfeed/2016-11-20-object-oriented-programming-with-ansi-c.html +++ b/gemfeed/2016-11-20-object-oriented-programming-with-ansi-c.html @@ -31,37 +31,37 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
#include <stdio.h>
+
#include <stdio.h>
 
-typedef struct {
-    double (*calculate)(const double, const double);
-    char *name;
-} something_s;
+typedef struct {
+    double (*calculate)(const double, const double);
+    char *name;
+} something_s;
 
-double multiplication(const double a, const double b) {
-    return a * b;
-}
+double multiplication(const double a, const double b) {
+    return a * b;
+}
 
-double division(const double a, const double b) {
-    return a / b;
-}
+double division(const double a, const double b) {
+    return a / b;
+}
 
-int main(void) {
-    something_s mult = (something_s) {
-        .calculate = multiplication,
-        .name = "Multiplication"
-    };
+int main(void) {
+    something_s mult = (something_s) {
+        .calculate = multiplication,
+        .name = "Multiplication"
+    };
 
-    something_s div = (something_s) {
-        .calculate = division,
-        .name = "Division"
-    };
+    something_s div = (something_s) {
+        .calculate = division,
+        .name = "Division"
+    };
 
-    const double a = 3, b = 2;
+    const double a = 3, b = 2;
 
-    printf("%s(%f, %f) => %f\n", mult.name, a, b, mult.calculate(a,b));
-    printf("%s(%f, %f) => %f\n", div.name, a, b, div.calculate(a,b));
-}
+    printf("%s(%f, %f) => %f\n", mult.name, a, b, mult.calculate(a,b));
+    printf("%s(%f, %f) => %f\n", div.name, a, b, div.calculate(a,b));
+}
 

As you can see, you can call the function (pointed by the function pointer) with the same syntax as in C++ or Java:
@@ -70,8 +70,8 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
printf("%s(%f, %f) => %f\n", mult.name, a, b, mult.calculate(a,b));
-printf("%s(%f, %f) => %f\n", div.name, a, b, div.calculate(a,b));
+
printf("%s(%f, %f) => %f\n", mult.name, a, b, mult.calculate(a,b));
+printf("%s(%f, %f) => %f\n", div.name, a, b, div.calculate(a,b));
 

However, that's just syntactic sugar for:
@@ -80,8 +80,8 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
printf("%s(%f, %f) => %f\n", mult.name, a, b, (*mult.calculate)(a,b));
-printf("%s(%f, %f) => %f\n", div.name, a, b, (*div.calculate)(a,b));
+
printf("%s(%f, %f) => %f\n", mult.name, a, b, (*mult.calculate)(a,b));
+printf("%s(%f, %f) => %f\n", div.name, a, b, (*div.calculate)(a,b));
 

Output:
@@ -90,10 +90,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
pbuetow ~/git/blog/source [38268]% gcc oop-c-example.c -o oop-c-example
-pbuetow ~/git/blog/source [38269]% ./oop-c-example
-Multiplication(3.000000, 2.000000) => 6.000000
-Division(3.000000, 2.000000) => 1.500000
+
pbuetow ~/git/blog/source [38268]% gcc oop-c-example.c -o oop-c-example
+pbuetow ~/git/blog/source [38269]% ./oop-c-example
+Multiplication(3.000000, 2.000000) => 6.000000
+Division(3.000000, 2.000000) => 1.500000
 

Not complicated at all, but nice to know and helps to make the code easier to read!
@@ -106,7 +106,7 @@ Division(3.000000 -
mult.calculate(mult,a,b));
+
mult.calculate(mult,a,b));
 

Real object oriented programming with C


diff --git a/gemfeed/2021-05-16-personal-bash-coding-style-guide.html b/gemfeed/2021-05-16-personal-bash-coding-style-guide.html index ab1aea8c..408b3c65 100644 --- a/gemfeed/2021-05-16-personal-bash-coding-style-guide.html +++ b/gemfeed/2021-05-16-personal-bash-coding-style-guide.html @@ -41,7 +41,7 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
#!/bin/bash 
+
#!/bin/bash 
 

... as the shebang line, but that does not work on all Unix and Unix-like operating systems (e.g., the *BSDs don't have Bash installed to /bin/bash). Better is:
@@ -50,7 +50,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
#!/usr/bin/env bash
+
#!/usr/bin/env bash
 

Two space soft-tabs indentation


@@ -71,14 +71,14 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
# All fits on one line
-command1 | command2
+
# All fits on one line
+command1 | command2
 
-# Long commands
-command1 \
-  | command2 \
-  | command3 \
-  | command4
+# Long commands
+command1 \
+  | command2 \
+  | command3 \
+  | command4
 

I think there is a better way like the following, which is less noisy. The pipe | already indicates the Bash that another command is expected, thus making the explicit line breaks with \ obsolete:
@@ -87,11 +87,11 @@ command1 \ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
# Long commands
-command1 |
-    command2 |
-    command3 |
-    command4
+
# Long commands
+command1 |
+    command2 |
+    command3 |
+    command4
 

Update: It's 2023 now, and I have changed my mind. I think Google's way is the better one. It may be a bit more to type, but the leading | are a nice eye catcher, so you know immediately what is going on!
@@ -104,11 +104,11 @@ command1 | by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
greet () {
-    local -r greeting="${1}"
-    local -r name="${2}"
-    echo "${greeting} ${name}!"
-}
+
greet () {
+    local -r greeting="${1}"
+    local -r name="${2}"
+    echo "${greeting} ${name}!"
+}
 

In this particular example, I agree that you should quote them as you don't know the input (are there, for example, whitespace characters?). But if you are sure that you are only using simple bare words, then I think that the code looks much cleaner when you do this instead:
@@ -117,11 +117,11 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
say_hello_to_paul () {
-    local -r greeting=Hello
-    local -r name=Paul
-    echo "$greeting $name!"
-}
+
say_hello_to_paul () {
+    local -r greeting=Hello
+    local -r name=Paul
+    echo "$greeting $name!"
+}
 

You see, I also omitted the curly braces { } around the variables. I only use the curly braces around variables when it makes the code either easier/clearer to read or if it is necessary to use them:
@@ -130,9 +130,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
declare FOO=bar
-# Curly braces around FOO are necessary
-echo "foo${FOO}baz"
+
declare FOO=bar
+# Curly braces around FOO are necessary
+echo "foo${FOO}baz"
 

A few more words on always quoting the variables: For the sake of consistency (and for making ShellCheck happy), I am not against quoting everything I encounter. I also think that the larger the Bash script becomes, the more critical it becomes always to quote variables. That's because it will be more likely that you might not remember that some of the functions don't work on values with spaces in them, for example. It's just that I won't quote everything in every small script I write.
@@ -145,13 +145,13 @@ echo "foo${FOO}baz" by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
# Prefer this:
-addition=$(( X + Y ))
-substitution="${string/#foo/bar}"
+
# Prefer this:
+addition=$(( X + Y ))
+substitution="${string/#foo/bar}"
 
-# Instead of this:
-addition="$(expr "${X}" + "${Y}")"
-substitution="$(echo "${string}" | sed -e 's/^foo/bar/')"
+# Instead of this:
+addition="$(expr "${X}" + "${Y}")"
+substitution="$(echo "${string}" | sed -e 's/^foo/bar/')"
 

I can't entirely agree here. The external commands (especially sed) are much more sophisticated and powerful than the built-in Bash versions. Sed can do much more than the Bash can ever do by itself when it comes to text manipulation (the name "sed" stands for streaming editor, after all).
@@ -172,20 +172,20 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
declare -r SUGAR_FREE=yes
-declare -r I_NEED_THE_BUZZ=no
+
declare -r SUGAR_FREE=yes
+declare -r I_NEED_THE_BUZZ=no
 
-buy_soda () {
-    local -r sugar_free=$1
+buy_soda () {
+    local -r sugar_free=$1
 
-    if [[ $sugar_free == yes ]]; then
-        echo 'Diet Dr. Pepper'
-    else
-        echo 'Pepsi Coke'
-    fi
-}
+    if [[ $sugar_free == yes ]]; then
+        echo 'Diet Dr. Pepper'
+    else
+        echo 'Pepsi Coke'
+    fi
+}
 
-buy_soda $I_NEED_THE_BUZZ
+buy_soda $I_NEED_THE_BUZZ
 

Non-evil alternative to variable assignments via eval


@@ -196,12 +196,12 @@ buy_soda $I_NEED_THE_BUZZ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
# What does this set?
-# Did it succeed? In part or whole?
-eval $(set_my_variables)
+
# What does this set?
+# Did it succeed? In part or whole?
+eval $(set_my_variables)
 
-# What happens if one of the returned values has a space in it?
-variable="$(eval some_function)"
+# What happens if one of the returned values has a space in it?
+variable="$(eval some_function)"
 

However, if I want to read variables from another file, I don't have to use eval here. I only have to source the file:
@@ -240,39 +240,39 @@ Hello paul, it is Sat 15 May 19:21:12 BST 2021 by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
filter_lines () {
-    echo 'Start filtering lines in a fancy way!' >&2
-    grep ... | sed ....
-}
+
filter_lines () {
+    echo 'Start filtering lines in a fancy way!' >&2
+    grep ... | sed ....
+}
 
-process_lines () {
-    echo 'Start processing line by line!' >&2
-    while read -r line; do
-        ... do something and produce a result...
-        echo "$result"
-    done 
-}
+process_lines () {
+    echo 'Start processing line by line!' >&2
+    while read -r line; do
+        ... do something and produce a result...
+        echo "$result"
+    done 
+}
 
-# Do some post-processing of the data
-postprocess_lines () {
-    echo 'Start removing duplicates!' >&2
-    sort -u
-}
+# Do some post-processing of the data
+postprocess_lines () {
+    echo 'Start removing duplicates!' >&2
+    sort -u
+}
 
-genreate_report () {
-    echo 'My boss wants to have a report!' >&2
-    tee outfile.txt
-    wc -l outfile.txt
-}
+genreate_report () {
+    echo 'My boss wants to have a report!' >&2
+    tee outfile.txt
+    wc -l outfile.txt
+}
 
-main () {
-    filter_lines |
-        process_lines |
-        postprocess_lines |
-        generate_report
-}
+main () {
+    filter_lines |
+        process_lines |
+        postprocess_lines |
+        generate_report
+}
 
-main
+main
 

The stdout is always passed as a pipe to the next following stage. The stderr is used for info logging.
@@ -287,13 +287,13 @@ main by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
some_function () {
-    local -r param_foo="$1"; shift
-    local -r param_baz="$1"; shift
-    local -r param_bay="$1"; shift
+
some_function () {
+    local -r param_foo="$1"; shift
+    local -r param_baz="$1"; shift
+    local -r param_bay="$1"; shift
 
-    # ...
-}
+    # ...
+}
 

Want to add a param_baz? Just do this:
@@ -302,14 +302,14 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
some_function () {
-    local -r param_foo="$1"; shift
-    local -r param_bar="$1"; shift
-    local -r param_baz="$1"; shift
-    local -r param_bay="$1"; shift
+
some_function () {
+    local -r param_foo="$1"; shift
+    local -r param_bar="$1"; shift
+    local -r param_baz="$1"; shift
+    local -r param_bay="$1"; shift
 
-    # ...
-}
+    # ...
+}
 

Want to remove param_foo? Nothing easier than that:
@@ -318,13 +318,13 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
some_function () {
-    local -r param_bar="$1"; shift
-    local -r param_baz="$1"; shift
-    local -r param_bay="$1"; shift
-    
-    # ...
-}
+
some_function () {
+    local -r param_bar="$1"; shift
+    local -r param_baz="$1"; shift
+    local -r param_bay="$1"; shift
+    
+    # ...
+}
 

As you can see, I didn't need to change any other assignments within the function. Of course, you would also need to change the function argument lists at every occasion where the function is invoked - you would do that within the same refactoring session.
@@ -337,9 +337,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
set -e
-grep -q foo <<< bar
-echo Jo
+
set -e
+grep -q foo <<< bar
+echo Jo
 

Here 'Jo' will never be printed out as the grep didn't find any match. It's unrealistic for most scripts to run in paranoid mode purely, so there must be a way to add exceptions. Critical Bash scripts of mine tend to look like this:
@@ -348,26 +348,26 @@ echo Jo by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
#!/usr/bin/env bash
+
#!/usr/bin/env bash
 
-set -e
+set -e
 
-some_function () {
-    # .. some critical code
-    # ...
+some_function () {
+    # .. some critical code
+    # ...
 
-    set +e
-    # Grep might fail, but that's OK now
-    grep ....
-    local -i ec=$?
-    set -e
+    set +e
+    # Grep might fail, but that's OK now
+    grep ....
+    local -i ec=$?
+    set -e
 
-    # .. critical code continues ...
-    if [[ $ec -ne 0 ]]; then
-        : # ...
-    fi
-    # ...
-}
+    # .. critical code continues ...
+    if [[ $ec -ne 0 ]]; then
+        : # ...
+    fi
+    # ...
+}
 

Learned


@@ -382,10 +382,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
if [[ "${my_var}" > 3 ]]; then
-    # True for 4, false for 22.
-    do_something
-fi
+
if [[ "${my_var}" > 3 ]]; then
+    # True for 4, false for 22.
+    do_something
+fi
 

... but it is probably an unintended lexicographical comparison. A correct way would be:
@@ -394,9 +394,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
if (( my_var > 3 )); then
-    do_something
-fi
+
if (( my_var > 3 )); then
+    do_something
+fi
 

or
@@ -405,9 +405,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
if [[ "${my_var}" -gt 3 ]]; then
-    do_something
-fi
+
if [[ "${my_var}" -gt 3 ]]; then
+    do_something
+fi
 

PIPESTATUS


@@ -420,10 +420,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
tar -cf - ./* | ( cd "${dir}" && tar -xf - )
-if (( PIPESTATUS[0] != 0 || PIPESTATUS[1] != 0 )); then
-    echo "Unable to tar files to ${dir}" >&2
-fi
+
tar -cf - ./* | ( cd "${dir}" && tar -xf - )
+if (( PIPESTATUS[0] != 0 || PIPESTATUS[1] != 0 )); then
+    echo "Unable to tar files to ${dir}" >&2
+fi
 

However, as PIPESTATUS will be overwritten as soon as you do any other command, if you need to act differently on errors based on where it happened in the pipe, you'll need to assign PIPESTATUS to another variable immediately after running the command (don't forget that [ is a command and will wipe out PIPESTATUS).
@@ -432,14 +432,14 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
tar -cf - ./* | ( cd "${DIR}" && tar -xf - )
-return_codes=( "${PIPESTATUS[@]}" )
-if (( return_codes[0] != 0 )); then
-    do_something
-fi
-if (( return_codes[1] != 0 )); then
-    do_something_else
-fi
+
tar -cf - ./* | ( cd "${DIR}" && tar -xf - )
+return_codes=( "${PIPESTATUS[@]}" )
+if (( return_codes[0] != 0 )); then
+    do_something
+fi
+if (( return_codes[1] != 0 )); then
+    do_something_else
+fi
 

Use common sense and BE CONSISTENT.


diff --git a/gemfeed/2021-06-05-gemtexter-one-bash-script-to-rule-it-all.html b/gemfeed/2021-06-05-gemtexter-one-bash-script-to-rule-it-all.html index edbdab2b..4c1e8c40 100644 --- a/gemfeed/2021-06-05-gemtexter-one-bash-script-to-rule-it-all.html +++ b/gemfeed/2021-06-05-gemtexter-one-bash-script-to-rule-it-all.html @@ -94,18 +94,18 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
paul in uranus in gemtexter on 🌱 main
-❯ wc -l gemtexter lib/*
-    117 gemtexter
-     59 lib/assert.source.sh
-    128 lib/atomfeed.source.sh
-     64 lib/gemfeed.source.sh
-    161 lib/generate.source.sh
-     50 lib/git.source.sh
-    162 lib/html.source.sh
-     30 lib/log.source.sh
-     63 lib/md.source.sh
-     834 total
+
paul in uranus in gemtexter on 🌱 main
+❯ wc -l gemtexter lib/*
+    117 gemtexter
+     59 lib/assert.source.sh
+    128 lib/atomfeed.source.sh
+     64 lib/gemfeed.source.sh
+    161 lib/generate.source.sh
+     50 lib/git.source.sh
+    162 lib/html.source.sh
+     30 lib/log.source.sh
+     63 lib/md.source.sh
+     834 total
 

This way, the script could grow far beyond 1000 lines of code and still be maintainable. With more features, execution speed may slowly become a problem, though. I already notice that Gemtexter doesn't produce results instantly but requires few seconds of runtime already. That's not a problem yet, though.
@@ -140,9 +140,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
gemtext='=> http://example.org Description of the link'
-assert::equals "$(generate::make_link html "$gemtext")" \
-    '<a class="textlink" href="http://example.org">Description of the link</a><br />'
+
gemtext='=> http://example.org Description of the link'
+assert::equals "$(generate::make_link html "$gemtext")" \
+    '<a class="textlink" href="http://example.org">Description of the link</a><br />'
 

Markdown unit test example


@@ -151,9 +151,9 @@ assert::equals "$(generate::m by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
gemtext='=> http://example.org Description of the link'
-assert::equals "$(generate::make_link md "$gemtext")" \
-    '[Description of the link](http://example.org)  '
+
gemtext='=> http://example.org Description of the link'
+assert::equals "$(generate::make_link md "$gemtext")" \
+    '[Description of the link](http://example.org)  '
 

Handcrafted HTML styles


diff --git a/gemfeed/2022-08-27-gemtexter-1.1.0-lets-gemtext-again.html b/gemfeed/2022-08-27-gemtexter-1.1.0-lets-gemtext-again.html index abc13376..ab84385c 100644 --- a/gemfeed/2022-08-27-gemtexter-1.1.0-lets-gemtext-again.html +++ b/gemfeed/2022-08-27-gemtexter-1.1.0-lets-gemtext-again.html @@ -40,23 +40,23 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
check_dependencies () {
-    # At least, Bash 5 is required
-    local -i required_version=5
-    IFS=. read -ra version <<< "$BASH_VERSION"
-    if [ "${version[0]}" -lt $required_version ]; then
-        log ERROR "ERROR, \"bash\" must be at least at major version $required_version!"
-        exit 2
-    fi
+
check_dependencies () {
+    # At least, Bash 5 is required
+    local -i required_version=5
+    IFS=. read -ra version <<< "$BASH_VERSION"
+    if [ "${version[0]}" -lt $required_version ]; then
+        log ERROR "ERROR, \"bash\" must be at least at major version $required_version!"
+        exit 2
+    fi
 
-    # These must be the GNU versions of the commands
-    for tool in $DATE $SED $GREP; do
-        if ! $tool --version | grep -q GNU; then
-            log ERROR "ERROR, \"$tool\" command is not the GNU version, please install!"
-            exit 2
-        fi
-    done
-}
+    # These must be the GNU versions of the commands
+    for tool in $DATE $SED $GREP; do
+        if ! $tool --version | grep -q GNU; then
+            log ERROR "ERROR, \"$tool\" command is not the GNU version, please install!"
+            exit 2
+        fi
+    done
+}
 

Especially macOS users didn't read the README carefully enough to install GNU Grep, GNU Sed and GNU Date before using Gemtexter.
@@ -77,7 +77,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
./gemtexter --generate '.*hello.*'
+
./gemtexter --generate '.*hello.*'
 

Revamped git support


diff --git a/gemfeed/2022-11-24-i-tried-emacs-but-i-switched-back-to-neovim.html b/gemfeed/2022-11-24-i-tried-emacs-but-i-switched-back-to-neovim.html index 8a1fa368..05bde577 100644 --- a/gemfeed/2022-11-24-i-tried-emacs-but-i-switched-back-to-neovim.html +++ b/gemfeed/2022-11-24-i-tried-emacs-but-i-switched-back-to-neovim.html @@ -79,10 +79,10 @@ Art by \ \_! / __! by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
" Clipboard
-vnoremap ,y !pbcopy<CR>ugv
-vnoremap ,i !pbpaste<CR>
-nmap ,i !wpbpaste<CR>
+
" Clipboard
+vnoremap ,y !pbcopy<CR>ugv
+vnoremap ,i !pbpaste<CR>
+nmap ,i !wpbpaste<CR>
 

That's only a very few lines and does precisely what I want. It's quick and dirty but get's the job done! If VimScript becomes too cumbersome, I can use Lua for NeoVim scripting.
diff --git a/gemfeed/2023-03-25-gemtexter-2.0.0-lets-gemtext-again-2.html b/gemfeed/2023-03-25-gemtexter-2.0.0-lets-gemtext-again-2.html index 478cee72..4b8a9c74 100644 --- a/gemfeed/2023-03-25-gemtexter-2.0.0-lets-gemtext-again-2.html +++ b/gemfeed/2023-03-25-gemtexter-2.0.0-lets-gemtext-again-2.html @@ -109,8 +109,8 @@ Blablabla... by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
declare -xr PRE_GENERATE_HOOK=./pre_generate_hook.sh
-declare -xr POST_PUBLISH_HOOK=./post_publish_hook.sh
+
declare -xr PRE_GENERATE_HOOK=./pre_generate_hook.sh
+declare -xr POST_PUBLISH_HOOK=./post_publish_hook.sh
 

Use of safer Bash options


@@ -127,10 +127,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
% cat gemfeed/2023-02-26-title-here.gmi
-# Title here
+
% cat gemfeed/2023-02-26-title-here.gmi
+# Title here
 
-The remaining content of the Gemtext file...
+The remaining content of the Gemtext file...
 

Gemtexter will add a line starting with > Published at ... now. Any subsequent Atom feed generation will then use that date.
@@ -139,12 +139,12 @@ The remaining content of the Gemtext file... by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
% cat gemfeed/2023-02-26-title-here.gmi
-# Title here
+
% cat gemfeed/2023-02-26-title-here.gmi
+# Title here
 
-> Published at 2023-02-26T21:43:51+01:00
+> Published at 2023-02-26T21:43:51+01:00
 
-The remaining content of the Gemtext file...
+The remaining content of the Gemtext file...
 

XMLLint support


diff --git a/gemfeed/2023-04-09-algorithms-and-data-structures-in-golang-part-1.html b/gemfeed/2023-04-09-algorithms-and-data-structures-in-golang-part-1.html index bc6d9b75..389b9b6f 100644 --- a/gemfeed/2023-04-09-algorithms-and-data-structures-in-golang-part-1.html +++ b/gemfeed/2023-04-09-algorithms-and-data-structures-in-golang-part-1.html @@ -40,19 +40,19 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
package ds
+
package ds
 
-import (
-	"golang.org/x/exp/constraints"
-)
+import (
+	"golang.org/x/exp/constraints"
+)
 
-type Integer interface {
-	constraints.Integer
-}
+type Integer interface {
+	constraints.Integer
+}
 
-type Number interface {
-	constraints.Integer | constraints.Float
-}
+type Number interface {
+	constraints.Integer | constraints.Float
+}
 
 

@@ -64,19 +64,19 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
package ds
+
package ds
 
-import (
-	"fmt"
-	"math/rand"
-	"strings"
-)
+import (
+	"fmt"
+	"math/rand"
+	"strings"
+)
 
-type ArrayList[V Number] []V
+type ArrayList[V Number] []V
 
-func NewArrayList[V Number](l int) ArrayList[V] {
-	return make(ArrayList[V], l)
-}
+func NewArrayList[V Number](l int) ArrayList[V] {
+	return make(ArrayList[V], l)
+}
 

As you can see, the code uses Go generics, which I refactored recently. Besides the default constructor (which only returns an empty ArrayList with a given capacity), there are also a bunch of special constructors. NewRandomArrayList is returning an ArrayList with random numbers, NewAscendingArrayList and NewDescendingArrayList are returning ArrayLists in either ascending or descending order. They all will be used later on for testing and benchmarking the algorithms.
@@ -85,35 +85,35 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
func NewRandomArrayList[V Number](l, max int) ArrayList[V] {
-	a := make(ArrayList[V], l)
-	for i := 0; i < l; i++ {
-		if max > 0 {
-			a[i] = V(rand.Intn(max))
-			continue
-		}
-		a[i] = V(rand.Int())
-	}
-	return a
-}
+
func NewRandomArrayList[V Number](l, max int) ArrayList[V] {
+	a := make(ArrayList[V], l)
+	for i := 0; i < l; i++ {
+		if max > 0 {
+			a[i] = V(rand.Intn(max))
+			continue
+		}
+		a[i] = V(rand.Int())
+	}
+	return a
+}
 
-func NewAscendingArrayList[V Number](l int) ArrayList[V] {
-	a := make(ArrayList[V], l)
-	for i := 0; i < l; i++ {
-		a[i] = V(i)
-	}
-	return a
-}
+func NewAscendingArrayList[V Number](l int) ArrayList[V] {
+	a := make(ArrayList[V], l)
+	for i := 0; i < l; i++ {
+		a[i] = V(i)
+	}
+	return a
+}
 
-func NewDescendingArrayList[V Number](l int) ArrayList[V] {
-	a := make(ArrayList[V], l)
-	j := l - 1
-	for i := 0; i < l; i++ {
-		a[i] = V(j)
-		j--
-	}
-	return a
-}
+func NewDescendingArrayList[V Number](l int) ArrayList[V] {
+	a := make(ArrayList[V], l)
+	j := l - 1
+	for i := 0; i < l; i++ {
+		a[i] = V(j)
+		j--
+	}
+	return a
+}
 

Helper methods


@@ -124,25 +124,25 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
func (a ArrayList[V]) FirstN(n int) string {
-	var sb strings.Builder
-	j := n
+
func (a ArrayList[V]) FirstN(n int) string {
+	var sb strings.Builder
+	j := n
 
-	l := len(a)
-	if j > l {
-		j = l
-	}
+	l := len(a)
+	if j > l {
+		j = l
+	}
 
-	for i := 0; i < j; i++ {
-		fmt.Fprintf(&sb, "%v ", a[i])
-	}
+	for i := 0; i < j; i++ {
+		fmt.Fprintf(&sb, "%v ", a[i])
+	}
 
-	if j < l {
-		fmt.Fprintf(&sb, "... ")
-	}
+	if j < l {
+		fmt.Fprintf(&sb, "... ")
+	}
 
-	return sb.String()
-}
+	return sb.String()
+}
 

The Sorted method checks whether the ArrayList is sorted. This will be used by the unit tests later on:
@@ -151,14 +151,14 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
func (a ArrayList[V]) Sorted() bool {
-	for i := len(a) - 1; i > 0; i-- {
-		if a[i] < a[i-1] {
-			return false
-		}
-	}
-	return true
-}
+
func (a ArrayList[V]) Sorted() bool {
+	for i := len(a) - 1; i > 0; i-- {
+		if a[i] < a[i-1] {
+			return false
+		}
+	}
+	return true
+}
 

And the last utility method used is Swap, which allows swapping the values of two indices in the ArrayList:
@@ -167,11 +167,11 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
func (a ArrayList[V]) Swap(i, j int) {
-	aux := a[i]
-	a[i] = a[j]
-	a[j] = aux
-}
+
func (a ArrayList[V]) Swap(i, j int) {
+	aux := a[i]
+	a[i] = a[j]
+	a[j] = aux
+}
 
 

@@ -184,40 +184,40 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
package sort
+
package sort
 
-import (
-	"codeberg.org/snonux/algorithms/ds"
-	"sync"
-	"time"
-)
+import (
+	"codeberg.org/snonux/algorithms/ds"
+	"sync"
+	"time"
+)
 
-func Sleep[V ds.Integer](a ds.ArrayList[V]) ds.ArrayList[V] {
-	sorted := ds.NewArrayList[V](len(a))
+func Sleep[V ds.Integer](a ds.ArrayList[V]) ds.ArrayList[V] {
+	sorted := ds.NewArrayList[V](len(a))
 
-	numCh := make(chan V)
-	var wg sync.WaitGroup
-	wg.Add(len(a))
+	numCh := make(chan V)
+	var wg sync.WaitGroup
+	wg.Add(len(a))
 
-	go func() {
-		wg.Wait()
-		close(numCh)
-	}()
+	go func() {
+		wg.Wait()
+		close(numCh)
+	}()
 
-	for _, num := range a {
-		go func(num V) {
-			defer wg.Done()
-			time.Sleep(time.Duration(num) * time.Second)
-			numCh <- num
-		}(num)
-	}
+	for _, num := range a {
+		go func(num V) {
+			defer wg.Done()
+			time.Sleep(time.Duration(num) * time.Second)
+			numCh <- num
+		}(num)
+	}
 
-	for num := range numCh {
-		sorted = append(sorted, num)
-	}
+	for num := range numCh {
+		sorted = append(sorted, num)
+	}
 
-	return sorted
-}
+	return sorted
+}
 

This Go code implements the sleep sort algorithm using generics and goroutines. The main function Sleep[V ds.Integer](a ds.ArrayList[V]) ds.ArrayList[V] takes a generic ArrayList as input and returns a sorted ArrayList. The code creates a separate goroutine for each element in the input array, sleeps for a duration proportional to the element's value, and then sends the element to a channel. Another goroutine waits for all the sleeping goroutines to finish and then closes the channel. The sorted result ArrayList is constructed by appending the elements received from the channel in the order they arrive. The sync.WaitGroup is used to synchronize goroutines and ensure that all of them have completed before closing the channel.
@@ -230,22 +230,22 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
package sort
+
package sort
 
-import (
-	"fmt"
-	"testing"
+import (
+	"fmt"
+	"testing"
 
-	"codeberg.org/snonux/algorithms/ds"
-)
+	"codeberg.org/snonux/algorithms/ds"
+)
 
-func TestSleepSort(t *testing.T) {
-	a := ds.NewRandomArrayList[int](10, 10)
-	a = Sleep(a)
-	if !a.Sorted() {
-		t.Errorf("Array not sorted: %v", a)
-	}
-}
+func TestSleepSort(t *testing.T) {
+	a := ds.NewRandomArrayList[int](10, 10)
+	a = Sleep(a)
+	if !a.Sorted() {
+		t.Errorf("Array not sorted: %v", a)
+	}
+}
 

As you can see, it takes 9s here for the algorithm to finish (which is the highest value in the ArrayList):
@@ -254,11 +254,11 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
❯ go test ./sort -v -run SleepSort
-=== RUN   TestSleepSort
---- PASS: TestSleepSort (9.00s)
-PASS
-ok      codeberg.org/snonux/algorithms/sort     9.002s
+
❯ go test ./sort -v -run SleepSort
+=== RUN   TestSleepSort
+--- PASS: TestSleepSort (9.00s)
+PASS
+ok      codeberg.org/snonux/algorithms/sort     9.002s
 

I won't write any benchmark for sleep sort; that will be done for the algorithms to come in this series :-).
diff --git a/gemfeed/2023-05-01-unveiling-guprecords:-uptime-records-with-raku.html b/gemfeed/2023-05-01-unveiling-guprecords:-uptime-records-with-raku.html index 29e46420..2afa6d09 100644 --- a/gemfeed/2023-05-01-unveiling-guprecords:-uptime-records-with-raku.html +++ b/gemfeed/2023-05-01-unveiling-guprecords:-uptime-records-with-raku.html @@ -65,7 +65,7 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
$ raku guprecords.raku --stats=dir=$HOME/git/uprecords/stats --all
+
$ raku guprecords.raku --stats=dir=$HOME/git/uprecords/stats --all
 

This command will generate a comprehensive uptime report from the collected statistics, making it easy to review and enjoy the data.
diff --git a/gemfeed/2023-06-01-kiss-server-monitoring-with-gogios.html b/gemfeed/2023-06-01-kiss-server-monitoring-with-gogios.html index f79b7b62..1aea4149 100644 --- a/gemfeed/2023-06-01-kiss-server-monitoring-with-gogios.html +++ b/gemfeed/2023-06-01-kiss-server-monitoring-with-gogios.html @@ -98,11 +98,11 @@ Have a nice day! by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
git clone https://codeberg.org/snonux/gogios.git
-cd gogios
-go build -o gogios cmd/gogios/main.go
-doas cp gogios /usr/local/bin/gogios
-doas chmod 755 /usr/local/bin/gogios
+
git clone https://codeberg.org/snonux/gogios.git
+cd gogios
+go build -o gogios cmd/gogios/main.go
+doas cp gogios /usr/local/bin/gogios
+doas chmod 755 /usr/local/bin/gogios
 

You can use cross-compilation if you want to compile Gogios for OpenBSD on a Linux system without installing the Go compiler on OpenBSD. Follow these steps:
@@ -111,9 +111,9 @@ doas chmod 755 /usr/local/bin/gogios by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
export GOOS=openbsd
-export GOARCH=amd64
-go build -o gogios cmd/gogios/main.go
+
export GOOS=openbsd
+export GOARCH=amd64
+go build -o gogios cmd/gogios/main.go
 

On your OpenBSD system, copy the binary to /usr/local/bin/gogios and set the correct permissions as described in the previous section. All steps described here you could automate with your configuration management system of choice. I use Rexify, the friendly configuration management system, to automate the installation, but that is out of the scope of this document.
@@ -128,11 +128,11 @@ go build -o gogios cmd/gogios/main.go by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
doas adduser -group _gogios -batch _gogios
-doas usermod -d /var/run/gogios _gogios
-doas mkdir -p /var/run/gogios
-doas chown _gogios:_gogios /var/run/gogios
-doas chmod 750 /var/run/gogios
+
doas adduser -group _gogios -batch _gogios
+doas usermod -d /var/run/gogios _gogios
+doas mkdir -p /var/run/gogios
+doas chown _gogios:_gogios /var/run/gogios
+doas chmod 750 /var/run/gogios
 

Please note that creating a user and group might differ depending on your operating system. For other operating systems, consult their documentation for creating system users and groups.
@@ -145,8 +145,8 @@ doas chmod 750 /var/run/gogios by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
doas pkg_add monitoring-plugins
-doas pkg_add nrpe # If you want to execute checks remotely via NRPE.
+
doas pkg_add monitoring-plugins
+doas pkg_add nrpe # If you want to execute checks remotely via NRPE.
 

Once the installation is complete, you can find the monitoring plugins in the /usr/local/libexec/nagios directory, which then can be configured to be used in gogios.json.
@@ -173,41 +173,41 @@ echo 'This is a test email from OpenBSD.' | mail -s 'Test Email' by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
{
-  "EmailTo": "paul@dev.buetow.org",
-  "EmailFrom": "gogios@buetow.org",
-  "CheckTimeoutS": 10,
-  "CheckConcurrency": 2,
-  "StateDir": "/var/run/gogios",
-  "Checks": {
-    "Check ICMP4 www.foo.zone": {
-      "Plugin": "/usr/local/libexec/nagios/check_ping",
-      "Args": [ "-H", "www.foo.zone", "-4", "-w", "50,10%", "-c", "100,15%" ],
-      "Retries": 3,
-      "RetryInterval": 10
-    },
-    "Check ICMP6 www.foo.zone": {
-      "Plugin": "/usr/local/libexec/nagios/check_ping",
-      "Args": [ "-H", "www.foo.zone", "-6", "-w", "50,10%", "-c", "100,15%" ],
-      "Retries": 3,
-      "RetryInterval": 10
-    },
-    "www.foo.zone HTTP IPv4": {
-      "Plugin": "/usr/local/libexec/nagios/check_http",
-      "Args": ["www.foo.zone", "-4"],
-      "DependsOn": ["Check ICMP4 www.foo.zone"]
-    },
-    "www.foo.zone HTTP IPv6": {
-      "Plugin": "/usr/local/libexec/nagios/check_http",
-      "Args": ["www.foo.zone", "-6"],
-      "DependsOn": ["Check ICMP6 www.foo.zone"]
-    }
-    "Check NRPE Disk Usage foo.zone": {
-      "Plugin": "/usr/local/libexec/nagios/check_nrpe",
-      "Args": ["-H", "foo.zone", "-c", "check_disk", "-p", "5666", "-4"]
-    }
-  }
-}
+
{
+  "EmailTo": "paul@dev.buetow.org",
+  "EmailFrom": "gogios@buetow.org",
+  "CheckTimeoutS": 10,
+  "CheckConcurrency": 2,
+  "StateDir": "/var/run/gogios",
+  "Checks": {
+    "Check ICMP4 www.foo.zone": {
+      "Plugin": "/usr/local/libexec/nagios/check_ping",
+      "Args": [ "-H", "www.foo.zone", "-4", "-w", "50,10%", "-c", "100,15%" ],
+      "Retries": 3,
+      "RetryInterval": 10
+    },
+    "Check ICMP6 www.foo.zone": {
+      "Plugin": "/usr/local/libexec/nagios/check_ping",
+      "Args": [ "-H", "www.foo.zone", "-6", "-w", "50,10%", "-c", "100,15%" ],
+      "Retries": 3,
+      "RetryInterval": 10
+    },
+    "www.foo.zone HTTP IPv4": {
+      "Plugin": "/usr/local/libexec/nagios/check_http",
+      "Args": ["www.foo.zone", "-4"],
+      "DependsOn": ["Check ICMP4 www.foo.zone"]
+    },
+    "www.foo.zone HTTP IPv6": {
+      "Plugin": "/usr/local/libexec/nagios/check_http",
+      "Args": ["www.foo.zone", "-6"],
+      "DependsOn": ["Check ICMP6 www.foo.zone"]
+    }
+    "Check NRPE Disk Usage foo.zone": {
+      "Plugin": "/usr/local/libexec/nagios/check_nrpe",
+      "Args": ["-H", "foo.zone", "-c", "check_disk", "-p", "5666", "-4"]
+    }
+  }
+}
 

    @@ -236,7 +236,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    doas -u _gogios /usr/local/bin/gogios -cfg /etc/gogios.json
    +
    doas -u _gogios /usr/local/bin/gogios -cfg /etc/gogios.json
     

    To run Gogios via CRON on OpenBSD as the gogios user and check all services once per minute, follow these steps:
    diff --git a/gemfeed/2023-07-21-gemtexter-2.1.0-lets-gemtext-again-3.html b/gemfeed/2023-07-21-gemtexter-2.1.0-lets-gemtext-again-3.html index 732d285e..76372e00 100644 --- a/gemfeed/2023-07-21-gemtexter-2.1.0-lets-gemtext-again-3.html +++ b/gemfeed/2023-07-21-gemtexter-2.1.0-lets-gemtext-again-3.html @@ -57,9 +57,9 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    if [ -n "$foo" ]; then
    -  echo "$foo"
    -fi
    +
    if [ -n "$foo" ]; then
    +  echo "$foo"
    +fi
     

    Please run source-highlight --lang-list for a list of all supported languages.
    @@ -88,7 +88,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    declare -xr MASTODON_URI='https://fosstodon.org/@snonux'
    +
    declare -xr MASTODON_URI='https://fosstodon.org/@snonux'
     

    and add the following into your index.gmi:
    @@ -103,7 +103,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    <a href='https://fosstodon.org/@snonux' rel='me'>Me at Mastodon</a>
    +
    <a href='https://fosstodon.org/@snonux' rel='me'>Me at Mastodon</a>
     

    More


    diff --git a/gemfeed/2023-09-25-dtail-usage-examples.html b/gemfeed/2023-09-25-dtail-usage-examples.html index f07fed00..e66dcf82 100644 --- a/gemfeed/2023-09-25-dtail-usage-examples.html +++ b/gemfeed/2023-09-25-dtail-usage-examples.html @@ -50,7 +50,7 @@ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail --servers serverlist.txt --grep INFO --files "/var/log/dserver/*.log"
    +
    % dtail --servers serverlist.txt --grep INFO --files "/var/log/dserver/*.log"
     

    Hint: you can also provide a comma separated server list, e.g.: servers server1.example.org,server2.example.org:PORT,...
    @@ -63,7 +63,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail --servers serverlist.txt --grep INFO "/var/log/dserver/*.log"
    +
    % dtail --servers serverlist.txt --grep INFO "/var/log/dserver/*.log"
     

    Aggregating logs


    @@ -76,10 +76,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail --servers serverlist.txt \
    -    --files '/var/log/dserver/*.log' \
    -    --query 'from STATS select sum($goroutines),sum($cgocalls),
    -             last($time),max(lifetimeConnections)'
    +
    % dtail --servers serverlist.txt \
    +    --files '/var/log/dserver/*.log' \
    +    --query 'from STATS select sum($goroutines),sum($cgocalls),
    +             last($time),max(lifetimeConnections)'
     

    Beware: For map-reduce queries to work, you have to ensure that DTail supports your log format. Check out the documentaiton of the DTail query language and the DTail log formats on the DTail homepage for more information.
    @@ -92,10 +92,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail --servers serverlist.txt \
    -    --files '/var/log/dserver/*.log' \
    -    'from STATS select sum($goroutines),sum($cgocalls),
    -     last($time),max(lifetimeConnections)'
    +
    % dtail --servers serverlist.txt \
    +    --files '/var/log/dserver/*.log' \
    +    'from STATS select sum($goroutines),sum($cgocalls),
    +     last($time),max(lifetimeConnections)'
     

    Here is another example:
    @@ -104,10 +104,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail --servers serverlist.txt \
    -    --files '/var/log/dserver/*.log' \
    -    --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    -             lifetimeConnections group by $hostname order by max($cgocalls)'
    +
    % dtail --servers serverlist.txt \
    +    --files '/var/log/dserver/*.log' \
    +    --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    +             lifetimeConnections group by $hostname order by max($cgocalls)'
     

    Tail map-reduce example 2
    @@ -118,9 +118,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail --servers serverlist.txt \
    -    --files '/var/log/dserver/*.log' \
    -    --query 'from STATS select ... outfile append result.csv'
    +
    % dtail --servers serverlist.txt \
    +    --files '/var/log/dserver/*.log' \
    +    --query 'from STATS select ... outfile append result.csv'
     

    How to use dcat


    @@ -133,7 +133,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dcat --servers serverlist.txt --files /etc/hostname
    +
    % dcat --servers serverlist.txt --files /etc/hostname
     

    Cat example
    @@ -144,7 +144,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dcat --servers serverlist.txt /etc/hostname
    +
    % dcat --servers serverlist.txt /etc/hostname
     

    How to use dgrep


    @@ -155,9 +155,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dgrep --servers server1.example.org:2223 \
    -    --files /etc/passwd \
    -    --regex nologin
    +
    % dgrep --servers server1.example.org:2223 \
    +    --files /etc/passwd \
    +    --regex nologin
     

    Generally, dgrep is also a very useful way to search historic application logs for certain content.
    @@ -174,10 +174,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dmap --servers serverlist.txt \
    -    --files '/var/log/dserver/*.log' \
    -    --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    -             lifetimeConnections group by $hostname order by max($cgocalls)'
    +
    % dmap --servers serverlist.txt \
    +    --files '/var/log/dserver/*.log' \
    +    --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    +             lifetimeConnections group by $hostname order by max($cgocalls)'
     

    Remember: For that to work, you have to make sure that DTail supports your log format. You can either use the ones already defined in internal/mapr/logformat or add an extension to support a custom log format. The example here works out of the box though, as DTail understands its own log format already.
    @@ -200,9 +200,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dmap --files /var/log/dserver/dserver.log
    -    --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    -              lifetimeConnections group by $hostname order by max($cgocalls)'
    +
    % dmap --files /var/log/dserver/dserver.log
    +    --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    +              lifetimeConnections group by $hostname order by max($cgocalls)'
     

    As a shorthand version the following command can be used:
    @@ -211,9 +211,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dmap 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    -        lifetimeConnections group by $hostname order by max($cgocalls)' \
    -        /var/log/dsever/dserver.log
    +
    % dmap 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    +        lifetimeConnections group by $hostname order by max($cgocalls)' \
    +        /var/log/dsever/dserver.log
     

    You can also use a file input pipe as follows:
    @@ -222,9 +222,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % cat /var/log/dserver/dserver.log | \
    -    dmap 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    -          lifetimeConnections group by $hostname order by max($cgocalls)'
    +
    % cat /var/log/dserver/dserver.log | \
    +    dmap 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    +          lifetimeConnections group by $hostname order by max($cgocalls)'
     

    Aggregating CSV files


    @@ -235,16 +235,16 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % cat example.csv
    -name,lastname,age,profession
    -Michael,Jordan,40,Basketball player
    -Michael,Jackson,100,Singer
    -Albert,Einstein,200,Physician
    -% dmap --query 'select lastname,name where age > 40 logformat csv outfile result.csv' example.csv
    -% cat result.csv
    -lastname,name
    -Jackson,Michael
    -Einstein,Albert
    +
    % cat example.csv
    +name,lastname,age,profession
    +Michael,Jordan,40,Basketball player
    +Michael,Jackson,100,Singer
    +Albert,Einstein,200,Physician
    +% dmap --query 'select lastname,name where age > 40 logformat csv outfile result.csv' example.csv
    +% cat result.csv
    +lastname,name
    +Jackson,Michael
    +Einstein,Albert
     

    DMap can also be used to query and aggregate CSV files from remote servers.
    @@ -257,44 +257,44 @@ Einstein,Albert by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail /var/log/dserver/dserver.log
    +
    % dtail /var/log/dserver/dserver.log
     

    -
    % dtail --logLevel trace /var/log/dserver/dserver.log
    +
    % dtail --logLevel trace /var/log/dserver/dserver.log
     

    -
    % dcat /etc/passwd
    +
    % dcat /etc/passwd
     

    -
    % dcat --plain /etc/passwd > /etc/test
    -# Should show no differences.
    -diff /etc/test /etc/passwd 
    +
    % dcat --plain /etc/passwd > /etc/test
    +# Should show no differences.
    +diff /etc/test /etc/passwd 
     

    -
    % dgrep --regex ERROR --files /var/log/dserver/dsever.log
    +
    % dgrep --regex ERROR --files /var/log/dserver/dsever.log
     

    -
    % dgrep --before 10 --after 10 --max 10 --grep ERROR /var/log/dserver/dsever.log
    +
    % dgrep --before 10 --after 10 --max 10 --grep ERROR /var/log/dserver/dsever.log
     

    Use --help for more available options. Or go to the DTail page for more information! Hope you find DTail useful!
    diff --git a/gemfeed/2023-10-29-kiss-static-web-photo-albums-with-photoalbum.sh.html b/gemfeed/2023-10-29-kiss-static-web-photo-albums-with-photoalbum.sh.html index 0293ba9c..0e3b8396 100644 --- a/gemfeed/2023-10-29-kiss-static-web-photo-albums-with-photoalbum.sh.html +++ b/gemfeed/2023-10-29-kiss-static-web-photo-albums-with-photoalbum.sh.html @@ -117,42 +117,42 @@ photoalbum makemake by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % photoalbum makemake
    -You may now customize ./photoalbumrc and run make
    +
    % photoalbum makemake
    +You may now customize ./photoalbumrc and run make
     
    -% cat Makefile
    -all:
    -	photoalbum generate photoalbumrc
    -clean:
    -	photoalbum clean photoalbumrc
    +% cat Makefile
    +all:
    +	photoalbum generate photoalbumrc
    +clean:
    +	photoalbum clean photoalbumrc
     
    -% cat photoalbumrc
    -# The title of the photoalbum
    -TITLE='A simple Photoalbum'
    +% cat photoalbumrc
    +# The title of the photoalbum
    +TITLE='A simple Photoalbum'
     
    -# Thumbnail height geometry
    -THUMBHEIGHT=300
    -# Normal geometry height (when viewing photo). Uncomment, to keep original size.
    -HEIGHT=1200
    -# Max previews per page.
    -MAXPREVIEWS=40
    -# Randomly shuffle all previews.
    -# SHUFFLE=yes
    +# Thumbnail height geometry
    +THUMBHEIGHT=300
    +# Normal geometry height (when viewing photo). Uncomment, to keep original size.
    +HEIGHT=1200
    +# Max previews per page.
    +MAXPREVIEWS=40
    +# Randomly shuffle all previews.
    +# SHUFFLE=yes
     
    -# Diverse directories, need to be full paths, not relative!
    -INCOMING_DIR=$(pwd)/incoming
    -DIST_DIR=$(pwd)/dist
    -TEMPLATE_DIR=/usr/share/photoalbum/templates/default
    -#TEMPLATE_DIR=/usr/share/photoalbum/templates/minimal
    +# Diverse directories, need to be full paths, not relative!
    +INCOMING_DIR=$(pwd)/incoming
    +DIST_DIR=$(pwd)/dist
    +TEMPLATE_DIR=/usr/share/photoalbum/templates/default
    +#TEMPLATE_DIR=/usr/share/photoalbum/templates/minimal
     
    -# Includes a .tar of the incoming dir in the dist, can be yes or no
    -TARBALL_INCLUDE=yes
    -TARBALL_SUFFIX=.tar
    -TAR_OPTS='-c'
    +# Includes a .tar of the incoming dir in the dist, can be yes or no
    +TARBALL_INCLUDE=yes
    +TARBALL_SUFFIX=.tar
    +TAR_OPTS='-c'
     
    -# Some debugging options
    -#set -e
    -#set -x
    +# Some debugging options
    +#set -e
    +#set -x
     

    In the case for irregular.ninja, I changed the defaults to the following:
    @@ -161,38 +161,38 @@ clean: by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    --- photoalbumrc        2023-10-29 21:42:00.894202045 +0200
    -+++ photoalbumrc.new 2023-06-04 10:40:08.030994440 +0300
    -@@ -1,23 +1,24 @@
    - # The title of the photoalbum
    --TITLE='A simple Photoalbum'
    -+TITLE='Irregular.Ninja'
    +
    --- photoalbumrc        2023-10-29 21:42:00.894202045 +0200
    ++++ photoalbumrc.new 2023-06-04 10:40:08.030994440 +0300
    +@@ -1,23 +1,24 @@
    + # The title of the photoalbum
    +-TITLE='A simple Photoalbum'
    ++TITLE='Irregular.Ninja'
     
    - # Thumbnail height geometry
    --THUMBHEIGHT=300
    -+THUMBHEIGHT=400
    - # Normal geometry height (when viewing photo). Uncomment, to keep original size.
    --HEIGHT=1200
    -+HEIGHT=1800
    - # Max previews per page.
    - MAXPREVIEWS=40
    --# Randomly shuffle all previews.
    --# SHUFFLE=yes
    -+# Randomly shuffle
    -+SHUFFLE=yes
    + # Thumbnail height geometry
    +-THUMBHEIGHT=300
    ++THUMBHEIGHT=400
    + # Normal geometry height (when viewing photo). Uncomment, to keep original size.
    +-HEIGHT=1200
    ++HEIGHT=1800
    + # Max previews per page.
    + MAXPREVIEWS=40
    +-# Randomly shuffle all previews.
    +-# SHUFFLE=yes
    ++# Randomly shuffle
    ++SHUFFLE=yes
     
    - # Diverse directories, need to be full paths, not relative!
    --INCOMING_DIR=$(pwd)/incoming
    -+INCOMING_DIR=~/Nextcloud/Photos/irregular.ninja
    - DIST_DIR=$(pwd)/dist
    - TEMPLATE_DIR=/usr/share/photoalbum/templates/default
    - #TEMPLATE_DIR=/usr/share/photoalbum/templates/minimal
    + # Diverse directories, need to be full paths, not relative!
    +-INCOMING_DIR=$(pwd)/incoming
    ++INCOMING_DIR=~/Nextcloud/Photos/irregular.ninja
    + DIST_DIR=$(pwd)/dist
    + TEMPLATE_DIR=/usr/share/photoalbum/templates/default
    + #TEMPLATE_DIR=/usr/share/photoalbum/templates/minimal
     
    - # Includes a .tar of the incoming dir in the dist, can be yes or no
    --TARBALL_INCLUDE=yes
    -+TARBALL_INCLUDE=no
    - TARBALL_SUFFIX=.tar
    - TAR_OPTS='-c'
    + # Includes a .tar of the incoming dir in the dist, can be yes or no
    +-TARBALL_INCLUDE=yes
    ++TARBALL_INCLUDE=no
    + TARBALL_SUFFIX=.tar
    + TAR_OPTS='-c'
     

    So I changed the album title, adjusted some image and thumbnail dimensions, and I want all images to be randomly shuffled every time the album is generated! I also have all my photos in my Nextcloud Photo directory and don't want to copy them to the local incoming directory. Also, a tarball containing the whole album as a download isn't provided.
    diff --git a/gemfeed/2023-12-10-bash-golf-part-3.html b/gemfeed/2023-12-10-bash-golf-part-3.html index 021faf6f..5baa4fb8 100644 --- a/gemfeed/2023-12-10-bash-golf-part-3.html +++ b/gemfeed/2023-12-10-bash-golf-part-3.html @@ -39,24 +39,24 @@ jgs^^^^^^^`^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -log () {
    -    local -r level="$1"; shift
    -    local -r message="$1"; shift
    -    local -i pid="$$"
    +log () {
    +    local -r level="$1"; shift
    +    local -r message="$1"; shift
    +    local -i pid="$$"
     
    -    local -r callee=${FUNCNAME[1]}
    -    local -r stamp=$(date +%Y%m%d-%H%M%S)
    +    local -r callee=${FUNCNAME[1]}
    +    local -r stamp=$(date +%Y%m%d-%H%M%S)
     
    -    echo "$level|$stamp|$pid|$callee|$message" >&2
    -}
    +    echo "$level|$stamp|$pid|$callee|$message" >&2
    +}
     
    -at_home_friday_evening () {
    -    log INFO 'One Peperoni Pizza, please'
    -}
    +at_home_friday_evening () {
    +    log INFO 'One Peperoni Pizza, please'
    +}
     
    -at_home_friday_evening
    +at_home_friday_evening
     

    The output is as follows:
    @@ -65,8 +65,8 @@ at_home_friday_evening by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    ./logexample.sh
    -INFO|20231210-082732|123002|at_home_friday_evening|One Peperoni Pizza, please
    +
    ./logexample.sh
    +INFO|20231210-082732|123002|at_home_friday_evening|One Peperoni Pizza, please
     

    :(){ :|:& };:


    @@ -100,18 +100,18 @@ INFO|20231210- -
    #!/usr/bin/env bash
    -
    -outer() {
    -  inner() {
    -    echo 'Intel inside!'
    -  }
    -  inner
    -}
    -
    -inner
    -outer
    -inner
    +
    #!/usr/bin/env bash
    +
    +outer() {
    +  inner() {
    +    echo 'Intel inside!'
    +  }
    +  inner
    +}
    +
    +inner
    +outer
    +inner
     

    And let's execute it:
    @@ -129,26 +129,26 @@ Intel inside! by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    -
    -outer1() {
    -  inner() {
    -    echo 'Intel inside!'
    -  }
    -  inner
    -}
    -
    -outer2() {
    -  inner() {
    -    echo 'Wintel inside!'
    -  }
    -  inner
    -}
    -
    -outer1
    -inner
    -outer2
    -inner
    +
    #!/usr/bin/env bash
    +
    +outer1() {
    +  inner() {
    +    echo 'Intel inside!'
    +  }
    +  inner
    +}
    +
    +outer2() {
    +  inner() {
    +    echo 'Wintel inside!'
    +  }
    +  inner
    +}
    +
    +outer1
    +inner
    +outer2
    +inner
     

    And let's run it:
    @@ -169,14 +169,14 @@ Wintel inside! by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -some_expensive_operations() {
    -  echo "Doing expensive operations with '$1' from pid $$"
    -}
    +some_expensive_operations() {
    +  echo "Doing expensive operations with '$1' from pid $$"
    +}
     
    -for i in {0..9}; do echo $i; done \
    -  | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
    +for i in {0..9}; do echo $i; done \
    +  | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
     

    We try here to run ten parallel processes; each of them should run the some_expensive_operations function with a different argument. The arguments are provided to xargs through STDIN one per line. When executed, we get this:
    @@ -201,15 +201,15 @@ bash: line 1: some_expensive_operations: command not found by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -some_expensive_operations() {
    -  echo "Doing expensive operations with '$1' from pid $$"
    -}
    -export -f some_expensive_operations
    +some_expensive_operations() {
    +  echo "Doing expensive operations with '$1' from pid $$"
    +}
    +export -f some_expensive_operations
     
    -for i in {0..9}; do echo $i; done \
    -  | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
    +for i in {0..9}; do echo $i; done \
    +  | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
     

    When we run this now, we get:
    @@ -234,19 +234,19 @@ Doing expensive operations with '9' from pid 132840 by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -some_other_function() {
    -  echo "$1"
    -}
    +some_other_function() {
    +  echo "$1"
    +}
     
    -some_expensive_operations() {
    -  some_other_function "Doing expensive operations with '$1' from pid $$"
    -}
    -export -f some_expensive_operations
    +some_expensive_operations() {
    +  some_other_function "Doing expensive operations with '$1' from pid $$"
    +}
    +export -f some_expensive_operations
     
    -for i in {0..9}; do echo $i; done \
    -  | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
    +for i in {0..9}; do echo $i; done \
    +  | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
     

    ... because some_other_function isn't exported! You will also need to add an export -f some_other_function!
    @@ -259,22 +259,22 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    -
    -foo() {
    -  local foo=bar # Declare local/dynamic variable
    -  bar
    -  echo "$foo"
    -}
    -
    -bar() {
    -  echo "$foo"
    -  foo=baz
    -}
    -
    -foo=foo # Declare global variable
    -foo # Call function foo
    -echo "$foo"
    +
    #!/usr/bin/env bash
    +
    +foo() {
    +  local foo=bar # Declare local/dynamic variable
    +  bar
    +  echo "$foo"
    +}
    +
    +bar() {
    +  echo "$foo"
    +  foo=baz
    +}
    +
    +foo=foo # Declare global variable
    +foo # Call function foo
    +echo "$foo"
     

    Let's pause a minute. What do you think the output would be?
    @@ -299,34 +299,34 @@ foo by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -declare -r foo=foo
    -declare -r bar=bar
    +declare -r foo=foo
    +declare -r bar=bar
     
    -if [ "$foo" = foo ]; then
    -  if [ "$bar" = bar ]; then
    -    echo ok1
    -  fi
    -fi
    +if [ "$foo" = foo ]; then
    +  if [ "$bar" = bar ]; then
    +    echo ok1
    +  fi
    +fi
     
    -if [ "$foo" = foo ] && [ "$bar" == bar ]; then
    -  echo ok2a
    -fi
    +if [ "$foo" = foo ] && [ "$bar" == bar ]; then
    +  echo ok2a
    +fi
     
    -[ "$foo" = foo ] && [ "$bar" == bar ] && echo ok2b
    +[ "$foo" = foo ] && [ "$bar" == bar ] && echo ok2b
     
    -if [[ "$foo" = foo && "$bar" == bar ]]; then
    -  echo ok3a
    -fi
    +if [[ "$foo" = foo && "$bar" == bar ]]; then
    +  echo ok3a
    +fi
     
    - [[ "$foo" = foo && "$bar" == bar ]] && echo ok3b
    + [[ "$foo" = foo && "$bar" == bar ]] && echo ok3b
     
    -if test "$foo" = foo && test "$bar" = bar; then
    -  echo ok4a
    -fi
    +if test "$foo" = foo && test "$bar" = bar; then
    +  echo ok4a
    +fi
     
    -test "$foo" = foo && test "$bar" = bar && echo ok4b
    +test "$foo" = foo && test "$bar" = bar && echo ok4b
     

    The output we get is:
    @@ -350,18 +350,18 @@ ok4b by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -# Single line comment
    +# Single line comment
     
    -# These are two single line
    -# comments one after another
    +# These are two single line
    +# comments one after another
     
    -: <<COMMENT
    -This is another way a
    -multi line comment
    -could be written!
    -COMMENT
    +: <<COMMENT
    +This is another way a
    +multi line comment
    +could be written!
    +COMMENT
     

    I will not demonstrate the execution of this script, as it won't print anything! It's obviously not the most pretty way of commenting on your code, but it could sometimes be handy!
    @@ -374,11 +374,11 @@ COMMENT by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -echo foo
    -echo echo baz >> $0
    -echo bar
    +echo foo
    +echo echo baz >> $0
    +echo bar
     

    When it is run, it will do:
    diff --git a/gemfeed/2024-01-13-one-reason-why-i-love-openbsd.html b/gemfeed/2024-01-13-one-reason-why-i-love-openbsd.html index 49c2ed28..0ab47be0 100644 --- a/gemfeed/2024-01-13-one-reason-why-i-love-openbsd.html +++ b/gemfeed/2024-01-13-one-reason-why-i-love-openbsd.html @@ -36,8 +36,8 @@ SSFISHKISSFISHKISSFISHKISSFISHKIS SFIS by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    $ doas installboot sd0 # Update the bootloader (not for every upgrade required)
    -$ doas sysupgrade # Update all binaries (including Kernel)
    +
    $ doas installboot sd0 # Update the bootloader (not for every upgrade required)
    +$ doas sysupgrade # Update all binaries (including Kernel)
     

    sysupgrade downloaded and upgraded to the next release and rebooted the system. After the reboot, I run:
    @@ -46,9 +46,9 @@ $ doas sysupgrade # Update all binaries (including Kern by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    $ doas sysmerge # Update system configuration files
    -$ doas pkg_add -u # Update all packages
    -$ doas reboot # Just in case, reboot one more time
    +
    $ doas sysmerge # Update system configuration files
    +$ doas pkg_add -u # Update all packages
    +$ doas reboot # Just in case, reboot one more time
     

    That's it! Took me around 5 minutes in total! No issues, only these few comands, only 5 minutes! It just works! No problems, no conflicts, no tons (actually none) config file merge conflicts.
    diff --git a/gemfeed/2024-04-01-KISS-high-availability-with-OpenBSD.html b/gemfeed/2024-04-01-KISS-high-availability-with-OpenBSD.html index ffd80d59..c142a1a3 100644 --- a/gemfeed/2024-04-01-KISS-high-availability-with-OpenBSD.html +++ b/gemfeed/2024-04-01-KISS-high-availability-with-OpenBSD.html @@ -97,38 +97,38 @@ KISS high-availability with OpenBSD by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/bin/ksh
    +
    #!/bin/ksh
     
    -ZONES_DIR=/var/nsd/zones/master/
    -DEFAULT_MASTER=fishfinger.buetow.org
    -DEFAULT_STANDBY=blowfish.buetow.org
    +ZONES_DIR=/var/nsd/zones/master/
    +DEFAULT_MASTER=fishfinger.buetow.org
    +DEFAULT_STANDBY=blowfish.buetow.org
     
    -determine_master_and_standby () {
    -    local master=$DEFAULT_MASTER
    -    local standby=$DEFAULT_STANDBY
    +determine_master_and_standby () {
    +    local master=$DEFAULT_MASTER
    +    local standby=$DEFAULT_STANDBY
     
    -    .
    -    .
    -    .
    -    
    -    local -i health_ok=1
    -    if ! ftp -4 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
    -        echo "https://$master/index.txt IPv4 health check failed"
    -        health_ok=0
    -    elif ! ftp -6 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
    -        echo "https://$master/index.txt IPv6 health check failed"
    -        health_ok=0
    -    fi
    -    if [ $health_ok -eq 0 ]; then
    -        local tmp=$master
    -        master=$standby
    -        standby=$tmp
    -    fi
    +    .
    +    .
    +    .
    +    
    +    local -i health_ok=1
    +    if ! ftp -4 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
    +        echo "https://$master/index.txt IPv4 health check failed"
    +        health_ok=0
    +    elif ! ftp -6 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
    +        echo "https://$master/index.txt IPv6 health check failed"
    +        health_ok=0
    +    fi
    +    if [ $health_ok -eq 0 ]; then
    +        local tmp=$master
    +        master=$standby
    +        standby=$tmp
    +    fi
     
    -    .
    -    .
    -    .
    -}
    +    .
    +    .
    +    .
    +}
     

    The failover scripts looks for the ; Enable failover string in the DNS zone files and swaps the A and AAAA records of the DNS entries accordingly:
    @@ -137,42 +137,42 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    fishfinger$ grep failover /var/nsd/zones/master/foo.zone.zone
    -        300 IN A 46.23.94.99 ; Enable failover
    -        300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
    -www     300 IN A 46.23.94.99 ; Enable failover
    -www     300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
    -standby  300 IN A 23.88.35.144 ; Enable failover
    -standby  300 IN AAAA 2a01:4f8:c17:20f1::42 ; Enable failover
    +
    fishfinger$ grep failover /var/nsd/zones/master/foo.zone.zone
    +        300 IN A 46.23.94.99 ; Enable failover
    +        300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
    +www     300 IN A 46.23.94.99 ; Enable failover
    +www     300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
    +standby  300 IN A 23.88.35.144 ; Enable failover
    +standby  300 IN AAAA 2a01:4f8:c17:20f1::42 ; Enable failover
     

    -
    transform () {
    -  sed -E '
    -	/IN A .*; Enable failover/ {
    -	    /^standby/! {
    -	        s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/master_a)' ; \3/;
    -	    }
    -	    /^standby/ {
    -	        s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/standby_a)' ; \3/;
    -	    }
    -	}
    -	/IN AAAA .*; Enable failover/ {
    -	    /^standby/! {
    -	        s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/master_aaaa)' ; \3/;
    -	    }
    -	    /^standby/ {
    -	        s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/standby_aaaa)' ; \3/;
    -	    }
    -	}
    -	/ ; serial/ {
    -	    s/^( +) ([0-9]+) .*; (.*)/\1 '$(date +%s)' ; \3/;
    -	}
    -  '
    -}
    +
    transform () {
    +  sed -E '
    +	/IN A .*; Enable failover/ {
    +	    /^standby/! {
    +	        s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/master_a)' ; \3/;
    +	    }
    +	    /^standby/ {
    +	        s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/standby_a)' ; \3/;
    +	    }
    +	}
    +	/IN AAAA .*; Enable failover/ {
    +	    /^standby/! {
    +	        s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/master_aaaa)' ; \3/;
    +	    }
    +	    /^standby/ {
    +	        s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/standby_aaaa)' ; \3/;
    +	    }
    +	}
    +	/ ; serial/ {
    +	    s/^( +) ([0-9]+) .*; (.*)/\1 '$(date +%s)' ; \3/;
    +	}
    +  '
    +}
     

    After the failover, the script reloads nsd and performs a sanity check to see if DNS still works. If not, a rollback will be performed:
    @@ -181,48 +181,48 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #! Race condition !#
    -   
    -if [ -f $zone_file.bak ]; then
    -    mv $zone_file.bak $zone_file
    -fi
    +
    #! Race condition !#
    +   
    +if [ -f $zone_file.bak ]; then
    +    mv $zone_file.bak $zone_file
    +fi
     
    -cat $zone_file | transform > $zone_file.new.tmp 
    +cat $zone_file | transform > $zone_file.new.tmp 
     
    -grep -v ' ; serial' $zone_file.new.tmp > $zone_file.new.noserial.tmp
    -grep -v ' ; serial' $zone_file > $zone_file.old.noserial.tmp
    +grep -v ' ; serial' $zone_file.new.tmp > $zone_file.new.noserial.tmp
    +grep -v ' ; serial' $zone_file > $zone_file.old.noserial.tmp
     
    -echo "Has zone $zone_file changed?"
    -if diff -u $zone_file.old.noserial.tmp $zone_file.new.noserial.tmp; then
    -    echo "The zone $zone_file hasn't changed"
    -    rm $zone_file.*.tmp
    -    return 0
    -fi
    +echo "Has zone $zone_file changed?"
    +if diff -u $zone_file.old.noserial.tmp $zone_file.new.noserial.tmp; then
    +    echo "The zone $zone_file hasn't changed"
    +    rm $zone_file.*.tmp
    +    return 0
    +fi
     
    -cp $zone_file $zone_file.bak
    -mv $zone_file.new.tmp $zone_file
    -rm $zone_file.*.tmp
    -echo "Reloading nsd"
    -nsd-control reload
    +cp $zone_file $zone_file.bak
    +mv $zone_file.new.tmp $zone_file
    +rm $zone_file.*.tmp
    +echo "Reloading nsd"
    +nsd-control reload
     
    -if ! zone_is_ok $zone; then
    -    echo "Rolling back $zone_file changes"
    -    cp $zone_file $zone_file.invalid
    -    mv $zone_file.bak $zone_file
    -    echo "Reloading nsd"
    -    nsd-control reload
    -    zone_is_ok $zone
    -    return 3
    -fi
    +if ! zone_is_ok $zone; then
    +    echo "Rolling back $zone_file changes"
    +    cp $zone_file $zone_file.invalid
    +    mv $zone_file.bak $zone_file
    +    echo "Reloading nsd"
    +    nsd-control reload
    +    zone_is_ok $zone
    +    return 3
    +fi
     
    -for cleanup in invalid bak; do
    -    if [ -f $zone_file.$cleanup ]; then
    -        rm $zone_file.$cleanup
    -    fi
    -done
    +for cleanup in invalid bak; do
    +    if [ -f $zone_file.$cleanup ]; then
    +        rm $zone_file.$cleanup
    +    fi
    +done
     
    -echo "Failover of zone $zone to $MASTER completed"
    -return 1
    +echo "Failover of zone $zone to $MASTER completed"
    +return 1
     

    A non-zero return code (here, 3 when a rollback and 1 when a DNS failover was performed) will cause CRON to send an E-Mail with the whole script output.
    @@ -279,13 +279,13 @@ echo "Failover of zone $zone to $MASTER completed" by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    # Weekly auto-failover for Let's Encrypt automation
    -local -i -r week_of_the_year=$(date +%U)
    -if [ $(( week_of_the_year % 2 )) -eq 0 ]; then
    -    local tmp=$master
    -    master=$standby
    -    standby=$tmp
    -fi
    +
    # Weekly auto-failover for Let's Encrypt automation
    +local -i -r week_of_the_year=$(date +%U)
    +if [ $(( week_of_the_year % 2 )) -eq 0 ]; then
    +    local tmp=$master
    +    master=$standby
    +    standby=$tmp
    +fi
     

    This way, a DNS failover is performed weekly so that the ACME automation can update the Let's Encrypt certificates (for master and standby) before they expire on each VM.
    diff --git a/gemfeed/2024-05-03-projects-i-currently-dont-have-time-for.html b/gemfeed/2024-05-03-projects-i-currently-dont-have-time-for.html index c2dd4a32..9b6358cb 100644 --- a/gemfeed/2024-05-03-projects-i-currently-dont-have-time-for.html +++ b/gemfeed/2024-05-03-projects-i-currently-dont-have-time-for.html @@ -222,12 +222,12 @@ Projects I currently don't have time for by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    Cluster :UK, :uk01 do
    -  Customer.C1A1.segments.volumes.each do |volume|
    -    puts volume.usage_stats
    -    volume.move_off! if volume.over_subscribed?
    -  end
    -end
    +
    Cluster :UK, :uk01 do
    +  Customer.C1A1.segments.volumes.each do |volume|
    +    puts volume.usage_stats
    +    volume.move_off! if volume.over_subscribed?
    +  end
    +end
     

    I am abandoning this project because my workplace has stopped the annual pet project competition, and I have other more important projects to work on at the moment.
    diff --git a/gemfeed/DRAFT-KISS-high-availability-with-OpenBSD.html b/gemfeed/DRAFT-KISS-high-availability-with-OpenBSD.html index 857bcb0f..7986609d 100644 --- a/gemfeed/DRAFT-KISS-high-availability-with-OpenBSD.html +++ b/gemfeed/DRAFT-KISS-high-availability-with-OpenBSD.html @@ -77,38 +77,38 @@ _____|_:_:_| (o)-(o) |_:_:_|--'`-. ,--. ksh under-water (((\'/ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/bin/ksh
    +
    #!/bin/ksh
     
    -ZONES_DIR=/var/nsd/zones/master/
    -DEFAULT_MASTER=fishfinger.buetow.org
    -DEFAULT_STANDBY=blowfish.buetow.org
    +ZONES_DIR=/var/nsd/zones/master/
    +DEFAULT_MASTER=fishfinger.buetow.org
    +DEFAULT_STANDBY=blowfish.buetow.org
     
    -determine_master_and_standby () {
    -    local master=$DEFAULT_MASTER
    -    local standby=$DEFAULT_STANDBY
    +determine_master_and_standby () {
    +    local master=$DEFAULT_MASTER
    +    local standby=$DEFAULT_STANDBY
     
    -    .
    -    .
    -    .
    -    
    -    local -i health_ok=1
    -    if ! ftp -4 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
    -        echo "https://$master/index.txt IPv4 health check failed"
    -        health_ok=0
    -    elif ! ftp -6 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
    -        echo "https://$master/index.txt IPv6 health check failed"
    -        health_ok=0
    -    fi
    -    if [ $health_ok -eq 0 ]; then
    -        local tmp=$master
    -        master=$standby
    -        standby=$tmp
    -    fi
    +    .
    +    .
    +    .
    +    
    +    local -i health_ok=1
    +    if ! ftp -4 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
    +        echo "https://$master/index.txt IPv4 health check failed"
    +        health_ok=0
    +    elif ! ftp -6 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
    +        echo "https://$master/index.txt IPv6 health check failed"
    +        health_ok=0
    +    fi
    +    if [ $health_ok -eq 0 ]; then
    +        local tmp=$master
    +        master=$standby
    +        standby=$tmp
    +    fi
     
    -    .
    -    .
    -    .
    -}
    +    .
    +    .
    +    .
    +}
     

    The failover scripts looks for the ; Enable failover string in the DNS zone files and swaps the A and AAAA records of the DNS entries accordingly:
    @@ -117,42 +117,42 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    fishfinger$ grep failover /var/nsd/zones/master/foo.zone.zone
    -        300 IN A 46.23.94.99 ; Enable failover
    -        300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
    -www     300 IN A 46.23.94.99 ; Enable failover
    -www     300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
    -standby  300 IN A 23.88.35.144 ; Enable failover
    -standby  300 IN AAAA 2a01:4f8:c17:20f1::42 ; Enable failover
    +
    fishfinger$ grep failover /var/nsd/zones/master/foo.zone.zone
    +        300 IN A 46.23.94.99 ; Enable failover
    +        300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
    +www     300 IN A 46.23.94.99 ; Enable failover
    +www     300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
    +standby  300 IN A 23.88.35.144 ; Enable failover
    +standby  300 IN AAAA 2a01:4f8:c17:20f1::42 ; Enable failover
     

    -
    tramsform () {
    -	sed -E '
    -	/IN A .*; Enable failover/ {
    -	    /^standby/! {
    -	        s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/master_a)' ; \3/;
    -	    }
    -	    /^standby/ {
    -	        s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/standby_a)' ; \3/;
    -	    }
    -	}
    -	/IN AAAA .*; Enable failover/ {
    -	    /^standby/! {
    -	        s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/master_aaaa)' ; \3/;
    -	    }
    -	    /^standby/ {
    -	        s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/standby_aaaa)' ; \3/;
    -	    }
    -	}
    -	/ ; serial/ {
    -	    s/^( +) ([0-9]+) .*; (.*)/\1 '$(date +%s)' ; \3/;
    -	}
    -	'
    -}
    +
    tramsform () {
    +	sed -E '
    +	/IN A .*; Enable failover/ {
    +	    /^standby/! {
    +	        s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/master_a)' ; \3/;
    +	    }
    +	    /^standby/ {
    +	        s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/standby_a)' ; \3/;
    +	    }
    +	}
    +	/IN AAAA .*; Enable failover/ {
    +	    /^standby/! {
    +	        s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/master_aaaa)' ; \3/;
    +	    }
    +	    /^standby/ {
    +	        s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/standby_aaaa)' ; \3/;
    +	    }
    +	}
    +	/ ; serial/ {
    +	    s/^( +) ([0-9]+) .*; (.*)/\1 '$(date +%s)' ; \3/;
    +	}
    +	'
    +}
     

    After the failover, the script reloads nsd and performs a sanity check to see if DNS still works. If not, a rollback will be performed:
    @@ -161,47 +161,47 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    # Race condition (e.g. script execution abored in the middle of the previous run)
    -if [ -f $zone_file.bak ]; then
    -    mv $zone_file.bak $zone_file
    -fi
    +
    # Race condition (e.g. script execution abored in the middle of the previous run)
    +if [ -f $zone_file.bak ]; then
    +    mv $zone_file.bak $zone_file
    +fi
     
    -cat $zone_file | transform > $zone_file.new.tmp 
    +cat $zone_file | transform > $zone_file.new.tmp 
     
    -grep -v ' ; serial' $zone_file.new.tmp > $zone_file.new.noserial.tmp
    -grep -v ' ; serial' $zone_file > $zone_file.old.noserial.tmp
    +grep -v ' ; serial' $zone_file.new.tmp > $zone_file.new.noserial.tmp
    +grep -v ' ; serial' $zone_file > $zone_file.old.noserial.tmp
     
    -echo "Has zone $zone_file changed?"
    -if diff -u $zone_file.old.noserial.tmp $zone_file.new.noserial.tmp; then
    -    echo "The zone $zone_file hasn't changed"
    -    rm $zone_file.*.tmp
    -    return 0
    -fi
    +echo "Has zone $zone_file changed?"
    +if diff -u $zone_file.old.noserial.tmp $zone_file.new.noserial.tmp; then
    +    echo "The zone $zone_file hasn't changed"
    +    rm $zone_file.*.tmp
    +    return 0
    +fi
     
    -cp $zone_file $zone_file.bak
    -mv $zone_file.new.tmp $zone_file
    -rm $zone_file.*.tmp
    -echo "Reloading nsd"
    -nsd-control reload
    +cp $zone_file $zone_file.bak
    +mv $zone_file.new.tmp $zone_file
    +rm $zone_file.*.tmp
    +echo "Reloading nsd"
    +nsd-control reload
     
    -if ! zone_is_ok $zone; then
    -    echo "Rolling back $zone_file changes"
    -    cp $zone_file $zone_file.invalid
    -    mv $zone_file.bak $zone_file
    -    echo "Reloading nsd"
    -    nsd-control reload
    -    zone_is_ok $zone
    -    return 3
    -fi
    +if ! zone_is_ok $zone; then
    +    echo "Rolling back $zone_file changes"
    +    cp $zone_file $zone_file.invalid
    +    mv $zone_file.bak $zone_file
    +    echo "Reloading nsd"
    +    nsd-control reload
    +    zone_is_ok $zone
    +    return 3
    +fi
     
    -for cleanup in invalid bak; do
    -    if [ -f $zone_file.$cleanup ]; then
    -        rm $zone_file.$cleanup
    -    fi
    -done
    +for cleanup in invalid bak; do
    +    if [ -f $zone_file.$cleanup ]; then
    +        rm $zone_file.$cleanup
    +    fi
    +done
     
    -echo "Failover of zone $zone to $MASTER completed"
    -return 1
    +echo "Failover of zone $zone to $MASTER completed"
    +return 1
     

    A non-zero return code (here, 3 when a rollback and 1 when a DNS failover was performed) will cause CRON to send an E-Mail with the whole script output.
    @@ -258,13 +258,13 @@ echo "Failover of zone $zone to $MASTER completed" by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    # Weekly auto-failover for Let's Encrypt automation
    -local -i -r week_of_the_year=$(date +%U)
    -if [ $(( week_of_the_year % 2 )) -eq 0 ]; then
    -    local tmp=$master
    -    master=$standby
    -    standby=$tmp
    -fi
    +
    # Weekly auto-failover for Let's Encrypt automation
    +local -i -r week_of_the_year=$(date +%U)
    +if [ $(( week_of_the_year % 2 )) -eq 0 ]; then
    +    local tmp=$master
    +    master=$standby
    +    standby=$tmp
    +fi
     

    This way, a DNS failover is performed weekly so that the ACME automation can update the Let's Encrypt certificates (for master and standby) before they expire on each VM.
    diff --git a/gemfeed/atom.xml b/gemfeed/atom.xml index 583d9b18..67fcc004 100644 --- a/gemfeed/atom.xml +++ b/gemfeed/atom.xml @@ -1,6 +1,6 @@ - 2024-05-12T14:48:38+03:00 + 2024-05-18T13:15:08+03:00 foo.zone feed To be in the .zone! @@ -232,12 +232,12 @@ Projects I currently don't have time for by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    Cluster :UK, :uk01 do
    -  Customer.C1A1.segments.volumes.each do |volume|
    -    puts volume.usage_stats
    -    volume.move_off! if volume.over_subscribed?
    -  end
    -end
    +
    Cluster :UK, :uk01 do
    +  Customer.C1A1.segments.volumes.each do |volume|
    +    puts volume.usage_stats
    +    volume.move_off! if volume.over_subscribed?
    +  end
    +end
     

    I am abandoning this project because my workplace has stopped the annual pet project competition, and I have other more important projects to work on at the moment.
    @@ -599,38 +599,38 @@ KISS high-availability with OpenBSD by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/bin/ksh
    -
    -ZONES_DIR=/var/nsd/zones/master/
    -DEFAULT_MASTER=fishfinger.buetow.org
    -DEFAULT_STANDBY=blowfish.buetow.org
    -
    -determine_master_and_standby () {
    -    local master=$DEFAULT_MASTER
    -    local standby=$DEFAULT_STANDBY
    -
    -    .
    -    .
    -    .
    -    
    -    local -i health_ok=1
    -    if ! ftp -4 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
    -        echo "https://$master/index.txt IPv4 health check failed"
    -        health_ok=0
    -    elif ! ftp -6 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
    -        echo "https://$master/index.txt IPv6 health check failed"
    -        health_ok=0
    -    fi
    -    if [ $health_ok -eq 0 ]; then
    -        local tmp=$master
    -        master=$standby
    -        standby=$tmp
    -    fi
    -
    -    .
    -    .
    -    .
    -}
    +
    #!/bin/ksh
    +
    +ZONES_DIR=/var/nsd/zones/master/
    +DEFAULT_MASTER=fishfinger.buetow.org
    +DEFAULT_STANDBY=blowfish.buetow.org
    +
    +determine_master_and_standby () {
    +    local master=$DEFAULT_MASTER
    +    local standby=$DEFAULT_STANDBY
    +
    +    .
    +    .
    +    .
    +    
    +    local -i health_ok=1
    +    if ! ftp -4 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
    +        echo "https://$master/index.txt IPv4 health check failed"
    +        health_ok=0
    +    elif ! ftp -6 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
    +        echo "https://$master/index.txt IPv6 health check failed"
    +        health_ok=0
    +    fi
    +    if [ $health_ok -eq 0 ]; then
    +        local tmp=$master
    +        master=$standby
    +        standby=$tmp
    +    fi
    +
    +    .
    +    .
    +    .
    +}
     

    The failover scripts looks for the ; Enable failover string in the DNS zone files and swaps the A and AAAA records of the DNS entries accordingly:
    @@ -639,42 +639,42 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    fishfinger$ grep failover /var/nsd/zones/master/foo.zone.zone
    -        300 IN A 46.23.94.99 ; Enable failover
    -        300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
    -www     300 IN A 46.23.94.99 ; Enable failover
    -www     300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
    -standby  300 IN A 23.88.35.144 ; Enable failover
    -standby  300 IN AAAA 2a01:4f8:c17:20f1::42 ; Enable failover
    +
    fishfinger$ grep failover /var/nsd/zones/master/foo.zone.zone
    +        300 IN A 46.23.94.99 ; Enable failover
    +        300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
    +www     300 IN A 46.23.94.99 ; Enable failover
    +www     300 IN AAAA 2a03:6000:6f67:624::99 ; Enable failover
    +standby  300 IN A 23.88.35.144 ; Enable failover
    +standby  300 IN AAAA 2a01:4f8:c17:20f1::42 ; Enable failover
     

    -
    transform () {
    -  sed -E '
    -	/IN A .*; Enable failover/ {
    -	    /^standby/! {
    -	        s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/master_a)' ; \3/;
    -	    }
    -	    /^standby/ {
    -	        s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/standby_a)' ; \3/;
    -	    }
    -	}
    -	/IN AAAA .*; Enable failover/ {
    -	    /^standby/! {
    -	        s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/master_aaaa)' ; \3/;
    -	    }
    -	    /^standby/ {
    -	        s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/standby_aaaa)' ; \3/;
    -	    }
    -	}
    -	/ ; serial/ {
    -	    s/^( +) ([0-9]+) .*; (.*)/\1 '$(date +%s)' ; \3/;
    -	}
    -  '
    -}
    +
    transform () {
    +  sed -E '
    +	/IN A .*; Enable failover/ {
    +	    /^standby/! {
    +	        s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/master_a)' ; \3/;
    +	    }
    +	    /^standby/ {
    +	        s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/standby_a)' ; \3/;
    +	    }
    +	}
    +	/IN AAAA .*; Enable failover/ {
    +	    /^standby/! {
    +	        s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/master_aaaa)' ; \3/;
    +	    }
    +	    /^standby/ {
    +	        s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/standby_aaaa)' ; \3/;
    +	    }
    +	}
    +	/ ; serial/ {
    +	    s/^( +) ([0-9]+) .*; (.*)/\1 '$(date +%s)' ; \3/;
    +	}
    +  '
    +}
     

    After the failover, the script reloads nsd and performs a sanity check to see if DNS still works. If not, a rollback will be performed:
    @@ -683,48 +683,48 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #! Race condition !#
    -   
    -if [ -f $zone_file.bak ]; then
    -    mv $zone_file.bak $zone_file
    -fi
    -
    -cat $zone_file | transform > $zone_file.new.tmp 
    -
    -grep -v ' ; serial' $zone_file.new.tmp > $zone_file.new.noserial.tmp
    -grep -v ' ; serial' $zone_file > $zone_file.old.noserial.tmp
    -
    -echo "Has zone $zone_file changed?"
    -if diff -u $zone_file.old.noserial.tmp $zone_file.new.noserial.tmp; then
    -    echo "The zone $zone_file hasn't changed"
    -    rm $zone_file.*.tmp
    -    return 0
    -fi
    -
    -cp $zone_file $zone_file.bak
    -mv $zone_file.new.tmp $zone_file
    -rm $zone_file.*.tmp
    -echo "Reloading nsd"
    -nsd-control reload
    -
    -if ! zone_is_ok $zone; then
    -    echo "Rolling back $zone_file changes"
    -    cp $zone_file $zone_file.invalid
    -    mv $zone_file.bak $zone_file
    -    echo "Reloading nsd"
    -    nsd-control reload
    -    zone_is_ok $zone
    -    return 3
    -fi
    -
    -for cleanup in invalid bak; do
    -    if [ -f $zone_file.$cleanup ]; then
    -        rm $zone_file.$cleanup
    -    fi
    -done
    -
    -echo "Failover of zone $zone to $MASTER completed"
    -return 1
    +
    #! Race condition !#
    +   
    +if [ -f $zone_file.bak ]; then
    +    mv $zone_file.bak $zone_file
    +fi
    +
    +cat $zone_file | transform > $zone_file.new.tmp 
    +
    +grep -v ' ; serial' $zone_file.new.tmp > $zone_file.new.noserial.tmp
    +grep -v ' ; serial' $zone_file > $zone_file.old.noserial.tmp
    +
    +echo "Has zone $zone_file changed?"
    +if diff -u $zone_file.old.noserial.tmp $zone_file.new.noserial.tmp; then
    +    echo "The zone $zone_file hasn't changed"
    +    rm $zone_file.*.tmp
    +    return 0
    +fi
    +
    +cp $zone_file $zone_file.bak
    +mv $zone_file.new.tmp $zone_file
    +rm $zone_file.*.tmp
    +echo "Reloading nsd"
    +nsd-control reload
    +
    +if ! zone_is_ok $zone; then
    +    echo "Rolling back $zone_file changes"
    +    cp $zone_file $zone_file.invalid
    +    mv $zone_file.bak $zone_file
    +    echo "Reloading nsd"
    +    nsd-control reload
    +    zone_is_ok $zone
    +    return 3
    +fi
    +
    +for cleanup in invalid bak; do
    +    if [ -f $zone_file.$cleanup ]; then
    +        rm $zone_file.$cleanup
    +    fi
    +done
    +
    +echo "Failover of zone $zone to $MASTER completed"
    +return 1
     

    A non-zero return code (here, 3 when a rollback and 1 when a DNS failover was performed) will cause CRON to send an E-Mail with the whole script output.
    @@ -781,13 +781,13 @@ echo "Failover of zone $zone to $MASTER completed" by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    # Weekly auto-failover for Let's Encrypt automation
    -local -i -r week_of_the_year=$(date +%U)
    -if [ $(( week_of_the_year % 2 )) -eq 0 ]; then
    -    local tmp=$master
    -    master=$standby
    -    standby=$tmp
    -fi
    +
    # Weekly auto-failover for Let's Encrypt automation
    +local -i -r week_of_the_year=$(date +%U)
    +if [ $(( week_of_the_year % 2 )) -eq 0 ]; then
    +    local tmp=$master
    +    master=$standby
    +    standby=$tmp
    +fi
     

    This way, a DNS failover is performed weekly so that the ACME automation can update the Let's Encrypt certificates (for master and standby) before they expire on each VM.
    @@ -1133,8 +1133,8 @@ SSFISHKISSFISHKISSFISHKISSFISHKIS SFIS by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    $ doas installboot sd0 # Update the bootloader (not for every upgrade required)
    -$ doas sysupgrade # Update all binaries (including Kernel)
    +
    $ doas installboot sd0 # Update the bootloader (not for every upgrade required)
    +$ doas sysupgrade # Update all binaries (including Kernel)
     

    sysupgrade downloaded and upgraded to the next release and rebooted the system. After the reboot, I run:
    @@ -1143,9 +1143,9 @@ $ doas sysupgrade # Update all binaries (including Kern by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    $ doas sysmerge # Update system configuration files
    -$ doas pkg_add -u # Update all packages
    -$ doas reboot # Just in case, reboot one more time
    +
    $ doas sysmerge # Update system configuration files
    +$ doas pkg_add -u # Update all packages
    +$ doas reboot # Just in case, reboot one more time
     

    That's it! Took me around 5 minutes in total! No issues, only these few comands, only 5 minutes! It just works! No problems, no conflicts, no tons (actually none) config file merge conflicts.
    @@ -1289,24 +1289,24 @@ jgs^^^^^^^`^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -log () {
    -    local -r level="$1"; shift
    -    local -r message="$1"; shift
    -    local -i pid="$$"
    +log () {
    +    local -r level="$1"; shift
    +    local -r message="$1"; shift
    +    local -i pid="$$"
     
    -    local -r callee=${FUNCNAME[1]}
    -    local -r stamp=$(date +%Y%m%d-%H%M%S)
    +    local -r callee=${FUNCNAME[1]}
    +    local -r stamp=$(date +%Y%m%d-%H%M%S)
     
    -    echo "$level|$stamp|$pid|$callee|$message" >&2
    -}
    +    echo "$level|$stamp|$pid|$callee|$message" >&2
    +}
     
    -at_home_friday_evening () {
    -    log INFO 'One Peperoni Pizza, please'
    -}
    +at_home_friday_evening () {
    +    log INFO 'One Peperoni Pizza, please'
    +}
     
    -at_home_friday_evening
    +at_home_friday_evening
     

    The output is as follows:
    @@ -1315,8 +1315,8 @@ at_home_friday_evening by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    ./logexample.sh
    -INFO|20231210-082732|123002|at_home_friday_evening|One Peperoni Pizza, please
    +
    ./logexample.sh
    +INFO|20231210-082732|123002|at_home_friday_evening|One Peperoni Pizza, please
     

    :(){ :|:& };:


    @@ -1350,18 +1350,18 @@ INFO|20231210- -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -outer() {
    -  inner() {
    -    echo 'Intel inside!'
    -  }
    -  inner
    -}
    +outer() {
    +  inner() {
    +    echo 'Intel inside!'
    +  }
    +  inner
    +}
     
    -inner
    -outer
    -inner
    +inner
    +outer
    +inner
     

    And let's execute it:
    @@ -1379,26 +1379,26 @@ Intel inside! by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -outer1() {
    -  inner() {
    -    echo 'Intel inside!'
    -  }
    -  inner
    -}
    +outer1() {
    +  inner() {
    +    echo 'Intel inside!'
    +  }
    +  inner
    +}
     
    -outer2() {
    -  inner() {
    -    echo 'Wintel inside!'
    -  }
    -  inner
    -}
    +outer2() {
    +  inner() {
    +    echo 'Wintel inside!'
    +  }
    +  inner
    +}
     
    -outer1
    -inner
    -outer2
    -inner
    +outer1
    +inner
    +outer2
    +inner
     

    And let's run it:
    @@ -1419,14 +1419,14 @@ Wintel inside! by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -some_expensive_operations() {
    -  echo "Doing expensive operations with '$1' from pid $$"
    -}
    +some_expensive_operations() {
    +  echo "Doing expensive operations with '$1' from pid $$"
    +}
     
    -for i in {0..9}; do echo $i; done \
    -  | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
    +for i in {0..9}; do echo $i; done \
    +  | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
     

    We try here to run ten parallel processes; each of them should run the some_expensive_operations function with a different argument. The arguments are provided to xargs through STDIN one per line. When executed, we get this:
    @@ -1451,15 +1451,15 @@ bash: line 1: some_expensive_operations: command not found by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -some_expensive_operations() {
    -  echo "Doing expensive operations with '$1' from pid $$"
    -}
    -export -f some_expensive_operations
    +some_expensive_operations() {
    +  echo "Doing expensive operations with '$1' from pid $$"
    +}
    +export -f some_expensive_operations
     
    -for i in {0..9}; do echo $i; done \
    -  | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
    +for i in {0..9}; do echo $i; done \
    +  | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
     

    When we run this now, we get:
    @@ -1484,19 +1484,19 @@ Doing expensive operations with '9' from pid 132840 by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -some_other_function() {
    -  echo "$1"
    -}
    +some_other_function() {
    +  echo "$1"
    +}
     
    -some_expensive_operations() {
    -  some_other_function "Doing expensive operations with '$1' from pid $$"
    -}
    -export -f some_expensive_operations
    +some_expensive_operations() {
    +  some_other_function "Doing expensive operations with '$1' from pid $$"
    +}
    +export -f some_expensive_operations
     
    -for i in {0..9}; do echo $i; done \
    -  | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
    +for i in {0..9}; do echo $i; done \
    +  | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
     

    ... because some_other_function isn't exported! You will also need to add an export -f some_other_function!
    @@ -1509,22 +1509,22 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -foo() {
    -  local foo=bar # Declare local/dynamic variable
    -  bar
    -  echo "$foo"
    -}
    +foo() {
    +  local foo=bar # Declare local/dynamic variable
    +  bar
    +  echo "$foo"
    +}
     
    -bar() {
    -  echo "$foo"
    -  foo=baz
    -}
    +bar() {
    +  echo "$foo"
    +  foo=baz
    +}
     
    -foo=foo # Declare global variable
    -foo # Call function foo
    -echo "$foo"
    +foo=foo # Declare global variable
    +foo # Call function foo
    +echo "$foo"
     

    Let's pause a minute. What do you think the output would be?
    @@ -1549,34 +1549,34 @@ foo by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -declare -r foo=foo
    -declare -r bar=bar
    +declare -r foo=foo
    +declare -r bar=bar
     
    -if [ "$foo" = foo ]; then
    -  if [ "$bar" = bar ]; then
    -    echo ok1
    -  fi
    -fi
    +if [ "$foo" = foo ]; then
    +  if [ "$bar" = bar ]; then
    +    echo ok1
    +  fi
    +fi
     
    -if [ "$foo" = foo ] && [ "$bar" == bar ]; then
    -  echo ok2a
    -fi
    +if [ "$foo" = foo ] && [ "$bar" == bar ]; then
    +  echo ok2a
    +fi
     
    -[ "$foo" = foo ] && [ "$bar" == bar ] && echo ok2b
    +[ "$foo" = foo ] && [ "$bar" == bar ] && echo ok2b
     
    -if [[ "$foo" = foo && "$bar" == bar ]]; then
    -  echo ok3a
    -fi
    +if [[ "$foo" = foo && "$bar" == bar ]]; then
    +  echo ok3a
    +fi
     
    - [[ "$foo" = foo && "$bar" == bar ]] && echo ok3b
    + [[ "$foo" = foo && "$bar" == bar ]] && echo ok3b
     
    -if test "$foo" = foo && test "$bar" = bar; then
    -  echo ok4a
    -fi
    +if test "$foo" = foo && test "$bar" = bar; then
    +  echo ok4a
    +fi
     
    -test "$foo" = foo && test "$bar" = bar && echo ok4b
    +test "$foo" = foo && test "$bar" = bar && echo ok4b
     

    The output we get is:
    @@ -1600,18 +1600,18 @@ ok4b by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -# Single line comment
    +# Single line comment
     
    -# These are two single line
    -# comments one after another
    +# These are two single line
    +# comments one after another
     
    -: <<COMMENT
    -This is another way a
    -multi line comment
    -could be written!
    -COMMENT
    +: <<COMMENT
    +This is another way a
    +multi line comment
    +could be written!
    +COMMENT
     

    I will not demonstrate the execution of this script, as it won't print anything! It's obviously not the most pretty way of commenting on your code, but it could sometimes be handy!
    @@ -1624,11 +1624,11 @@ COMMENT by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    #!/usr/bin/env bash
    +
    #!/usr/bin/env bash
     
    -echo foo
    -echo echo baz >> $0
    -echo bar
    +echo foo
    +echo echo baz >> $0
    +echo bar
     

    When it is run, it will do:
    @@ -1977,42 +1977,42 @@ photoalbum makemake by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % photoalbum makemake
    -You may now customize ./photoalbumrc and run make
    -
    -% cat Makefile
    -all:
    -	photoalbum generate photoalbumrc
    -clean:
    -	photoalbum clean photoalbumrc
    -
    -% cat photoalbumrc
    -# The title of the photoalbum
    -TITLE='A simple Photoalbum'
    -
    -# Thumbnail height geometry
    -THUMBHEIGHT=300
    -# Normal geometry height (when viewing photo). Uncomment, to keep original size.
    -HEIGHT=1200
    -# Max previews per page.
    -MAXPREVIEWS=40
    -# Randomly shuffle all previews.
    -# SHUFFLE=yes
    -
    -# Diverse directories, need to be full paths, not relative!
    -INCOMING_DIR=$(pwd)/incoming
    -DIST_DIR=$(pwd)/dist
    -TEMPLATE_DIR=/usr/share/photoalbum/templates/default
    -#TEMPLATE_DIR=/usr/share/photoalbum/templates/minimal
    -
    -# Includes a .tar of the incoming dir in the dist, can be yes or no
    -TARBALL_INCLUDE=yes
    -TARBALL_SUFFIX=.tar
    -TAR_OPTS='-c'
    -
    -# Some debugging options
    -#set -e
    -#set -x
    +
    % photoalbum makemake
    +You may now customize ./photoalbumrc and run make
    +
    +% cat Makefile
    +all:
    +	photoalbum generate photoalbumrc
    +clean:
    +	photoalbum clean photoalbumrc
    +
    +% cat photoalbumrc
    +# The title of the photoalbum
    +TITLE='A simple Photoalbum'
    +
    +# Thumbnail height geometry
    +THUMBHEIGHT=300
    +# Normal geometry height (when viewing photo). Uncomment, to keep original size.
    +HEIGHT=1200
    +# Max previews per page.
    +MAXPREVIEWS=40
    +# Randomly shuffle all previews.
    +# SHUFFLE=yes
    +
    +# Diverse directories, need to be full paths, not relative!
    +INCOMING_DIR=$(pwd)/incoming
    +DIST_DIR=$(pwd)/dist
    +TEMPLATE_DIR=/usr/share/photoalbum/templates/default
    +#TEMPLATE_DIR=/usr/share/photoalbum/templates/minimal
    +
    +# Includes a .tar of the incoming dir in the dist, can be yes or no
    +TARBALL_INCLUDE=yes
    +TARBALL_SUFFIX=.tar
    +TAR_OPTS='-c'
    +
    +# Some debugging options
    +#set -e
    +#set -x
     

    In the case for irregular.ninja, I changed the defaults to the following:
    @@ -2021,38 +2021,38 @@ clean: by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    --- photoalbumrc        2023-10-29 21:42:00.894202045 +0200
    -+++ photoalbumrc.new 2023-06-04 10:40:08.030994440 +0300
    -@@ -1,23 +1,24 @@
    - # The title of the photoalbum
    --TITLE='A simple Photoalbum'
    -+TITLE='Irregular.Ninja'
    -
    - # Thumbnail height geometry
    --THUMBHEIGHT=300
    -+THUMBHEIGHT=400
    - # Normal geometry height (when viewing photo). Uncomment, to keep original size.
    --HEIGHT=1200
    -+HEIGHT=1800
    - # Max previews per page.
    - MAXPREVIEWS=40
    --# Randomly shuffle all previews.
    --# SHUFFLE=yes
    -+# Randomly shuffle
    -+SHUFFLE=yes
    -
    - # Diverse directories, need to be full paths, not relative!
    --INCOMING_DIR=$(pwd)/incoming
    -+INCOMING_DIR=~/Nextcloud/Photos/irregular.ninja
    - DIST_DIR=$(pwd)/dist
    - TEMPLATE_DIR=/usr/share/photoalbum/templates/default
    - #TEMPLATE_DIR=/usr/share/photoalbum/templates/minimal
    -
    - # Includes a .tar of the incoming dir in the dist, can be yes or no
    --TARBALL_INCLUDE=yes
    -+TARBALL_INCLUDE=no
    - TARBALL_SUFFIX=.tar
    - TAR_OPTS='-c'
    +
    --- photoalbumrc        2023-10-29 21:42:00.894202045 +0200
    ++++ photoalbumrc.new 2023-06-04 10:40:08.030994440 +0300
    +@@ -1,23 +1,24 @@
    + # The title of the photoalbum
    +-TITLE='A simple Photoalbum'
    ++TITLE='Irregular.Ninja'
    +
    + # Thumbnail height geometry
    +-THUMBHEIGHT=300
    ++THUMBHEIGHT=400
    + # Normal geometry height (when viewing photo). Uncomment, to keep original size.
    +-HEIGHT=1200
    ++HEIGHT=1800
    + # Max previews per page.
    + MAXPREVIEWS=40
    +-# Randomly shuffle all previews.
    +-# SHUFFLE=yes
    ++# Randomly shuffle
    ++SHUFFLE=yes
    +
    + # Diverse directories, need to be full paths, not relative!
    +-INCOMING_DIR=$(pwd)/incoming
    ++INCOMING_DIR=~/Nextcloud/Photos/irregular.ninja
    + DIST_DIR=$(pwd)/dist
    + TEMPLATE_DIR=/usr/share/photoalbum/templates/default
    + #TEMPLATE_DIR=/usr/share/photoalbum/templates/minimal
    +
    + # Includes a .tar of the incoming dir in the dist, can be yes or no
    +-TARBALL_INCLUDE=yes
    ++TARBALL_INCLUDE=no
    + TARBALL_SUFFIX=.tar
    + TAR_OPTS='-c'
     

    So I changed the album title, adjusted some image and thumbnail dimensions, and I want all images to be randomly shuffled every time the album is generated! I also have all my photos in my Nextcloud Photo directory and don't want to copy them to the local incoming directory. Also, a tarball containing the whole album as a download isn't provided.
    @@ -2208,7 +2208,7 @@ blurs html index.html photos thumbs by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail --servers serverlist.txt --grep INFO --files "/var/log/dserver/*.log"
    +
    % dtail --servers serverlist.txt --grep INFO --files "/var/log/dserver/*.log"
     

    Hint: you can also provide a comma separated server list, e.g.: servers server1.example.org,server2.example.org:PORT,...
    @@ -2221,7 +2221,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail --servers serverlist.txt --grep INFO "/var/log/dserver/*.log"
    +
    % dtail --servers serverlist.txt --grep INFO "/var/log/dserver/*.log"
     

    Aggregating logs


    @@ -2234,10 +2234,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail --servers serverlist.txt \
    -    --files '/var/log/dserver/*.log' \
    -    --query 'from STATS select sum($goroutines),sum($cgocalls),
    -             last($time),max(lifetimeConnections)'
    +
    % dtail --servers serverlist.txt \
    +    --files '/var/log/dserver/*.log' \
    +    --query 'from STATS select sum($goroutines),sum($cgocalls),
    +             last($time),max(lifetimeConnections)'
     

    Beware: For map-reduce queries to work, you have to ensure that DTail supports your log format. Check out the documentaiton of the DTail query language and the DTail log formats on the DTail homepage for more information.
    @@ -2250,10 +2250,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail --servers serverlist.txt \
    -    --files '/var/log/dserver/*.log' \
    -    'from STATS select sum($goroutines),sum($cgocalls),
    -     last($time),max(lifetimeConnections)'
    +
    % dtail --servers serverlist.txt \
    +    --files '/var/log/dserver/*.log' \
    +    'from STATS select sum($goroutines),sum($cgocalls),
    +     last($time),max(lifetimeConnections)'
     

    Here is another example:
    @@ -2262,10 +2262,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail --servers serverlist.txt \
    -    --files '/var/log/dserver/*.log' \
    -    --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    -             lifetimeConnections group by $hostname order by max($cgocalls)'
    +
    % dtail --servers serverlist.txt \
    +    --files '/var/log/dserver/*.log' \
    +    --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    +             lifetimeConnections group by $hostname order by max($cgocalls)'
     

    Tail map-reduce example 2
    @@ -2276,9 +2276,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail --servers serverlist.txt \
    -    --files '/var/log/dserver/*.log' \
    -    --query 'from STATS select ... outfile append result.csv'
    +
    % dtail --servers serverlist.txt \
    +    --files '/var/log/dserver/*.log' \
    +    --query 'from STATS select ... outfile append result.csv'
     

    How to use dcat


    @@ -2291,7 +2291,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dcat --servers serverlist.txt --files /etc/hostname
    +
    % dcat --servers serverlist.txt --files /etc/hostname
     

    Cat example
    @@ -2302,7 +2302,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dcat --servers serverlist.txt /etc/hostname
    +
    % dcat --servers serverlist.txt /etc/hostname
     

    How to use dgrep


    @@ -2313,9 +2313,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dgrep --servers server1.example.org:2223 \
    -    --files /etc/passwd \
    -    --regex nologin
    +
    % dgrep --servers server1.example.org:2223 \
    +    --files /etc/passwd \
    +    --regex nologin
     

    Generally, dgrep is also a very useful way to search historic application logs for certain content.
    @@ -2332,10 +2332,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dmap --servers serverlist.txt \
    -    --files '/var/log/dserver/*.log' \
    -    --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    -             lifetimeConnections group by $hostname order by max($cgocalls)'
    +
    % dmap --servers serverlist.txt \
    +    --files '/var/log/dserver/*.log' \
    +    --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    +             lifetimeConnections group by $hostname order by max($cgocalls)'
     

    Remember: For that to work, you have to make sure that DTail supports your log format. You can either use the ones already defined in internal/mapr/logformat or add an extension to support a custom log format. The example here works out of the box though, as DTail understands its own log format already.
    @@ -2358,9 +2358,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dmap --files /var/log/dserver/dserver.log
    -    --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    -              lifetimeConnections group by $hostname order by max($cgocalls)'
    +
    % dmap --files /var/log/dserver/dserver.log
    +    --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    +              lifetimeConnections group by $hostname order by max($cgocalls)'
     

    As a shorthand version the following command can be used:
    @@ -2369,9 +2369,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dmap 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    -        lifetimeConnections group by $hostname order by max($cgocalls)' \
    -        /var/log/dsever/dserver.log
    +
    % dmap 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    +        lifetimeConnections group by $hostname order by max($cgocalls)' \
    +        /var/log/dsever/dserver.log
     

    You can also use a file input pipe as follows:
    @@ -2380,9 +2380,9 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % cat /var/log/dserver/dserver.log | \
    -    dmap 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    -          lifetimeConnections group by $hostname order by max($cgocalls)'
    +
    % cat /var/log/dserver/dserver.log | \
    +    dmap 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg,
    +          lifetimeConnections group by $hostname order by max($cgocalls)'
     

    Aggregating CSV files


    @@ -2393,16 +2393,16 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % cat example.csv
    -name,lastname,age,profession
    -Michael,Jordan,40,Basketball player
    -Michael,Jackson,100,Singer
    -Albert,Einstein,200,Physician
    -% dmap --query 'select lastname,name where age > 40 logformat csv outfile result.csv' example.csv
    -% cat result.csv
    -lastname,name
    -Jackson,Michael
    -Einstein,Albert
    +
    % cat example.csv
    +name,lastname,age,profession
    +Michael,Jordan,40,Basketball player
    +Michael,Jackson,100,Singer
    +Albert,Einstein,200,Physician
    +% dmap --query 'select lastname,name where age > 40 logformat csv outfile result.csv' example.csv
    +% cat result.csv
    +lastname,name
    +Jackson,Michael
    +Einstein,Albert
     

    DMap can also be used to query and aggregate CSV files from remote servers.
    @@ -2415,44 +2415,44 @@ Einstein,Albert by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    % dtail /var/log/dserver/dserver.log
    +
    % dtail /var/log/dserver/dserver.log
     

    -
    % dtail --logLevel trace /var/log/dserver/dserver.log
    +
    % dtail --logLevel trace /var/log/dserver/dserver.log
     

    -
    % dcat /etc/passwd
    +
    % dcat /etc/passwd
     

    -
    % dcat --plain /etc/passwd > /etc/test
    -# Should show no differences.
    -diff /etc/test /etc/passwd 
    +
    % dcat --plain /etc/passwd > /etc/test
    +# Should show no differences.
    +diff /etc/test /etc/passwd 
     

    -
    % dgrep --regex ERROR --files /var/log/dserver/dsever.log
    +
    % dgrep --regex ERROR --files /var/log/dserver/dsever.log
     

    -
    % dgrep --before 10 --after 10 --max 10 --grep ERROR /var/log/dserver/dsever.log
    +
    % dgrep --before 10 --after 10 --max 10 --grep ERROR /var/log/dserver/dsever.log
     

    Use --help for more available options. Or go to the DTail page for more information! Hope you find DTail useful!
    @@ -2609,9 +2609,9 @@ DC on fire: by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    if [ -n "$foo" ]; then
    -  echo "$foo"
    -fi
    +
    if [ -n "$foo" ]; then
    +  echo "$foo"
    +fi
     

    Please run source-highlight --lang-list for a list of all supported languages.
    @@ -2640,7 +2640,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    declare -xr MASTODON_URI='https://fosstodon.org/@snonux'
    +
    declare -xr MASTODON_URI='https://fosstodon.org/@snonux'
     

    and add the following into your index.gmi:
    @@ -2655,7 +2655,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    <a href='https://fosstodon.org/@snonux' rel='me'>Me at Mastodon</a>
    +
    <a href='https://fosstodon.org/@snonux' rel='me'>Me at Mastodon</a>
     

    More


    @@ -3104,11 +3104,11 @@ Have a nice day! by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    git clone https://codeberg.org/snonux/gogios.git
    -cd gogios
    -go build -o gogios cmd/gogios/main.go
    -doas cp gogios /usr/local/bin/gogios
    -doas chmod 755 /usr/local/bin/gogios
    +
    git clone https://codeberg.org/snonux/gogios.git
    +cd gogios
    +go build -o gogios cmd/gogios/main.go
    +doas cp gogios /usr/local/bin/gogios
    +doas chmod 755 /usr/local/bin/gogios
     

    You can use cross-compilation if you want to compile Gogios for OpenBSD on a Linux system without installing the Go compiler on OpenBSD. Follow these steps:
    @@ -3117,9 +3117,9 @@ doas chmod 755 /usr/local/bin/gogios by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    export GOOS=openbsd
    -export GOARCH=amd64
    -go build -o gogios cmd/gogios/main.go
    +
    export GOOS=openbsd
    +export GOARCH=amd64
    +go build -o gogios cmd/gogios/main.go
     

    On your OpenBSD system, copy the binary to /usr/local/bin/gogios and set the correct permissions as described in the previous section. All steps described here you could automate with your configuration management system of choice. I use Rexify, the friendly configuration management system, to automate the installation, but that is out of the scope of this document.
    @@ -3134,11 +3134,11 @@ go build -o gogios cmd/gogios/main.go by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    doas adduser -group _gogios -batch _gogios
    -doas usermod -d /var/run/gogios _gogios
    -doas mkdir -p /var/run/gogios
    -doas chown _gogios:_gogios /var/run/gogios
    -doas chmod 750 /var/run/gogios
    +
    doas adduser -group _gogios -batch _gogios
    +doas usermod -d /var/run/gogios _gogios
    +doas mkdir -p /var/run/gogios
    +doas chown _gogios:_gogios /var/run/gogios
    +doas chmod 750 /var/run/gogios
     

    Please note that creating a user and group might differ depending on your operating system. For other operating systems, consult their documentation for creating system users and groups.
    @@ -3151,8 +3151,8 @@ doas chmod 750 /var/run/gogios by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    doas pkg_add monitoring-plugins
    -doas pkg_add nrpe # If you want to execute checks remotely via NRPE.
    +
    doas pkg_add monitoring-plugins
    +doas pkg_add nrpe # If you want to execute checks remotely via NRPE.
     

    Once the installation is complete, you can find the monitoring plugins in the /usr/local/libexec/nagios directory, which then can be configured to be used in gogios.json.
    @@ -3179,41 +3179,41 @@ echo 'This is a test email from OpenBSD.' | mail -s 'Test Email' by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
    {
    -  "EmailTo": "paul@dev.buetow.org",
    -  "EmailFrom": "gogios@buetow.org",
    -  "CheckTimeoutS": 10,
    -  "CheckConcurrency": 2,
    -  "StateDir": "/var/run/gogios",
    -  "Checks": {
    -    "Check ICMP4 www.foo.zone": {
    -      "Plugin": "/usr/local/libexec/nagios/check_ping",
    -      "Args": [ "-H", "www.foo.zone", "-4", "-w", "50,10%", "-c", "100,15%" ],
    -      "Retries": 3,
    -      "RetryInterval": 10
    -    },
    -    "Check ICMP6 www.foo.zone": {
    -      "Plugin": "/usr/local/libexec/nagios/check_ping",
    -      "Args": [ "-H", "www.foo.zone", "-6", "-w", "50,10%", "-c", "100,15%" ],
    -      "Retries": 3,
    -      "RetryInterval": 10
    -    },
    -    "www.foo.zone HTTP IPv4": {
    -      "Plugin": "/usr/local/libexec/nagios/check_http",
    -      "Args": ["www.foo.zone", "-4"],
    -      "DependsOn": ["Check ICMP4 www.foo.zone"]
    -    },
    -    "www.foo.zone HTTP IPv6": {
    -      "Plugin": "/usr/local/libexec/nagios/check_http",
    -      "Args": ["www.foo.zone", "-6"],
    -      "DependsOn": ["Check ICMP6 www.foo.zone"]
    -    }
    -    "Check NRPE Disk Usage foo.zone": {
    -      "Plugin": "/usr/local/libexec/nagios/check_nrpe",
    -      "Args": ["-H", "foo.zone", "-c", "check_disk", "-p", "5666", "-4"]
    -    }
    -  }
    -}
    +
    {
    +  "EmailTo": "paul@dev.buetow.org",
    +  "EmailFrom": "gogios@buetow.org",
    +  "CheckTimeoutS": 10,
    +  "CheckConcurrency": 2,
    +  "StateDir": "/var/run/gogios",
    +  "Checks": {
    +    "Check ICMP4 www.foo.zone": {
    +      "Plugin": "/usr/local/libexec/nagios/check_ping",
    +      "Args": [ "-H", "www.foo.zone", "-4", "-w", "50,10%", "-c", "100,15%" ],
    +      "Retries": 3,
    +      "RetryInterval": 10
    +    },
    +    "Check ICMP6 www.foo.zone": {
    +      "Plugin": "/usr/local/libexec/nagios/check_ping",
    +      "Args": [ "-H", "www.foo.zone", "-6", "-w", "50,10%", "-c", "100,15%" ],
    +      "Retries": 3,
    +      "RetryInterval": 10
    +    },
    +    "www.foo.zone HTTP IPv4": {
    +      "Plugin": "/usr/local/libexec/nagios/check_http",
    +      "Args": ["www.foo.zone", "-4"],
    +      "DependsOn": ["Check ICMP4 www.foo.zone"]
    +    },
    +    "www.foo.zone HTTP IPv6": {
    +      "Plugin": "/usr/local/libexec/nagios/check_http",
    +      "Args": ["www.foo.zone", "-6"],
    +      "DependsOn": ["Check ICMP6 www.foo.zone"]
    +    }
    +    "Check NRPE Disk Usage foo.zone": {
    +      "Plugin": "/usr/local/libexec/nagios/check_nrpe",
    +      "Args": ["-H", "foo.zone", "-c", "check_disk", "-p", "5666", "-4"]
    +    }
    +  }
    +}
     

      @@ -3242,7 +3242,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      doas -u _gogios /usr/local/bin/gogios -cfg /etc/gogios.json
      +
      doas -u _gogios /usr/local/bin/gogios -cfg /etc/gogios.json
       

      To run Gogios via CRON on OpenBSD as the gogios user and check all services once per minute, follow these steps:
      @@ -3467,7 +3467,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      $ raku guprecords.raku --stats=dir=$HOME/git/uprecords/stats --all
      +
      $ raku guprecords.raku --stats=dir=$HOME/git/uprecords/stats --all
       

      This command will generate a comprehensive uptime report from the collected statistics, making it easy to review and enjoy the data.
      @@ -3624,19 +3624,19 @@ no1 in 455 days, 18:52:44 | at Sun Jul 21 07:37:51 2024 by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      package ds
      +
      package ds
       
      -import (
      -	"golang.org/x/exp/constraints"
      -)
      +import (
      +	"golang.org/x/exp/constraints"
      +)
       
      -type Integer interface {
      -	constraints.Integer
      -}
      +type Integer interface {
      +	constraints.Integer
      +}
       
      -type Number interface {
      -	constraints.Integer | constraints.Float
      -}
      +type Number interface {
      +	constraints.Integer | constraints.Float
      +}
       
       

      @@ -3648,19 +3648,19 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      package ds
      +
      package ds
       
      -import (
      -	"fmt"
      -	"math/rand"
      -	"strings"
      -)
      +import (
      +	"fmt"
      +	"math/rand"
      +	"strings"
      +)
       
      -type ArrayList[V Number] []V
      +type ArrayList[V Number] []V
       
      -func NewArrayList[V Number](l int) ArrayList[V] {
      -	return make(ArrayList[V], l)
      -}
      +func NewArrayList[V Number](l int) ArrayList[V] {
      +	return make(ArrayList[V], l)
      +}
       

      As you can see, the code uses Go generics, which I refactored recently. Besides the default constructor (which only returns an empty ArrayList with a given capacity), there are also a bunch of special constructors. NewRandomArrayList is returning an ArrayList with random numbers, NewAscendingArrayList and NewDescendingArrayList are returning ArrayLists in either ascending or descending order. They all will be used later on for testing and benchmarking the algorithms.
      @@ -3669,35 +3669,35 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      func NewRandomArrayList[V Number](l, max int) ArrayList[V] {
      -	a := make(ArrayList[V], l)
      -	for i := 0; i < l; i++ {
      -		if max > 0 {
      -			a[i] = V(rand.Intn(max))
      -			continue
      -		}
      -		a[i] = V(rand.Int())
      -	}
      -	return a
      -}
      -
      -func NewAscendingArrayList[V Number](l int) ArrayList[V] {
      -	a := make(ArrayList[V], l)
      -	for i := 0; i < l; i++ {
      -		a[i] = V(i)
      -	}
      -	return a
      -}
      -
      -func NewDescendingArrayList[V Number](l int) ArrayList[V] {
      -	a := make(ArrayList[V], l)
      -	j := l - 1
      -	for i := 0; i < l; i++ {
      -		a[i] = V(j)
      -		j--
      -	}
      -	return a
      -}
      +
      func NewRandomArrayList[V Number](l, max int) ArrayList[V] {
      +	a := make(ArrayList[V], l)
      +	for i := 0; i < l; i++ {
      +		if max > 0 {
      +			a[i] = V(rand.Intn(max))
      +			continue
      +		}
      +		a[i] = V(rand.Int())
      +	}
      +	return a
      +}
      +
      +func NewAscendingArrayList[V Number](l int) ArrayList[V] {
      +	a := make(ArrayList[V], l)
      +	for i := 0; i < l; i++ {
      +		a[i] = V(i)
      +	}
      +	return a
      +}
      +
      +func NewDescendingArrayList[V Number](l int) ArrayList[V] {
      +	a := make(ArrayList[V], l)
      +	j := l - 1
      +	for i := 0; i < l; i++ {
      +		a[i] = V(j)
      +		j--
      +	}
      +	return a
      +}
       

      Helper methods


      @@ -3708,25 +3708,25 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      func (a ArrayList[V]) FirstN(n int) string {
      -	var sb strings.Builder
      -	j := n
      +
      func (a ArrayList[V]) FirstN(n int) string {
      +	var sb strings.Builder
      +	j := n
       
      -	l := len(a)
      -	if j > l {
      -		j = l
      -	}
      +	l := len(a)
      +	if j > l {
      +		j = l
      +	}
       
      -	for i := 0; i < j; i++ {
      -		fmt.Fprintf(&sb, "%v ", a[i])
      -	}
      +	for i := 0; i < j; i++ {
      +		fmt.Fprintf(&sb, "%v ", a[i])
      +	}
       
      -	if j < l {
      -		fmt.Fprintf(&sb, "... ")
      -	}
      +	if j < l {
      +		fmt.Fprintf(&sb, "... ")
      +	}
       
      -	return sb.String()
      -}
      +	return sb.String()
      +}
       

      The Sorted method checks whether the ArrayList is sorted. This will be used by the unit tests later on:
      @@ -3735,14 +3735,14 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      func (a ArrayList[V]) Sorted() bool {
      -	for i := len(a) - 1; i > 0; i-- {
      -		if a[i] < a[i-1] {
      -			return false
      -		}
      -	}
      -	return true
      -}
      +
      func (a ArrayList[V]) Sorted() bool {
      +	for i := len(a) - 1; i > 0; i-- {
      +		if a[i] < a[i-1] {
      +			return false
      +		}
      +	}
      +	return true
      +}
       

      And the last utility method used is Swap, which allows swapping the values of two indices in the ArrayList:
      @@ -3751,11 +3751,11 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      func (a ArrayList[V]) Swap(i, j int) {
      -	aux := a[i]
      -	a[i] = a[j]
      -	a[j] = aux
      -}
      +
      func (a ArrayList[V]) Swap(i, j int) {
      +	aux := a[i]
      +	a[i] = a[j]
      +	a[j] = aux
      +}
       
       

      @@ -3768,40 +3768,40 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      package sort
      +
      package sort
       
      -import (
      -	"codeberg.org/snonux/algorithms/ds"
      -	"sync"
      -	"time"
      -)
      +import (
      +	"codeberg.org/snonux/algorithms/ds"
      +	"sync"
      +	"time"
      +)
       
      -func Sleep[V ds.Integer](a ds.ArrayList[V]) ds.ArrayList[V] {
      -	sorted := ds.NewArrayList[V](len(a))
      +func Sleep[V ds.Integer](a ds.ArrayList[V]) ds.ArrayList[V] {
      +	sorted := ds.NewArrayList[V](len(a))
       
      -	numCh := make(chan V)
      -	var wg sync.WaitGroup
      -	wg.Add(len(a))
      +	numCh := make(chan V)
      +	var wg sync.WaitGroup
      +	wg.Add(len(a))
       
      -	go func() {
      -		wg.Wait()
      -		close(numCh)
      -	}()
      +	go func() {
      +		wg.Wait()
      +		close(numCh)
      +	}()
       
      -	for _, num := range a {
      -		go func(num V) {
      -			defer wg.Done()
      -			time.Sleep(time.Duration(num) * time.Second)
      -			numCh <- num
      -		}(num)
      -	}
      +	for _, num := range a {
      +		go func(num V) {
      +			defer wg.Done()
      +			time.Sleep(time.Duration(num) * time.Second)
      +			numCh <- num
      +		}(num)
      +	}
       
      -	for num := range numCh {
      -		sorted = append(sorted, num)
      -	}
      +	for num := range numCh {
      +		sorted = append(sorted, num)
      +	}
       
      -	return sorted
      -}
      +	return sorted
      +}
       

      This Go code implements the sleep sort algorithm using generics and goroutines. The main function Sleep[V ds.Integer](a ds.ArrayList[V]) ds.ArrayList[V] takes a generic ArrayList as input and returns a sorted ArrayList. The code creates a separate goroutine for each element in the input array, sleeps for a duration proportional to the element's value, and then sends the element to a channel. Another goroutine waits for all the sleeping goroutines to finish and then closes the channel. The sorted result ArrayList is constructed by appending the elements received from the channel in the order they arrive. The sync.WaitGroup is used to synchronize goroutines and ensure that all of them have completed before closing the channel.
      @@ -3814,22 +3814,22 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      package sort
      +
      package sort
       
      -import (
      -	"fmt"
      -	"testing"
      +import (
      +	"fmt"
      +	"testing"
       
      -	"codeberg.org/snonux/algorithms/ds"
      -)
      +	"codeberg.org/snonux/algorithms/ds"
      +)
       
      -func TestSleepSort(t *testing.T) {
      -	a := ds.NewRandomArrayList[int](10, 10)
      -	a = Sleep(a)
      -	if !a.Sorted() {
      -		t.Errorf("Array not sorted: %v", a)
      -	}
      -}
      +func TestSleepSort(t *testing.T) {
      +	a := ds.NewRandomArrayList[int](10, 10)
      +	a = Sleep(a)
      +	if !a.Sorted() {
      +		t.Errorf("Array not sorted: %v", a)
      +	}
      +}
       

      As you can see, it takes 9s here for the algorithm to finish (which is the highest value in the ArrayList):
      @@ -3838,11 +3838,11 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      ❯ go test ./sort -v -run SleepSort
      -=== RUN   TestSleepSort
      ---- PASS: TestSleepSort (9.00s)
      -PASS
      -ok      codeberg.org/snonux/algorithms/sort     9.002s
      +
      ❯ go test ./sort -v -run SleepSort
      +=== RUN   TestSleepSort
      +--- PASS: TestSleepSort (9.00s)
      +PASS
      +ok      codeberg.org/snonux/algorithms/sort     9.002s
       

      I won't write any benchmark for sleep sort; that will be done for the algorithms to come in this series :-).
      @@ -4123,8 +4123,8 @@ Blablabla... by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      declare -xr PRE_GENERATE_HOOK=./pre_generate_hook.sh
      -declare -xr POST_PUBLISH_HOOK=./post_publish_hook.sh
      +
      declare -xr PRE_GENERATE_HOOK=./pre_generate_hook.sh
      +declare -xr POST_PUBLISH_HOOK=./post_publish_hook.sh
       

      Use of safer Bash options


      @@ -4141,10 +4141,10 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      % cat gemfeed/2023-02-26-title-here.gmi
      -# Title here
      +
      % cat gemfeed/2023-02-26-title-here.gmi
      +# Title here
       
      -The remaining content of the Gemtext file...
      +The remaining content of the Gemtext file...
       

      Gemtexter will add a line starting with > Published at ... now. Any subsequent Atom feed generation will then use that date.
      @@ -4153,12 +4153,12 @@ The remaining content of the Gemtext file... by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      % cat gemfeed/2023-02-26-title-here.gmi
      -# Title here
      +
      % cat gemfeed/2023-02-26-title-here.gmi
      +# Title here
       
      -> Published at 2023-02-26T21:43:51+01:00
      +> Published at 2023-02-26T21:43:51+01:00
       
      -The remaining content of the Gemtext file...
      +The remaining content of the Gemtext file...
       

      XMLLint support


      @@ -5326,23 +5326,23 @@ jgs (________\ \ by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      check_dependencies () {
      -    # At least, Bash 5 is required
      -    local -i required_version=5
      -    IFS=. read -ra version <<< "$BASH_VERSION"
      -    if [ "${version[0]}" -lt $required_version ]; then
      -        log ERROR "ERROR, \"bash\" must be at least at major version $required_version!"
      -        exit 2
      -    fi
      -
      -    # These must be the GNU versions of the commands
      -    for tool in $DATE $SED $GREP; do
      -        if ! $tool --version | grep -q GNU; then
      -            log ERROR "ERROR, \"$tool\" command is not the GNU version, please install!"
      -            exit 2
      -        fi
      -    done
      -}
      +
      check_dependencies () {
      +    # At least, Bash 5 is required
      +    local -i required_version=5
      +    IFS=. read -ra version <<< "$BASH_VERSION"
      +    if [ "${version[0]}" -lt $required_version ]; then
      +        log ERROR "ERROR, \"bash\" must be at least at major version $required_version!"
      +        exit 2
      +    fi
      +
      +    # These must be the GNU versions of the commands
      +    for tool in $DATE $SED $GREP; do
      +        if ! $tool --version | grep -q GNU; then
      +            log ERROR "ERROR, \"$tool\" command is not the GNU version, please install!"
      +            exit 2
      +        fi
      +    done
      +}
       

      Especially macOS users didn't read the README carefully enough to install GNU Grep, GNU Sed and GNU Date before using Gemtexter.
      @@ -5363,7 +5363,7 @@ http://www.gnu.org/software/src-highlite --> by Lorenzo Bettini http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite --> -
      ./gemtexter --generate '.*hello.*'
      +
      ./gemtexter --generate '.*hello.*'
       

      Revamped git support


      diff --git a/index.html b/index.html index 1abca178..2b40f752 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@

      foo.zone



      -This site was generated at 2024-05-18T00:12:59+03:00 by Gemtexter
      +This site was generated at 2024-05-18T13:24:26+03:00 by Gemtexter

          |\---/|
      diff --git a/testpage.html b/testpage.html
      index d1224374..741cf910 100644
      --- a/testpage.html
      +++ b/testpage.html
      @@ -46,31 +46,31 @@
       by Lorenzo Bettini
       http://www.lorenzobettini.it
       http://www.gnu.org/software/src-highlite -->
      -
      if [ -f "foo" ]; then
      -    echo foo
      -else
      -    echo bar
      -fi
      +
      if [ -f "foo" ]; then
      +    echo foo
      +else
      +    echo bar
      +fi
       

      -
      # Jo
      -❯ exec 5<>/dev/tcp/google.de/80
      -❯ echo -e "GET / HTTP/1.1\nhost: google.de\n\n" >&5
      -❯ cat <&5 | head
      -HTTP/1.1 301 Moved Permanently
      -Location: http://www.google.de/
      -Content-Type: text/html; charset=UTF-8
      -Date: Thu, 18 Nov 2021 08:27:18 GMT
      -Expires: Sat, 18 Dec 2021 08:27:18 GMT
      -Cache-Control: public, max-age=2592000
      -Server: gws
      -Content-Length: 218
      -X-XSS-Protection: 0
      -X-Frame-Options: SAMEORIGIN
      +
      # Jo
      +exec 5<>/dev/tcp/google.de/80
      +❯ echo -e "GET / HTTP/1.1\nhost: google.de\n\n" >&5
      +❯ cat <&5 | head
      +HTTP/1.1 301 Moved Permanently
      +Location: http://www.google.de/
      +Content-Type: text/html; charset=UTF-8
      +Date: Thu, 18 Nov 2021 08:27:18 GMT
      +Expires: Sat, 18 Dec 2021 08:27:18 GMT
      +Cache-Control: public, max-age=2592000
      +Server: gws
      +Content-Length: 218
      +X-XSS-Protection: 0
      +X-Frame-Options: SAMEORIGIN
       

      Foo0
      diff --git a/uptime-stats.html b/uptime-stats.html index 0e9aa3f4..3b7e593f 100644 --- a/uptime-stats.html +++ b/uptime-stats.html @@ -10,7 +10,7 @@

      My machine uptime stats



      -This site was last updated at 2024-05-18T00:12:59+03:00
      +This site was last updated at 2024-05-18T13:24:26+03:00

      The following stats were collected via uptimed on all of my personal computers over many years and the output was generated by guprecords, the global uptime records stats analyser of mine.

      -- cgit v1.2.3