Akom's Tech Ruminations

Various tech outbursts - code and solutions to practical problems

Hardware Hacks Increasing capacity of the PetSafe Simply Clean Litter box

Posted by Admin • Tuesday, March 10. 2015 • Category: Hardware Hacks
Although I wrote a somewhat harsh review of the PetSafe Simply Clean Litterbox on Amazon, I still felt that there was some potential to this thing. What I wanted most from it was a very low maintenance experience, and having to empty the waste bin every 3 days simply didn't seem to qualify. When I go on vacation (and please don't start a neglect flame war over this) I leave the cats alone - monitored by 4 cameras, auto feeder, 5 gallon water dispenser and many litter boxes. I don't want to bother relatives with the long drive to come over just to clean cat poo, and my cats do not take well to being moved. Or to strangers. Or to basically anything besides the quiet at-home life that is exactly like yesterday.

Therefore, what I'm looking for is a larger waste bin. The litterbox doesn't handle capacity problems well - it backs up, jamming up against the chute cover, making a mess and eventually just shutting itself off. What I need to do is to create a jam-resistant path for the waste to go, somewhat like this patent here. The idea is good but it seems a bit too complex for my taste, and of course it is intended for a rectangular raking box like the LitterMaid. So, I chose to do the simplest and most reliable thing I could think of.

Continue reading "Increasing capacity of the PetSafe Simply Clean Litter box"

Linux Building RPMs for an older version of CentOS

Posted by Admin • Thursday, November 20. 2014 • Category: Linux
If you build RPMs on Centos 6.X (6.5 in my case) and then try to install them on Centos 5.X (5.10 in my case), bad things happen. Ironically, bad things happen even though my RPM contains a single jar file, and is thus entirely platform independent. Here is what I see:
Running rpm_check_debug
ERROR with rpm_check_debug vs depsolve:
rpmlib(FileDigests) is needed by my-rpm-1.0.x86_64
rpmlib(PayloadIsXz) is needed by my-rpm-1.0.x86_64
If you google for a solution, most people suggest running a virtual with Centos 5 just so you can build the RPMs, but this is apparently not necessary in this simple case, as you can simply specify a few flags. Basically, Centos 5 can't decompress the default archive format, and doesn't support the new digest algorithm.

Since I am using maven-rpm-plugin to build RPMs, my modifications look as follows:


                      <!-- skipping irrelevant items -->

                            <!-- don't strip jar files, it takes forever and is useless -->
                            <defineStatement>__os_install_post %{nil}</defineStatement>
                            <!-- for Centos6 -> Centos5 forwards compatibility -->
                            <defineStatement>_source_filedigest_algorithm md5</defineStatement>
                            <defineStatement>_binary_filedigest_algorithm md5</defineStatement>
                            <defineStatement>_source_payload w9.bzdio</defineStatement>
                            <defineStatement>_binary_payload w9.bzdio</defineStatement>

If you're using fpm or rpmbuild, you can just take these lines and make them %define's in your spec.

Linux Backing up cPanel 11 hosted account with wget and dav/rsync

Posted by Admin • Thursday, August 21. 2014 • Category: Linux
I want to back up my hosting account regularly by retrieving everything onto my box somewhere else (my home server). By regularly, I mean every day. I want this to happen automatically. cPanel makes that hard to do, but there is always a way to script things.

First, let's break down what we want to back up:
  1. Files
  2. Databases and email forwarders
Files are fairly easy. Obviously we don't want to use the full backup functionality of cPanel because we'd be transferring your entire storage space each and every time, even if nothing has changed. In order to do it efficiently, you have a few options:
  1. FTP account using recursive wget (create an FTP account with required access and teach an ftp client of your choice to recursively transfer everything. Hopefully this client skips unchanged files)
  2. WebDAV using rsync (this is what I'm using). Just mount, back up, unmount
Databases and Email stuff is not as easy, as we do have to log into cPanel. The trick to logging in to cPanel is:
  1. Submit your login to the log-in page and save cookies
  2. Parse the resulting file, find the backup link which includes your session name in the URL and hit that
  3. Only accept .gz files (DB backups and email stuff), but avoid hitting /logout, and don't start spidering the entire website
So, how do we do this? Here is the plan

Continue reading "Backing up cPanel 11 hosted account with wget and dav/rsync"

Bash completion for tmux multi-window like cssh/mssh

Posted by Admin • Monday, May 19. 2014
Although I normally use mssh for my multi-window SSH client, sometimes I work through an non-graphical SSH connection, and tmux really comes in handy. I've been using the ssh-multi script by D.Kovalov, but since I already have "clusters" files for cssh and mssh, I figured that it should be more convenient to use them by typing aliases. The script below is the result. )

This goes into /etc/bash_completion.d/tmuxmulti

Hope it helps

Continue reading "Bash completion for tmux multi-window like cssh/mssh"

Linux mssh Bash completion

Posted by Admin • Friday, February 28. 2014 • Category: Linux
Clusterssh (cssh) is great, but I was getting a little fed up with unmanageable terminal windows. They either go all over my monitors or get lost, and they are hard to move and resize.

So I switched to mssh, which solves all that because all the terminals are in one window.... but, it doesn't read my /etc/clusters file! In fact, nobody seemed to even know what file it does read.

What to do? First of all, for the record, it reads its aliases (-a) from ~/.mssh_clusters This file is exactly like /etc/clusters, except for a colon, like so:
alias1: host host host
alias2: host host host

Now that we got that straight, let's make a bash completion file

Continue reading "mssh Bash completion "

Low Tech Hacks Importance of Small Engine Preventative Maintenance for seasonal tools

Posted by Admin • Wednesday, February 12. 2014 • Category: Low Tech Hacks
Lawmowers, snowblowers, chainsaws, generators, trimmers (even motorcycles) ... I have all of these, but, obviously, they are used seasonally. That means that they spend a fair amount of time sitting around. While most preventative maintenance advice tends to focus on the maintenance of frequently used engines, I find that it is the stored machines that get overlooked. Therefore:

Preventing In-Storage Problems in just 2 steps

  1. Stabil

    While people will tell you that gasoline doesn't usually break down, that's not true in my experience. After sitting around in your carburetor for a few months, the fuel does and will separate. The issue here is that one part of it will literally varnish the surfaces, either sticking moving parts together, or restricting flow. The result? Popping, backfiring, or an engine that will only run with the choke on (if it runs at all). The only solution is to take the carb apart and clean everything - perhaps even changing the seals and needle seat. In the ideal world you'd have no fuel in the carburetor at all during storage, but since you're unlikely to get it all out, this is the next best thing.

    In other words:
    • Simply add fuel stabilizer of your choice (eg Stabil) to gasoline the day you buy gasoline, and use only treated gas in seasonally used engines.
    • When you shut off the engine before storage (or any time), let it run out of fuel - either shut off the valve, or use up what's in the tank if you have no valve.

  2. End-of-season Oil Change

    Oil absorbs byproducts of combustion, which are acidic. The more the engine runs, the more acidic the oil becomes. This acidic medium, coupled with 6 months in storage means corrosion risk to all the lubricated engine surfaces.

    In other words:
    • Simply change the oil when the season is over - spring for snowblowers, fall for lawnmowers, etc.
      Warm up the engine, let it run out of fuel (see above), then change the oil. Don't start it again before storage.

That's it - you'll have years of reliable service from your engines. It's amazing how many people overlook these two steps that can and do prevent so many issues. I used a trashed lawnmower for 8 more seasons after I found it by following these steps. I've had my snowblower 12 years and it always starts on the first pull. Speaking of snowblowers, see also how to change oil without making a mess.

But wait, what about spark plugs? Air filters?

In my experience, on occasionally used engines, spark plugs never actually wear out. They can get fouled from improper carburetor adjustment or over-priming, but when the system is functioning properly - a good quality plug might outlast the engine. Go ahead and change it if it makes you feel better, but I've run my lawnmower weekly on the same plug for 8 seasons and it still looks and works just fine. As for air filters - that's another story, but their maintenance has nothing to do with seasonal use. Every once in a while it's good to check that the filter is clean enough to let some air through and that it's not torn so it's not letting dirt into the carb. Otherwise, I tend to leave them alone.

Ubuntu 13.10, Dell M4700 and Enlightenment E17 on dual monitors

Posted by Admin • Wednesday, November 20. 2013
I've been waiting a long time for E17 to become stable... and it has. But installation is not without quirks on this Dell Precision laptop. Everything works fine with a single display, but dual, or dual external monitors is not so simple.

  1. There is a choice of 3 video drivers (see Update Manager->Hardware Drivers). The open source driver is great for an environment like XFCE or LXDE, but E17 simply cannot run on that driver. I've given up trying to guess why.
  2. Using the proprietary driver ( fglrx-updates and fglrx-amdcccle-updates ), E17 now works, but you cannot use xrandr to enable the second monitor (you get the "required virtual size does not fit available size"). This driver is old school and requires a static configuration in xorg.conf ... Of course there is no xorg.conf anymore, thus you add your pieces to a xorg.conf.d directory. What you need to do is configure a virtual size according to the above error message (or calculate it as the sum-total of the resolutions of your monitors). For example:
    Section "Screen" Identifier "default Screen Section" SubSection "Display" Virtual 3840 1200 EndSubSection EndSection
  3. Now when you log in, you might even see both monitors work. If not, you can fix it with xrandr, or you can add it to your config as well, something like this:
    Section "Monitor" Identifier "VGA-0" Modeline "1280x1024_60.00" 109.00 1280 1368 1496 1712 1024 1027 1034 1063 -hsync +vsync Option "RightOf" "DVI-0" EndSection
Much gratitude to this poster for the info

Linux Upgrading pfSense fails due to low disk space

Posted by Admin • Tuesday, October 22. 2013 • Category: Linux
I have an embedded installation of pfSense 2.0.2-RELEASE running from a 512MB compact flash card via an IDE adapter. At the time this was what I had on hand, and it seemed like plenty of space - but now that I tried to upgrade to 2.1, the process failed because there wasn't enough room to download the new image...

I tried all sorts of ways including both webconfigurator upgrade and trying to scp the image to the box, but either way there simply wasn't enough space. "OK" I said, "let me install 2.1 on a new (larger) card and restore the config.xml" .... bad idea. The firewall becomes unbootable when you do this - I think that no upgrade processing is performed on the configuration, it is assumed to be a match for your software version. Not to mention that I tried a 4GB card, but the old Pentium III running the firewall can't handle anything over 2GB!

Ultimately, this is the process:
  1. Download and install the same version as what you're running on the larger card
  2. Restore your config.xml backup onto the new instance of pfSense. You can do this through webconfigurator, or if you are (like me) running on a temporary rig without multiple NIC's, you can scp it over manually
  3. Confirm that the system boots, but don't make any changes (to the interfaces, for instance). Put the card into your real system
  4. Now you can use the auto-updater as normal, and your old config.xml will be upconverted

Linux amixer toggle mutes but does not unmute

Posted by Admin • Monday, July 22. 2013 • Category: Linux
It seems that the common approach to mute the audio in Ubuntu 13.04 is amixer -q sset Master toggle ... which works great when muting, but fails to unmute. This command is, for example, the default for openbox's handling of XF86AudioPlay shortcut.

The problem, it would appear, is that muting the Master channel causes other channels (eg Headphone and Front on my machine) to be muted as well. I have no idea why this works this way and why it doesn't undo what it did... and, frankly, I don't really care that much. It's much easier to code around this, see the following workaround script:

Continue reading "amixer toggle mutes but does not unmute"

Switchable Storage Locations in an Android App

Posted by Admin • Saturday, October 13. 2012 • Category: Android
This is also a typical pattern. In my app, I need to offer the user a choice of storage locations without getting too low-level. I am content with offering three options in a ListPreference:
  1. Private to application
  2. Public but on the main storage
  3. Public but on the removable storage (actual SD card)
Here is how I am doing it in a relatively generic and reusable manner (using an enum)

Continue reading "Switchable Storage Locations in an Android App"

Getting location of the removable storage on Android

Posted by Admin • Saturday, October 13. 2012 • Category: Android
Seems like a fairly typical problem, yet there are dozens of implementations and no standard. Here is mine:

        private static File s_removableStoragePath;

          Utility function that attempts to find the removable storage directory
(as opposed to {@link Environment#getExternalStorageDirectory()} which is usually non-removable)
          by running "mount" and parsing the output.   This implementation looks for
the strings "vfat" and "vold", eg:
          /dev/block/vold/179:97 /mnt/extSdCard vfat rw,dirsync,nosuid,nodev,noexec,noatime,nodiratime,uid=1000,gid=1023,fmask=0002,dmask=0002,allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0

          The result will be cached indefinitely.

         * @return either a valid file or null.  This may not be accessible, but it does exist

        public static File findRemovableStorage() {
                if (s_removableStoragePath != null && s_removableStoragePath.exists()) {
                        return s_removableStoragePath;
                s_removableStoragePath = null;
                String result = null;
                try {
                        Process process = new ProcessBuilder().command("mount")


                        InputStream is = process.getInputStream();
                        BufferedReader isr = new BufferedReader(new InputStreamReader(is));

                        String line = null;
                        while ((line = isr.readLine()) != null) {
                                if (-1 != line.indexOf("vold") && -1 != line.indexOf("vfat")) {
                                        String[] blocks = line.split("\\s");
                                        if (blocks.length > 2) {
                                                result = blocks[1];
                        if (result != null) {
                                s_removableStoragePath = new File(result);
                                if (!s_removableStoragePath.exists()) {
                                        s_removableStoragePath = null;
                } catch (Throwable t) {
                                        "Unable to find external mount point");
                return s_removableStoragePath;

Linux motion drops MySQL support, but you can get around it with a shell script

Posted by Admin • Monday, September 24. 2012 • Category: Linux
I use motion as a surveillance system for a sizable office (9 cameras). Motion is good. But the current package of motion in Ubuntu 12.04 is no longer compiled with MySQL support (used to have it in 10.04). Compiling motion from source really didn't sound appealing... but I do want to add events to a database for my own in-house motion history browser. What to do?

Motion supports command execution on events, such as on_movie_end and on_picture_save... which makes it really easy to do a one-liner like this:
on_movie_end bash -c "echo insert into security(camera, filename, frame, file_type, time_stamp, event_time_stamp, event_id) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C', '%v') | mysql -uUSER -pPASS"
if you'd like to do something fancier, you can break it out into a shell script:


logger -t test "$0 executing with $*"
sql="insert into security(camera, filename, frame, file_type, time_stamp, event_time_stamp, event_id) values('$1', '$2', '$3', '$4', '$5', '$6', '$7')"
echo $sql | mysql -u$U -p$P motion
and invoke like this:
on_movie_end U=USER P=PASS bash /usr/local/sbin/motion-insert-event.sh '%t' '%f' '%q' '%n' '%Y-%m-%d %T' '%C' '%v

(same for on_picture_save, if needed). You can also daisy-chain commands with semicolon if you have multiple. Also, note that the query above is for my table, yours may have different columns. The rest are my specific examples of usage:

Continue reading "motion drops MySQL support, but you can get around it with a shell script"

Code and Hacks Converting .NET String.format pattern to Java with a regular expression

Posted by Admin • Monday, September 10. 2012 • Category: Code and Hacks
For this exercise in futility, I want to accomplish the following:

From .NET: "Hello, {0} Today is the {1} day"  
To JAVA: "Hello, {%1$s} Today is the {%2$s} day"

Note that a simple regex would work here if it weren't for the zero-based indexes. We need to increment the number as well do a pattern replace. Since I'm comfortable with PHP, I took a sample from preg_replace_callback description and modified it accordingly:

Continue reading "Converting .NET String.format pattern to Java with a regular expression"

Linux Splunk high CPU utilization starting July 1, 2012

Posted by Admin • Thursday, July 5. 2012 • Category: Linux
This has to be written down for posterity: My single server installation of splunk started using all of the CPU about then. Nagios caught it, but I had no time to debug it. I tried disabling indexes, apps, and inputs - none of that made any difference. I reduced an index size, which again had no effect. I cleaned it out and installed it fresh (empty database), only to see the now familiar steady CPU usage.

In desperation I went to open a question on splunk support forums where it suggested I read a related thread which in fact had the solution: http://splunk-base.splunk.com/answers/52109/universal-forwarder-high-cpu-after-leap-second-correction Apparently the culprit is the leap year second inserted at midnight on June 30. Why that makes splunk go nuts I'm not quite sure, but i did see a warning about it in my dmesg:
[3073222.768708] Clock: inserting leap second 23:59:60 UTC

Apparently this is the same problem that took down Amazon. The solution involves running a perl command to alter the system date ever so slightly in the absence of ntp.

Linux VirtualBox Extension Pack on Ubuntu Precise Pangolin 12.04

Posted by Admin • Thursday, May 31. 2012 • Category: Linux
Not sure why this so unintuitive, but here goes:
  1. You want to use USB 2.0 with Virtual Box on Ubuntu 12.04 (or recent version
  2. You're told to install the extension pack from this page
  3. The download is not the same version as your version of virtual box itself
  4. It doesn't work

Do not despair:
  1. Shorten the extension pack download URL to http://download.virtualbox.org/virtualbox/
  2. Find a directory matching your version ( dpkg -i virtualbox )
  3. Download the extension pack