Air Date:
Latest update:
I expected to use this "new" eslint as follows:
- have a user-wide eslint installation with a personal default
configuration;
- given #1, to be able to run eslint in any project (mine or not)
to check it against my personal rules;
- if a project has
node_modules/.bin/eslint
script (implying there
is a config file in the project's root directory), running
node_modules/.bin/eslint
should ignore the global config and use
the local one;
- Flycheck in Emacs should automatically execute either
node_modules/.bin/eslint
(if it exists) or the global version
otherwise.
Naïvely installing eslint via 'npm i -g' won't do much good since any
plugins must still be installed locally.
Hence, I created a directory ~/lib/dotfiles/eslint
solely for a
"global", user-wide installation & configuration:
|-- eslint*
|-- eslint.config.mjs
|-- node_modules/
| |-- .bin/
| | `-- eslint -> ../eslint/bin/eslint.js*
| `-- eslint/
`-- package.json
where eslint is a shell script, symlinked from a directory in PATH:
$ stat -c%N `which eslint`
'/home/alex/bin/eslint' -> '/home/alex/lib/dotfiles/eslint/eslint'
$ cat eslint
#!/bin/sh
__dir__=$(dirname "$(readlink -f "$0")")
"$__dir__"/node_modules/.bin/eslint -c "$__dir__"/eslint.config.mjs "$@"
and eslint.config.mjs
has common rules for .js files and files
without extensions:
import globals from 'globals'
import js from '@eslint/js'
import react from 'eslint-plugin-react'
export default [
js.configs.recommended,
{
rules: {
"no-unused-vars": [ "warn", { "argsIgnorePattern": "^_" } ],
…
},
languageOptions: {
globals: {
...globals.browser,
...globals.node,
…
}
}
},
{
files: ["**/!(*.*)"],
ignores: ["**/{Makefile,Rakefile,Gemfile,LICENSE,README}"],
},
…
]
If you don't care about any custom configurations that arrive with
almost any JS project, you may stop here. Otherwise, we need to
instruct Emacs where to search for eslint executable.
(defun my--npm-exec-path()
(let ((npm-root (string-trim
(shell-command-to-string "npm root 2>/dev/null"))))
(when (not (string= "" npm-root))
(make-local-variable 'exec-path)
(add-to-list 'exec-path (file-name-concat npm-root ".bin"))
)))
(add-hook 'js-mode-hook 'my--npm-exec-path)
(add-hook 'js-mode-hook 'flycheck-mode)
This tells the editor to invoke my--npm-exec-path
function every
time Emacs opens a .js file. The function runs npm root
to guess the
proper path for node_modules
directory and prepends Emacs'
internal exec-path
list with the path where the eslint script
might be installed. Iff such a script is found by Flycheck, our global
~/lib/dotfiles/eslint/eslint.config.mjs
is ignored.
Tags: ойті
Authors: ag
Air Date:
Latest update:
If downloading from a server is slow, how would you prove to a devops
guy that you're experiencing a slowdown? There are a couple of
possibilities, the worst of which would be sending a video. What if
you send a speed graph using data from curl?
Every second curl prints to stderr the following:
fprintf(tool_stderr,
"\r"
"%-3s " /* percent downloaded */
"%-3s " /* percent uploaded */
"%s " /* Dled */
"%s " /* Uled */
"%5" CURL_FORMAT_CURL_OFF_T " " /* Xfers */
"%5" CURL_FORMAT_CURL_OFF_T " " /* Live */
" %s " /* Total time */
"%s " /* Current time */
"%s " /* Time left */
"%s " /* Speed */
"%5s" /* final newline */,
…
Therefore, by replacing \r with \n we can send a download log:
$ curl http://example.com/1.zip -o 1.zip 2>&1 | tr \\r \\n
To draw a graph with gnuplot, we can use Current time and Speed
columns. Gnuplot understands time as input data, but I don't know how
to persuade it to interpret values like 100k or 200M, thus we need to
convert them into 'bytes'. This is a cute little problem for code
golf, but amusingly, it was already solved in coreutils > 12 years ago
via numfmt(1).
$ echo 1M and 10M | numfmt --from iec --field 3
1M and 10485760
(macOS & FreeBSD both have coreutils package, where the utility
executable is prefixed with 'g'.)
#!/usr/bin/env -S stdbuf -o0 bash
set -e -o pipefail
numfmt=`type -p gnumfmt numfmt;:`; test "${numfmt:?}"
cat <<E
set xdata time
set timefmt "%H:%M:%S"
set xlabel "Time, MM:SS or HH:MM:SS"
set format y "%.0s%cB"
set ylabel "Speed, Unit/second" offset -1,0
set grid
plot "-" using 1:2 with lines title ""
E
curl "$@" -fL -o /dev/null 2>&1 | tr \\r \\n | awk '
/[0-9.][kMGTP]?$/ {
time = index($10, ":") == 0 ? $11 : $10
if (time != "--:--:--") print time, $NF
}' | tr k K | $numfmt --from iec --field 2
Usage:
$ ./curlbench http://example.com/1.zip | gnuplot -p
Tags: ойті
Authors: ag
Air Date:
Latest update:
I wanted to replace my old trusty 'router' (with an attached
HDD)--that was not working as a router, but as a network drive after
flashing OpenWRT onto it--I wanter to replace it with an SBC+HDD
combo.
This new device should not only preserve all the services the old one
provided (samba, git, rsyncd, a dnf repo), but also perform faster,
for having a potato instead of a CPU, the ex-router struggled with
rsync over ssh &, being gravely RAM limited, choked when I did 'git
push' commits containing binaries > 15MB.
Searching for a suitable SBC led me to libre.computer, a company I had
never heard of before. At first glance, they had the el cheapo
AML-S805X-AC board I needed:
- LAN port (but 100 Mb only);
- 2 USB-A (but 2.0 only);
- 4-core ARM Cortex-A53;
- 1 GB RAM;
- booting from an USB;
- up-to-date Debian;
- easy to buy without hunting it down.
100Mb may seem like a joke nowadays, but the main purpose of such a
toy NAS for me is to keep a copy of a directory with ~200K small
files. Having 1Gb would only marginally improve the syncing speed even
if the SBC supported USB 3.0.
But this is just a board. I also needed an hdd enclosure with an
external power supply (for the device provides up to 900mA for
each USB-A), at least 3A power supply & a micro-USB cable that can
handle 3A.
Item | Price, € | Comment |
SBC | 20 | |
HDD enclosure | 12 | |
3A Power Supply | 5 | |
Micro-USB cable | 3 | |
4 bolts, 12 nuts | 0 | I think the ones I found are older than me |
TTL to USB dongle | 3 | Optional, the board has an HDMI output |
Total | 43 | |
(I didn't include an HDD in the table, for I presume everyone has a
couple of them lying around.)
When I bought the HDD enclosure, I didn't read the description
carefully & thought it was going to be a small plastic container for
2.5-inch drives, but when the package arrived, it turned out to be a
box for 3.5-inch ones. Hence, I decided to shove the SBC into it too.
After connecting the TTL-to-USB dongle to the board's GPIO
& typing
$ sudo screen /dev/ttyUSB0 115200
one of the 1st readouts appeared as:
U-Boot 2023.07+ (Nov 03 2023 - 15:10:36 -0400) Libre Computer AML-S805X-AC
Model: Libre Computer AML-S805X-AC
SoC: Amlogic Meson GXL (S805X) Revision 21:d (34:2)
DRAM: 512 MiB (effective 1 GiB)
What does the last line mean exactly? After I dd'ed Debian-12 onto a
flash drive, free(1) said it saw 1GB. Anyway, libre.computer has an
official OS image, based on stock Debian:
$ fdisk debian-12-base-arm64+arm64.img -l
Disk debian-12-base-arm64+arm64.img: 2.25 GiB, 2415919104 bytes, 4718592 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x71f3f7cf
Device Boot Start End Sectors Size Id Type
debian-12-base-arm64+arm64.img1 * 2048 524287 522240 255M ef EFI (FAT-12/16/32)
debian-12-base-arm64+arm64.img2 524288 4718591 4194304 2G 83 Linux
Yes, it has an EFI partition with the MBR layout! The 2nd partition is
btrfs (supposedly it's faster & more gentle to flash storage than
ext4; no idea if both claims are true). You can examine its contents via:
$ sudo mount -o loop,offset=$((524288*512)) debian-12-base-arm64+arm64.img ~/mnt/misc
This partition gets auto-resized on the 1st boot to fill the rest of
the free space available on the drive. Doing this on USB dongles
proved to be a miserable experience: of the 3 I had available, one
permanently got stuck on resizing, and another, despite finishing the
operation, became so sluggish afterwards that a 20-year-old PC would've
felt snappier.
This is I didn't like at all. There is no repo with from which the OS
image gets generated. The explanation is bizarre:
"The distribution builder is a proprietary commercial offering as it
involves a lot of customer IP and integrations so it cannot be
public."
but with an consolation advice:
"If you want to study them [images], bootstrap and do a diff. We
don't make any changes to the standard distros outside of setting a
few configs since we're not distro maintainers."
Make of it what you will.
Then I connected the HDD enclosure to the board. This time, the
process went much, much faster (though there were still some
unexpected delays in random places). Right after logging in, I started
getting uas_eh_abort_handler
errors from the kernel. It turns out I
got one of the worst HDD enclosure innards possible, if you believe
reviews from the interwebs:
$ lsusb
Bus 001 Device 002: ID 152d:0578 JMicron Technology Corp. / JMicron USA Technology Corp. JMS578 SATA 6Gb/s
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
The remedy is to turn UAS off via adding
usb-storage.quirks=152d:0578:u
to the kernel cmdline. It did help,
the delays went away, although 'benchmarks' became hardly thrilling:
$ lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci-hcd/2p, 480M
|__ Port 2: Dev 2, If 0, Class=Mass Storage, Driver=usb-storage, 480M
$ sync; time sh -c "dd if=/dev/urandom of=1 bs=500k count=1k && sync"; rm 1
1024+0 records in
1024+0 records out
524288000 bytes (524 MB, 500 MiB) copied, 15.1014 s, 34.7 MB/s
real 0m21.876s
user 0m0.001s
sys 0m7.976s
which means MB/s on an ext4 partition.
Would I recommend this setup? I wouldn't. One of the reasons I've
chosen the path with an SBC instead of a common micro-ITX route is to
save on power consumption. If you don't have similar
problems, I see 0 reasons to struggle with such a finicky Chinese
device.
Tags: ойті
Authors: ag