Syntax highlighting in pagers (eg. like less) using GNU source-highlight
Mar 21st, 2021 by miki

There is this nifty OS project, GNU, which has this nifty piece of software for syntax highlighting, source-highlight (aka. src-highlite), together with which is distributed this nifty shell script,, meant for piping arbitrary text through the highlighter selecting and applying a sensible highlight language definition, before being paged in some nifty pager which is able to interpret ANSI escape codes (ISO/IEC 6429 or ECMA-48, previously ANSI X3.64/FIPS PUB 86) like fx. the nifty and ubiquitous less.

Sadly, even after having installed less and source-highlight on modern Ubuntu and Debian systems they are not inter-operating by default. You’d have to feel the itch of syntax highlighting, discover source-highlight and dig its documentation to find out about said script.

TL;DR – quick and simple setup

Below is a quick two-line shell HOW-TO which sets up environment variables for the current user to enable auto-detection of language and subsequent syntax highlighting pr. default in less using GNU source-highlight (here done on Ubuntu 20.04 LTS, should behave similarly on Debian and derived distributions);

$ sudo apt install source-highlight
$ echo -e "\nexport LESSOPEN=\"| /usr/share/source-highlight/ %s\"\nexport LESS=' -R '" >> ~/.bash_aliases


This setup will make fx. some C source code display as below in less.

environment set up for less to enable ANSI color codes and pass any text through source-highlighter for potential ANSI escape code addition

less showing highlighted C code, auto-detected and highlighted by GNU source-highlighter

For the conservative

If you’d still like to have a “plain less” not messing with and amending you text, you could make an alias to use specifically when you want syntax highlighting. Put these somewhere interpreted by you shell (for bash fx. ~/.bash_aliases);

# syntax highligt in less
alias lesssh="LESSOPEN='|/usr/share/source-highlight/ %s' LESS=' -R ' less"
function lessurl() { wget -O- -q $1 |source-highlight -f esc -s html |less -R; }

Line two is a bonus shell function pulling some HTML from a webserver using wget, adding syntax highlighting and showing it in less.

Digging deeper

For the brave, take a tour of the “info source-highlight” (or “man source-highlight”) manuals (also here) to become familiar with the tool. You can use it anywhere you’d like some colour on arbitrary text and where color are supported in various ways and encodings, for example HTML and latex;

source-highlight adding color encoding to C code using HTML and latex encoding

If you are a programmer wanting to add highlighting features to you own application, the command line utilities are building on a highlighting library which you can utilise (API documentation here).

GitHub CLI on Ubuntu LTS (16.04 & 18.04)
Mar 4th, 2020 by miki

Inspired by a John Sullivan (of FSF) tweet asking about opinions on the new and shiny MS(TM) GitHub(TM) CLI(TM) tool named “gh”(TM) I wanted to try it out on one of my Ubuntu LTS systems (16.04).

I’ve always disliked the proprietary and centralised monoculture of github, especially after that thing with MS, so I’ve mostly avoided using the service for code I produce myself. If interested in independence and decentralisation maybe you should read up on that long fabled subject? Thus I’ve never even tried the predecessor “hub”(TM) tool (main page), and exactly how it differs from this new “CLI” thing is not obviously apparent from the communications.

Nevertheless, the “gh” tool, officially dubbed  GitHub CLI, being distributed under MIT license and written in go(lang) (afterwards, found out that this is indeed also applicable to the predecessing “hub” tool) made me curious enough to go see what they’re up to. Maybe its not that sinister a plot and they really just want to improve the independent and freely available mechanisms for source code storage, distribution and maintenance (I wish)?


A fairly recent (2019-09) version of go, >=1.13, is required so some gymnastics are needed to make stuff work on older distros like Ubuntu’s LTS (with 5 years support from Canonical). Anyway, this is what I did to build a useable “gh” ELF executable (20 MiB!, se below), this is from source, no precompiled stuff, no snaps. It was done on Ubuntu 16.04 (xenial) but I’ve been somewhat careful to inspect that things ought to be good for 18.04 (bionic) too. Non-essential output from the commands is largely discarded here. See Gory Details section below for the full monty.

Add go PPA & install packages

$ sudo add-apt-repository ppa:longsleep/golang-backports
$ sudo apt update
$ sudo apt install golang
$ go version
go version go1.13.4 linux/amd64

Clone repo & build

$ cd
$ git clone .githubcli
$ cd .githubcli
$ make

Setup PATH & test

$ echo 'export PATH="$HOME/.githubcli/bin:$PATH"' >> ~/.bash_profile
$ bash --login
$ gh
Work seamlessly with GitHub from the command line.

GitHub CLI is in early stages of development, and we'd love to hear your
feedback at <>

  gh [command]

Available Commands:
  help        Help about any command
  issue       Create and view issues
  pr          Create, view, and checkout pull requests
  repo        Create, clone, fork, and view repositories

      --help              Show help for command
  -R, --repo OWNER/REPO   Select another repository using the OWNER/REPO format
      --version           Show gh version

Use "gh [command] --help" for more information about a command.
subcommand is required

Trying it out

Randomly picked one of my few github repos, it contains some js experiments on parsing NMEA formatted coordinates, rather uninterestingly empty.


user@host:~$ gh repo clone mikini/coordinates 
Notice: authentication required
Press Enter to open in your browser... 

<auth session in browser>

Authentication complete. Press Enter to continue...

Cloning into 'coordinates'...
remote: Enumerating objects: 10, done.
remote: Total 10 (delta 0), reused 0 (delta 0), pack-reused 10
Unpacking objects: 100% (10/10), done.
Checking connectivity... done.

An ordinary OAuth request was spawned for authentication on The javascript executed in the browser seemed to interact with the gh tool through a local TCP connection on localhost:45454 which was the redirection target on authorisation (URL parameter: “redirect_uri=http://localhost:45454/callback”). The socket was rightfully not bound after the authentication had succeeded but this is definitely an attack vector, albeit hopefully only for locally running processes.

Listing issues & prs

user@host:~$ cd coordinates/
user@host:~$:~/coordinates$ gh issue list

Issues for mikini/coordinates

There are no open issues
miki@vcas-miki2:~/coordinates$ gh pr view
no open pull requests found for branch "master"

Creating issues

miki@vcas-miki2:~/coordinates$ gh issue create

Creating issue in mikini/coordinates

? Title Testing gh
? Body <Received>
? What's next? Preview in browser
Opening in your browser.

miki@vcas-miki2:~/coordinates$ gh issue create

Creating issue in mikini/coordinates

? Title Testing gh tool
? Body <Received>
? What's next? [Use arrows to move, type to filter]
> Preview in browser

On the first issue creation interaction I selected “preview in browser” which opened a draft issue in the browser, and dumped me back into the shell on the command line. The second interaction actually resulted in #1.

Gory Details

PPA options

The golang-backports PPA is maintained independently by Simon Eisenmann (credits: ~longsleep, @github, and carries packages up to:

There’s also an official PPA from the golang project (~gophers) which however only carries packages up to 1.11 for both.

Full (mostly) installation dump

Add go PPA, install packages

user@host:~$ sudo add-apt-repository ppa:longsleep/golang-backports
Golang 1.8, 1.9, 1.10, 1.11, 1.12, 1.13 and 1.14 PPA for Ubuntu
 More info:
Press [ENTER] to continue or ctrl-c to cancel adding it

gpg: keyring `/tmp/tmpvnuym97a/secring.gpg' created
gpg: keyring `/tmp/tmpvnuym97a/pubring.gpg' created
gpg: requesting key 56A3D45E from hkp server
gpg: /tmp/tmpvnuym97a/trustdb.gpg: trustdb created
gpg: key 56A3D45E: public key "Launchpad PPA for Simon Eisenmann" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

user@host:~$ sudo apt update
Hit:1 xenial InRelease
Get:2 xenial-updates InRelease [109 kB] 
Get:37 xenial-security/universe DEP-11 64x64 Icons [194 kB]
Get:38 xenial-security/multiverse amd64 DEP-11 Metadata [2.468 B]
Fetched 7.614 kB in 3s (2.346 kB/s) 
Reading package lists... Done
Building dependency tree 
Reading state information... Done
419 packages can be upgraded. Run 'apt list --upgradable' to see them.

user@host:~$ apt list --upgradeable golang -a
Listing... Done
golang/xenial,xenial 2:1.13~1longsleep1+xenial all [upgradable from: 2:1.6-1ubuntu4]
golang/xenial,xenial,now 2:1.6-1ubuntu4 all [installed,upgradable to: 2:1.13~1longsleep1+xenial]


user@host:~$ sudo apt install golang
Reading package lists... Done
Building dependency tree 
Reading state information... Done
The following packages were automatically installed and are no longer required:
golang-1.6 golang-1.6-doc golang-1.6-go golang-1.6-src
Use 'sudo apt autoremove' to remove them.
The following additional packages will be installed:
golang-1.13 golang-1.13-doc golang-1.13-go golang-1.13-src golang-doc golang-go golang-src
Recommended packages:
The following NEW packages will be installed
golang-1.13 golang-1.13-doc golang-1.13-go golang-1.13-src
The following packages will be upgraded:
golang golang-doc golang-go golang-src
4 to upgrade, 4 to newly install, 0 to remove and 413 not to upgrade.
Need to get 60,2 MB of archives.
After this operation, 322 MB of additional disk space will be used.
Do you want to continue? [Y/n] 
Get:1 xenial/main amd64 golang-1.13-src amd64 1.13.4-1longsleep1+xenial [12,7 MB]
Get:2 xenial/main amd64 golang-1.13-go amd64 1.13.4-1longsleep1+xenial [44,9 MB]
Get:3 xenial/main amd64 golang-1.13-doc all 1.13.4-1longsleep1+xenial [2.542 kB]
Get:4 xenial/main amd64 golang-1.13 all 1.13.4-1longsleep1+xenial [25,2 kB]
Get:5 xenial/main amd64 golang-src amd64 2:1.13~1longsleep1+xenial [3.838 B]
Get:6 xenial/main amd64 golang-go amd64 2:1.13~1longsleep1+xenial [23,0 kB]
Get:7 xenial/main amd64 golang-doc all 2:1.13~1longsleep1+xenial [3.880 B]
Get:8 xenial/main amd64 golang all 2:1.13~1longsleep1+xenial [3.826 B]
Fetched 60,2 MB in 5s (10,8 MB/s) 
Selecting previously unselected package golang-1.13-src.
(Reading database ... 460737 files and directories currently installed.)
Preparing to unpack .../golang-1.13-src_1.13.4-1longsleep1+xenial_amd64.deb ...
Unpacking golang-1.13-src (1.13.4-1longsleep1+xenial) ...
Selecting previously unselected package golang-1.13-go.
Preparing to unpack .../golang-1.13-go_1.13.4-1longsleep1+xenial_amd64.deb ...
Unpacking golang-1.13-go (1.13.4-1longsleep1+xenial) ...
Selecting previously unselected package golang-1.13-doc.
Preparing to unpack .../golang-1.13-doc_1.13.4-1longsleep1+xenial_all.deb ...
Unpacking golang-1.13-doc (1.13.4-1longsleep1+xenial) ...
Selecting previously unselected package golang-1.13.
Preparing to unpack .../golang-1.13_1.13.4-1longsleep1+xenial_all.deb ...
Unpacking golang-1.13 (1.13.4-1longsleep1+xenial) ...
Preparing to unpack .../golang-src_2%3a1.13~1longsleep1+xenial_amd64.deb ...
Unpacking golang-src (2:1.13~1longsleep1+xenial) over (2:1.6-1ubuntu4) ...
Preparing to unpack .../golang-go_2%3a1.13~1longsleep1+xenial_amd64.deb ...
Unpacking golang-go (2:1.13~1longsleep1+xenial) over (2:1.6-1ubuntu4) ...
Preparing to unpack .../golang-doc_2%3a1.13~1longsleep1+xenial_all.deb ...
Unpacking golang-doc (2:1.13~1longsleep1+xenial) over (2:1.6-1ubuntu4) ...
Preparing to unpack .../golang_2%3a1.13~1longsleep1+xenial_all.deb ...
Unpacking golang (2:1.13~1longsleep1+xenial) over (2:1.6-1ubuntu4) ...
Processing triggers for man-db (2.7.5-1) ...
Setting up golang-1.13-src (1.13.4-1longsleep1+xenial) ...
Setting up golang-1.13-go (1.13.4-1longsleep1+xenial) ...
Setting up golang-1.13-doc (1.13.4-1longsleep1+xenial) ...
Setting up golang-1.13 (1.13.4-1longsleep1+xenial) ...
Setting up golang-src (2:1.13~1longsleep1+xenial) ...
Setting up golang-go (2:1.13~1longsleep1+xenial) ...
Setting up golang-doc (2:1.13~1longsleep1+xenial) ...
Setting up golang (2:1.13~1longsleep1+xenial) ...

user@host:~$ go version
go version go1.13.4 linux/amd64

Clone repo & build

user@host:~$ git clone .githubcli
Cloning into '.githubcli'...
remote: Enumerating objects: 168, done.
remote: Counting objects: 100% (168/168), done.
remote: Compressing objects: 100% (100/100), done.
remote: Total 5577 (delta 93), reused 122 (delta 67), pack-reused 5409
Receiving objects: 100% (5577/5577), 7.53 MiB | 2.61 MiB/s, done.
Resolving deltas: 100% (3269/3269), done.
Checking connectivity... done.

user@host:~$ cd .githubcli
user@host:~/.githubcli (master=)$ make
go: downloading v0.0.0-20191202100458-e7afc7fbc510
go: downloading v1.1.0
go: downloading v0.1.6
go: downloading v0.0.6
go: downloading v3.0.0-20200121175148-a6ecf24a6d71
go: downloading v0.0.12
go: downloading v0.3.2
go: extracting v1.1.0
go: extracting v0.1.6
go: extracting v0.0.0-20191202100458-e7afc7fbc510
go: extracting v0.0.6
go: extracting v0.0.12
go: downloading v0.0.0-20200223170610-d5e6a3e2c0ae
go: downloading v0.0.0-20200219234226-1ad67e1f0ef4
go: downloading v0.0.0-20170206155736-9520e82c474b
go: downloading v1.9.0
go: extracting v3.0.0-20200121175148-a6ecf24a6d71
go: downloading v1.2.0
go: downloading v1.0.5
go: downloading v2.0.7
go: downloading v0.0.0-20180428030007-95032a82bc51
go: downloading v0.1.1-0.20200304134224-7e5c90143acc
go: extracting v0.0.0-20170206155736-9520e82c474b
go: extracting v1.0.5
go: extracting v1.2.0
go: downloading v2.2.8
go: downloading v2.0.0
go: downloading v0.0.4
go: extracting v0.0.0-20180428030007-95032a82bc51
go: extracting v1.9.0
go: extracting v2.0.7
go: downloading v1.7.0
go: extracting v0.1.1-0.20200304134224-7e5c90143acc
go: downloading v1.1.24
go: downloading v1.0.2
go: extracting v2.2.8
go: extracting v0.0.4
go: downloading v0.0.4
go: downloading v0.1.0
go: extracting v1.7.0
go: extracting v1.0.2
go: extracting v2.0.0
go: extracting v0.0.0-20200223170610-d5e6a3e2c0ae
go: extracting v0.1.0
go: extracting v0.0.4
go: downloading v0.0.0-20200219183655-46282727080f
go: extracting v1.1.24
go: downloading v0.7.2-0.20200304075647-34d9c7143bf5
go: downloading v0.0.8
go: downloading v0.4.0
go: downloading v2.0.1
go: extracting v0.0.0-20200219234226-1ad67e1f0ef4
go: extracting v0.0.8
go: extracting v2.0.1
go: downloading v1.0.0
go: extracting v0.7.2-0.20200304075647-34d9c7143bf5
go: extracting v1.0.0
go: extracting v0.4.0
go: downloading v1.2.0
go: downloading v1.0.3
go: downloading v0.0.0-20190703233501-fc88cf888a3f
go: downloading v0.0.0-20160403171240-cbb64ac3d964
go: extracting v0.3.2
go: extracting v0.0.0-20190703233501-fc88cf888a3f
go: extracting v0.0.0-20160403171240-cbb64ac3d964
go: extracting v0.0.0-20200219183655-46282727080f
go: extracting v1.0.3
go: extracting v1.2.0
go: finding v0.0.6
go: finding v2.0.7
go: finding v0.0.4
go: finding v0.0.0-20191202100458-e7afc7fbc510
go: finding v0.0.0-20170206155736-9520e82c474b
go: finding v3.0.0-20200121175148-a6ecf24a6d71
go: finding v1.0.5
go: finding v1.2.0
go: finding v1.1.0
go: finding v1.9.0
go: finding v0.3.2
go: finding v2.0.0
go: finding v0.1.1-0.20200304134224-7e5c90143acc
go: finding v0.0.0-20180428030007-95032a82bc51
go: finding v0.1.6
go: finding v2.2.8
go: finding v2.0.1
go: finding v0.0.12
go: finding v1.7.0
go: finding v0.0.0-20200219234226-1ad67e1f0ef4
go: finding v0.4.0
go: finding v0.0.0-20200223170610-d5e6a3e2c0ae
go: finding v1.0.0
go: finding v1.1.24
go: finding v0.7.2-0.20200304075647-34d9c7143bf5
go: finding v0.0.0-20190703233501-fc88cf888a3f
go: finding v1.2.0
go: finding v1.0.3
go: finding v0.1.0
go: finding v1.0.2
go: finding v0.0.0-20160403171240-cbb64ac3d964
go: finding v0.0.4
go: finding v0.0.8
go: finding v0.0.0-20200219183655-46282727080f
user@host:~/.githubcli (master=)$ 

Cursory inspection of exec

user@host:~/.githubcli (master=)$ ls -l bin/gh
-rwxrwxr-x 1 user user 21097487 Mar  4 18:03 bin/gh
user@host:~/.githubcli (master=)$ 

user@host:~/.githubcli (master=)$ file bin/gh
bin/gh: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, not stripped
user@host:~/.githubcli (master=)$ 

user@host:~/.githubcli (master=)$ ldd bin/gh =>  (0x00007ffdc4329000) => /lib/x86_64-linux-gnu/ (0x00007fb1018c2000) => /lib/x86_64-linux-gnu/ (0x00007fb1014f8000)
	/lib64/ (0x00007fb101adf000)
user@host:~/.githubcli (master=)$ 

user@host:~/.githubcli (master=)$ nm -D bin/gh
                 U abort
00000000004fd140 T _cgo_panic
000000000045bf10 T _cgo_topofstack
00000000004fd190 T crosscall2
                 U __errno_location
                 U __fprintf_chk
                 U fputc
                 U free
                 U freeaddrinfo
                 U fwrite
                 U gai_strerror
                 U getaddrinfo
                 U getnameinfo
                 U malloc
                 U mmap
                 U munmap
                 U nanosleep
                 U pthread_attr_destroy
                 U pthread_attr_getstacksize
                 U pthread_attr_init
                 U pthread_cond_broadcast
                 U pthread_cond_wait
                 U pthread_create
                 U pthread_detach
                 U pthread_mutex_lock
                 U pthread_mutex_unlock
                 U pthread_sigmask
                 U setenv
                 U sigaction
                 U sigaddset
                 U sigemptyset
                 U sigfillset
                 U sigismember
                 U __stack_chk_fail
                 U stderr
                 U strerror
                 U unsetenv
                 U __vfprintf_chk
user@host:~/.githubcli (master=)$ 

Setup PATH & test

user@host:~/.githubcli (master=)$ cd
user@host:~$ echo 'export PATH="$HOME/.githubcli/bin:$PATH"' >> ~/.bash_profile
user@host:~$ bash --login
user@host:~$ gh
Work seamlessly with GitHub from the command line.

GitHub CLI is in early stages of development, and we'd love to hear your
feedback at <>

  gh [command]

Available Commands:
  help        Help about any command
  issue       Create and view issues
  pr          Create, view, and checkout pull requests
  repo        Create, clone, fork, and view repositories

      --help              Show help for command
  -R, --repo OWNER/REPO   Select another repository using the OWNER/REPO format
      --version           Show gh version

Use "gh [command] --help" for more information about a command.
subcommand is required
Bookmarklet to view OSM from coordinates parsed from URL
Aug 12th, 2016 by miki

Here’s a quick Javascript bookmarklet I threw together for opening a new browser window showing an area in OpenStreetMap that is defined from extracting the current window’s URL and searching after useable values for latitude, longitude and zoom.

It grew out of an annoyance over Mapillary’s rendering of the Danish endpoint of the under construction HVDC Cobra Cable(more about it from 4C, even more from EnergiNet and the EU) in Endrup nearby where I live.

In Mapillary’s tiles rendering it is just a bunch of roads and a single POI indication. Whereas the Mapnik rendering shows the existing power infrastructure and the area under construction.

Cobra HVDC, Endrup, Mapillary vs. OpenStreetMap

Well, I have been subjecting my oldstyle C brain to some Javascript lately so I decided to use that haemorrhage for attempting to put together a bookmarklet extracting coordinates from the current window’s URL and opening a new with the same approximate location in OSM.

It ended up like the below code block, and should also be usable on any other sites which receives locations via URL (both using HTTP GET notation with ‘?’ and locally in the page using anchors with ‘#’) and identifying them with key-value pairs using common names ({z,zoom},{lat},{lng,lon}). Note that this doesn’t include OpenStreetMap itself neither Google Maps as they only use the lat/lon values.

javascript:(function (){params={};kvs=document.location.href.split('&');kvs.forEach(function(kv){if(kv.indexOf('?'))kv=kv.substr(kv.indexOf('?')+1);if(kv.indexOf('#'))kv=kv.substr(kv.indexOf('#')+1);skv=kv.split('=');params[skv[0]]=skv[1];});''+(params.z?params.z:13)+'/'+('/'+(params.lng?params.lng:(params.lon?params.lon:8.5)));console.log(params);})();

Copy and paste the above into the “Location” or “URL” of a bookmark and you’ll be able to click it to open a new OSM window on, at least for Mapillary maps pages, the same location as the original site. If nothing is found it will default to coordinates of my hometown of Esbjerg at 55.5/.8.5.

Here’s a prettified edition of the code:

}); ''

Possible TODOs

  • get rid of default location, warn instead
  • support and test more sites (gmaps/osm!)
  • scan page contents for other geo markers
Subversion on Debian ARM: commit failing with space in URL
Sep 16th, 2014 by miki

Working on a Beaglebone Black based product, running the latest Debian GNU/Linux system image (bone-debian-7.5-2014-05-14-2gb.img) from the BB HQ at I just had the following strange experience.

Using Subversion I wanted to commit a change to a file made locally on the BBB. The file resided  in a working copy of a repository on which I had done the initial work on my x86_64 laptop. The working copy was checked out and updated on the BBB without any problems, but comitting I got the following error:

debian@beaglebone:~/VCAS_FR$ svn ci rc.local -m"Append to vncserver.log."
Authentication realm: <https://svn.xx.xx> Subversion Repository
Password for 'yaya': 
Sending        rc.local
Transmitting file data .svn: Commit failed (details follow):
svn: File not found: transaction '414-1', path '/trunk/BBB%20deployment/rc.local'

This failed repeatedly, and checking out a fresh new working copy exhibited the same result.

For the fun of it, because file name issues are long gone in my everyday computing life, I tried to remove the space from the directory path. And voila, unexpectedly it succeeded!

debian@beaglebone:~/VCAS_FR$ svn ci rc.local -m"Append to vncserver.log."
Authentication realm: <https://svn.xx.xx> Subversion Repository
Password for 'yaya': 
Sending        rc.local
Transmitting file data .
Committed revision 416.

Without spaces, things actually did work. Apparently there’s an issue with ARM built subversion and repositories containing spaces.

URL before

debian@beaglebone:~/VCAS_FR$ svn info | grep URL
URL: https://svn.xx.xx/trunk/BBB%20deployment

URL after

debian@beaglebone:~/VCAS_FR$ svn info | grep URL
URL: https://svn.xx.xx/trunk/BBB_deployment

Investigating a bit further narrowed down that the Debian distribution uses an old (old, old) subversion 1.6.17 release from 2009:

debian@beaglebone:~/VCAS_FR$ svn --version
svn, version 1.6.17 (r1128011)
   compiled Mar 15 2014, 21:37:31

Copyright (C) 2000-2009 CollabNet.
Subversion is open source software, see
This product includes software developed by CollabNet (http://www.Collab.Net/).

Probaly, this has been fixed since, a quick investigation in svn issue tracker revealed no open issues regarding this. I’ll look further into this later, and of course report it appropriately if this is an unknown issue.

But as you see, you can still experience basic issues on the latest and greatest stuff out there. Be wary!

»  Substance:WordPress   »  Style:Ahren Ahimsa
© 2020 Mikkel Kirkgaard Nielsen, contents CC BY-SA 4.0