Thursday, September 25, 2025

Running GitHub actions locally (on MacOS)

 1. Install act

brew install act

2. Create directory for artifacts

mkdir /tmp/artifacts

3. Run act

act -P ubuntu-latest=quay.io/jamezp/act-maven --artifact-server-path /tmp/artifacts


Thursday, March 6, 2025

Using special fonts in R plots

For a paper in CEUR format, I wanted to change the fonts of the figures in the paper to the "Libertinus" font, which is used in the CEUR template. Some figures were created as graph plots in R. MS Copilot suggested using the extrafonts package in R, which did not work. 

Here's what worked instead. I copied the ttf file of the font to a fonts subdirectory and added this to my rmd script:

library(showtext)

font_add("Libertinus Sans", "fonts/LibertinusSans-Regular.ttf")  # Use the actual file path

showtext_auto()


Then, in each ggplot statement, I added the font name in the theme parameters:

ggplot(knowledge_stats, aes(x=item, y=median, group=survey, fill=survey))+

  geom_bar(stat="identity", position="dodge")+

  facet_grid(.~departement)+

  scale_fill_manual(values = c("steelblue1", "grey80"))+

  labs(title=paste("ASE: Knowledge gain", subtitle="L: 6 persons, T: 32"))+

  theme_bw()+

  theme(text = element_text(family = "Libertinus Sans"),plot.title = element_text(size=14), legend.title=element_text(size=16), legend.text=element_text(size=12),

          axis.title.x=element_blank(), axis.title.y=element_text(size=16), 

          axis.text.x=element_text(size=14, angle = 90), axis.text.y=element_text(size=14), legend.position="bottom",

        strip.text.x=element_text(size=12), strip.text.y=element_text(size=12), 

        )


Using 

ggsave("ase_knowledge_gain.pdf", units="cm", width=16, height=12)

the font was correctly used in the generated PDF file.

Sunday, December 17, 2023

Dell Wyse 5070 hardware upgrade

Dell Wyse 5070 is a thin client running a basic OS (ThinOS) with basically one application - an RDP client. It can do much more though - by upgrading the hardware and installing Linux. There are a few caveats though.

Memory

The manual states that 8 GB is the maximum memory capacity. I supports a lot more though. I successfully installed 16 GB of RAM. The RAM I am using is Corsair Value Select 2 x 8GB, 2133 MHz, DDR4-RAM, SO-DIMM.

Storage

The manual states that "One M.2 2260/2280 slot" is supported. However, it is not explicit about NVME SSDs not being supported. This is an issue because most SSDs sold nowadays use NVME controllers. Thus, the Samsung 970 EVO Plus SSD I ordered does not work. What worked though was a Adata Ultimate SU650 - 240 GB SSD -M.2 2280 (it has two notches; the NVME SSDs seem to have one notch only).

Advanced LDPC ECC Technology

Saturday, December 17, 2022

Browsing Synology shared drives from Mac is slow

 Browsing network volumes on a Synology NAS from my Mac was very slow. In particular, previewing (even small!) PDFs. The solution posted here seems to work.

Monday, June 13, 2022

Disconnecting USB-C hub kills network

 I have had several problems with my home network recently, where parts of the Ethernet connected devices were not reachable anymore. The problem seemed to be a recently new 8-port Ethernet switch. Turning off and on one of the switch solved the problem for a while.

I figured out (after a long time) that the switch would fail when I disconnect my DELL DA310u USB-C hub from my Macbook. When I plugged the hub back in (even after hours), the network switch came back. Interestingly, the network connection from the USB-C hub to the failing switch is through another switch.

I found this article that describes a pause frame to be sent across the network from the USB-C hub. Man, that sucks....

Sending emails about live/dead server

This code checks if a host on a network is reachable via ping; if not, it sends an email through ssmtp (which needs to be configured beforehand). All parameters are declared in the first few lines.

TODO: remove duplicate code

#!/bin/bash

NUMBER_OF_PINGS=3

HOST_NAME="myhostname.local"

FLAG_FILE=/home/pi/$HOST_NAME.isdead

EMAIL_SENDER=foo@gmail.com

EMAIL_RECEIVER=bar@gmail.com


#ping returns 0 if target could be reached


if ping -c $NUMBER_OF_PINGS $HOST_NAME &> /dev/null

then # host is reachable

  if test -f $FLAG_FILE  # flag file exists

  then

  { echo To: $EMAIL_RECEIVER

    echo From: $EMAIL_SENDER

    echo Subject: 👍 $HOST_NAME is alive again

    echo Congrats! $HOST_NAME is alive again. 

  } | /usr/sbin/ssmtp $EMAIL_RECEIVER

  rm $FLAG_FILE   # delete flag file and send email

  else # nothing to do

    :

  fi

else # host is NOT reachable

  if test -f $FLAG_FILE  # flag file exists, which means that an email has already been sent

  then  # nothing to do

    :

  else  # send an email otherwise and create flag file

  { echo To: $EMAIL_RECEIVER

    echo From: $EMAIL_SENDER

    echo Subject: ☠️  $HOST_NAME is dead

    echo My condolences. I tried to ping $HOST_NAME $NUMBER_OF_PINGS times, but did not get a response. 

  } | /usr/sbin/ssmtp $EMAIL_RECEIVER

  touch $FLAG_FILE

  fi

fi

Sunday, January 30, 2022

apache2, flask, python3 on macos 12.2 (Monterey)

   Here are the steps:

1. Install homebrew

    https://brew.sh/

2. Install apache

    brew install apache2

3. Install python

    brew install python3 

4. Install mod-wsgi (apache module to run scripts)

    pip3 install mod-wsgi

5. Modify /opt/homebrew/etc/httpd/httpd.conf; add this (and adapt names in bold to your specific installation)

LoadModule rewrite_module lib/httpd/modules/mod_rewrite.so

LoadModule wsgi_module /opt/homebrew/lib/python3.9/site-packages/mod_wsgi/server/mod_wsgi-py39.cpython-39-darwin.so

WSGIApplicationGroup %{GLOBAL}

<Directory "/Users/wahl/Development/excel_ws">

        Options Indexes MultiViews

        AllowOverride none

        Require all granted

</Directory>

WSGIScriptAlias /excel_ws /Users/wahl/Development/excel_ws/WebService.wsgi        

        assuming that the Flask application resides in /Users/wahl/Development/excel_ws and that the relative URL is /excel_ws.

6. Create the .wsgi file - this is a short python script that launches flask (in the example above, it is called WebService.wsgi residing in our flask application directory). We further assume that the Python source files reside in the directory src relative to the .wsgi file. The flask app is defined in src/WebService.py.

        #! /usr/bin/python3

    import logging

    import sys

    import os

    logging.basicConfig(stream=sys.stderr)

    sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/src')

    from WebService import app  as application

    application.secret_key = 'some super secret string'


 

Sunday, November 28, 2021

Recovering deleted photos from an SD card

 On Linux, the photorec tool is fantastic for recovering deleted files from an SD card.

Here's a link.

tl;dr (or if the link goes down): dd the contents of the SD card to a file, apt install testdisk, then run photorec on the file.

Tuesday, November 20, 2018

SSL authentication for git in Visual Studio 2017

Setup: VS2017 on Windows 10, bash using WSL. Key pair exists in ~/.ssh

I could not authenticate with a gitlab instance through SSH. Therefore, in bash, I ran this to copy the key pair to my Windows user directory.

~$ cp -r .ssh /mnt/c/Users/<username>/

A restart of VS may be required such that it uses the keys.

Thursday, August 25, 2016

Renaming branches in git

git branch -m old_branch new_branch         # Rename branch locally  
git push origin :old_branch                 # Delete the old branch  
git push --set-upstream origin new_branch   # Push the new branch, set local branch to track the new remote

(source)

Tuesday, June 21, 2016

[Ubuntu] Install missing LaTeX packages

Here is a script that installs missing LaTeX packages.


#!/bin/bash

EMPHASISCOLOR="\e[7m"
RESETEMPHASIS="\e[27m"
DEFAULTCOLOR="\e[39m"
GREENCOLOR="\e[32m"
LIGHGRAYCOLOR="\e[37m"
BLUECOLOR="\e[34m"
YELLOWCOLOR="\e[93m"

echo -e "************************************************************************"
echo -e "* LaTeX Package Installer"
echo -e "************************************************************************"
printf "* Checking dependencies....... "
# check if required programs are installed
hash apt-file 2>/dev/null || { echo >&2 "false\nI require apt-file but it's not installed.  Aborting."; exit 1; }
echo -e "${GREENCOLOR}ok${DEFAULTCOLOR}"


printf "* Packet name................. "
if [ -z "$1" ]; then 
echo -e "${YELLOWCOLOR}Please provide a packet name as argument$DEFAULTCOLOR"; 
exit 1
else 
PACKETNAME=$1; 
echo -e "${GREENCOLOR}$PACKETNAME$DEFAULTCOLOR"; 
fi

RESULT=`apt-file -x search "/${PACKETNAME}$"`

# if package is found, result is
# texlive-latex-extra: /usr/share/texlive/texmf-dist/tex/latex/preprint/balance.sty
# otherwise, result is empty
# exit code from apt-file is 0 in either case


IFS=':' read -a myarray <<< "$RESULT"

APTPACKAGE=${myarray[0]}

printf "* Result...................... "
if [[ $RESULT ]]; then
    echo -e "${GREENCOLOR}$APTPACKAGE$DEFAULTCOLOR"; 
else
    echo -e "${YELLOWCOLOR}no apt package found$DEFAULTCOLOR"; 
    exit 0
fi

echo "* Installing APT package...... "

sudo apt-get install $APTPACKAGE


echo -e "************************************************************************"
exit 0

Wednesday, June 15, 2016

Calculating statistics on the output EasyPMD's Copy/Paste Detector

Here is a shell script that computes the number of duplicate code segments and the total number of copied lines based on the output of EasyPMD's Copy/Paste Detector. This output is structured by segments starting with:

Found a x line (y tokens) duplication in the following files:

The script extracts these lines and sums up the occurrences and number of lines.



#!/bin/bash

if [[ $# -eq 0 ]] ; then
    echo 'Please specify a file name.'
    exit 0
fi

# Extract strings like:
# Found a X line (Y tokens) duplication in the following files: 
cat $1 | grep Found > tmp.txt    

# define counters
sum_lines=0
occurrences=0

# parse temp file and extract # of lines
while read line
do
    tmp=(`echo $line | tr ' ' ' '`)
    lines=${tmp[2]}
    sum_lines=`expr $sum_lines + $lines`
    occurrences=`expr $occurrences + 1`
done < tmp.txt

rm tmp.txt

echo "$occurrences code duplicates, $sum_lines lines in total."

Thursday, March 10, 2016

Make Virtualbox guests use the host's VPN connection

In my home office my guest OS in Virtualbox was not able to use its host's VPN connection. As shown here, VBoxManage can do the trick:

VBoxManage list vms
VBoxManage modifyvm <uuid here> --natdnshostresolver1 on

Thursday, August 13, 2015

Embedding fonts in Windows-generated PDF files

Problem: PDF files generated from Office use TrueType fonts, which are not embedded into the PDF.

Solution: Run this script:

#!/bin/bash
mv $1 $1.bak

gs -dCompatibilityLevel=1.4 \
    -dPDFSETTINGS=/screen \
    -dCompressFonts=true \
    -dSubsetFonts=true \
    -dNOPAUSE \
    -dBATCH \
    -sDEVICE=pdfwrite \
    -sOutputFile=$1 \
    -c ".setpdfwrite <</NeverEmbed [ ]>> setdistillerparams" \
    -f $1.bak

pdffonts $1




See also: 

Tuesday, June 23, 2015

I/O error when booting Linux-on-USB through Virtualbox on Windows 7

This article provides remedy (in particular the setting to remove the read-only attribute).

Wednesday, April 22, 2015

Interesting Linux distributions

- elementary OS - looks very clean and seems to be suitable for weaker PCs (1 GB RAM, 15 GB disk space)
- Kubuntu 15.04 with Plasma 5 desktop - beautiful UI; for more powerful PCs

Monday, September 29, 2014

Finding Type 3 fonts in PDFs

It can be painful to fail the IEEE PDF check because of wrong fonts that made it into your PDF file. Here's a little shell script that helps to locate where Type 3 fonts are hiding.

#!/bin/bash

 for i in `seq 1 1 \`pdfinfo XXX.pdf|grep 'Pages'|cut -d: -f2|sed -e 's/ //g'\``
 do
   echo ""
   echo Page $i;
   echo "font name                            type              emb sub uni object ID"
   echo ------------------------------------ ----------------- --- --- --- ---------
   pdffonts -f $i -l $i XXX.pdf|grep 'Type 3';
 done