Recently I needed to sort a file of entries by the date in each entry, where the date was a human-readable string across a few whitespace breaks. The format of each line was like this:
1 | ENTRY-0009 FAIL Thu Sep 5 17:39:24 2019 PASS 7 FAIL 6
|
But the most obvious sort command
sort entries.txt -k7 -k4M -k5 -k6
didn't produce results sorted in the expected order (2019, Sep [month], 5, 17:39:24). Let me show you after the break:
We have some Brother label makers and I wanted to programmatically make one print stuff, from a mac. First, I installed the ptouch drivers from the Brother website. Took ages to fiddle with it just right, but the product is very simple. Here's an example with 12mm wide tape and 12-character-wide printing.
Brother PT 2730:
123 | echo "0123456789AB" | \
lpr -o media=12mm -o PageSize=Custom.30x99 -o page-top=8 \
-o landscape -P Brother_PT_2730;
|
Brother PT D600:
123 | echo "0123456789AB" | \
lpr -o media=12mm -o PageSize=Custom.28x93 -o page-top=8 \
-o landscape -P Brother_PT_D600;
|
You can see some small differences - details after the jump.
We wanted to set up some infrastructure that would send mail through a shared icloud account. Here's how we did that:
- Set up icloud account.
- Set up AppleID for said icloud account / the mac(s) running the infrastructure.
- Fully log in to your Apple ... stuff. Mac, icloud, apple ID, etc. You must use two-factor authentication to do so.
- Go to your AppleID management interface, once fully logged in and authenticated.
- Create an "app specific password."
You should now be fully set up and ready to go! Invoke your
script. Let's assume your icloud account is
myfakeaccount@icloud.com. This should be it!
123456789 | python mailer.py \
--user myfakeaccount \
--passwd <app specific password in the format: aaaa-aaaa-aaaa-aaaa> \
--host smtp.mail.me.com \
--port 587 \
--from_addr myfakeaccount@icloud.com \
--to_addr <your address> \
--subj "Your subject" \
--attach your_file.txt
|
If that doesn't work, well, check the
reference document we used to get going and see what's wrong.
Work based on a
previous reference: my python script to send mail on MacOS. (As previously mentioned, on Linux I just use mail/sendmail.) I believe interacting with this script is cleaner and simpler. The password is hardcoded, but for the automation infrastructure we're using, something has to store the password, so why not the caller? We can probably do better ... but.
Script after the jump.
We recently needed to clone some SD cards - or, more precisely, copy a directory structure. Apparently SD card cloners are kind of expensive. We didn't really need a block-type copy, just a standard copy, so I whipped up a script. Details after the jump.
I have a Razer mouse. Linux Mint seems to switch the side buttons' actions, where the button that I feel means "forward" does "back," and vice versa. I wrote a startup script to solve this problem by flipping them around.
To start, I used xev
to figure out which my side buttons were. I found that they were 8 and 9.
Next, I used xinput to figure out the buttons currently set up:
12 | $ xinput | grep -i "usb optical mouse" | sed -e "s/.*id=\(\S*\)\s*.*/\1/"
8
|
So the USB optical mouse is ID 8. Next, check the button map:
12 | $ xinput get-button-map 8
1 2 3 4 5 6 7 8 9 10 11 12 13
|
Finally, to switch them:
1 | xinput set-button-map 8 1 2 3 4 5 6 7 9 8 10 11 12 13
|
And it worked! Then I added the code to my ~/.profile
:
123456789 | MOUSE_SW_BTNS_ID=`xinput | grep -i "usb optical mouse" | sed -e "s/.*id=\(\S*\)\s*.*/\1/"`
if [ ! -z "$MOUSE_SW_BTNS_ID" ]; then
MOUSE_SW_BTNS_MAP=`xinput get-button-map $MOUSE_SW_BTNS_ID`
MOUSE_SW_BTNS_CMP="1 2 3 4 5 6 7 8 9 10 11 12 13 "
if [ "$MOUSE_SW_BTNS_MAP" = "$MOUSE_SW_BTNS_CMP" ]; then
MOUSE_SW_BTNS_SET="1 2 3 4 5 6 7 9 8 10 11 12 13"
xinput set-button-map $MOUSE_SW_BTNS_ID $MOUSE_SW_BTNS_SET
fi
fi
|
Well, I had a really good one today. Thankfully, I only wasted about an hour.
Here's the outline: I have a userspace driver that does some relatively generic things that I compiled as a dynamic library (let's call it libmydev_ctrl.dylib). On top of that, I have a device-specific userspace driver for specific functionality that I compiled as a dynamic library (let's call it libmydev_ctrl_spec.dylib). On top of that, I have binaries that use device-specific drivers (let's call it myexecutable).
Compiling is fairly straightforward. First, the "generic" dylib:
12345678910 | DYLIB_ALL_NAME := libmydev_ctrl.dylib
TARGET_DYLIB_ALL := $(TARGET_DIR)/$(DYLIB_ALL_NAME)
INST_DYLIB_ALL := $(INSTALL_DIR)/$(DYLIB_ALL_NAME)
$(TARGET_DYLIB_ALL): $(OBJECTS_ALL) | $(TARGET_DIR)
@printf "%-16s %-8s %s\n" "link" "LLD" $(notdir $@)
@$(COMPILER) -o $@ \
-install_name $(INST_DYLIB_ALL) -dynamiclib \
$^ $(FLAGS) $(INCLUDES) $(LIBRARIES)
|
And then we do something very similar to compile the device-specific dylib; as you can see, the only real difference in the makefile is that the "generic" dylib is a pre-requisite of the "specific" dylib:
12345678910 | DYLIB_PLAT_NAME := libmydev_ctrl_$(TARGET_NAME).dylib
TARGET_DYLIB_PLAT := $(TARGET_DIR)/$(DYLIB_PLAT_NAME)
INST_DYLIB_PLAT := $(INSTALL_DIR)/$(DYLIB_PLAT_NAME)
$(TARGET_DYLIB_PLAT): $(OBJECTS_PLAT) $(TARGET_DYLIB_ALL) | $(TARGET_DIR)
@printf "%-16s %-8s %s\n" "link" "LLD" $(notdir $@)
@$(COMPILER) -o $@ \
-install_name $(INST_DYLIB_PLAT) -dynamiclib \
$^ $(FLAGS) $(INCLUDES) $(LIBRARIES)
|
Finally, we compile the binary/executable; we make the "generic" and "specific" dylibs pre-requisites, along with the source file with the main function:
1234 | $(TARGET): $(TARGET_DYLIB_ALL) $(TARGET_DYLIB_PLAT) $(SRC)
@printf "%-16s %-8s %s\n" "compile/link" "C++/LLD" $(notdir $@)
@$(COMPILER) -o $@ $^ $(FLAGS) $(INCLUDES) $(LIBRARIES)
|
If you're trying to follow along without make, the commands look like this:
1234567891011121314151617181920 | c++ -o libmydev_ctrl.dylib \
-install_name /usr/local/opt/libmydev_ctrl.dylib -dynamiclib \
source1.o source2.o source3.o \
-Wall -Werror -Wextra -Wno-unused-variable \
-Wno-unused-parameter -Wno-unused-function \
-Wno-unused-private-field \
-std=c++1y -g
c++ -o libmydev_ctrl_spec.dylib \
-install_name /usr/local/opt/libmydev_ctrl_spec.dylib -dynamiclib \
spec_source.o libmydev_ctrl.dylib \
-Wall -Werror -Wextra -Wno-unused-variable \
-Wno-unused-parameter -Wno-unused-function \
-Wno-unused-private-field \
-std=c++1y -g
c++ -o myexecutable libmydev_ctrl.dylib libmydev_ctrl_spec.dylib dostuff.cpp \
-Wall -Werror -Wextra -Wno-unused-variable -Wno-unused-parameter \
-Wno-unused-function -Wno-unused-private-field -std=c++1y -g
|
But what falls out? Not good things. Solution after the jump:
1234567 | dyld: lazy symbol binding failed: Symbol not found: __Z4init8dev_type
Referenced from: myexecutable
Expected in: /usr/local/opt/libmydev_ctrl.dylib
dyld: Symbol not found: __Z4init8dev_type
Referenced from: myexecutable
Expected in: /usr/local/opt/libmydev_ctrl.dylib
|
MySQL has an interesting issue - I call it a problem, I think MySQL calls it documented and expected behavior - where if you attempt to insert a row into a table (InnoDB) and the insertion fails due to a constraint violation, it will still increment the auto-increment counter.
The solution, annoying as it is, is to basically do a check while inserting to not even attempt the insert if that particular constraint (or, really, any other constraint you decide) would fail.
Let's say I have a table of "seen devices." Let's say each device checks in once in a while, but I want to poll the list of active devices far more frequently. I don't want to insert entries for devices showing up present if an identical entry (ID and last-seen timestamp) is already present. (Actually, for safety, let's say that if an entry with the same ID and a greater-than-or-equal-to last-seen timestamp is present.) The code (using prepared statements) looks something like this:
123456 | INSERT INTO devs_alive (dev_id, last_seen)
SELECT * FROM (SELECT ?, ?) AS tmp
WHERE NOT EXISTS (
SELECT entry_id FROM devs_alive
WHERE dev_id = ? AND last_seen >= ?
) LIMIT 1;
|
And since we're using prepared statements, you obviously have to bind the parameters, which might look something like:
1234 | $stmt = $conn->prepare($query);
$stmt->bind_param('iiii', $dev_id, $last_seen, $dev_id, $last_seen);
$stmt->execute();
$stmt->close();
|
Or
123 | $stmt = $conn->prepare($query);
$rows = $stmt->execute($dev_id, $last_seen, $dev_id, $last_seen);
$stmt->finish;
|
Archive: August 2017 »