summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorDavid Wührer <def@gmx.at>2024-05-18 21:04:34 +0200
committerDavid Wührer <def@gmx.at>2024-05-18 21:04:34 +0200
commit77cfffee6177fb0421fa0fce15d6a1875bde4816 (patch)
tree251428cdd482ea50cfb019dbd3c3bafd79d2fd14 /bin
parent75b23ce1ff0daab363725a2a5755ea80bbeaa68e (diff)
manuals, sum-down, radix
Diffstat (limited to 'bin')
-rwxr-xr-xbin/all6
-rwxr-xr-xbin/any6
-rwxr-xr-xbin/capitalise137
-rwxr-xr-xbin/clone24
-rwxr-xr-xbin/colourlist26
-rwxr-xr-xbin/countdown23
-rwxr-xr-xbin/countdown230
-rwxr-xr-xbin/ean1322
-rwxr-xr-xbin/embolden390
-rwxr-xr-xbin/giteval15
-rwxr-xr-xbin/italicise269
-rwxr-xr-xbin/map11
-rwxr-xr-xbin/map-db60
-rwxr-xr-xbin/pf38
-rwxr-xr-xbin/pivot11
-rwxr-xr-xbin/radix39
-rwxr-xr-xbin/reduce9
-rwxr-xr-xbin/spt55
-rwxr-xr-xbin/strjoin6
-rw-r--r--bin/sum-down14
-rwxr-xr-xbin/sum-up4
-rwxr-xr-xbin/xmlbrowser39
-rwxr-xr-xbin/yamlbrowser58
23 files changed, 1292 insertions, 0 deletions
diff --git a/bin/all b/bin/all
new file mode 100755
index 0000000..dc33367
--- /dev/null
+++ b/bin/all
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+for i in $(seq 1 $#)
+do
+ [[ ${!i} ]] || exit 1
+done
diff --git a/bin/any b/bin/any
new file mode 100755
index 0000000..9fd9234
--- /dev/null
+++ b/bin/any
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+for i in $(seq 1 $#)
+do
+ [[ ${!i} ]] && exit 0
+done
diff --git a/bin/capitalise b/bin/capitalise
new file mode 100755
index 0000000..479c55d
--- /dev/null
+++ b/bin/capitalise
@@ -0,0 +1,137 @@
+#!/bin/bash
+
+
+# Latin letter small capital a: UTF-8: e1 b4 80 UTF-16BE: 1d00
+# .0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .A .B .C .D .E .F
+# 1D0. ᴀ ᴁ ᴂ ᴃ ᴄ ᴅ ᴆ ᴇ ᴈ ᴉ ᴊ ᴋ ᴌ ᴍ ᴎ ᴏ
+# 1D1. ᴐ ᴑ ᴒ ᴓ ᴔ ᴕ ᴖ ᴗ ᴘ ᴙ ᴚ ᴛ ᴜ ᴝ ᴞ ᴟ
+# 1D2. ᴠ ᴡ ᴢ ᴣ ᴤ ᴥ ᴦ ᴧ ᴨ ᴩ ᴪ ᴫ ᴬ ᴭ ᴮ ᴯ
+# 1D3. ᴰ ᴱ ᴲ ᴳ ᴴ ᴵ ᴶ ᴷ ᴸ ᴹ ᴺ ᴻ ᴼ ᴽ ᴾ ᴿ
+# 1D4. ᵀ ᵁ ᵂ ᵃ ᵄ ᵅ ᵆ ᵇ ᵈ ᵉ ᵊ ᵋ ᵌ ᵍ ᵎ ᵏ
+# 1D5. ᵐ ᵑ ᵒ ᵓ ᵔ ᵕ ᵖ ᵗ ᵘ ᵙ ᵚ ᵛ ᵜ ᵝ ᵞ ᵟ
+# 1D6. ᵠ ᵡ ᵢ ᵣ ᵤ ᵥ ᵦ ᵧ ᵨ ᵩ ᵪ ᵫ ᵬ ᵭ ᵮ ᵯ
+# 1D7. ᵰ ᵱ ᵲ ᵳ ᵴ ᵵ ᵶ ᵷ ᵸ ᵹ ᵺ ᵻ ᵼ ᵽ ᵾ ᵿ
+# 1D8. ᶀ ᶁ ᶂ ᶃ ᶄ ᶅ ᶆ ᶇ ᶈ ᶉ ᶊ ᶋ ᶌ ᶍ ᶎ ᶏ
+# 1D9. ᶐ ᶑ ᶒ ᶓ ᶔ ᶕ ᶖ ᶗ ᶘ ᶙ ᶚ ᶛ ᶜ ᶝ ᶞ ᶟ
+# 1DA. ᶠ ᶡ ᶢ ᶣ ᶤ ᶥ ᶦ ᶧ ᶨ ᶩ ᶪ ᶫ ᶬ ᶭ ᶮ ᶯ
+# 1DB. ᶰ ᶱ ᶲ ᶳ ᶴ ᶵ ᶶ ᶷ ᶸ ᶹ ᶺ ᶻ ᶼ ᶽ ᶾ ᶿ
+# TODO: Greek letter small capital
+declare -A smallcaps=(
+ [a]=$'\xe1\xb4\x80'
+ [æ]=$'\xe1\xb4\x81'
+ [b]=$'\xca\x99'
+ [c]=$'\xe1\xb4\x84'
+ [d]=$'\xe1\xb4\x85'
+ [e]=$'\xe1\xb4\x87'
+ [f]=$'\xea\x9c\xb0'
+ [g]=$'\xc9\xa2'
+ [h]=$'\xca\x9c'
+ [i]=$'\xc9\xaa'
+ [j]=$'\xe1\xb4\x8a'
+ [k]=$'\xe1\xb4\x8b'
+ [l]=$'\xca\x9f'
+ [m]=$'\xe1\xb4\x8d'
+ [n]=$'\xc9\xb4'
+ [o]=$'\xe1\xb4\x8f'
+ [œ]=$'\xc9\xb6'
+ [p]=$'\xe1\xb4\x98'
+ [q]=$'\xea\x9e\xaf'
+ [r]=$'\xca\x80'
+ [s]=$'\xea\x9c\xb1'
+ [t]=$'\xe1\xb4\x9b'
+ [u]=$'\xe1\xb4\x9c'
+ [v]=$'\xe1\xb4\xa0'
+ [w]=$'\xe1\xb4\xa1'
+ [x]=x # Missing
+ [y]=$'\xca\x8f'
+ [z]=$'\xe1\xb4\xa2'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+# []=$'\x1d\x'
+)
+
+while IFS= read -r line
+do
+ replacement=""
+ for i in $(seq 0 "$((${#line}-1))")
+ do
+ c1=${line:$i:1}
+ # if [[ $c1 =~ [a-zA-Zα-ωΑ-Ω] ]]
+ if [[ $c1 =~ [a-zæœ] ]]
+ then replacement+=${smallcaps[$c1]}
+ else replacement+=$c1
+ fi
+ done
+ echo "$replacement"
+done
diff --git a/bin/clone b/bin/clone
new file mode 100755
index 0000000..cfad1af
--- /dev/null
+++ b/bin/clone
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -eu
+
+args=()
+for url in "$@"
+do
+ case $url in
+ https://*|git://*)
+ dir=${url#*//}
+ dir=${dir%/*}
+ ;; git@*)
+ dir=${url#git@}
+ dir=${dir/://}
+ dir=${dir%/*}
+ ;; *)
+ args+=("$url")
+ continue
+ esac
+ mkdir -vp ~/src/"$dir"
+ cd ~/src/"$dir"
+ git clone --verbose --progress "${args[@]}" "$url"
+ args=()
+done
diff --git a/bin/colourlist b/bin/colourlist
new file mode 100755
index 0000000..49b8442
--- /dev/null
+++ b/bin/colourlist
@@ -0,0 +1,26 @@
+#!/usr/bin/python3
+
+import tkinter
+from tkinter.constants import *
+
+window = tkinter.Tk ()
+window.wm_title ('X11 Colours')
+
+canvas = tkinter.Canvas (window)
+frame = tkinter.Frame (canvas)
+scrollbar = tkinter.Scrollbar (window, command=canvas.yview)
+canvas.configure (yscrollcommand=scrollbar.set)
+
+scrollbar.pack(fill=Y, expand=1, side=RIGHT)
+canvas.pack (fill=BOTH, expand=1, side=LEFT)
+canvas.create_window ((0,0), window=frame, anchor=NW)
+frame.bind ("<Configure>", lambda e: canvas.configure (scrollregion=canvas.bbox ('all')))
+
+with open ("/etc/X11/rgb.txt") as txt:
+ colours = txt.readlines ()
+
+for r,g,b,name in ((int(l[0]),int(l[1]),int(l[2]),l[3]) for l in (colour.rstrip ().split (maxsplit=3) for colour in colours[1:])):
+ # Each colour band should be weighted: Half red is not as bright as half green.
+ tkinter.Label (frame, text=f'{name} ({r+b+g})', bg=f'#{r:02x}{g:02x}{b:02x}',fg='black' if r+g+b > 381 else 'white').pack (fill=X, expand=1)
+
+window.mainloop ()
diff --git a/bin/countdown b/bin/countdown
new file mode 100755
index 0000000..59daf56
--- /dev/null
+++ b/bin/countdown
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+declare -i t=$1
+
+while [ $((t--)) -ne 0 ]; do
+ if [ $t -gt 5400 ]; then
+ h=$((t/3600))
+ m=$(((t-(h*3600))/60))
+ if [ $m -lt 10 ]; then m=0$m; fi
+ s=$((t%60))
+ if [ $s -lt 10 ]; then s=0$s; fi
+ echo -en "\r$h:$m:$s "
+ elif [ $t -gt 90 ]; then
+ m=$((t/60))
+ s=$((t%60))
+ if [ $s -lt 10 ]; then s=0$s; fi
+ echo -en "\r$m:$s "
+ else
+ echo -en "\r$t "
+ fi
+ sleep 1
+done
+echo -en "\r"
diff --git a/bin/countdown2 b/bin/countdown2
new file mode 100755
index 0000000..615f6eb
--- /dev/null
+++ b/bin/countdown2
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+if [ -z "$1" ]; then echo "usage $0 date"; exit 1; fi
+
+declare -ir t=`date +%s -d "$1"`;
+
+declare -i d=t-`date +%s`;
+while [ $d -gt 0 ]; do
+ #yyyy-mm-ddThh:mm:ss
+ #ww-dd hh:mm:ss
+ if [ $d -gt 5400 ]; then
+ h=$((d/3600))
+ m=$(((d-(h*3600))/60))
+ if [ $m -lt 10 ]; then m=0$m; fi
+ s=$((d%60))
+ if [ $s -lt 10 ]; then s=0$s; fi
+ echo -en "\r$h:$m:$s "
+ elif [ $d -gt 90 ]; then
+ m=$((d/60))
+ s=$((d%60))
+ if [ $s -lt 10 ]; then s=0$s; fi
+ echo -en "\r$m:$s "
+ else
+ echo -en "\r$d "
+ fi
+ #echo -en "\r$d\t";
+ sleep 1;
+ d=t-`date +%s`;
+done
+echo -en "\r"
diff --git a/bin/ean13 b/bin/ean13
new file mode 100755
index 0000000..6fd125a
--- /dev/null
+++ b/bin/ean13
@@ -0,0 +1,22 @@
+#!/bin/bash
+while [[ $1 ]]
+do
+[[ ${#1} -eq 13 ]] || [[ ${#1} -eq 12 ]] || {
+ printf >&2 'length is %d, should be 13\n' ${#1}
+ exit 1
+}
+declare -i checksum=0
+declare -i factor=1
+for i in {0..11}
+do
+ v=${1:i:1}
+ checksum=$((checksum+factor*v))
+ factor=$((factor^2))
+#printf >&2 'v: %s : cs=%d f=%d\n' "$v" $checksum $factor
+done
+if [[ ${#1} -eq 12 ]]
+then echo "$1"$((10-checksum%10))
+else [[ $((10-checksum%10)) -eq ${1:12} ]] || exit
+fi
+shift
+done
diff --git a/bin/embolden b/bin/embolden
new file mode 100755
index 0000000..75df549
--- /dev/null
+++ b/bin/embolden
@@ -0,0 +1,390 @@
+#!/bin/bash
+
+# For bold and italic we can use the Mathematical font variant mappings,
+# although those are only defined for Latin and Greek.
+# Latin bold capital: u1d400 - u1d419
+# Latin bold small: u1d41a - u1d433
+# Latin italic capital: u1d434 - u1d44d
+# Latin italic small: u1d44e - u1d467
+# Latin bold italic capital: u1d468 - u1d481
+# Latin bold italic small: u1d482 - u1d49b
+# (Script capital, script small, bold script capital, bold script small)
+# (Fraktur capital, fraktur small)
+# (Double-struck capital, double-struck small)
+# (some Hebrew symbol variants)
+# (Bold fraktur capital, bold fraktur small)
+# (Sans-serif capital, sans-serif small)
+# (Sans-serif bold capital, sans-serif bold small)
+# (Sans-serif italic capital, sans-serif italic small)
+# (Sans-serif bold italic capital, sans-serif bold italic small)
+# (Monospace capital, monospace small)
+# Greek bold capital: u1d6a8 - u1d6c0
+# Greek bold small: u1d6c2 - u1d6da
+# Greek italic capital: u1d6e2 - u1d6fa
+# Greek italic small: u1dcfc - u1d714
+# Greek bold italic capital: u1d71c - u1d734
+# Greek bold italic small: u1d736 - u1d74e
+# (Greek sans-serif bold capital: u1d756 - u1d76e)
+# (Greek sans-serif bold small: u1d770 - u1d788)
+# (Greek sans-serif bold italic capital: u1d790 - u1d7a8)
+# (Greek sans-serif bold italic small: u1d7aa - u1d7c2)
+# bold digits: u1d7ce - u1d7d7
+# (double-struck digits)
+# (sans-serif digits)
+# (sans-serif bold digits)
+# (monospace digits)
+# (Arabic mathematical)
+# (Arabic stretched)
+# (Arabic looped)
+# (Arabic double-struck)
+#
+# It turns out there are no Unicode control codes for marking text
+# bold or italic. There are for subscript and superscript,
+# and ASCII has similar codes which nobody ever uses.
+
+declare -A bold=(
+ [0]=$'\xf0\x9d\x9f\x8e'
+ [1]=$'\xf0\x9d\x9f\x8f'
+ [2]=$'\xf0\x9d\x9f\x90'
+ [3]=$'\xf0\x9d\x9f\x91'
+ [4]=$'\xf0\x9d\x9f\x92'
+ [5]=$'\xf0\x9d\x9f\x93'
+ [6]=$'\xf0\x9d\x9f\x94'
+ [7]=$'\xf0\x9d\x9f\x95'
+ [8]=$'\xf0\x9d\x9f\x96'
+ [9]=$'\xf0\x9d\x9f\x97'
+ [A]=$'\xf0\x9d\x90\x80'
+ [B]=$'\xf0\x9d\x90\x81'
+ [C]=$'\xf0\x9d\x90\x82'
+ [D]=$'\xf0\x9d\x90\x83'
+ [E]=$'\xf0\x9d\x90\x84'
+ [F]=$'\xf0\x9d\x90\x85'
+ [G]=$'\xf0\x9d\x90\x86'
+ [H]=$'\xf0\x9d\x90\x87'
+ [I]=$'\xf0\x9d\x90\x88'
+ [J]=$'\xf0\x9d\x90\x89'
+ [K]=$'\xf0\x9d\x90\x8a'
+ [L]=$'\xf0\x9d\x90\x8b'
+ [M]=$'\xf0\x9d\x90\x8c'
+ [N]=$'\xf0\x9d\x90\x8d'
+ [O]=$'\xf0\x9d\x90\x8e'
+ [P]=$'\xf0\x9d\x90\x8f'
+ [Q]=$'\xf0\x9d\x90\x90'
+ [R]=$'\xf0\x9d\x90\x91'
+ [S]=$'\xf0\x9d\x90\x92'
+ [T]=$'\xf0\x9d\x90\x93'
+ [U]=$'\xf0\x9d\x90\x94'
+ [V]=$'\xf0\x9d\x90\x95'
+ [W]=$'\xf0\x9d\x90\x96'
+ [X]=$'\xf0\x9d\x90\x97'
+ [Y]=$'\xf0\x9d\x90\x98'
+ [Z]=$'\xf0\x9d\x90\x99'
+ [a]=$'\xf0\x9d\x90\x9a'
+ [b]=$'\xf0\x9d\x90\x9b'
+ [c]=$'\xf0\x9d\x90\x9c'
+ [d]=$'\xf0\x9d\x90\x9d'
+ [e]=$'\xf0\x9d\x90\x9e'
+ [f]=$'\xf0\x9d\x90\x9f'
+ [g]=$'\xf0\x9d\x90\xa0'
+ [h]=$'\xf0\x9d\x90\xa1'
+ [i]=$'\xf0\x9d\x90\xa2'
+ [j]=$'\xf0\x9d\x90\xa3'
+ [k]=$'\xf0\x9d\x90\xa4'
+ [l]=$'\xf0\x9d\x90\xa5'
+ [m]=$'\xf0\x9d\x90\xa6'
+ [n]=$'\xf0\x9d\x90\xa7'
+ [o]=$'\xf0\x9d\x90\xa8'
+ [p]=$'\xf0\x9d\x90\xa9'
+ [q]=$'\xf0\x9d\x90\xaa'
+ [r]=$'\xf0\x9d\x90\xab'
+ [s]=$'\xf0\x9d\x90\xac'
+ [t]=$'\xf0\x9d\x90\xad'
+ [u]=$'\xf0\x9d\x90\xae'
+ [v]=$'\xf0\x9d\x90\xaf'
+ [w]=$'\xf0\x9d\x90\xb0'
+ [x]=$'\xf0\x9d\x90\xb1'
+ [y]=$'\xf0\x9d\x90\xb2'
+ [z]=$'\xf0\x9d\x90\xb3'
+ [Α]=$'\xf0\x9d\x9a\xa8'
+ [Β]=$'\xf0\x9d\x9a\xa9'
+ [Γ]=$'\xf0\x9d\x9a\xaa'
+ [Δ]=$'\xf0\x9d\x9a\xab'
+ [Ε]=$'\xf0\x9d\x9a\xac'
+ [Ζ]=$'\xf0\x9d\x9a\xad'
+ [Η]=$'\xf0\x9d\x9a\xae'
+ [Θ]=$'\xf0\x9d\x9a\xaf'
+ [Ι]=$'\xf0\x9d\x9a\xb0'
+ [Κ]=$'\xf0\x9d\x9a\xb1'
+ [Λ]=$'\xf0\x9d\x9a\xb2'
+ [Μ]=$'\xf0\x9d\x9a\xb3'
+ [Ν]=$'\xf0\x9d\x9a\xb4'
+ [Ξ]=$'\xf0\x9d\x9a\xb5'
+ [Ο]=$'\xf0\x9d\x9a\xb6'
+ [Π]=$'\xf0\x9d\x9a\xb7'
+ [Ρ]=$'\xf0\x9d\x9a\xb8'
+ [Σ]=$'\xf0\x9d\x9a\xba'
+ [Τ]=$'\xf0\x9d\x9a\xbb'
+ [Υ]=$'\xf0\x9d\x9a\xbc'
+ [Φ]=$'\xf0\x9d\x9a\xbd'
+ [Χ]=$'\xf0\x9d\x9a\xbe'
+ [Ψ]=$'\xf0\x9d\x9a\xbf'
+ [Ω]=$'\xf0\x9d\x9b\x80'
+ [α]=$'\xf0\x9d\x9b\x82'
+ [β]=$'\xf0\x9d\x9b\x83'
+ [γ]=$'\xf0\x9d\x9b\x84'
+ [δ]=$'\xf0\x9d\x9b\x85'
+ [ε]=$'\xf0\x9d\x9b\x86'
+ [ζ]=$'\xf0\x9d\x9b\x87'
+ [η]=$'\xf0\x9d\x9b\x88'
+ [θ]=$'\xf0\x9d\x9b\x89'
+ [ι]=$'\xf0\x9d\x9b\x8a'
+ [κ]=$'\xf0\x9d\x9b\x8b'
+ [λ]=$'\xf0\x9d\x9b\x8c'
+ [μ]=$'\xf0\x9d\x9b\x8d'
+ [ν]=$'\xf0\x9d\x9b\x8e'
+ [ξ]=$'\xf0\x9d\x9b\x8f'
+ [ο]=$'\xf0\x9d\x9b\x90'
+ [π]=$'\xf0\x9d\x9b\x91'
+ [ρ]=$'\xf0\x9d\x9b\x92'
+ [ς]=$'\xf0\x9d\x9b\x93'
+ [σ]=$'\xf0\x9d\x9b\x94'
+ [τ]=$'\xf0\x9d\x9b\x95'
+ [υ]=$'\xf0\x9d\x9b\x96'
+ [φ]=$'\xf0\x9d\x9b\x97'
+ [χ]=$'\xf0\x9d\x9b\x98'
+ [ψ]=$'\xf0\x9d\x9b\x99'
+ [ω]=$'\xf0\x9d\x9b\x9a'
+# [𝐴̱]=
+# [𝐵̱]=
+# [𝐶̱]=
+# [𝐷̱]=
+# [𝐸̱]=
+# [𝐹̱]=
+# [𝐺̱]=
+# [𝐻̱]=
+# [𝐼̱]=
+# [𝐽̱]=
+# [𝐾̱]=
+# [𝐿̱]=
+# [𝑀̱]=
+# [𝑁̱]=
+# [𝑂̱]=
+# [𝑃̱]=
+# [𝑄̱]=
+# [𝑅̱]=
+# [𝑆̱]=
+# [𝑇̱]=
+# [𝑈̱]=
+# [𝑉̱]=
+# [𝑊̱]=
+# [𝑋̱]=
+# [𝑌̱]=
+# [𝑍̱]=
+# [𝑎̱]=
+# [𝑏̱]=
+# [𝑐̱]=
+# [𝑑̱]=
+# [𝑒̱]=
+# [𝑓̱]=
+# [𝑔̱]=
+# [𝘩̱]=
+# [𝑖̱]=
+# [𝑗̱]=
+# [𝑘̱]=
+# [𝑙̱]=
+# [𝑚̱]=
+# [𝑛̱]=
+# [𝑜̱]=
+# [𝑝̱]=
+# [𝑞̱]=
+# [𝑟̱]=
+# [𝑠̱]=
+# [𝑡̱]=
+# [𝑢̱]=
+# [𝑣̱]=
+# [𝑤̱]=
+# [𝑥̱]=
+# [𝑦̱]=
+# [𝑧]=
+ [𝟢]=$'\xf0\x9d\x9f\xac'
+ [𝟣]=$'\xf0\x9d\x9f\xad'
+ [𝟤]=$'\xf0\x9d\x9f\xae'
+ [𝟥]=$'\xf0\x9d\x9f\xaf'
+ [𝟦]=$'\xf0\x9d\x9f\xb0'
+ [𝟧]=$'\xf0\x9d\x9f\xb1'
+ [𝟨]=$'\xf0\x9d\x9f\xb2'
+ [𝟩]=$'\xf0\x9d\x9f\xb3'
+ [𝟪]=$'\xf0\x9d\x9f\xb4'
+ [𝟫]=$'\xf0\x9d\x9f\xb5'
+)
+
+declare -A italic=(
+ [A]=$'\xf0\x9d\x90\xb4'
+ [B]=$'\xf0\x9d\x90\xb5'
+ [C]=$'\xf0\x9d\x90\xb6'
+ [D]=$'\xf0\x9d\x90\xb7'
+ [E]=$'\xf0\x9d\x90\xb8'
+ [F]=$'\xf0\x9d\x90\xb9'
+ [G]=$'\xf0\x9d\x90\xba'
+ [H]=$'\xf0\x9d\x90\xbb'
+ [I]=$'\xf0\x9d\x90\xbc'
+ [J]=$'\xf0\x9d\x90\xbd'
+ [K]=$'\xf0\x9d\x90\xbe'
+ [L]=$'\xf0\x9d\x90\xbf'
+ [M]=$'\xf0\x9d\x91\x80'
+ [N]=$'\xf0\x9d\x91\x81'
+ [O]=$'\xf0\x9d\x91\x82'
+ [P]=$'\xf0\x9d\x91\x83'
+ [Q]=$'\xf0\x9d\x91\x84'
+ [R]=$'\xf0\x9d\x91\x85'
+ [S]=$'\xf0\x9d\x91\x86'
+ [T]=$'\xf0\x9d\x91\x87'
+ [U]=$'\xf0\x9d\x91\x88'
+ [V]=$'\xf0\x9d\x91\x89'
+ [W]=$'\xf0\x9d\x91\x8a'
+ [X]=$'\xf0\x9d\x91\x8b'
+ [Y]=$'\xf0\x9d\x91\x8c'
+ [Z]=$'\xf0\x9d\x91\x8d'
+ [a]=$'\xf0\x9d\x91\x8e'
+ [b]=$'\xf0\x9d\x91\x8f'
+ [c]=$'\xf0\x9d\x91\x90'
+ [d]=$'\xf0\x9d\x91\x91'
+ [e]=$'\xf0\x9d\x91\x92'
+ [f]=$'\xf0\x9d\x91\x93'
+ [g]=$'\xf0\x9d\x91\x94'
+ [h]=$'\xf0\x9d\x98\xa9' # Sans-serif, because f0 9d 91 95 is not assigned.
+ [i]=$'\xf0\x9d\x91\x96'
+ [j]=$'\xf0\x9d\x91\x97'
+ [k]=$'\xf0\x9d\x91\x98'
+ [l]=$'\xf0\x9d\x91\x99'
+ [m]=$'\xf0\x9d\x91\x9a'
+ [n]=$'\xf0\x9d\x91\x9b'
+ [o]=$'\xf0\x9d\x91\x9c'
+ [p]=$'\xf0\x9d\x91\x9d'
+ [q]=$'\xf0\x9d\x91\x9e'
+ [r]=$'\xf0\x9d\x91\x9f'
+ [s]=$'\xf0\x9d\x91\xa0'
+ [t]=$'\xf0\x9d\x91\xa1'
+ [u]=$'\xf0\x9d\x91\xa2'
+ [v]=$'\xf0\x9d\x91\xa3'
+ [w]=$'\xf0\x9d\x91\xa4'
+ [x]=$'\xf0\x9d\x91\xa5'
+ [y]=$'\xf0\x9d\x91\xa6'
+ [z]=$'\xf0\x9d\x91\xa7'
+ [Α]=$'\xf0\x9d\x9b\xa2'
+ [Β]=$'\xf0\x9d\x9b\xa3'
+ [Γ]=$'\xf0\x9d\x9b\xa4'
+ [Δ]=$'\xf0\x9d\x9b\xa5'
+ [Ε]=$'\xf0\x9d\x9b\xa6'
+ [Ζ]=$'\xf0\x9d\x9b\xa7'
+ [Η]=$'\xf0\x9d\x9b\xa8'
+ [Θ]=$'\xf0\x9d\x9b\xa9'
+ [Ι]=$'\xf0\x9d\x9b\xaa'
+ [Κ]=$'\xf0\x9d\x9b\xab'
+ [Λ]=$'\xf0\x9d\x9b\xac'
+ [Μ]=$'\xf0\x9d\x9b\xad'
+ [Ν]=$'\xf0\x9d\x9b\xae'
+ [Ξ]=$'\xf0\x9d\x9b\xaf'
+ [Ο]=$'\xf0\x9d\x9b\xb0'
+ [Π]=$'\xf0\x9d\x9b\xb1'
+ [Ρ]=$'\xf0\x9d\x9b\xb2'
+ [Σ]=$'\xf0\x9d\x9b\xb4'
+ [Τ]=$'\xf0\x9d\x9b\xb5'
+ [Υ]=$'\xf0\x9d\x9b\xb6'
+ [Φ]=$'\xf0\x9d\x9b\xb7'
+ [Χ]=$'\xf0\x9d\x9b\xb8'
+ [Ψ]=$'\xf0\x9d\x9b\xb9'
+ [Ω]=$'\xf0\x9d\x9b\xba'
+ [α]=$'\xf0\x9d\x9b\xbc'
+ [β]=$'\xf0\x9d\x9b\xbd'
+ [γ]=$'\xf0\x9d\x9b\xbe'
+ [δ]=$'\xf0\x9d\x9b\xbf'
+ [ε]=$'\xf0\x9d\x9c\x80'
+ [ζ]=$'\xf0\x9d\x9c\x81'
+ [η]=$'\xf0\x9d\x9c\x82'
+ [θ]=$'\xf0\x9d\x9c\x83'
+ [ι]=$'\xf0\x9d\x9c\x84'
+ [κ]=$'\xf0\x9d\x9c\x85'
+ [λ]=$'\xf0\x9d\x9c\x86'
+ [μ]=$'\xf0\x9d\x9c\x87'
+ [ν]=$'\xf0\x9d\x9c\x88'
+ [ξ]=$'\xf0\x9d\x9c\x89'
+ [ο]=$'\xf0\x9d\x9c\x8a'
+ [π]=$'\xf0\x9d\x9c\x8b'
+ [ρ]=$'\xf0\x9d\x9c\x8c'
+ [ς]=$'\xf0\x9d\x9c\x8d'
+ [σ]=$'\xf0\x9d\x9c\x8e'
+ [τ]=$'\xf0\x9d\x9c\x8f'
+ [υ]=$'\xf0\x9d\x9c\x90'
+ [φ]=$'\xf0\x9d\x9c\x91'
+ [χ]=$'\xf0\x9d\x9c\x92'
+ [ψ]=$'\xf0\x9d\x9c\x93'
+ [ω]=$'\xf0\x9d\x9c\x94'
+# [𝐀̱]=
+# [𝐁̱]=
+# [𝐂̱]=
+# [𝐃̱]=
+# [𝐄̱]=
+# [𝐅̱]=
+# [𝐆̱]=
+# [𝐇̱]=
+# [𝐈̱]=
+# [𝐉̱]=
+# [𝐊̱]=
+# [𝐋̱]=
+# [𝐌̱]=
+# [𝐍̱]=
+# [𝐎̱]=
+# [𝐏̱]=
+# [𝐐̱]=
+# [𝐑̱]=
+# [𝐒̱]=
+# [𝐓̱]=
+# [𝐔̱]=
+# [𝐕̱]=
+# [𝐖̱]=
+# [𝐗̱]=
+# [𝐘̱]=
+# [𝐙̱]=
+# [𝐚̱]=
+# [𝐛̱]=
+# [𝐜̱]=
+# [𝐝̱]=
+# [𝐞̱]=
+# [𝐟̱]=
+# [𝐠̱]=
+# [𝐡̱]=
+# [𝐢̱]=
+# [𝐣̱]=
+# [𝐤̱]=
+# [𝐥̱]=
+# [𝐦̱]=
+# [𝐧̱]=
+# [𝐨̱]=
+# [𝐩̱]=
+# [𝐪̱]=
+# [𝐫̱]=
+# [𝐬̱]=
+# [𝐭̱]=
+# [𝐮̱]=
+# [𝐯̱]=
+# [𝐰̱]=
+# [𝐱̱]=
+# [𝐲̱]=
+# [𝐳]=
+)
+
+# case $0 in embolden) italicise) script) fracture) double-strike) sans-serif) monospace) stretch) loop) mathise)
+
+while IFS= read -r line
+do for i in $(seq 0 $((${#line}-1)))
+ do
+ c1=${line:$i:1}
+ # if [[ ${bold[$c1]} ]]
+ if [[ $c1 =~ [0-9a-zA-Zα-ωΑ-Ω𝐴̱-𝑍̱𝑎̱-𝑧] ]]
+ then replacement+=${bold[$c1]}
+ else replacement+=$'\u0331'$c1
+ fi
+ done
+ echo "$replacement"
+done
diff --git a/bin/giteval b/bin/giteval
new file mode 100755
index 0000000..48d35a8
--- /dev/null
+++ b/bin/giteval
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+b=$(git branch --show-current 2> /dev/null) && {
+ case $(env - git status --no-ahead-behind | tail -n1) in
+ 'nothing to commit'*)
+ printf '\[\e[32m\][%s]\[\e[0m\]' "$b"
+ ;; 'no changes added to commit'*)
+ printf '\[\e[33m\][%s]\[\e[0m\]' "$b"
+ ;; 'nothing added to commit'*)
+ printf '\[\e[36m\][%s]\[\e[0m\]' "$b"
+ ;; *)
+ printf '\[\e[31m\][%s]\[\e[0m\]' "$b"
+ esac
+}
+echo
diff --git a/bin/italicise b/bin/italicise
new file mode 100755
index 0000000..d9fcb57
--- /dev/null
+++ b/bin/italicise
@@ -0,0 +1,269 @@
+#!/bin/bash
+
+
+# For bold and italic we can use the Mathematical font variant mappings,
+# although those are only defined for Latin and Greek.
+# Latin letter small capital a: UTF-8: e1 b4 80 UTF-16BE: 1d00 Decimal: &#7424; Octal: \016400
+# Latin bold capital: u1d400 - u1d419
+# Latin bold small: u1d41a - u1d433
+# Latin italic capital: u1d434 - u1d44d
+# Latin italic small: u1d44e - u1d467
+# Latin bold italic capital: u1d468 - u1d481
+# Latin bold italic small: u1d482 - u1d49b
+# (Script capital, script small, bold script capital, bold script small)
+# (Fraktur capital, fraktur small)
+# (Double-struck capital, double-struck small)
+# (some Hebrew symbol variants)
+# (Bold fraktur capital, bold fraktur small)
+# (Sans-serif capital, sans-serif small)
+# (Sans-serif bold capital, sans-serif bold small)
+# (Sans-serif italic capital, sans-serif italic small)
+# (Sans-serif bold italic capital, sans-serif bold italic small)
+# (Monospace capital, monospace small)
+# Greek bold capital: u1d6a8 - u1d6c0
+# Greek bold small: u1d6c2 - u1d6da
+# Greek italic capital: u1d6e2 - u1d6fa
+# Greek italic small: u1dcfc - u1d714
+# Greek bold italic capital: u1d71c - u1d734
+# Greek bold italic small: u1d736 - u1d74e
+# (Greek sans-serif bold capital: u1d756 - u1d76e)
+# (Greek sans-serif bold small: u1d770 - u1d788)
+# (Greek sans-serif bold italic capital: u1d790 - u1d7a8)
+# (Greek sans-serif bold italic small: u1d7aa - u1d7c2)
+# bold digits: u1d7ce - u1d7d7
+# (double-struck digits)
+# (sans-serif digits)
+# (sans-serif bold digits)
+# (monospace digits)
+# (Arabic mathematical)
+# (Arabic stretched)
+# (Arabic looped)
+# (Arabic double-struck)
+#
+# It turns out there are no Unicode control codes for marking text
+# bold or italic. There are for subscript and superscript,
+# and ASCII has similar codes which nobody ever uses.
+
+declare -A bold=(
+ [A]=$'\xf0\x9d\x90\x80'
+ [B]=$'\xf0\x9d\x90\x81'
+ [C]=$'\xf0\x9d\x90\x82'
+ [D]=$'\xf0\x9d\x90\x83'
+ [E]=$'\xf0\x9d\x90\x84'
+ [F]=$'\xf0\x9d\x90\x85'
+ [G]=$'\xf0\x9d\x90\x86'
+ [H]=$'\xf0\x9d\x90\x87'
+ [I]=$'\xf0\x9d\x90\x88'
+ [J]=$'\xf0\x9d\x90\x89'
+ [K]=$'\xf0\x9d\x90\x8a'
+ [L]=$'\xf0\x9d\x90\x8b'
+ [M]=$'\xf0\x9d\x90\x8c'
+ [N]=$'\xf0\x9d\x90\x8d'
+ [O]=$'\xf0\x9d\x90\x8e'
+ [P]=$'\xf0\x9d\x90\x8f'
+ [Q]=$'\xf0\x9d\x90\x90'
+ [R]=$'\xf0\x9d\x90\x91'
+ [S]=$'\xf0\x9d\x90\x92'
+ [T]=$'\xf0\x9d\x90\x93'
+ [U]=$'\xf0\x9d\x90\x94'
+ [V]=$'\xf0\x9d\x90\x95'
+ [W]=$'\xf0\x9d\x90\x96'
+ [X]=$'\xf0\x9d\x90\x97'
+ [Y]=$'\xf0\x9d\x90\x98'
+ [Z]=$'\xf0\x9d\x90\x99'
+ [a]=$'\xf0\x9d\x90\x9a'
+ [b]=$'\xf0\x9d\x90\x9b'
+ [c]=$'\xf0\x9d\x90\x9c'
+ [d]=$'\xf0\x9d\x90\x9d'
+ [e]=$'\xf0\x9d\x90\x9e'
+ [f]=$'\xf0\x9d\x90\x9f'
+ [g]=$'\xf0\x9d\x90\xa0'
+ [h]=$'\xf0\x9d\x90\xa1'
+ [i]=$'\xf0\x9d\x90\xa2'
+ [j]=$'\xf0\x9d\x90\xa3'
+ [k]=$'\xf0\x9d\x90\xa4'
+ [l]=$'\xf0\x9d\x90\xa5'
+ [m]=$'\xf0\x9d\x90\xa6'
+ [n]=$'\xf0\x9d\x90\xa7'
+ [o]=$'\xf0\x9d\x90\xa8'
+ [p]=$'\xf0\x9d\x90\xa9'
+ [q]=$'\xf0\x9d\x90\xaa'
+ [r]=$'\xf0\x9d\x90\xab'
+ [s]=$'\xf0\x9d\x90\xac'
+ [t]=$'\xf0\x9d\x90\xad'
+ [u]=$'\xf0\x9d\x90\xae'
+ [v]=$'\xf0\x9d\x90\xaf'
+ [w]=$'\xf0\x9d\x90\xb0'
+ [x]=$'\xf0\x9d\x90\xb1'
+ [y]=$'\xf0\x9d\x90\xb2'
+ [z]=$'\xf0\x9d\x90\xb3'
+ [Α]=$'\xf0\x9d\x9a\xa8'
+ [Β]=$'\xf0\x9d\x9a\xa9'
+ [Γ]=$'\xf0\x9d\x9a\xaa'
+ [Δ]=$'\xf0\x9d\x9a\xab'
+ [Ε]=$'\xf0\x9d\x9a\xac'
+ [Ζ]=$'\xf0\x9d\x9a\xad'
+ [Η]=$'\xf0\x9d\x9a\xae'
+ [Θ]=$'\xf0\x9d\x9a\xaf'
+ [Ι]=$'\xf0\x9d\x9a\xb0'
+ [Κ]=$'\xf0\x9d\x9a\xb1'
+ [Λ]=$'\xf0\x9d\x9a\xb2'
+ [Μ]=$'\xf0\x9d\x9a\xb3'
+ [Ν]=$'\xf0\x9d\x9a\xb4'
+ [Ξ]=$'\xf0\x9d\x9a\xb5'
+ [Ο]=$'\xf0\x9d\x9a\xb6'
+ [Π]=$'\xf0\x9d\x9a\xb7'
+ [Ρ]=$'\xf0\x9d\x9a\xb8'
+ [Σ]=$'\xf0\x9d\x9a\xba'
+ [Τ]=$'\xf0\x9d\x9a\xbb'
+ [Υ]=$'\xf0\x9d\x9a\xbc'
+ [Φ]=$'\xf0\x9d\x9a\xbd'
+ [Χ]=$'\xf0\x9d\x9a\xbe'
+ [Ψ]=$'\xf0\x9d\x9a\xbf'
+ [Ω]=$'\xf0\x9d\x9b\x80'
+ [α]=$'\xf0\x9d\x9b\x82'
+ [β]=$'\xf0\x9d\x9b\x83'
+ [γ]=$'\xf0\x9d\x9b\x84'
+ [δ]=$'\xf0\x9d\x9b\x85'
+ [ε]=$'\xf0\x9d\x9b\x86'
+ [ζ]=$'\xf0\x9d\x9b\x87'
+ [η]=$'\xf0\x9d\x9b\x88'
+ [θ]=$'\xf0\x9d\x9b\x89'
+ [ι]=$'\xf0\x9d\x9b\x8a'
+ [κ]=$'\xf0\x9d\x9b\x8b'
+ [λ]=$'\xf0\x9d\x9b\x8c'
+ [μ]=$'\xf0\x9d\x9b\x8d'
+ [ν]=$'\xf0\x9d\x9b\x8e'
+ [ξ]=$'\xf0\x9d\x9b\x8f'
+ [ο]=$'\xf0\x9d\x9b\x90'
+ [π]=$'\xf0\x9d\x9b\x91'
+ [ρ]=$'\xf0\x9d\x9b\x92'
+ [ς]=$'\xf0\x9d\x9b\x93'
+ [σ]=$'\xf0\x9d\x9b\x94'
+ [τ]=$'\xf0\x9d\x9b\x95'
+ [υ]=$'\xf0\x9d\x9b\x96'
+ [φ]=$'\xf0\x9d\x9b\x97'
+ [χ]=$'\xf0\x9d\x9b\x98'
+ [ψ]=$'\xf0\x9d\x9b\x99'
+ [ω]=$'\xf0\x9d\x9b\x9a'
+)
+
+declare -A italic=(
+ [A]=$'\xf0\x9d\x90\xb4'
+ [B]=$'\xf0\x9d\x90\xb5'
+ [C]=$'\xf0\x9d\x90\xb6'
+ [D]=$'\xf0\x9d\x90\xb7'
+ [E]=$'\xf0\x9d\x90\xb8'
+ [F]=$'\xf0\x9d\x90\xb9'
+ [G]=$'\xf0\x9d\x90\xba'
+ [H]=$'\xf0\x9d\x90\xbb'
+ [I]=$'\xf0\x9d\x90\xbc'
+ [J]=$'\xf0\x9d\x90\xbd'
+ [K]=$'\xf0\x9d\x90\xbe'
+ [L]=$'\xf0\x9d\x90\xbf'
+ [M]=$'\xf0\x9d\x91\x80'
+ [N]=$'\xf0\x9d\x91\x81'
+ [O]=$'\xf0\x9d\x91\x82'
+ [P]=$'\xf0\x9d\x91\x83'
+ [Q]=$'\xf0\x9d\x91\x84'
+ [R]=$'\xf0\x9d\x91\x85'
+ [S]=$'\xf0\x9d\x91\x86'
+ [T]=$'\xf0\x9d\x91\x87'
+ [U]=$'\xf0\x9d\x91\x88'
+ [V]=$'\xf0\x9d\x91\x89'
+ [W]=$'\xf0\x9d\x91\x8a'
+ [X]=$'\xf0\x9d\x91\x8b'
+ [Y]=$'\xf0\x9d\x91\x8c'
+ [Z]=$'\xf0\x9d\x91\x8d'
+ [a]=$'\xf0\x9d\x91\x8e'
+ [b]=$'\xf0\x9d\x91\x8f'
+ [c]=$'\xf0\x9d\x91\x90'
+ [d]=$'\xf0\x9d\x91\x91'
+ [e]=$'\xf0\x9d\x91\x92'
+ [f]=$'\xf0\x9d\x91\x93'
+ [g]=$'\xf0\x9d\x91\x94'
+ [h]=$'\xf0\x9d\x98\xa9' # Sans-serif, because f0 9d 91 95 is not assigned.
+ [i]=$'\xf0\x9d\x91\x96'
+ [j]=$'\xf0\x9d\x91\x97'
+ [k]=$'\xf0\x9d\x91\x98'
+ [l]=$'\xf0\x9d\x91\x99'
+ [m]=$'\xf0\x9d\x91\x9a'
+ [n]=$'\xf0\x9d\x91\x9b'
+ [o]=$'\xf0\x9d\x91\x9c'
+ [p]=$'\xf0\x9d\x91\x9d'
+ [q]=$'\xf0\x9d\x91\x9e'
+ [r]=$'\xf0\x9d\x91\x9f'
+ [s]=$'\xf0\x9d\x91\xa0'
+ [t]=$'\xf0\x9d\x91\xa1'
+ [u]=$'\xf0\x9d\x91\xa2'
+ [v]=$'\xf0\x9d\x91\xa3'
+ [w]=$'\xf0\x9d\x91\xa4'
+ [x]=$'\xf0\x9d\x91\xa5'
+ [y]=$'\xf0\x9d\x91\xa6'
+ [z]=$'\xf0\x9d\x91\xa7'
+ [Α]=$'\xf0\x9d\x9b\xa2'
+ [Β]=$'\xf0\x9d\x9b\xa3'
+ [Γ]=$'\xf0\x9d\x9b\xa4'
+ [Δ]=$'\xf0\x9d\x9b\xa5'
+ [Ε]=$'\xf0\x9d\x9b\xa6'
+ [Ζ]=$'\xf0\x9d\x9b\xa7'
+ [Η]=$'\xf0\x9d\x9b\xa8'
+ [Θ]=$'\xf0\x9d\x9b\xa9'
+ [Ι]=$'\xf0\x9d\x9b\xaa'
+ [Κ]=$'\xf0\x9d\x9b\xab'
+ [Λ]=$'\xf0\x9d\x9b\xac'
+ [Μ]=$'\xf0\x9d\x9b\xad'
+ [Ν]=$'\xf0\x9d\x9b\xae'
+ [Ξ]=$'\xf0\x9d\x9b\xaf'
+ [Ο]=$'\xf0\x9d\x9b\xb0'
+ [Π]=$'\xf0\x9d\x9b\xb1'
+ [Ρ]=$'\xf0\x9d\x9b\xb2'
+ [Σ]=$'\xf0\x9d\x9b\xb4'
+ [Τ]=$'\xf0\x9d\x9b\xb5'
+ [Υ]=$'\xf0\x9d\x9b\xb6'
+ [Φ]=$'\xf0\x9d\x9b\xb7'
+ [Χ]=$'\xf0\x9d\x9b\xb8'
+ [Ψ]=$'\xf0\x9d\x9b\xb9'
+ [Ω]=$'\xf0\x9d\x9b\xba'
+ [α]=$'\xf0\x9d\x9b\xbc'
+ [β]=$'\xf0\x9d\x9b\xbd'
+ [γ]=$'\xf0\x9d\x9b\xbe'
+ [δ]=$'\xf0\x9d\x9b\xbf'
+ [ε]=$'\xf0\x9d\x9c\x80'
+ [ζ]=$'\xf0\x9d\x9c\x81'
+ [η]=$'\xf0\x9d\x9c\x82'
+ [θ]=$'\xf0\x9d\x9c\x83'
+ [ι]=$'\xf0\x9d\x9c\x84'
+ [κ]=$'\xf0\x9d\x9c\x85'
+ [λ]=$'\xf0\x9d\x9c\x86'
+ [μ]=$'\xf0\x9d\x9c\x87'
+ [ν]=$'\xf0\x9d\x9c\x88'
+ [ξ]=$'\xf0\x9d\x9c\x89'
+ [ο]=$'\xf0\x9d\x9c\x8a'
+ [π]=$'\xf0\x9d\x9c\x8b'
+ [ρ]=$'\xf0\x9d\x9c\x8c'
+ [ς]=$'\xf0\x9d\x9c\x8d'
+ [σ]=$'\xf0\x9d\x9c\x8e'
+ [τ]=$'\xf0\x9d\x9c\x8f'
+ [υ]=$'\xf0\x9d\x9c\x90'
+ [φ]=$'\xf0\x9d\x9c\x91'
+ [χ]=$'\xf0\x9d\x9c\x92'
+ [ψ]=$'\xf0\x9d\x9c\x93'
+ [ω]=$'\xf0\x9d\x9c\x94'
+)
+
+# TODO: bold italics.
+
+while IFS= read -r line
+do
+ replacement=""
+ for i in $(seq 0 "$((${#line}-1))")
+ do
+ c1=${line:$i:1}
+ if [[ $c1 =~ [a-zA-Zα-ωΑ-Ω] ]]
+ then replacement+=${italic[$c1]}
+ else replacement+=$'\u0331'$c1
+ fi
+ done
+ echo "$replacement"
+done
diff --git a/bin/map b/bin/map
new file mode 100755
index 0000000..ec514ad
--- /dev/null
+++ b/bin/map
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+fn=$1
+if [[ "$fn" = *\$1* ]]
+then f(){ eval "$fn";}
+else f(){ eval "$fn" "$1";}
+fi
+shift
+for x in "$@"
+do f "$x"
+done
diff --git a/bin/map-db b/bin/map-db
new file mode 100755
index 0000000..feb528c
--- /dev/null
+++ b/bin/map-db
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+query(){
+# psql-gridware -A -F$'\t' -t -P pager=off -c "$@"
+# psql-gridware -A -F$'\t' -P pager=off -P title=off -c "$@"
+ psql-gridware -A -F$'\t' -P pager=off -c "$@"
+}
+
+exec {in}<&0
+
+pforkey(){
+ echo '</TABLE>>]'
+ open_table=0
+ data=forkey
+}
+forkey(){
+ # ${constraint name} FOREIGN KEY (${Column}) REFERENCES ${table}(${Column})
+ read -ra line <<<"$Column"
+ this_column=${line[3]%)}
+ this_column=${this_column#(}
+ other_table=${line[5]%%(*}
+ other_column=${line[5]##*\(}
+ other_column=${other_column%)}
+ printf '%s:%s_out -> %s:%s_in\n' "$table" "$this_column" "$other_table" "$other_column"
+}
+
+record(){
+ if [[ $Nullable = 'not null' ]]
+ then
+ echo "<TR><TD PORT=\"${Column}_in\"><U>$Column</U></TD><TD PORT=\"${Column}_out\">$Type</TD></TR>"
+ else
+ echo "<TR><TD PORT=\"${Column}_in\">$Column</TD><TD PORT=\"${Column}_out\">$Type</TD></TR>"
+ fi
+}
+
+echo 'strict digraph db {'
+echo 'node[shape=plain]'
+query '\d' -t | cut -f 2,3 | grep table\$ | cut -f1 | while read -r table
+do
+ printf '\e[1m%s\e[0m\n' "$table" >&2
+ data=record
+ open_table=1
+ echo
+ echo "$table [label=<<TABLE BORDER=\"0\"><TR><TD COLSPAN=\"2\">\\N</TD></TR>"
+ echo '<HR/>'
+ while IFS=$'\t' read -r Column Type Collation Nullable Default
+ do
+ case $Column in
+ Foreign-key\ constraints:)
+ echo >&2 'foreign keys'
+ data=pforkey
+ ;; *:)
+ echo >&2 '… skipping '"$Column"
+ data=:
+ esac
+ $data
+ done < <(query '\d '"$table" <&${in} | tail -n+3 | tr -d $'\r')
+ [[ $open_table = 1 ]] && echo '</TABLE>>]'
+done
+echo '}'
diff --git a/bin/pf b/bin/pf
new file mode 100755
index 0000000..0358689
--- /dev/null
+++ b/bin/pf
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+set -ue
+
+get_parent () {
+ ps hoppid p$1
+}
+
+get_children () {
+ ps hopid --ppid "$1"
+}
+
+get_ancestors () {
+ case $1 in
+ 0|1|'') :
+ ;; *) get_ancestors $(get_parent $1)
+ esac
+ echo "$1"
+}
+
+get_descendents () {
+ for c in $(get_children "$1")
+ do echo "$c"
+ get_descendents "$c"
+ done
+}
+
+declare -i p
+for p in "$@"
+do
+ [[ $p -ne 0 ]] && {
+ get_ancestors "$p"
+ get_descendents "$p"
+ } | {
+ readarray -t pids
+ ps -Hf "${pids[@]}" | sed "/^[^ ]* *$p /s/.*/&/"
+ }
+done
diff --git a/bin/pivot b/bin/pivot
new file mode 100755
index 0000000..3c750f2
--- /dev/null
+++ b/bin/pivot
@@ -0,0 +1,11 @@
+#!/usr/bin/awk -f
+
+{
+ split ($0, _columns, "\t")
+ for (i=0;i<length(_columns);++i) {
+ columns[i] = columns[i] "\t" _columns[i]
+} }
+END {
+ for (i=0;i<length(columns);++i) {
+ print substr(columns[i],2)
+} }
diff --git a/bin/radix b/bin/radix
new file mode 100755
index 0000000..670107d
--- /dev/null
+++ b/bin/radix
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+# bc -q <<<"obase=$1;$2"
+
+set -eu
+
+if [[ $# -eq 0 ]] || [[ $# -gt 2 ]]
+then
+ cat >&2 <<-HERE
+ usage: $0 radix decimal
+ HERE
+ exit
+fi
+
+declare -i radix=$1
+declare -i decimal=$2
+
+[[ radix -gt 0 ]] || exit 1
+
+if [[ $decimal -lt 0 ]]
+then
+ printf -- -
+ decimal=-$decimal
+fi
+
+if [[ $radix -eq 12 ]]
+then digits=({0..9} ↊ ↋)
+else digits=({0..9} {a..z})
+fi
+number=''
+
+while [[ $decimal -gt 0 ]]
+do
+ digit=$((decimal%radix))
+ number=${digits[$digit]}$number
+# decimal=$((decimal-(digit*radix)))
+ decimal=$((decimal/radix))
+done
+echo "$number"
diff --git a/bin/reduce b/bin/reduce
new file mode 100755
index 0000000..b9b69fe
--- /dev/null
+++ b/bin/reduce
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+fn=$1
+f() { eval "$fn" "$@"; }
+a=$2
+b=$3
+shift 3
+[[ -z "$b" ]] && exec echo "$a"
+exec "$0" "$fn" "$(f "$a" "$b")" "${@@Q}"
diff --git a/bin/spt b/bin/spt
new file mode 100755
index 0000000..e237d93
--- /dev/null
+++ b/bin/spt
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+###
+# Single pass tabulate.
+#
+# Turn grid-aligned tables into tab-separated values
+# using the first line as a template.
+# Pre-existing tabs are preserved,
+# which is probably not good.
+##
+# TODO:
+# - Optionally require more than one space for column separation.
+
+shopt -s extglob
+
+spitline(){
+ declare -i prevtab=0
+ for tabstop in ${tabstops[@]}
+ do
+ # Strip trailing spaces.
+ field=${line:$prevtab:$((tabstop-prevtab))}
+ field=${field%%*( )}
+ printf '%s\t' "$field"
+ prevtab=$tabstop
+ done
+ printf '%s\n' "${line:$prevtab}"
+}
+
+##
+# First line:
+##
+# The tab stops are where stretches of empty space end.
+IFS=$'\n'
+read -r firstline
+declare -i skip=1
+for ((i=0;i<${#firstline};i++))
+do
+ case ${firstline:$i:1} in
+ \ )
+ skip=0
+ ;; *)
+ [[ $skip -eq 0 ]] && tabstops+=($i)
+ skip=1
+ esac
+done
+#echo >&2 ${tabstops[@]}
+line=$firstline
+spitline
+
+##
+# All other lines:
+declare -i prevtab
+while read -r line
+do spitline
+done
diff --git a/bin/strjoin b/bin/strjoin
new file mode 100755
index 0000000..83b2a9c
--- /dev/null
+++ b/bin/strjoin
@@ -0,0 +1,6 @@
+#!/bin/sh
+sep=$1
+shift
+printf '%s' "$1"
+shift
+printf "$sep"'%s' "$@"
diff --git a/bin/sum-down b/bin/sum-down
new file mode 100644
index 0000000..49717ea
--- /dev/null
+++ b/bin/sum-down
@@ -0,0 +1,14 @@
+#!/usr/bin/awk -E
+
+{ split($0, _columns, "\t")
+ for(i in _columns){
+ columns[i] += _columns[i]
+ }
+}
+END {
+ output=columns[0]
+ for(i in columns){
+ output = output "\t" columns[i]
+ }
+ print output
+}
diff --git a/bin/sum-up b/bin/sum-up
new file mode 100755
index 0000000..1d035d7
--- /dev/null
+++ b/bin/sum-up
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+#sed 's/\t/ + /g'| bc -q
+sed 's/\t/ + /g'| python3 -qqIi 2> /dev/null
diff --git a/bin/xmlbrowser b/bin/xmlbrowser
new file mode 100755
index 0000000..731b466
--- /dev/null
+++ b/bin/xmlbrowser
@@ -0,0 +1,39 @@
+#!/usr/bin/python3
+
+import sys
+import xml.etree.ElementTree as ET
+
+from qtpy import QtGui, QtWidgets, QtCore
+from qtpy.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem, QLabel
+
+def _make_item(element) -> QTreeWidgetItem:
+ r = QTreeWidgetItem([element.tag, None, element.text])
+ r.addChildren([QTreeWidgetItem([None, name, value]) for name, value in element.attrib.items()])
+ r.addChildren([_make_item(child) for child in element])
+ return r
+
+def main():
+ app = QApplication(sys.argv)
+ # TODO: Check for suitable arguments first.
+ # Parameter may be a Qt option.
+ if len(sys.argv) == 1:
+ print("Usage:", sys.argv[0], "[file …]", file=sys.stderr)
+ return
+
+ items = []
+ for arg in sys.argv[1:]:
+ with open(arg) as xmlfile:
+ xmltree = ET.parse(xmlfile)
+ fileItem = QTreeWidgetItem([arg])
+ items.append(fileItem)
+ fileItem.addChildren([_make_item(xmltree.getroot())])
+
+ tree = QTreeWidget()
+ tree.setColumnCount(2)
+ tree.setHeaderLabels(["Element", "attribute", "text"])
+ tree.insertTopLevelItems(0, items)
+ tree.show()
+ sys.exit(app.exec_()) # Main loop.
+
+if __name__ == '__main__':
+ main()
diff --git a/bin/yamlbrowser b/bin/yamlbrowser
new file mode 100755
index 0000000..92068b4
--- /dev/null
+++ b/bin/yamlbrowser
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+
+import sys
+import yaml
+from qtpy import QtGui, QtWidgets, QtCore
+from qtpy.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem, QLabel
+
+def _make_children (parent:QTreeWidgetItem, d) -> QTreeWidgetItem:
+ """
+ If the item is a container item, i.e. list or dict,
+ its contents are added as children to the parent.
+
+ If the item is not a container item,
+ it becomes the value to its parent.
+ """
+ def transform_l (p:QTreeWidgetItem, d:list) -> QTreeWidgetItem:
+ p.addChildren (_make_children (QTreeWidgetItem (), x) for x in d)
+ return p
+ def transform_d (p:QTreeWidgetItem, d:dict) -> QTreeWidgetItem:
+ p.addChildren (_make_children (QTreeWidgetItem ([key]), value) for key, value in d.items ())
+ return p
+ return {
+ list: lambda p, d : transform_l (p, d)
+ , dict: lambda p, d : transform_d (p, d)
+ , str: lambda p, d : QTreeWidgetItem ([p.text (0), d])
+ , int: lambda p, d : QTreeWidgetItem ([p.text (0), str(d)])
+ , float: lambda p, d : QTreeWidgetItem ([p.text (0), str(d)])
+ , bool: lambda p, d : QTreeWidgetItem ([p.text (0), str(d)])
+ , type(None): lambda p, d : QTreeWidgetItem ([p.text (0), str(d)])
+ }[type (d)] (parent, d)
+
+def main ():
+ app = QApplication (sys.argv)
+ # TODO: Check for suitable arguments first.
+ # Parameter may be a Qt option.
+ if len (sys.argv) == 1:
+ print ("Usage:", sys.argv[0], "[file …]", file=sys.stderr)
+ return
+ try:
+ items = []
+ for arg in sys.argv[1:]:
+ with open (arg) as file:
+ data = list (yaml.safe_load_all (file))
+ items.append (_make_children (QTreeWidgetItem ([arg]), data[0] if len (data) == 1 else data))
+
+ tree = QTreeWidget ()
+ tree.setColumnCount (2)
+ tree.setHeaderLabels (["Key", "Value"])
+ tree.insertTopLevelItems(0, items)
+ tree.show ()
+ except Exception as x:
+ print (x, file=sys.stderr)
+ label = QtWidgets.QLabel (str(x))
+ label.show () # Opens window.
+ sys.exit (app.exec_()) # Main loop. Display the label.
+
+if __name__=='__main__':
+ main ()