firefox keeps reloading existing tabs when i switch

Firefox will unload tabs if you’re running low on memory (for whatever reason). Change these settings in about:config to keep the tabs loaded, and then restart Firefox.

browser.tabs.unloadOnLowMemory = false
accessibility.blockautorefresh = true



  1. How To Stop Firefox Tabs From Auto-Refreshing on Tab Switch – Super User
  2. [Fix] Mozilla Firefox Automatically Suspends Tabs and Reloads When You Visit – AskVG

Internet searches

  1. firefox having to reload loaded tabs

ansible use jump box

If you need to connect through an intermediate jump box, or bastion server, here’s how you configure the inventory file:

ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p -q"'

If the jump box can resolve the target name as is, you don’t need to specify the IP address. However, you can also force a specific IP address.

c7-prod-app-01 ansible_host=10.300.15.3



Shamelessly ripped from Ansible with a bastion host / jump box? []

Hexedit stronghold.cfg to easily unlock military campaign missions

When I installed the Stronghold HD patch to take my CD installation of Stronghold v1.2 up to the latest, version 1.3, I had to rearrange the savegame files as indicated in the helpful documentation (for me, that was file ~/.wine/drive_c/Program Files/FireFly Studios/Stronghold/readme_en.html).

Old savegames and settings

Stronghold HD stores user maps, saves and settings in the Documents\Stronghold folder. If you have upgraded to Stronghold HD from an old version of Stronghold you will need to copy the maps, saves and settings from the Program Files\Firefly Studios\Stronghold folder (default location) to the Documents\Stronghold folder.

Savegames (.sav files)

Old Location: Program Files\Firefly Studios\Stronghold\saves
New Location: Documents\Stronghold\Saves

Maps (custom .map files)

Old Location: Program Files\Firefly Studios\Stronghold\maps
New Location: Documents\Stronghold\maps

Settings (stronghold.cfg)

Old Location: Program Files\Firefly Studios\Stronghold
New Location: Documents\Stronghold

Because I’m using the proper ISO saved from the original game disc, I’ve never needed a no-cd patch.
Anyway, I noticed that my military campaign mission status was not transferred to the new HD installation. I ensured the .sco files were in the new spot (the Saves directory) but it did not unlock the missions. I helpfully had a mission 17 b save that was right at the tail end of that mission, so loading and finishing it got me up to mission 18. However, I didn’t want to have to go through the difficult fixed-force invasion of the Pig’s castle, so I looked for cheat codes for a computer game for the first time in about a decade. Believe it or not, but I couldn’t find any (working) cheats that just declare “success” for a mission. So, I decided to hack the stronghold.cfg.

I’m old-school, so I whipped out vim and :%!xxd and here is the results of my research:

To set the military campaign level unlocked, modify byte 0x147 which is in line:

    00000140: 0000 0055 0000 0013 0000 0021 0000 0000  ...U.......!....
#                               ^
#                               +-- this is hex 0x13 or decimal 19.
This corresponds to being able to play level 19 of the military campaign.

You can use vi with :%!xxd and :%!xxd -r to convert stronghold.cfg to hexedecimal and back.

For Stronghold HD, that is file ~/Documents/Stronghold/stronghold.cfg

Of course you could abuse this, but I was just using it to recover my progress.
castle gate with soldiers garrisoned


My own original research and hacking on the config file.

How I use the OBS to build and host dpkgs for Devuan


I have started using the public instance of the Open Build Service (OBS), aka openSUSE Build Service.
This post documents my process for taking a package upstream, my packaging recipe (to use the OBS parlance), and getting a hosted package. If you want to duplicate my efforts with your own packages, I hope this helps.

The process

Install osc

The openbuild service command line tool is available in the Devuan ceres repos already, as package name osc.

Select what upstream package to build

My example will use FreeFileSync, because I already bundle it for Devuan and it only takes a few minutes to compile.
Additionally, because the upstream provides only a zip file, I am using my collaborative Opensource Tracking repo for the tarball which dpkg seemed to require and I gave up investigating how to get it to use a zip file as a source.

Prepare to use ocs locally

Osc seems to operate pretty similar to version control, with commits and so on.
If necessary, initialize osc and checkout the project. On the openSUSE OBS instance, it’s probably the home project.

mkdir -p ~/osc ; cd ~/osc
osc checkout home:bgstack15

Build package with osc

Make a new package, either on cli or on the web interface.

osc mkpac freefilesync

Source: Reference 3
Retrieve the upstream source tarball, and prepare the debian.tar.xz file.
I store my dpkg intructions in the exploded directory form in git. So to assemble the debian.tar.xz, I have a few additional steps.
In another location, extract the source tarball, and copy in the debian/ directory. Outside the directory from the tarball, run dpkg-source.

cd ~/deb
tar -zxf freefilesync_10.13.orig.tar.gz
cp -pr ~/dev/stackrpms/freefilesync/debian ./FreeFileSync-10.13/
dpkg-source -b FreeFileSync-10.13

Now the assets required by OBS should exist. Copy in the .dsc and debian tarball to the osc project directory.

[bgstack15@myhost|/home/bgstack15/osc/home:bgstack15/freefilesync]$ ls -al
total 2116
-rw-r--r-- 1 bgstack15 bgstack15    9588 Jun 28 13:49 freefilesync_10.13-1+devuan.debian.tar.xz
-rw-r--r-- 1 bgstack15 bgstack15    1073 Jun 28 13:49 freefilesync_10.13-1+devuan.dsc
-rw-rw-r-- 1 bgstack15 bgstack15 2147432 Jun 28 13:14 freefilesync_10.13.orig.tar.gz

I can perform a local build to ensure it builds correctly.

osc build --local-package Debian_Testing x86_64

That will run for a while, and have to download all the build dependencies on the first run too.
If all that was successful, it’s time to add the assets and commit.

osc add *
osc commit

Build package on OBS

The assets are now the public OBS.
debian tarball, dsc, and upstream tarball
My builds triggered right away when I committed the changes. It took time for build workers to kick off and return the results, but my packages were published within a few hours!

If you want to tell the OBS to rebuild a package, select the status message of the Build Results section.

At the top of the log page, select the “Trigger Rebuild” button.

Or you could run osc rebuild command.

Using the repository

Of course the reason you want to use the OBS is to build packages to install them! A pretty front page is available for a project. Here’s my freefilesync one. It shows up as debian unstable, but it should work on devuan too.

Install the apt key

wget -nv -O Release.key
apt-key add - > Release.key
apt-get update

Install the packages

You can inspect and make sure the package is in your metadata and coming from the expected repo.

$ apt-cache policy freefilesync
  Installed: (none)
  Candidate: 10.13-1+devuan
  Version table:
     10.13-1+devuan 500
        500  Packages

Install the package!

apt-get install freefilesync

Final thoughts

I tried using a _service file (example) to automate the build tasks. It involves having the .dsc files available (such as in source control), which is generated from dpkg-source -b dirname-of-package/. If I have to do all that, and upload the dsc file, and then have the build nodes do all the same work, it’s not really worth it to me. Also, I never got it working because I’m not as smart as that guy in the example.


A random, fellow Devuan user thinks it’s OK to use the OBS debian repos for Devuan packages.
Steven Pusser’s Pale Moon project was a great example to me.
Beginnerʼs Guide | Open Build Service
My debuild instructions:

cl ; time debuild -us -uc 2>&1 | tee -a ~/log/debuild.$( basename "$( pwd )" ).$( date "+%F" ).log ; echo $? ; debuild -- clean 1>/dev/null 2>&1 ;

How I use the COPR to build and host rpms for CentOS and Fedora


For about a year now, I have been using the Fedora Project’s public Cool Other Packages Repository (copr) to build and host rpms for my Fedora and CentOS GNU/Linux installations.
This post documents the process I use to take an upstream package, build the packages for the different chroots, and host them for download.

The process

No local tools are required, other than the source control software, normally git.

Select the upstream package

My example will use FreeFileSync, which is a great program and it’s quick to compile.
Additionally, because the upstream provides only a zip file, I am using my collaborative Opensource Tracking repo for the tarball which dpkg seemed to require and I gave up investigating how to get it to use a zip file as a source.

Prepare the spec file and additional artifacts

My spec file, patches, and additional items for building FreeFileSync on Fedora are on my gitlab page. This topic today is not intended to show you how to use rpmbuild, which is a deep and useful topic.

Add a package to copr

With the rpm sources available on the Internet, we’re ready to work in the copr environment.

Create a project

A project can host a single package or many. Also useful to note, that a spec file can produce more than one rpm. So for the copr, a “package” can include either a single rpm artifact or multiple. For example, a libssl.spec will probably produce a libssl-devel, libssl, and libss-docs rpms. You would only have to set up the libssl.spec, and any produced rpms will just be handled automatically.
So, on the main page of COPR, select “New Project.”

Name the project and include any long-form text you care to share. The build options, farther down the page, are important. You can always change these options later, so don’t feel that you have to be extremely careful right now. Select the chroot arch environments you want to build the rpms for.

The external repositories section is really nice. If you need the packages from your favorite Internet yum repo, you can paste the baseurl values here.

Create a new package

In your shiny new project, you will want to add some packages!
Select the Packages tab, and then “New package.”

Plug in the relevant information.
For FreeFileSync, my rpmbuild input artifacts are at, with a committish (I love that term!) of “freefilesync-bump” which is the dev tree I use for testing the latest version of FreeFileSync.
The subdir for just the freefilesync package, in my entire git tree, is freefilesync/. I’ve got a lot of other spec files in there, but the copr can look in just one dir, which is pretty great.
Use the “rpkg” option, based on the git source. I don’t actually know how the other methods work, and the rpkg has always been good enough for git-hosted spec files for me.

If the package needs to be excluded from certain architectures, there’s a blacklist field you can use.
Save the package settings.

Trigger a build

On the package list, find the new package and select “Rebuild.”

You can choose which chroots to use, and the checkboxes are pre-populated with your defaults and blacklist. My freefilesync package has some unresolvable build dependencies on EL6, so I have excluded those.

Also, specifically, FreeFileSync needed some very custom dependencies co build on EL7– some higher versions of libs like curl and openssl, so it’s a complex dependency tree so either include copr://bgstack15/FreeFileSync in your project’s external repository list.

Use virt-install to fully automate the install for Devuan with preseed

I recently discovered how to use a Debian preseed file while building a VM in kvm. After hand-crafting my Devuan preseed file, here it is in all my customized and I’m sure duplicate-filled and bogus-answer-encrusted glory.

How I use this

I define a variable, and plug it into the important parts.

vm=d2-04a ; time sudo virt-install -n "${vm}" --memory 2048 \
   --vcpus=1 --os-variant=debiantesting -v \
   --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 \
   -l /mnt/public/Support/SetupsBig/Linux/devuan_ascii_2.0.0-beta_amd64_DVD.iso \
   --initrd-inject=/mnt/public/Support/Platforms/devuan/preseed/preseed.cfg \
   --extra-args "hostname=${vm} interface=auto" \
   --debug --network type=bridge,source=br0 --noautoconsole

Some thoughts

For some reason I was unable to get the preseed to work with the non-beta Ascii iso. When I started the preseed vm activity, I already had the beta disc so I was using it first before I downloaded the release disc, which didn’t even work. So I reverted to the beta disc. Please share any results, working or otherwise, you have when trying this with the release disc.
I do some tricky stuff in here with grub and the ceres release. Apparently consolekit messes with some of the files grub wants to lay down in /boot (having to do with locales), so I had to create this complex solution. I don’t even care that it’s “grub-legacy.” It seems a little simpler for a simpler time, and also works, so why bother doing anything different?

The preseed file

# File: /mnt/public/Support/Platforms/devuan/devuan-preseed1.txt
# Locations:
#    /mnt/public/Support/Platforms/devuan/devuan-preseed1.txt
# Author: bgstack15
# Startdate: 2019-06-25
# Title: Kickstart for CentOS 7 for
# Purpose: To provide an easy installation for VMs and other systems in the Mersey network
# History:
#    2017-06 I learned how to use kickstart files for the RHCSA EX-200 exam
#    2017-08-08 Added notifyemail to --extra-args
#    2017-10-29 major revision to use local repository
#    2019-06-25 fork from centos7-ks.cfg
# Usage with virt-install:
#    vm=d2-04a ; time sudo virt-install -n "${vm}" --memory 2048 --vcpus=1 --os-variant=debiantesting -v --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 -l /mnt/public/Support/SetupsBig/Linux/devuan_ascii_2.0.0-beta_amd64_DVD.iso --initrd-inject=/mnt/public/Support/Platforms/devuan/preseed/preseed.cfg --extra-args "hostname=${vm} interface=auto" --debug --network type=bridge,source=br0 --noautoconsole
#    vm=d2-04a; sudo virsh destroy "${vm}"; sudo virsh undefine --remove-all-storage "${vm}";
# Reference:
#    /mnt/public/Support/Platforms/CentOS7/install-vm.txt
#    syntax for --location
#    example preseed
#    skip next dvd question
#    grub problem caused by consolekit:amd64
# Improve:
#    discover how to send email, using postfix or sendmail. Don't care which, but exclude exim4.
#    echo "$( hostname ) has IP $( ip -4 -o a s eth0 | awk '{print $4}' | sed -r -e 's/\/.*$//' )" | 
#    add the kernel lines: console=ttyS0 console=tty1. Get this to work; tried manually but perhaps devuan doesn't use console the same way?

d-i debian-installer/country string US
d-i debian-installer/keymap select us
d-i debian-installer/language string en
d-i debian-installer/locale string en_US
d-i localechooser/supported-locales string en_US.UTF-8

d-i keyboard-configuration/layoutcode string us
d-i keyboard-configuration/variantcode string
d-i keyboard-configuration/xkb-keymap select us

d-i netcfg/disable_autoconfig boolean false
d-i netcfg/get_domain string
d-i netcfg/wireless_wep string
# disable asking for non-free firmware, because this is a vm and has none
d-i hw-detect/load_firmware boolean false

#d-i apt-setup/enable-source-repositories boolean false
# ORIGINAL d-i apt-setup/services-select multiselect security updates, release updates, backported software
d-i apt-setup/contrib boolean true
d-i apt-setup/disable-cdrom-entries boolean true
d-i apt-setup/non-free boolean true
d-i apt-setup/use_mirror boolean true
d-i mirror/country string manual
d-i mirror/http/directory string /devuan
d-i mirror/http/hostname string
d-i mirror/http/proxy string
d-i mirror/protocol string http
d-i mirror/suite string testing

d-i apt-setup/cdrom/set-failed boolean false
d-i apt-setup/cdrom/set-first boolean false
d-i apt-setup/cdrom/set-next boolean false

# my repos and ceres
d-i apt-setup/local0/comment string smith122deb
d-i apt-setup/local0/key string
d-i apt-setup/local0/repository string /
d-i apt-setup/local1/comment string devuan-deb
d-i apt-setup/local1/key string
d-i apt-setup/local1/repository string /
d-i apt-setup/local2/comment string ceres
d-i apt-setup/local2/key string
d-i apt-setup/local2/repository string ceres main contrib non-free
# if for some reason I really need to turn off the gpg key check:
#d-i debian-installer/allow_unauthenticated boolean false

tasksel tasksel/first multiselect standard, ssh-server

# adapted from /mnt/public/Support/Platforms/devuan/devuan.txt, main fluxbox desktop, but for a vm
# no xscreensaver, for a vm.
d-i pkgsel/include string \
   alsamixergui alttab apt-transport-https bgconf bgscripts bgscripts-core \
   cifs-utils curl fluxbox freeipa-client git grub lightdm lightdm-gtk-greeter \
   mlocate net-tools nfs-common ntpdate oddjob-mkhomedir=0.1-1 openssh-server \
   p7zip palemoon palemoon-ublock-origin parted qemu-guest-agent rsync scite \
   screen spice-vdagent strace sudo tcpdump vim vlc volumeicon-alsa waterfox \
   xfce4-terminal xfe xserver-xorg-video-qxl

d-i pkgsel/upgrade select none

popularity-contest popularity-contest/participate boolean true

d-i clock-setup/ntp boolean true
d-i clock-setup/ntp-server string
d-i time/zone string America/New_York

# skip grub during main part, because we will do it in late_command
d-i grub-installer/skip boolean true
# these next 2 are experimental
d-i grub-installer/skip-again boolean true
d-i grub-installer/skip-confirm boolean true
d-i grub-installer/confirm_skip boolean true
d-i nobootloader/confirmation_common boolean true

d-i lilo-installer/skip boolean true
#d-i grub-installer/with_other_os boolean true
#d-i grub-installer/only_debian boolean true
#d-i grub-installer/grub2_instead_of_grub_legacy boolean true
#d-i grub-installer/bootdev string /dev/vda
#d-i grub-installer/choose_bootdev select /dev/vda
#grub-installer grub-installer/force-efi-extra-removable boolean false

d-i passwd/root-password password f0rg3tkickstart&
d-i passwd/root-password-again password f0rg3tkickstart&

d-i partman-auto/choose_recipe select home
d-i partman-auto-crypto/erase_disks boolean false
d-i partman-auto/disk string /dev/vda
d-i partman-auto/init_automatically_partition select biggest_free
d-i partman-auto/method string lvm
d-i partman/choose_label string gpt
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
d-i partman/confirm_write_new_label boolean true
d-i partman/default_label string gpt
#d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-md/confirm_nooverwrite boolean true
#d-i partman/mount_style select uuid
d-i partman-partitioning/confirm_write_new_label boolean true

# Uncomment this to add multiarch configuration for i386
#d-i apt-setup/multiarch string i386

d-i passwd/make-user boolean true
d-i passwd/user-fullname string bgstack15
d-i passwd/username string bgstack15
d-i passwd/user-password-crypted password $6$85aKM2DkiD5g9r3D$zkbcVES1Bzu.b5dBJxklSggEJzswZBlVAyc9LUUIzMA2OLRH2PD2ZWE9Q40Wtw/3OOxDM2nF031hfD4s5LGuG1
d-i passwd/user-default-groups string audio cdrom video

d-i finish-install/reboot_in_progress note
d-i cdrom-detect/eject boolean true

# additional application stuff just in case it works and is useful
# LDAP server URI:
d-i shared/ldapns/ldap-server	string	ldapi:///

d-i openssh-server/password-authentication	boolean	true
d-i openssh-server/permit-root-login	boolean	false

# Remove consolekit from ceres, which disrupts /boot/grub/local/*mo files, that grub-install wants.
d-i preseed/late_command string in-target apt-get purge -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" consolekit exim4\* ; \
   apt-get install -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" postfix ; \
   in-target grub-install /dev/vda ; in-target update-grub ; \
   in-target wget -O /usr/local/share/ca-certificates/ && update-ca-certificates || : ; \
   in-target su bgstack15 -c "sudo /usr/bin/" 1>/root/clone.log 2>&1 ; \
   in-target sed -i -r -e '/^kernel/s/(\s*console=.{1,7}[0-9])*\s*$/ console=tty0 console=ttyS0/;' /boot/grub/menu.lst ; \
   in-target sed -i -r -e '$aT0:23:respawn:/sbin/getty -L ttyS0 9600 vt100' /etc/inittab

Use virt-install to fully automate the install for CentOS/Fedora with kickstart

Here is my kickstart file for CentOS 7. I deploy VMs into my kvm environment with a oneliner, using this kickstart file.

How I use this

I define a variable, and plug it into the important parts.

vm=c7-04a ; time sudo virt-install -n "${vm}" --memory 2048 \
   --vcpus=1 --os-variant=centos7.0 --accelerate -v \
   --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 \
   -l /mnt/public/Support/SetupsBig/Linux/CentOS-7-x86_64-Minimal-1810.iso \
   --initrd-inject=/mnt/public/Support/Platforms/CentOS7/centos7-ks.cfg \
   --extra-args "ks=file:/centos7-ks.cfg SERVERNAME=${vm}" \
   --debug --network type=bridge,source=br0 --noautoconsole

Some thoughts

I had to download the 1810 release of the iso, because there was something wrong with the repos or perhaps files in the previous isos, with how they interacted with either the virtual environment or the network or something. But the CentOS-7-x86_64-minimal-1810.iso was important.
I found the SERVERNAME trick on the Internet. You can iterate over /proc/cmdline and react to values you find there, in the %pre or %post scripts.
You will see that I use my own local repositories for the regular CentOS repos, and I add my own internal one (smith122/repo/rpm). Obviously you should find a suitable set of repos for your own.
You will also see that I attempt to download my CA certificates at various points. I’m pretty sure the %pre effort fails, because the system is not on the network yet.


The kickstart file

# File: /mnt/public/Support/Platforms/CentOS7/centos7-ks.cfg
# Locations:
#    /mnt/public/Support/Platforms/CentOS7/centos7-ks.cfg
# Author: bgstack15
# Startdate: 2017-06-02
# Title: Kickstart for CentOS 7 for
# Purpose: To provide an easy installation for VMs and other systems in the Mersey network
# History:
#    2017-06 I learned how to use kickstart files for the RHCSA EX-200 exam
#    2017-08-08 Added notifyemail to --extra-args
#    2017-10-29 major revision to use local repository
# Usage with virt-install:
#    vm=c7-04a ; time sudo virt-install -n "${vm}" --memory 2048 --vcpus=1 --os-variant=centos7.0 --accelerate -v --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 -l /mnt/public/Support/SetupsBig/Linux/CentOS-7-x86_64-Minimal-1810.iso --initrd-inject=/mnt/public/Support/Platforms/CentOS7/centos7-ks.cfg --extra-args "ks=file:/centos7-ks.cfg SERVERNAME=${vm}" --debug --network type=bridge,source=br0 --noautoconsole
#    vm=c7-04a; sudo virsh destroy "${vm}"; sudo virsh undefine --remove-all-storage "${vm}";
# Reference:
#    /mnt/public/Support/Platforms/CentOS7/install-vm.txt

#platform=x86, AMD64, or Intel EM64T
# Install OS instead of upgrade
# Keyboard layouts
keyboard 'us'
# Root password
rootpw --plaintext SOMETHINGSTRONGHERE
# my user
user --groups=wheel --name=bgstack15-local --password=$6$.gh0u7vg2HDPJPX/$g4Y1l.q76fs7i0UK8t6h83bDIo2YnGGj/1DGeUzzbMTd0pBh4of6jNYWxxws/937sUiPgETqPsYFI5XNrkAle. --iscrypted --gecos="bgstack15-local"

# System language
lang en_US.UTF-8
# Firewall configuration
firewall --enabled --ssh
# Reboot after installation
# Network information
#attempting to put it in the included ks file that accepts hostname from the virsh command.
#network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate
%include /tmp/network.ks
# System timezone
timezone America/New_York --utc
# System authorization information
auth  --useshadow  --passalgo=sha512
# Use network installation instead of CDROM installation media
url --url=""

# Use text mode install
# SELinux configuration
selinux --enforcing
# Do not configure the X Window System

# Use all local repositories
# Online repos
repo --name=smith122rpm --baseurl=
repo --name=base --baseurl=$releasever/os/$basearch/
repo --name=updates --baseurl=$releasever/updates/$basearch/
repo --name=extras --baseurl=$releasever/extras/$basearch/
repo --name=epel --baseurl=$releasever/$basearch

# Offline repos

firstboot --disabled

# System bootloader configuration
bootloader --location=mbr
# Partition clearing information
clearpart --all --initlabel
# Disk partitioning information
autopart --type=lvm

echo "network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate --hostname" > /tmp/network.ks
for x in $( cat /proc/cmdline );
   case $x in
         eval $x
         echo "network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate --hostname ${SERVERNAME}" > /tmp/network.ks
         eval $x
         echo "${NOTIFYEMAIL}" > /mnt/sysroot/root/notifyemail.txt
cp -p /run/install/repo/ /etc/pki/ca-trust/source/anchors/ 2>/dev/null || :
wget -O /etc/pki/ca-trust/source/anchors/ || :
update-ca-trust || :

   # Set temporary hostname
   #hostnamectl set-hostname;

   # Get local mirror root ca certificate
   wget -O /etc/pki/ca-trust/source/anchors/ && update-ca-trust

   # Get local mirror repositories
   wget -O /etc/yum.repos.d/smith122rpm.repo;
   wget -O /etc/yum.repos.d/smith122rpm.mirrorlist
   distro=centos7 ; wget${distro}.repo -O /etc/yum.repos.d/smith122-bundle-${distro}.repo && grep -oP "(? /boot/grub2/grub.cfg

   # postfix is already started by default on centos7
   # Send IP address to myself
   thisip="$( ifconfig 2>/dev/null | awk '/Bcast|broadcast/{print $2}' | tr -cd '[^0-9\.\n]' | head -n1 )"
      echo "${SERVER} has IP ${thisip}."
      echo "system finished kickstart at $( date "+%Y-%m-%d %T" )";
   } | /usr/share/bgscripts/ -f "root@$( hostname --fqdn )" \
      -h -s "${SERVER} is ${thisip}" $( cat /root/notifyemail.txt 2>/dev/null )

   # No changes to graphical boot

   # fix the mkhomedir problem
   systemctl enable oddjobd.service && systemctl start oddjobd.service

   # Personal customizations
   mkdir -p /mnt/bgstack15 /mnt/public
   su bgstack15-local -c "sudo /usr/share/bgconf/"

) >> /root/install.log 2>&1


Convert vhs video tape to mkv file in Linux

I still own video tapes (VHS) and I have finally gotten around to getting a nice setup for saving them down to hard disk so I can clear out the old video tape collection. This is how I did it.
First of all, I knew I needed an RCA-to-something adapter. I found an “AV to USB converter” [] that does the trick. When attached to a Ubuntu 16.04 system, it shows up as /dev/video0. No additional steps required! To quote one of my role models [] on the Internet: “Linux — keep it simple.”
Now, I discovered over time that the audio input just didn’t work. But the video comes in perfectly! I was using vlc [] for the input capture. To get the audio to work, I had to find an RCA to mini-phono cable which I already owned. An example product is on [].
I also had to fiddle with the audio input settings to get the input to work right. I had to poke around with pulseaudio, alsa, and vlc to get the audio input to work the way I needed it.
For my setup (pictured below), I needed to make sure my input source was mic (the front jack on my desktop computer) and not line, which is probably the input in the back. I chose to set my mic boost (akin to gain) really low, and capture volume really high.

screenshot of alsa mixer on capture settings screen
I needed to set pulseaudio to allow the stereo input. I have discovered that pulseaudio is fragile, and also never remembers the settings I choose for it, so for every reboot or login or pulseaudio –start command, I have to go readjust the “profile.” I am starting to understand why people smarter (and more verbose) than me tend to dislike pulseaudio.
pavucontrol showing configuration
With alsa and pulse set up correctly, it is now a matter of getting vlc to accept the audio input while accepting the video input. I had to discover how my system identifies the audio jack.

$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: CX20641 Analog [CX20641 Analog]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 2: CX20641 Alt Analog [CX20641 Alt Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: USB20 [AV TO USB2.0], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

By trial and error, I learned the mic input is card 0, device 2. In alsa terms, that’s alsa://0,2.
So, to put it all together, I had to set VLC to open a “capture device” of /dev/video0, with audio device of hw:0,2. To get the audio and video to both be output by VLC, I had to go into advanced optiosn and se audio input = 0.
screenshot of vlc with /dev/video0, hw:0,2 and audio input=0 VLC always defaults to audio input=-1, so no audio will come through.
When I selected the Play button, it presents both audio and video from the VCR!
So, with the video on the screen that I want, I pressed the record button (from the toolbar visible when you select View -> Advanced controls). VLC records by default to avi format, which is not my preferred method, even though it is a temporary format.
So, I had to set all the settings again, and then select the drop-down arrow beside the Play button, and select “Convert.” A new window appears, and I select the file format I want and the output file.

With all the options set, I now return to the first options screen and select the “Convert” button.
After running through the whole video, I come back and hit stop in VLC.
I use HandBrake [] to convert the file to the format I want. The details of that are beyond the scope of this post.
For a bonus, I discovered that killing vlc safely closes the written file, so it is still viewable. So I just run a command in a terminal to kill vlc after the published length of the videotape:

$ sleep $(( 60 * 120 )) ; killall vlc

I could have done something fancier with xdotool to select the “stop” button, but why bother?

Display svg in tkinter python3

The Internet has a guide for displaying svgs in Tkinter in Python 2:
However, I have not found any guides for the process for python3. And since I don’t want to move backwards, I had to come up with something.

Here is my solution. (link)
Screenshot of tkinter window with svgs rendered as the images on buttons, one scaled and one unscaled.

#!/usr/bin/env python3
# File:
# License: CC-BY-SA 4.0
# Author: bgstack15
# Startdate: 2019-06-21 10:09
# Title: 
# Purpose: 
# History:
# Usage:
# References:
# Improve:
# Dependencies:
#    devuan: python3-tk python3-pil.imagetk python3-cairosvg
#    el7: python36-tkinter python36-pillow-tk ( pip3 install cairosvg )

import re
import tkinter as tk
from PIL import Image, ImageTk, PngImagePlugin

   from cairosvg import svg2png
   LM_USE_SVG = 1
   print("WARNING: Unable to import cairosvg. No svg images will be displayed.")
   LM_USE_SVG = 0

# graphical classes and functions
print("Loading graphics...")

def photoimage_from_svg(filename = "",size = "48"):
   # this one works, but does not allow me to set the size.
   # this is kept as an example of how to open a svg without saving to a file.
   # open svg
   item = svg2png(url=filename, parent_width = size, parent_height = size)
   return ImageTk.PhotoImage(data=item)

def empty_photoimage(size=24):
   photo ="RGBA",[size,size])
   return ImageTk.PhotoImage(image=photo)

def image_from_svg(filename = "",size = 0):
   # open svg
   if LM_USE_SVG == 1:
      if size == 0:
         # unscaled
         svg2png(url=filename,write_to="/tmp/example_temp_image.png",parent_width = size,parent_height = size)
      photo ="/tmp/example_temp_image.png")
      photo ="RGBA",[size,size])
   return photo

def get_scaled_icon(iconfilename, size = 0):

      print("Opening icon file",iconfilename)
      # try an svg
      if re.compile(".*\.svg").match(iconfilename):
         photo = image_from_svg(filename=iconfilename, size=size)
         photo =
   except Exception as f:
      print("Error with icon file:", f)
      return empty_photoimage()

   if size != 0 and (type(photo) is Image or type(photo) is PngImagePlugin.PngImageFile):
      photo.thumbnail(size=[size, size])

   if not type(photo) is ImageTk.PhotoImage:
         photo = ImageTk.PhotoImage(photo)
      except Exception as e:
         print("Error was ",e)
   return photo

class App:
   def __init__(self, master):
      frame = tk.Frame(master)

      self.photo1 = get_scaled_icon("/usr/share/icons/Numix/128/actions/system-log-out.svg", 20)
      self.button1 = tk.Button(frame, text="Scaled to 24x24", image=self.photo1, compound=tk.LEFT)

      self.photo2 = get_scaled_icon("/usr/share/icons/Numix/128/actions/system-log-out.svg")
      self.button2 = tk.Button(frame, text="Unscaled", image=self.photo2, compound=tk.LEFT)

      self.buttonCancel = tk.Button(frame, text="Cancel", underline=0, command=self.quitaction)

   def quitaction(self,b=None):
      print("Closing the window...")

root = tk.Tk()

root.title("SVG examples")
imgicon = get_scaled_icon("/usr/share/icons/Numix/128/actions/system-log-out.svg", 24)'wm','iconphoto', root._w, imgicon)
app = App(root)