Posts
-
Source |
Signature
Codegolf - Reverse NATO phonetic alphabet
A long time ago, I used to visit Codegolf Stack Exchange regularly, and took part in a few contests. Due to certain reasons, I have decided not to contribute to the Stack Exchange network anymore, but I recently came across a codegolf contest that looked interesting, so I thought I’d post my solution in my blog instead.
The post is linked here, but to summarise, the task is to convert a string spelled out in NATO phonetic alphabet, without any delimiter, back to a string spelled normally, so for example, from “ECHOXRAYALFAMIKEPAPALIMAECHO” to “EXAMPLE”.
I decided to attempt this in the RISC-V ISA, for no particular reason other than that I have been using it at work. My current score is 52 bytes.
A few details before getting to the code:
- Instead of a full program handling I/O, I will only be implementing a function, using the standard RISC-V ABI.
- I am using the 32-bit ISA with the Zca and Zcb extensions.
- I will assume C strings (i.e. NUL-terminated array of chars) in ASCII.
- I will assume the caller has allocated a sufficiently large output buffer.
My solution relies on the fact that all phonetic alphabets start with the letter it represents, for example, ALFA starts with A, BRAVO starts with B. So all it needs to do is know how long each phonetic alphabet is, and just copy the first letter and skip over the rest.
Here’s the assembly:
.globl revnato revnato: la a3, revnato_data - 65 revnato_loop: lbu a2, 0(a0) sb a2, 0(a1) beqz a2, revnato_ret add a2, a2, a3 lbu a2, 0(a2) add a0, a0, a2 addi a1, a1, 1 j revnato_loop revnato_ret: ret revnato_data: .byte 4,5,7,5,4,7,4,5,5,7,4,4,4,8,5,4,6,5,6,5,7,6,7,4,6,4
If you’re not familiar with the syntax, all operations are in the form
opcode destination operand
oropcode destination operand1 operand2
.Here,
a0
is expected to contain the input string, anda1
the output buffer. We first load the address (la
) of a lookup table toa3
. This table is the string length of each phonetic alphabet. The- 65
will be explained later.In the loop, we first load one unsigned byte (
lbu
) ata0[0]
intoa2
, and store that byte (sb
) intoa1[0]
, i.e. copy the first character. We exit from the loop (and return from the function) if the byte is NUL (beqz
: branch if equal to zero).If non-zero, we compute the index for the lookup table. The unoptimised way would be to subtract
'A'
(ASCII 65) from the byte, and then add it to the lookup table address. To optimise this, I have moved the “subtract 65” to the address itself, so that we can just adda3
toa2
. We then dereference the address by loading the unsigned byte.*We then increment the input pointer by the lookup table entry, and increment the output pointer by 1, and loop.
*: Note that another way to optimise it would be to leave the
a3
address as is, and dolbu a2, -65(a2)
instead. This may be more readable, but actually produces bigger code, because-65
is outside the range of the 16-bitlbu
immediate opcode range (see RISC-V Zcb), so a 32-bitlbu
has to be used instead.This can be compiled to an object file with:
YOUR-TOOLCHAIN-gcc -mabi=ilp32e -march=rv32emzca_zcb -c -o revnato.o revnato.s
We can look at the disassembly to check the binary size:†
YOUR-TOOLCHAIN-objdump -S revnato.o > revnato.dump
00000000 <revnato>: 0: 00000697 auipc a3,0x0 4: 00068693 mv a3,a3 00000008 <revnato_loop>: 8: 8110 lbu a2,0(a0) a: 8990 sb a2,0(a1) c: c611 beqz a2,18 <revnato_ret> e: 9636 add a2,a2,a3 10: 8210 lbu a2,0(a2) 12: 9532 add a0,a0,a2 14: 0585 addi a1,a1,1 16: bfcd j 8 <revnato_loop> 00000018 <revnato_ret>: 18: 8082 ret 0000001a <revnato_data>: 1a: 05070504 .word 0x05070504 1e: 05040704 .word 0x05040704 22: 04040705 .word 0x04040705 26: 04050804 .word 0x04050804 2a: 05060506 .word 0x05060506 2e: 04070607 .word 0x04070607 32: 0406 .short 0x0406
Note that the
mv a3,a3
, which looks like a NOP, is actually space reserved for a relocation. This is because we are only creating an object file without linking, so the address ofrevnato_data
is not yet known. You can prove this by generating a linked ELF withYOUR-TOOLCHAIN-gcc -mabi=ilp32e -march=rv32emzca_zcb -o revnato.elf revnato.s -nostdlib
and observing in that disassembly that the instruction has now changed, for example, toaddi a3,a3,-39
.†: Alternatively, we can just run
readelf -S revnato.o
and look at the size field of .text.Finally, just for completeness, an example C program to call this function:
#include <stdio.h> void revnato(const char *, char *); int main(void) { const char *in = "ECHOXRAYALFAMIKEPAPALIMAECHO"; char out[100]; revnato(in, out); puts(out); return 0; }
Preview clipped. Expand | Read full post in new tab
|
-
Source |
Signature
New Gachapon shop in London!
New Gachapon shop in London (Wing Yip Cricklewood)!
Gave up after spending £16 and still not getting Senjougahara :/
There are a lot other series. To name a few I’ve watched: Oshi no Ko, KiseKoi, Frieren, Spy × Family, TenSura, Cardcaptor Sakura.
Preview clipped. Expand | Read full post in new tab
|
-
Source |
Signature
Firefox custom search engine - search.json.mozlz4
So I have an ancient custom search engine XML that was broken by remote API changes. In trying to fix it, I inadvertently had it deleted from search.json.mozlz4, and have to figure out how to add it back.
This is basically a rewrite of this post by Frederick Zhang. That post is excellent, but there have been some changes since 2018. The following is tested on the latest stable Firefox (138.0.1).
First download this Python script. Use it to decompress search.json.mozlz4 (located in the Firefox profile directory):
python3 mozlz4a.py -d search.json.mozlz4 search.json
Optionally, format it with
python3 -m json.tool
.Add a new object to the
"engines"
array. My example for Startpage with custom params:{ "id": "38c37483-6e61-4f86-bfaf-2b99ed7d8464", "_name": "Startpage (Unfiltered)", "_loadPath": "[profile]/searchplugins/startpage-unfiltered.xml", "_iconMapObj": { "16": "data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2jkj+9YtD/vWLQ/71i0P+9otD/vaLRP72i0T+9YtE/vWLRP72i0T+9otD/vaNRP72jUT+9otF/vaLRf73kkv+9Yc///WJP//1iT//9Yk///rAmf/94Mz/+sCa//aRTv/1iUH/9ok///aJP//2i0H/9otB//aJQv/2iUL/9otC//aNRP/2jUT/9o1E//aNRP/6wpv////////////96dr/95dQ//aNRP/2kET/9pBG//aQRv/2kEb/9pBG//aRR//3lEz/95BH//mueP/7xJ3/959g//efYf/4p23//vDm//3p2//3kEr/95FJ//aRSf/niFH/95FK//aRSv/2mE//95hS/vq4iP/////////////////81bj/95xZ//q4iP//////+bF+//eZT//njFT/PSqi/2xGjv/2mVD/951V/vedVv783cX///////vQrf/++PP///////748//+8uj///////m3gf/olFr/PSuj/w8Pt/9sSJD/951V//eeWf73oVv++8ul///////5sXf/+KRi//vRsf////////////3r3v/olF//Piyk/w8Pt/9sSJH/+J5Z//ieWv/3oV/++KZf/vihXP/97N7//vn0//zTs//6wJP/+bBy//q6iP/onW//Piyl/w8Pt/8fGbH/m2iB/+icY//4pGD/96hl/viqZf74pmD/+Kxr//3iy/////////n1//ivbP/onGj/Pi2m/w8Pt/8uJKz/fFeQ/x8Zsf8+Lqb/6J9r//ivbP74rm3++Klm//mpZv/5q2f/+bR9//m0e//poW7/Pi6n/w8Pt/9sTZj/+Ktp//ira/+rd4P/Dw+3/4xijv/5snH++LN1/vmvbf/5r23/+a5t//mvb//4r2//TTuk/w8Pt/8fGrL/6ah1//ivcP/4r3P/q3yI/w8Pt/+MZpP/+bN5/vm4ev75t3X/+bV1//m1df/5t3X/+Ld3/8qUhP98XZn/Hxqz/+mse//5t3f/2p+B/x8as/8PD7f/u4qK//m7fv76u4D++bl7//m3fP/5uXz/+bl8//m5fP/5t3z/+bl//x8as/9NPKf/fWCb/x8as/8PD7f/bVOh//q5f//6v4X++sGI/vm9g//5voX/+b6F//m9hf/6vYX/+r6F//nCh/+bepr/Hxu0/w8Pt/8PD7f/fWOh//q+hf/6wof/+saN/vrGjf75xIv/+ceL//nEi//5xIv/+sSL//rHi//6x43/+ceN/+m7kP+7lpj/6ruQ//rHkP/6x43/+seQ//rLlf76ypT++seR//rJkf/6yZH/+seR//rJkf/6yZH/+8mR//vJlP/7yZT/+smU//rJlP/6yZT/+8yV//rJlf/6zpn+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" }, "_metaData": { "loadPathHash": "<SEE BELOW>", "alias": "sp", "hideOneOffButton": false, "order": 8 }, "_urls": [ { "params": [ { "name": "query", "value": "{searchTerms}" }, { "name": "cat", "value": "web" }, { "name": "lui", "value": "english" }, { "name": "prfe", "value": "c774daad5dd23ae2db70252aa321b9354508577d11ee4a79664d62c5d56672dd946c593d0daa5e9f3e7d1ebafaf773669d191e7b802605a743232b31a2254feeccf8ccc0f306bf45f8fa73f3" } ], "rels": [], "template": "https://www.startpage.com/sp/search", "method": "POST" } ], "_orderHint": null, "_telemetryId": null, "_filePath": "<ABSOLUTE PATH TO PROFILE DIRECTORY>/searchplugins/startpage-unfiltered.xml", "_definedAliases": [], "_updateInterval": null, "_updateURL": null }
I assume the
"id"
is just some UUID. I ended up reusing an existing one that I no longer needed. I’m not sure whether it would be “validated” in any way.The
"loadPathHash"
is calculated using the following function:function getVerificationHash(name, profileDir = PathUtils.profileDir) { let disclaimer = "By modifying this file, I agree that I am doing so " + "only within $appName itself, using official, user-driven search " + "engine selection processes, and in a way which does not circumvent " + "user consent. I acknowledge that any attempt to change this file " + "from outside of $appName is a malicious act, and will be responded " + "to accordingly."; let salt = PathUtils.filename(profileDir) + name + disclaimer.replace(/\$appName/g, Services.appinfo.name); let data = new TextEncoder().encode(salt); let hasher = Cc["@mozilla.org/security/hash;1"].createInstance( Ci.nsICryptoHash ); hasher.init(hasher.SHA256); hasher.update(data, data.length); return hasher.finish(true); }
This code is taken from the Firefox source code here. It is to be pasted into the Browser Console, then called with
getVerificationHash("<VALUE IN _loadPath>", "<ABSOLUTE PATH TO PROFILE DIRECTORY>")
. The second argument is required if you are running on a different profile.The
"order"
is just whichever unused number that comes next.Save this, then compress it again with:
python3 mozlz4a.py search.json search.json.mozlz4
.Finally, create a backup of the original search.json.mozlz4, and replace it with the new one.
Preview clipped. Expand | Read full post in new tab
|
-
Source |
Signature
Manjaro PinePhone no sound after October 2023 update
After running a software upgrade yesterday (10 October 2023) with
sudo pacman -Syu
, my PinePhone ended up with no sound.See this post on the Manjaro forum for my fix. To summarize:
- I downgraded everything by following the “Downgrading all upgraded packages” section in this article (parsing /var/log/pacman.log and restoring from /var/cache/pacman/pkg/), and uninstalled alsa-ucm-pinephone. I then re-upgraded and manually reinstalled alsa-ucm-pinephone, and it just magically worked.
- I suspect an easier fix will be to just edit
/usr/share/alsa/ucm2/conf.d/simple-card/PinePhone.conf
and only keep
Syntax 2
and theSectionUseCase."HiFi"
andSectionUseCase."Voice Call"
sections, and remove everything else.
Preview clipped. Expand | Read full post in new tab
|
-
Source |
Signature
LibDem misleading bar chart
LibDem MP Daisy Cooper’s newsletter for St Albans contains a misleading bar chart where a 0% bar will have a height of 6 mm (i.e. the baseline of the chart is at -3.5%). In other words, if you stack LAB’s 9% and CON’s 39% (total 48%), it will be taller than LIBDEM’s 50%.
Preview clipped. Expand | Read full post in new tab
|
-
Source |
Signature
PinePhone (Manjaro Phosh) automatic suspend bug
On 2023-06-06 I ran a system upgrade on my PinePhone (running Manjaro Phosh) using
pacman -Syu
. Afterwards, automatic suspend stopped working.The symptoms
If you are in the lock screen and have the display turned off (this can due to automatic blank screen, or due to manually pressing the power button), then shortly before the automatic suspend timeout, the notification blue LED will light up.
Previously (before the upgrade), if you ignore the notification, after reaching the timeout, the notification will be cleared, and the PinePhone will be suspended. If you turn on the screen before it suspended, it will very briefly show a notification that the phone will be automatically suspended. However the notification will clear itself almost immediately.
After the upgrade, the notification LED stays on, and the phone does not suspend. When the screen is turned on again, it will always display the notification (which will clear itself very quickly). Most notably, because it does not actually suspend, the battery drains itself within a few hours. I’d go to work in the morning (unplugging from the charger at 08:30), arrive back home at 18:00 and the phone has already turned itself off.
The solution
This has been provided by @alaraajavamma:urheiluaki.org from #pinephone.
gsettings set sm.puri.phosh.notifications wakeup-screen-triggers []
Note that this needs to be run on a terminal on the PinePhone. It does not work via
ssh
.For future reference, the original value was
['urgency']
.Other observations
Things we tried and found out before reaching the solution.
- Automatic suspend actually works if the display is turned on and not in the the lock screen.
sudo systemctl suspend
- works.systemctl suspend
- works on a terminal on the PP. Does not work viassh
.-
systemd-inhibit --list
gives the following output:WHO UID USER PID COMM WHAT WHY MODE ModemManager 0 root 3533 ModemManager sleep ModemManager needs to reset devices delay NetworkManager 0 root 3513 NetworkManager sleep NetworkManager needs to turn off networks delay UPower 0 root 3993 upowerd sleep Pause device polling delay eg25manager 0 root 3311 eg25-manager sleep eg25manager needs to prepare modem for sleep delay manjaro 1000 manjaro 3826 phosh handle-power-key Phosh handling power key block manjaro 1000 manjaro 4045 gsd-media-keys handle-power-key:handle-suspend-key:handle-hibernate-key GNOME handling keypresses block manjaro 1000 manjaro 4045 gsd-media-keys sleep GNOME handling keypresses delay manjaro 1000 manjaro 4046 gsd-power sleep GNOME needs to lock the screen delay manjaro 1000 manjaro 3826 phosh sleep Phosh handling suspend delay 9 inhibitors listed.
Preview clipped. Expand | Read full post in new tab
|
-
Source |
Signature
Playing 夏ノ終熄 Natsu no Owari on Wine
When playing this game on Wine 6.17 (64-bit), after the first day, I got this error on a pop-up:
Failed to call ConnectFilters( pSrc, pMPEG1Splitter ). : [0x80004005] Error: 0x80004005
When running on the command line I get this:
0024:fixme:quartz:mpeg_splitter_sink_query_accept Unsupported subtype {e436eb84-524f-11ce-9f53-0020af0ba770}.
Searched online for these messages and found a few different solutions, but the only one that worked for me was this one by jkfloris:
winetricks l3codecx directshow wmp10
Preview clipped. Expand | Read full post in new tab
|
-
Source |
Signature
Using spectral analysis to watch a YouTube video
So I went to watch a video on YouTube: https://www.youtube.com/watch?v=7fSq0_Ljb_s
And about a minute in, I noticed some strange high frequency in both audio channels. Here’s a sample:
Not sure what this is, I decided to download it to investigate further:
$ youtube-dl -F 'https://www.youtube.com/watch?v=7fSq0_Ljb_s'
One of the output lines is:
140 m4a audio only tiny 129k , m4a_dash container, mp4a.40.2@129k (44100Hz), 84.38MiB
So:
$ youtube-dl -f 140 'https://www.youtube.com/watch?v=7fSq0_Ljb_s' $ ffmpeg -i '【GAMABOOKS_コラボ企画】星空古本市開催!【新人VTuber】-7fSq0_Ljb_s.m4a' -ss 02:00 -t 30 gamabooks_cut.wav $ octave-cli octave:1> [y, Fs] = audioread('gamabooks_cut.wav'); octave:2> Y = fft(y); octave:3> plot(abs(Y));
Here’s our high frequency. Now zoom in to find the FFT index number:
The peak is at index 338543. Convert it to hertz (and note the 1-index):
octave:4> (338543-1) / length(y) * Fs ans = 1.1285e+04
So now we just need a way to suppress this frequency. Searching “mpv audio filter” online tells us that
mpv --af=help
will list all audio filters available. Looking through the list, I found:bandreject Apply a two-pole Butterworth band-reject filter.
So I just need to find out how to configure this filter. Searching online, I eventually came across some scripts that referenced the FFmpeg manual, specifically, the “equalizer” filter: (emphasis mine)
Apply a two-pole peaking equalisation (EQ) filter. With this filter, the signal-level at and around a selected frequency can be increased or decreased, whilst (unlike bandpass and bandreject filters) that at all other frequencies is unchanged.
Sounds like what I want. So to try it, with reference to the manual (the bandwidth and attenuation factor were determined by trial-and-error):
$ mpv --af=equalizer=f=11285:t=h:width=5:g=-100 gamabooks_cut.wav
Sounds a lot better. Now download the video:
$ youtube-dl -f 136 'https://www.youtube.com/watch?v=7fSq0_Ljb_s'
And play it:
$ mpv 【GAMABOOKS_コラボ企画】星空古本市開催!【新人VTuber】-7fSq0_Ljb_s.mp4 --audio-file=【GAMABOOKS_コラボ企画】星空古本市開催!【新人VTuber】-7fSq0_Ljb_s.m4a --af=equalizer=f=11285:t=h:width=5:g=-100
Done!
Preview clipped. Expand | Read full post in new tab
|
-
Source |
Signature
Arbitrariness and randomness
Veritasium seems to think that “arbitrariness” is the same as “randomness”. Without true randomness, upon repetition, the guard will gain information on how the renumbering method was chosen, thus decreasing the prisoners’ probability of success.
Preview clipped. Expand | Read full post in new tab
|
-
Source |
Signature
Cantilever Rock
I just learnt that there is something called “Cantilever Rock” / “Cantilever Stone” in Wales.
Uh, what? It looks more like a simply supported beam than a cantilever…
Photo: “Cantilever Stone on Glyder Fach” by George Tod, CC BY-SA 2.0 https://www.geograph.org.uk/photo/611071
Preview clipped. Expand | Read full post in new tab
|
subscribe via RSS