From dbe4c437f05686a0fd1a500159bc62380e8d010e Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Thu, 25 May 2023 20:04:12 +0300 Subject: Update content for gemtext --- gemfeed/atom.xml.tmp | 8982 ++++++++++++++++++++++++++++++++++ index.gmi | 2 +- notes/never-split-the-difference.gmi | 2 +- notes/the-obstacle-is-the-way.gmi | 2 +- notes/the-pragmatic-programmer.gmi | 2 +- uptime-stats.gmi | 2 +- 6 files changed, 8987 insertions(+), 5 deletions(-) create mode 100644 gemfeed/atom.xml.tmp diff --git a/gemfeed/atom.xml.tmp b/gemfeed/atom.xml.tmp new file mode 100644 index 00000000..1a04f5b7 --- /dev/null +++ b/gemfeed/atom.xml.tmp @@ -0,0 +1,8982 @@ + + + 2023-05-25T20:03:41+03:00 + foo.zone feed + To be in the .zone! + + + gemini://foo.zone/ + + 'The Obstacle is the Way' book notes + + gemini://foo.zone/gemfeed/2023-05-06-the-obstacle-is-the-way-book-notes.gmi + 2023-05-06T17:23:16+03:00 + + Paul Buetow + hi@paul.cyou + + These are my personal takeaways after reading 'The Obstacle Is the Way' by Ryan Holiday. This is mainly for my own use, but you might find it helpful too. + +
+

"The Obstacle is the Way" book notes


+
+Published at 2023-05-06T17:23:16+03:00
+
+These are my personal takeaways after reading "The Obstacle Is the Way" by Ryan Holiday. This is mainly for my own use, but you might find it helpful too.
+
+
+
+         ,..........   ..........,
+     ,..,'          '.'          ',..,
+    ,' ,'            :            ', ',
+   ,' ,'             :             ', ',
+  ,' ,'              :              ', ',
+ ,' ,'............., : ,.............', ',
+,'  '............   '.'   ............'  ',
+ '''''''''''''''''';''';''''''''''''''''''
+                    '''
+
+
+"The obstacle is the way" is a powerful statement that encapsulates the wisdom of turning challenges into opportunities for growth and success. We will explore using obstacles as fuel, transforming weaknesses into strengths, and adopting a mindset that allows us to be creative and persistent in the face of adversity.
+
+

Reframe your perspective


+
+The obstacle in your path can become your path to success. Instead of being paralyzed by challenges, see them as opportunities to learn and grow. Remember, the things that hurt us often instruct us.
+
+We spend a lot of time trying to get things perfect and look at the rules, but what matters is that it works; it doesn't need to be after the book. Focus on results rather than on beautiful methods. In Jujitsu, it does matter that you bring your opponent down, but not how. There are many ways from point A to point B; it doesn't need to be a straight line. So many try to find the best solution but need to catch up on what is in Infront of them. Think progress and not perfection.
+
+Don't always try to use the front door; a backdoor could open. It's nonsense. Don't fight the judo master with judo. Non-action can be action, exposing the weaknesses of others.
+
+
+

Embrace rationality


+
+It is a superpower to see things rationally when others are fearful. Focus on the reality of the situation without letting emotions, such as anger, cloud your judgment. This ability will enable you to make better decisions in adversity. Ability to see things what they really are. E.g. wine is old fermented grapes, or other people behaving like animals during a fight. Show the middle finger if someone persists on the stupid rules occasionally.
+
+

Control your response


+
+You can choose how you respond to obstacles. Focus on what you can control, and don't let yourself feel harmed by external circumstances. Remember, you decide how things affect you; nobody else does. Choose to feel good in response to any situation. Embrace the challenges and obstacles that come your way, as they are opportunities for growth and learning.
+
+

Practice emotional and physical resilience


+
+Martial artists know the importance of developing physical and emotional strength. Cultivate the art of not panicking; it will help you avoid making mistakes during high-pressure situations.
+
+Focus on what you can control. Don't choose to feel harmed, and then you won't be harmed. I decide things that affect me; nobody else does. E.g., in prison, your mind stays your own. Don't ignore fear but explain it away, have a different view.
+
+

Persistence and patience


+
+Practice persistence and patience in your pursuits. Focus on the process rather than the prize and take one step at a time. Remember, the journey is about finishing tasks, projects, or workouts to the best of your ability. Never be in a hurry and never be desperate. There is no reason to be rushed; there are all in the long haul. Follow the process and not the price. Take it one step at a time. The process is about finishing (workout, task, project, etc.).
+
+

Embrace failure


+
+Failure is a natural part of life and can make us stronger. Treat defeat as a stepping stone to success and education. What is defeat? The first step to education. Failure makes you stronger. If we do our best, we can be proud of it, regardless of the result. Do your job, but do it right. Only an asshole thinks he is too good at the things he does. Also, asking for forgiveness is easier than asking for permission.
+
+

Be adaptable


+
+There are many ways to achieve your goals; sometimes, unconventional methods are necessary. Feel free to break the rules or go off the beaten path if it will lead to better results. Transform weaknesses into strengths. We have a choice of how to respond to things. It's not about being positive but to be creative. Aim high, but stuff will happen; E.g., surprises will always happen.
+
+

Embrace non-action


+
+We constantly push to the next thing. Sometimes the best course of action is standing still or even going backwards. Obstacles might resolve by themselves. Or going sideways. Sometimes, the best action is to stand still, go sideways, or even go backwards. Obstacles may resolve themselves or present new opportunities if you're patient and observant. People always want your input before you have all the facts. They want you to play after their rules. The question is, do you let them? The English call it the cool head. Being in control of Stress; requires practice. Appear, the absence of fear (Greek). When all others do it one way, it does not mean it is the correct or best practice.
+
+

Leverage crisis


+
+In times of crisis, seize the chance to do things never done before. Great people use negative situations to their advantage and become the most effective in challenging circumstances.
+
+The art of not panicking; otherwise, you will make mistakes. When overs are shocked, you know which way to take due to your thinking of the problem at Hand. A crisis gives you a chance to do things which never done before. Ordinary people shy from negative situations; great people use these for their benefit and are the most effective. The obstacle is not just turned upside down but used as a catapult.
+
+Be prepared for nothing to work. Problems are an opportunity to do your best, not to do miracles. Always manage your expectations. It will suck, but it will be ok. Be prepared to begin from the beginning. Be cheerful and eagerly work on the next obstacle. Each time you become better. Life is not a sprint but a marathon. After each obstacle lies another obstacle, there won't be anything without obstacles. Passing one means you are ready for the next.
+
+

Build your inner citadel


+
+Develop your inner strength during good times so you can rely on it in bad times. Always prepare for adversity and face it with calmness and resilience. Be humble enough that things which happen will happen. Build your inner citadel. In good times strengthen it. In bad times rely on it.
+
+We should always prepare for things to get tough. Your house burns down: no worries, we eliminated much rubbish. Imagine what can go wrong before things go wrong. We are prepared for adversity; it's other people who aren't. Phil Jackson's hip problem example. To receive unexpected benefits, you must first accept the unexpected obstacles. Meditate on death. It's a universal obstacle. Use it as a reminder to do your best.
+
+

Love everything that happens


+
+Turn an obstacle the other way around for your benefit. Use it at fuel. It's simple but challenging. Most are paralyzed instead. The obstacle in the path becomes the path. Obstacles are neither good nor bad. The things which hurt, instruct.
+
+Should I hate people who hate me? That's their problem and not mine. Be always calm and relaxed during the fight. The story of the battle is the story of the smile. Cheerfulness in all situations, especially the bad ones. Love for everything that happens; if it happens, it was meant to happen. We can choose how we react to things, so why not choose to feel good? I love everything that happens. You must never lower yourself to the person you don't like.
+
+

Conclusion


+
+Life is a marathon, not a sprint. Each obstacle we overcome prepares us for the next one. Remember, the obstacle is not just a barrier to be turned upside down; it can also be used as a catapult to propel us forward. By embracing challenges and using them as opportunities for growth, we become stronger, more adaptable, and, ultimately, more successful.
+
+Other book notes of mine are:
+
+2023-05-06 "The Obstacle is the Way" book notes (You are currently reading this)
+2023-04-01 "Never split the difference" book notes
+2023-03-16 "The Pragmatic Programmer" book notes
+
+E-Mail your comments to hi@foo.zone :-)
+
+More books and other resources I found useful.
+Back to the main site
+
+
+
+ + Unveiling `guprecords.raku`: Global Uptime Records with Raku + + gemini://foo.zone/gemfeed/2023-05-01-unveiling-guprecords:-uptime-records-with-raku.gmi + 2023-04-30T13:10:26+03:00 + + Paul Buetow + hi@paul.cyou + + For fun, I am tracking the uptime of various personal machines (servers, laptops, workstations...). I have been doing this for over ten years now, so I have a lot of statistics collected. + +
+

Unveiling guprecords.raku: Global Uptime Records with Raku


+
+Published at 2023-04-30T13:10:26+03:00
+
+
++-----+-----------------+-----------------------------+
+| Pos |            Host |                    Lifespan |
++-----+-----------------+-----------------------------+
+|  1. |        dionysus |  8 years, 6 months, 17 days |
+|  2. |          uranus |  7 years, 2 months, 16 days |
+|  3. |   alphacentauri |  6 years, 9 months, 13 days |
+|  4. |         *vulcan |   4 years, 5 months, 6 days |
+|  5. |             sun |  3 years, 10 months, 2 days |
+|  6. |           uugrn |   3 years, 5 months, 5 days |
+|  7. |       deltavega |  3 years, 1 months, 21 days |
+|  8. |           pluto | 2 years, 10 months, 30 days |
+|  9. |         tauceti |  2 years, 3 months, 22 days |
+| 10. |        callisto |  2 years, 3 months, 13 days |
++-----+-----------------+-----------------------------+
+
+
+

Introduction


+
+For fun, I am tracking the uptime of various personal machines (servers, laptops, workstations...). I have been doing this for over ten years now, so I have a lot of statistics collected.
+
+As a result of this, I am introducing guprecords.raku, a handy Raku script that helps me combine uptime statistics from multiple servers into one comprehensive report. In this blog post, I'll explore what Guprecords is and some examples of its application. I will also add some notes on Raku.
+
+Guprecords, or global uptime records, is a Raku script designed to generate a consolidated uptime report from multiple hosts:
+
+https://codeberg.org/snonux/guprecords
+The Raku Programming Language
+
+A previous version of Guprecords was actually written in Perl, the older and more established language from which Raku was developed. One of the primary motivations for rewriting Guprecords in Raku was to learn the language and explore its features. Raku is a more modern and powerful language compared to Perl, and working on a real-world project like Guprecords provided a practical and engaging way to learn the language.
+
+Over the last years, I have been reading the following books and resources about Raku:
+
+
    +
  • Raku Guide (at raku.guide)
  • +
  • Think Perl 6
  • +
  • Raku Fundamentals
  • +
  • Raku Recipes
  • +

+And I have been following the Raku newsletter, and sometimes I have been lurking around in the IRC channels, too. Watching Raku coding challenges on YouTube was pretty fun, too. However, nothing beats actually using Raku to learn the language. After reading all of these resources, I may have a good idea about the features and paradigms, but I am by far not an expert.
+
+

How Guprecords works


+
+Guprecords works in three stages:
+
+
    +
  • 1. Generating uptime statistics using uptimed: First, I need to install and run uptimed on each host to generate uptime statistics. This tool is available for most common Linux and *BSD distributions and macOS via Homebrew.
  • +
  • 2. Collecting uptime records to a central location: The next step involves collecting the raw uptime statistics files generated by uptimed on each host. It's a good idea to store all record files in a central git repository. The records file contains information about the total uptime since boot, boot time, and the operating system and kernel version. Guprecords itself does not do the collection part, but have a look at the README.md in the git repository for some guidance.
  • +
  • 3. Generating global uptime stats: Finally, run the guprecords.raku script with the appropriate flags to create a global uptime report. For example, I can use the following command:
  • +

+ +
$ 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.
+
+Guprecords supports the following features:
+
+
    +
  • Supports multiple categories: Host, Kernel, KernelMajor, and KernelName
  • +
  • Supports multiple metrics: Boots, Uptime, Score, Downtime, and Lifespan
  • +
  • Output formats available: Plaintext, Markdown, and Gemtext
  • +
  • Provides top entries based on the specified limit
  • +

+

Example


+
+You have already seen an example at the very top of this post, where the hosts were grouped by their total lifespans (uptime+downtime). Here's an example of what the global uptime report (grouped by total host uptimes) might look like:
+
+
+Top 20 Uptime's by Host
+
++-----+-----------------+-----------------------------+
+| Pos |            Host |                      Uptime |
++-----+-----------------+-----------------------------+
+|  1. |         *vulcan |   4 years, 5 months, 6 days |
+|  2. |          uranus | 3 years, 11 months, 21 days |
+|  3. |             sun |  3 years, 9 months, 26 days |
+|  4. |           uugrn |   3 years, 5 months, 5 days |
+|  5. |       deltavega |  3 years, 1 months, 21 days |
+|  6. |           pluto | 2 years, 10 months, 29 days |
+|  7. |         tauceti |  2 years, 3 months, 19 days |
+|  8. |       tauceti-f |  1 years, 9 months, 18 days |
+|  9. | *ultramega15289 |  1 years, 8 months, 17 days |
+| 10. |          *earth |  1 years, 5 months, 22 days |
+| 11. |       *blowfish |  1 years, 4 months, 20 days |
+| 12. |   ultramega8477 |  1 years, 3 months, 25 days |
+| 13. |           host0 |   1 years, 3 months, 9 days |
+| 14. |       tauceti-e |  1 years, 2 months, 20 days |
+| 15. |        makemake |   1 years, 1 months, 6 days |
+| 16. |        callisto | 0 years, 10 months, 31 days |
+| 17. |   alphacentauri | 0 years, 10 months, 28 days |
+| 18. |          london |  0 years, 9 months, 16 days |
+| 19. |         twofish |  0 years, 8 months, 31 days |
+| 20. |     *fishfinger |  0 years, 8 months, 17 days |
++-----+-----------------+-----------------------------+
+
+
+This table ranks the top 20 hosts based on their total uptime, with the host having the highest uptime at the top. The hosts marked with * are still active, means stats were collected within the last couple of months.
+
+My up to date stats can be seen here:
+
+My machine uptime stats
+
+Just recently, I decommissioned vulcan (the number one stop from above), which used to be my CentOS 7 (initially CentOS 6) VM hosting my personal NextCloud and Wallabag (which I modernised just recently with a brand new shiny Rocky Linux 9 VM). This was the last uptimed output before shutting it down (it always makes me feel sentimental decommissioning one of my machines :'-():
+
+
+     #               Uptime | System                                     Boot up
+----------------------------+---------------------------------------------------
+     1   545 days, 17:58:15 | Linux 3.10.0-1160.15.2.e  Sun Jul 25 19:32:25 2021
+     2   279 days, 10:12:14 | Linux 3.10.0-957.21.3.el  Sun Jun 30 12:43:41 2019
+     3   161 days, 06:08:43 | Linux 3.10.0-1160.15.2.e  Sun Feb 14 11:05:38 2021
+     4   107 days, 01:26:35 | Linux 3.10.0-957.1.3.el7  Thu Dec 20 09:29:13 2018
+     5    96 days, 21:13:49 | Linux 3.10.0-1127.13.1.e  Sat Jul 25 17:56:22 2020
+->   6    89 days, 23:05:32 | Linux 3.10.0-1160.81.1.e  Sun Jan 22 12:39:36 2023
+     7    63 days, 18:30:45 | Linux 3.10.0-957.10.1.el  Sat Apr 27 18:12:43 2019
+     8    63 days, 06:53:33 | Linux 3.10.0-1127.8.2.el  Sat May 23 10:41:08 2020
+     9    48 days, 11:44:49 | Linux 3.10.0-1062.18.1.e  Sat Apr  4 22:56:07 2020
+    10    42 days, 08:00:13 | Linux 3.10.0-1127.19.1.e  Sat Nov  7 11:47:33 2020
+    11    36 days, 22:57:19 | Linux 3.10.0-1160.6.1.el  Sat Dec 19 19:47:57 2020
+    12    21 days, 06:16:28 | Linux 3.10.0-957.10.1.el  Sat Apr  6 11:56:01 2019
+    13    12 days, 20:11:53 | Linux 3.10.0-1160.11.1.e  Mon Jan 25 18:45:27 2021
+    14     7 days, 21:29:18 | Linux 3.10.0-1127.13.1.e  Fri Oct 30 14:18:04 2020
+    15     6 days, 20:07:18 | Linux 3.10.0-1160.15.2.e  Sun Feb  7 14:57:35 2021
+    16     1 day , 21:46:41 | Linux 3.10.0-957.1.3.el7  Tue Dec 18 11:42:19 2018
+    17     0 days, 01:25:57 | Linux 3.10.0-957.1.3.el7  Tue Dec 18 10:16:08 2018
+    18     0 days, 00:42:34 | Linux 3.10.0-1160.15.2.e  Sun Jul 25 18:49:38 2021
+    19     0 days, 00:08:32 | Linux 3.10.0-1160.81.1.e  Sun Jan 22 12:30:52 2023
+----------------------------+---------------------------------------------------
+1up in     6 days, 22:08:18 | at                        Sat Apr 29 10:53:25 2023
+no1 in   455 days, 18:52:44 | at                        Sun Jul 21 07:37:51 2024
+    up  1586 days, 00:20:28 | since                     Tue Dec 18 10:16:08 2018
+  down     0 days, 01:08:32 | since                     Tue Dec 18 10:16:08 2018
+   %up               99.997 | since                     Tue Dec 18 10:16:08 2018
+
+
+

Conclusion


+
+Guprecords is a small, yet powerful tool for analyzing uptime statistics. While developing Guprecords, I have come to truly appreciate and love Raku's expressiveness. The language is designed to be both powerful and flexible, allowing developers to express their intentions and logic more clearly and concisely.
+
+Raku's expressive syntax, support for multiple programming paradigms, and unique features, such as grammars and lazy evaluation, make it a joy to work with.
+
+Working on Guprecords in Raku has been an enjoyable experience, and I've found that Raku's expressiveness has significantly contributed to the overall quality and effectiveness of the script. The language's ability to elegantly express complex logic and data manipulation tasks makes it an excellent choice for developing tools like these, where expressiveness and productiveness are of the utmost importance.
+
+So far, I have only scratched the surface of what Raku can do. I hope to find more time to become a regular Rakoon (a Raku Programmer). I have many Ideas for other small tools like Guprecords, but the challenge is finding the time. I'd love to explore Raku Grammars and also I would love to explore writing concurrent code in Raku (I also love Go (Golang), btw!). Ideas for future Raku personal projects include:
+
+
    +
  • A log file analyzer, for generating anonymized foo.zone visitor stats for both, the Web and Gemini.
  • +
  • A social media sharing scheduler a la buffer.com. I am using Buffer at the moment to share posts on Mastadon, Twitter, Telegram and LinkedIn, but it is proprietary and also it's not really reliable.
  • +
  • Rewrite the static photo album generator of irregular.ninja in Raku (from Bash).
  • +

+Other related posts are:
+
+2023-05-01 Unveiling guprecords.raku: Global Uptime Records with Raku (You are currently reading this)
+2022-06-15 Sweating the small stuff - Tiny projects of mine
+2022-05-27 Perl is still a great choice
+2011-05-07 Perl Daemon (Service Framework)
+2008-06-26 Perl Poetry
+
+E-Mail your comments to hi@foo.zone :-)
+
+Back to the main site
+
+
+
+ + Algorithms and Data Structures in Go - Part 1 + + gemini://foo.zone/gemfeed/2023-04-09-algorithms-and-data-structures-in-golang-part-1.gmi + 2023-04-09T22:31:42+03:00 + + Paul Buetow + hi@paul.cyou + + This is the first blog post about my Algorithms and Data Structures in Go series. I am not a Software Developer in my day job. In my current role, programming and scripting skills are desirable but not mandatory. I have been learning about Data Structures and Algorithms many years ago at University. I thought it would be fun to revisit/refresh my knowledge here and implement many of the algorithms in Go. + +
+

Algorithms and Data Structures in Go - Part 1


+
+Published at 2023-04-09T22:31:42+03:00
+
+
+         ,_---~~~~~----._         
+  _,,_,*^____      _____``*g*\"*, 
+ / __/ /'     ^.  /      \ ^@q   f 
+[  @f | @))    |  | @))   l  0 _/  
+ \`/   \~____ / __ \_____/    \   
+  |           _l__l_           I   
+  }          [______]           I  
+  ]            | | |            |  
+  ]             ~ ~             |  
+  |                            |   
+   |                           |   
+
+
+This is the first blog post about my Algorithms and Data Structures in Go series. I am not a Software Developer in my day job. In my current role, programming and scripting skills are desirable but not mandatory. I have been learning about Data Structures and Algorithms many years ago at University. I thought it would be fun to revisit/refresh my knowledge here and implement many of the algorithms in Go.
+
+2023-04-09 Algorithms and Data Structures in Go - Part 1 (You are currently reading this)
+
+This post is about setting up some basic data structures and methods for this blog series. I promise, everything will be easy to follow in this post. It will become more interesting later in this series.
+
+

Type constraints


+
+First, the package ds (data structures) defines the types.go. All examples will either operate on the Integer or Number type:
+
+ +
package ds
+
+import (
+	"golang.org/x/exp/constraints"
+)
+
+type Integer interface {
+	constraints.Integer
+}
+
+type Number interface {
+	constraints.Integer | constraints.Float
+}
+
+
+
+

ArrayList


+
+Next comes the arraylist.go, which defines the underlying data structure all the algorithms of this series will use. ArrayList is just a type alias of a Go array (or slice) with custom methods on it:
+
+ +
package ds
+
+import (
+	"fmt"
+	"math/rand"
+	"strings"
+)
+
+type ArrayList[V Number] []V
+
+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.
+
+ +
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


+
+The FirstN method only returns the first N elements of the ArrayList. This is useful for printing out only parts of the data structure:
+
+ +
func (a ArrayList[V]) FirstN(n int) string {
+	var sb strings.Builder
+	j := n
+
+	l := len(a)
+	if j > l {
+		j = l
+	}
+
+	for i := 0; i < j; i++ {
+		fmt.Fprintf(&sb, "%v ", a[i])
+	}
+
+	if j < l {
+		fmt.Fprintf(&sb, "... ")
+	}
+
+	return sb.String()
+}
+
+
+The Sorted method checks whether the ArrayList is sorted. This will be used by the unit tests later on:
+
+ +
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:
+
+ +
func (a ArrayList[V]) Swap(i, j int) {
+	aux := a[i]
+	a[i] = a[j]
+	a[j] = aux
+}
+
+
+
+

Sleep sort


+
+Let's implement our first algorithm, sleep sort. Sleep sort is a non-traditional and unconventional sorting algorithm based on the idea of waiting a certain amount of time corresponding to the value of each element in the input ArrayList. It's more of a fun, creative concept rather than an efficient or practical sorting technique. This is not a sorting algorithm you would use in any production code. As you can imagine, it is quite an inefficient sorting algorithm (it's only listed here as a warm-up exercise). This sorting method may also return false results depending on how the Goroutines are scheduled by the Go runtime.
+
+
+ +
package sort
+
+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))
+
+	numCh := make(chan V)
+	var wg sync.WaitGroup
+	wg.Add(len(a))
+
+	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 numCh {
+		sorted = append(sorted, num)
+	}
+
+	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.
+
+

Testing


+
+For testing, we only allow values up to 10, as otherwise, it would take too long to finish:
+
+ +
package sort
+
+import (
+	"fmt"
+	"testing"
+
+	"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)
+	}
+}
+
+
+As you can see, it takes 9s here for the algorithm to finish (which is the highest value in the ArrayList):
+
+ +
❯ 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 :-).
+
+E-Mail your comments to hi@foo.zone :-)
+
+Back to the main site
+
+
+
+ + 'Never split the difference' book notes + + gemini://foo.zone/gemfeed/2023-04-01-never-split-the-difference-book-notes.gmi + 2023-04-01T20:00:17+03:00 + + Paul Buetow + hi@paul.cyou + + These are my personal takeaways after reading 'Never split the difference' by Chris Voss. Note that the book contains much more knowledge wisdom and that these notes only contain points I personally found worth writing down. This is mainly for my own use, but you might find it helpful too. + +
+

"Never split the difference" book notes


+
+Published at 2023-04-01T20:00:17+03:00
+
+These are my personal takeaways after reading "Never split the difference" by Chris Voss. Note that the book contains much more knowledge wisdom and that these notes only contain points I personally found worth writing down. This is mainly for my own use, but you might find it helpful too.
+
+
+         ,..........   ..........,
+     ,..,'          '.'          ',..,
+    ,' ,'            :            ', ',
+   ,' ,'             :             ', ',
+  ,' ,'              :              ', ',
+ ,' ,'............., : ,.............', ',
+,'  '............   '.'   ............'  ',
+ '''''''''''''''''';''';''''''''''''''''''
+                    '''
+
+
+

Tactical listening, spreading empathy


+
+Be a mirror, copy each other to be comfy with each other to build up trust. Mirroring is mainly body language. A mirror is to repeat the words the other just said. Simple but effective.
+
+
    +
  • A mirror needs space and silence between the words. At least 4 seconds.
  • +
  • A mirror might be awkward to be used at first, especially with a question coupled to it.
  • +
  • We fear what's different and are drawn to what is similar.
  • +

+Mirror training is like Jedi training. Simple but effective. A mirror needs space. Be silent after "you want this?"
+
+

Mindset of discovery


+
+Try to have multiple realities in your mind and use facts to distinguish between real and false.
+
+
    +
  • Focus on what the counterpart has to say and what he needs and wants. Understanding him makes him vulnerable.
  • +
  • Empathy understanding the other person from his perspective, but it does not mean agreeing with him.
  • +
  • Detect and label the emotions of others for your powers.
  • +
  • To be understood seems to solve all problems magically.
  • +

+Try: to put a label on someone's emotion and then be silent. Wait for the other to reveal himself. "You seem unhappy about this?"
+
+

More tips


+
+
    +
  • Put on a poker face and don't show emotions.
  • +
  • Slow things down. Don't be a problem solver.
  • +
  • Smile while you are talking, even on the phone. Be easy and encouraging.
  • +
  • Being right is not the key to successful negotiation; being mindful is.
  • +
  • Be in the safe zone of empathy and acknowledge bad news.
  • +

+

"No" starts the conversation


+
+When the opponent starts with a "no", he feels in control and comfortable. That's why he has to start with "no".
+
+
    +
  • "Yes" and "maybe" might be worthless, but "no" starts the conversation.
  • +
  • If someone is saying "no" to you, he will be open to what you have to say next.
  • +
  • "No" is not stopping the negotiation but will open up opportunities you were not thinking about before.
  • +
  • Start with "no". Great negotiators seek "no" because that's when the great discussions begin.
  • +
  • A "no" can be scary if you are not used to it. If your biggest fear is "no", then you can't negotiate.
  • +

+Get a "That's right" when negotiating. Don't get a "you're right". You can summarise the opponent to get a "that's right".
+
+

Win-win


+
+Win-win is a naive approach when encountering the win-lose counterpart, but always cooperate. Don't compromise, and don't split the difference. We don't compromise because it's right; we do it because it is easy. You must embrace the hard stuff; that's where the great deals are.
+
+

On Deadlines


+
+
    +
  • All deadlines are imaginary.
  • +
  • Most of the time, deadlines unsettle us without a good reason.
  • +
  • They push a deal to a conclusion.
  • +
  • They rush the counterpart to cause pressure and anxiety.
  • +

+

Analyse the opponent


+
+
    +
  • Understand the motivation of people behind the table as well.
  • +
  • Ask how affected they will be.
  • +
  • Determine your and the opposite negotiation style. Accommodation, analyst, assertive.
  • +
  • Treat them how they need to be treated.
  • +

+The person on the other side is never the issue; the problem is the issue. Keep this in mind to avoid emotional issues with the person and focus on the problem, not the person. The bond is essential; never create an enemy.
+
+

Use different ways of saying "no."


+
+I had paid my rent always in time. I had positive experiences with the building and would be sad for the landlord to lose a good tenant. I am looking for a win-win agreement between us. Pulling out the research, other neighbours offer much lower prices even if your building is a better location and services. How can I effort 200 more....
+
+...then put an extreme anker.
+
+You always have to embrace thoughtful confrontation for good negotiation and life. Don't avoid honest, clear conflict. It will give you the best deals. Compromises are mostly bad deals for both sides. Most people don't negotiate a win-win but a win-lose. Know the best and worst outcomes and what is acceptable for you.
+
+

Calibrated question


+
+Calibrated questions. Give the opponent a sense of power. Ask open-how questions to get the opponent to solve your problem and move him in your direction. Calibrated questions are the best tools. Summarise everything, and then ask, "how I am supposed to do that?". Asking for help this way with a calibrated question is a powerful tool for joint problem solving
+
+Being calm and respectful is essential. Without control of your emotions, it won't work. The counterpart will have no idea how constrained they are with your question. Avoid questions which get a yes or short answers. Use "why?".
+
+Counterparts are more involved if these are their solutions. The counterpart must answer with "that's right", not "you are right". He has to own the problem. If not, then add more why questions.
+
+
    +
  • Tone and body language need to align with what people are saying.
  • +
  • Deal with it via a labelled question.
  • +
  • Liers tend to talk with "them" and "their" and not with "I".
  • +
  • Also, liars tend to talk in complex sentences.
  • +

+Prepare 3 to 5 calibrated questions for your counterpart. Be curious what is really motivating the other side. You can get out the "Black Swan".
+
+

The black swan


+
+What we don't know can break our deal. Uncovering it can bring us unexpected success. You get what you ask for in this world, but you must learn to ask correctly. Reveal the black swan by asking questions.
+
+

More


+
+Establish a range at top places like corp. I get... (e.g. remote London on a project basis). Set a high salary range and not a number. Also, check on LinkedIn premium for the salaries.
+
+
    +
  • Give an unexpected gift, e.g. show them my pet project and publicity for engineering.
  • +
  • Use an odd number, which makes you seem to have thought a lot about the sum and calculated it.
  • +
  • Define success and metrics for your next raise.
  • +
  • What does it take to be successful here? Ask the question, and they will tell you and guide you.
  • +
  • Set an extreme anker. Make the counterpart the illusion of losing something.
  • +
  • Hope-based deals. Hope is not a strategy.
  • +
  • Tactical empathy, listening as a martial art. It is emotional intelligence on steroids.
  • +
  • Being right isn't the key to a successful negotiation, but having the correct mindset is.
  • +
  • Don't shop the groceries when you are hungry.
  • +

+Slow.... it.... down....
+
+Other book notes of mine are:
+
+2023-05-06 "The Obstacle is the Way" book notes
+2023-04-01 "Never split the difference" book notes (You are currently reading this)
+2023-03-16 "The Pragmatic Programmer" book notes
+
+E-Mail your comments to hi@foo.zone :-)
+
+Back to the main site
+
+
+
+ + Gemtexter 2.0.0 - Let's Gemtext again² + + gemini://foo.zone/gemfeed/2023-03-25-gemtexter-2.0.0-lets-gemtext-again-2.gmi + 2023-03-25T17:50:32+02:00 + + Paul Buetow + hi@paul.cyou + + I proudly announce that I've released Gemtexter version `2.0.0`. What is Gemtexter? It's my minimalist static site generator for Gemini Gemtext, HTML and Markdown written in GNU Bash. + +
+

Gemtexter 2.0.0 - Let's Gemtext again²


+
+Published at 2023-03-25T17:50:32+02:00
+
+
+-=[ typewriters ]=-  1/98
+
+       .-------.
+      _|~~ ~~  |_       .-------.
+    =(_|_______|_)=    _|~~ ~~  |_
+      |:::::::::|    =(_|_______|_)
+      |:::::::[]|      |:::::::::|
+      |o=======.|      |:::::::[]|
+ jgs  `"""""""""`      |o=======.|
+  mod. by Paul Buetow  `"""""""""`
+
+
+I proudly announce that I've released Gemtexter version 2.0.0. What is Gemtexter? It's my minimalist static site generator for Gemini Gemtext, HTML and Markdown written in GNU Bash.
+
+https://codeberg.org/snonux/gemtexter
+
+This is a new major release, so it contains a breaking change (see "Meta cache made obsolete").
+
+Let's list what's new!
+
+

Minimal template engine


+
+Gemtexter now supports templating, enabling dynamically generated content to .gmi files before converting anything to any output format like HTML and Markdown.
+
+A template file name must have the suffix gmi.tpl. A template must be put into the same directory as the Gemtext .gmi file to be generated. Gemtexter will generate a Gemtext file index.gmi from a given template index.gmi.tpl. A <<< and >>> encloses a multiline template. All lines starting with << will be evaluated as a single line of Bash code and the output will be written into the resulting Gemtext file.
+
+For example, the template index.gmi.tpl:
+
+
+# Hello world
+
+<< echo "> This site was generated at $(date --iso-8601=seconds) by \`Gemtexter\`"
+
+Welcome to this capsule!
+
+<<<
+  for i in {1..10}; do
+    echo Multiline template line $i
+  done
+>>>
+
+
+... results into the following index.gmi after running ./gemtexter --generate (or ./gemtexter --template, which instructs to do only template processing and nothing else):
+
+
+# Hello world
+
+> This site was generated at 2023-03-15T19:07:59+02:00 by `Gemtexter`
+
+Welcome to this capsule!
+
+Multiline template line 1
+Multiline template line 2
+Multiline template line 3
+Multiline template line 4
+Multiline template line 5
+Multiline template line 6
+Multiline template line 7
+Multiline template line 8
+Multiline template line 9
+Multiline template line 10
+
+
+Another thing you can do is insert an index with links to similar blog posts. E.g.:
+
+
+See more entries about DTail and Golang:
+
+<< template::inline::index dtail golang
+
+Blablabla...
+
+
+... scans all other post entries with dtail and golang in the file name and generates a link list like this:
+
+
+See more entries about DTail and Golang:
+
+=> ./2022-10-30-installing-dtail-on-openbsd.gmi 2022-10-30 Installing DTail on OpenBSD
+=> ./2022-04-22-programming-golang.gmi 2022-04-22 The Golang Programming language
+=> ./2022-03-06-the-release-of-dtail-4.0.0.gmi 2022-03-06 The release of DTail 4.0.0
+=> ./2021-04-22-dtail-the-distributed-log-tail-program.gmi 2021-04-22 DTail - The distributed log tail program (You are currently reading this)
+
+Blablabla...
+
+
+

Added hooks


+
+You can configure PRE_GENERATE_HOOK and POST_PUBLISH_HOOK to point to scripts to be executed before running --generate, or after running --publish. E.g. you could populate some of the content by an external script before letting Gemtexter do its thing or you could automatically deploy the site after running --publish.
+
+The sample config file gemtexter.conf includes this as an example now; these scripts will only be executed when they actually exist:
+
+ +
declare -xr PRE_GENERATE_HOOK=./pre_generate_hook.sh
+declare -xr POST_PUBLISH_HOOK=./post_publish_hook