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.

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)

Install cairosvg for python3 on el7

I wanted to install cairosvg on my CentOS 7 terminal server.
Come to find out, I had to install in using pip, because el7 only has cairosvg for the python2.

# yum list python-cairosvg
Loaded plugins: ulninfo
Installed Packages
python-cairosvg.noarch                                             1.0.7-3.el7                                             @epel

So, I had to go get pip3.
Enable the correct repos when installing pip3 and the dependencies for cairosvg.

yum --enablerepo=epel,updates install python36-pip cairo python36-devel libffi-devel

Use the http proxy when calling pip3 to update itself.

$ sudo https_proxy=http://10.123.456.789:3128 pip3 install --upgrade pip

And then, installing cairosvg failed.

# https_proxy=http://10.123.456.789:3128 pip3 install cairosvg
Collecting cairosvg
  Using cached
Collecting defusedxml (from cairosvg)
  Using cached
Collecting cairocffi (from cairosvg)
  Using cached
    ERROR: Complete output from command python egg_info:
    ERROR: warning: no previously-included files found matching 'setup.pyc'
    warning: no previously-included files matching 'yacctab.*' found under directory 'tests'
    warning: no previously-included files matching 'lextab.*' found under directory 'tests'
    warning: no previously-included files matching 'yacctab.*' found under directory 'examples'
    warning: no previously-included files matching 'lextab.*' found under directory 'examples'
    zip_safe flag not set; analyzing archive contents...
    pycparser.ply.__pycache__.lex.cpython-36: module references __file__
    pycparser.ply.__pycache__.lex.cpython-36: module MAY be using inspect.getsourcefile
    pycparser.ply.__pycache__.yacc.cpython-36: module references __file__
    pycparser.ply.__pycache__.yacc.cpython-36: module MAY be using inspect.getsourcefile
    pycparser.ply.__pycache__.yacc.cpython-36: module MAY be using inspect.stack
    pycparser.ply.__pycache__.ygen.cpython-36: module references __file__
    Installed /tmp/pip-install-lxiyvrgx/cairocffi/.eggs/pycparser-2.19-py3.6.egg
    Traceback (most recent call last):
      File "", line 1, in 
      File "/tmp/pip-install-lxiyvrgx/cairocffi/", line 13, in 
      File "/usr/lib/python3.6/site-packages/setuptools/", line 129, in setup
        return distutils.core.setup(**attrs)
      File "/usr/lib64/python3.6/distutils/", line 108, in setup
        _setup_distribution = dist = klass(attrs)
      File "/usr/lib/python3.6/site-packages/setuptools/", line 370, in __init__
        k: v for k, v in attrs.items()
      File "/usr/lib64/python3.6/distutils/", line 281, in __init__
      File "/usr/lib/python3.6/site-packages/setuptools/", line 529, in finalize_options
        ep.load()(self,, value)
      File "/tmp/pip-install-lxiyvrgx/cairocffi/.eggs/cffi-1.12.3-py3.6-linux-x86_64.egg/cffi/", line 217, in cffi_modules
        add_cffi_module(dist, cffi_module)
      File "/tmp/pip-install-lxiyvrgx/cairocffi/.eggs/cffi-1.12.3-py3.6-linux-x86_64.egg/cffi/", line 49, in add_cffi_module
        execfile(build_file_name, mod_vars)
      File "/tmp/pip-install-lxiyvrgx/cairocffi/.eggs/cffi-1.12.3-py3.6-linux-x86_64.egg/cffi/", line 25, in execfile
        exec(code, glob, glob)
      File "cairocffi/", line 26, in 
        ffi = FFI()
      File "/tmp/pip-install-lxiyvrgx/cairocffi/.eggs/cffi-1.12.3-py3.6-linux-x86_64.egg/cffi/", line 48, in __init__
        import _cffi_backend as backend
    ImportError: /tmp/pip-install-lxiyvrgx/cairocffi/.eggs/cffi-1.12.3-py3.6-linux-x86_64.egg/ failed to map segment from shared object: Operation not permitted
ERROR: Command "python egg_info" failed with error code 1 in /tmp/pip-install-lxiyvrgx/cairocffi/

So I had to remount /tmp temporarily with exec, because I know it was mounted with noexec.

mount -o rw,remount,exec /tmp

And after I reran the install command, it worked!

# https_proxy=http://10.123.456.789:3128 pip3 install cairosvg
Installing collected packages: pycparser, cffi, cairocffi, webencodings, tinycss2, cssselect2, defusedxml, cairosvg
  Running install for pycparser ... done
  Running install for cairocffi ... done


  2. Original research

Firefox disable a ping

What is an html a ping

An html “a ping” is a characteristic of an <a> tag that is used to track when a link is followed.
An example: the following link to the front page of this blog has an A ping characteristic:

The characteristic looks like:

<a href="" ping=""></a>

Disable html ping in Firefox

In about:config, set:

browser.send_pings = false