Day of the week calculation

For given date in year-month-day, the day of the week can be deduced for the rule of leap years [1] and the fact that January 1, 1 is a Monday [2].

Since a year is a leap year if the year number is a multiple of 4 that is not a multiple of 100 that is not a multiple of 400. The number of leap year up to year y is given by:

def num_leap(y):
    return y//4-y//100+y//400

For a common year, the numbers of days for the twelve months are:

[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

The number of days before each month in a common year is calculated with:

p = 0
days_before_month = [
    [p, p := p + m][0] for m in
    [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
]
print('[',', '.join(map(str,days_before_month)),']',sep='')

The result is:

[0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]

Since the extra day of a leap year is added to February, the leap status of current year is only relevant when month number m<3. We can calculate the number of days from January 1, 1 as:

def day_number(y,m,d):
    return (y-1)*365+num_leap(y-(m<3))+days_before_month[m-1]+d

Or, pack everything in the function:

def day_number(y,m,d):
    return (y-1)*365+(lambda y:y//4-y//100+y//400)(y-(m<3))+[0,31,59,90,120,151,181,212,243,273,304,334][m-1]+d

[1] https://en.wikipedia.org/wiki/Leap_year
[2] https://en.wikipedia.org/wiki/AD_1

Default values of GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER

From the documentation available at https://registry.khronos.org/OpenGL-Refpages/gl4/html/glTexParameter.xhtml, the default or initial values are:

GL_TEXTURE_MIN_FILTER = GL_NEAREST_MIPMAP_LINEAR
GL_TEXTURE_MAG_FILTER = GL_LINEAR

This makes glGenerateMipmap necessary after glTexImage2D. Otherwise, the texture rendering will not work properly.

Saving from pickle.dumps to h5py

Saving a chunk of pickled data to a h5py dataset with following code result in “ValueError: VLEN strings do not support embedded NULLs”.

a = [1,2,3,4,5]
with h5py.File('test.h5','a') as f:
	f['a'] = pickle.dumps(a)

This can be worked around with, e.g., “np.string_”:

a = [1,2,3,4,5]
with h5py.File('test.h5','a') as f:
	f['a'] = np.string_(pickle.dumps(a))

To load it back:

with h5py.File('test.h5','r') as f:
	a = pickle.loads(f['a'][()])

I am not aware if there is any problem with this approach.

Dovecot 2.3.18 failed to load certificate with OpenSSL 3.0

This problem prevents user login with SSL to the Dovecot IMAP server. The errors in the journal look like this:

... imap-login: Error: Failed to initialize SSL server context: Can't load SSL certificate (ssl_cert setting): error:25066067:DSO support routines:dlfcn_load:could not load the shared library: filename(libproviders.so): libproviders.so: cannot open shared object file: No such file or directory, error:25070067:DSO support routines:DSO_load:could not load the shared library, error:0E07506E:configuration file routines:module_load_dso:error loading dso: module=providers, path=providers, error:0E076071:configuration file routines:module_run:unknown module name: module=providers: ...

A fix/workaround was found at Bug#1011051: libssl3: upgrade to libssl3 broke my dovecot setup. By commenting out the line “providers = provider_sect” in the configuration file “/etc/ssl/openssl.cnf”, the service is restored. Hope this will be resolved properly in the near future.

Self-signed CA certificate

It’s useful for signing certificates for internal use. Here is a quick way for setting up a self-signed CA using the openssl command in Linux.

mkdir ca
cd ca
openssl req -nodes -new -x509 -keyout ca.key -out ca.crt -subj "/C=TW/ST=Taiwan/L=Taipei/O=ccdw.org/OU=sam/CN=sam.ccdw.org/emailAddress=root@sam.ccdw.org"

Server certificate

To create a server certificate signing request along with a new server key:

openssl req -nodes -new -keyout server.key -out server.csr -subj "/C=TW/ST=Taiwan/L=Taipei/O=ccdw.org/OU=server/CN=server.ccdw.org/emailAddress=server@ccdw.org"

To sign the server certificate:

openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650

The resulting key can certificate of the server can be combine into a PEM file:

cat server.key server.crt > server.pem

Client certificate

To create a client certificate signing request along with a new client key:

openssl req -nodes -new -keyout client.key -out client.csr -subj "/C=TW/ST=Taiwan/L=Taipei/O=ccdw.org/OU=client/CN=Good Client/emailAddress=good@client.ccdw.org"

To sign the client certificate:

openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAserial ca.srl -out client.crt -days 1000

The browser usually needs the certificate in PKCS#12 format. To convert the format of the certificate:

openssl pkcs12 -export -out client.pfx -inkey client.key -in client.crt

The .pfx file can then be imported into a browser.

Fetch images for html

Find img tags with remote source images in an HTML file and download the images to a local folder. Change the HTML files to use the local files instead.

This was done with the one liner:

grep img rbm.html|tr '"' '\n'|grep http|sort -u|while read f;do l=`basename ${f}`;ff=${l%.???};fe=${l##*\.};echo ${ff} ${fe};if [ -f "rbm_pics/${l}" ];then i=1;while [ -f "rbm_pics/${ff}-${i}.${fe}" ];do i=$((i+1));done;l="${ff}-${i}.${fe}";fi;curl --output rbm_pics/${l} "${f}";sed "sX${f}Xrbm_pics/${l}X" rbm0.html > t.html;mv t.html rbm0.html;done

A better formatted version is as follows:

grep img rbm.html|tr '"' '\n'|grep http|sort -u|while read f;do
	l=`basename ${f}`
	ff=${l%.???}
	fe=${l##*\.}
	echo ${ff} ${fe}
	if [ -f "rbm_pics/${l}" ];then
		i=1
		while [ -f "rbm_pics/${ff}-${i}.${fe}" ];do
			i=$((i+1))
		done
		l="${ff}-${i}.${fe}"
	fi
	curl --output rbm_pics/${l} "${f}"
	sed "sX${f}Xrbm_pics/${l}X" rbm0.html > t.html
	mv t.html rbm0.html
done