The Blog of Tom Webster

Chronic Ranter, Reviewer, and Developer. I speak only for myself, opinions are my own.

How to Change Date in a Git Commit

  2016-01-21 03:50:18 PST

Sometimes you just gotta fix a date in git commits, and this can happen for a wide variety of reasons. Maybe you were on a system with an unset clock and you want accurate timekeeping, maybe you don't want to admit you were up at 4AM coding. I get it. Here's the fix:

git filter-branch --env-filter \
'if [ $GIT_COMMIT = 119f9ecf58069b265ab22f1f97d2b648faf932e0 ]; then
export GIT_AUTHOR_DATE="Fri Jan 2 21:38:53 2009 -0800"
export GIT_COMMITTER_DATE="Sat May 19 01:01:01 2007 -0700"
fi'

Passphrases

  2016-01-05 01:13:00 PST

Passwords are so last year

Passphrases are the new hotness. Who cares about upper case, lower case, symbols, and numbers? Not me.

Caveats:

Time to crack is based on a massive cracking array that runs one hundred trillion guesses per second. (Thanks to GRCs password haystacks page for the calculations)

Take this password, typical, classical: tha2uy2Ieti+

And this one, a bit longer: ae3chav3Ho{cik6g

Let's get crazy: pahzoon2uCh9phoS'iSeeBa

And this passphrase: unlock syntax for tailspin

And this passphrase, but two words longer: unlock syntax for massive director tailspin

The evidence is clear, the four-word passphrase is not only easier to remember, but it's even more secure than the 23-character all-random password. Let's keep this in mind when choosing a new root passphrase.

Storing the passphrase

You should be using a password manager by now. Also, if you're storing the passphrases securely, why not make a 64-character random password for everything? Use a nice passphrase as your master password.

Startup Apps in Gnome 3

  2016-01-04 02:13:06 PST

I recently switched to Gnome 3 on my personal laptop. When Gnome 3 first launched, it was an utter train wreck. Completely unusable, poor design choices, and seemingly purposely-built to serve a non-existent straight-linux tablet market. While the tablet influences are still around, the project has moved towards its original roots.

While Gnome 3 still isn't the perfect being that Gnome 2 (now MATE) was, the tweak tool being part of the default install and the extension library are helping make up for the shortcomings. One thing I really wanted to do is add custom startup applications to my session, this is accomplished via the tweak tool for now, since there is no UI for session management (yes, really).

I found this great article on how to do this, it involves creating a app.desktop file that can be seen by the tweak tool. This means that for every command line startup utility you want run on gnome session start, it needs a .desktop file. Ridiculous, but it works.

In case the site ever disappears, I've paraphrased the content below:

Create a app.desktop file in ~/.config/autostart, if this directory doesn't exist, create it.

Here's the basic content of a app.desktop file:

[Desktop Entry]
Type=Application
Exec=/usr/bin/xflux -z 12345
Hidden=false
X-GNOME-Autostart-enabled=true
Name[en_US]=xflux
Name=xflux
Comment[en_US]=Screen color temperature changer
Comment=Screen color temperature changer

Then head over to the Gnome Tweak Tool and go to the Startup Applications tab. From there, you can select the program for the app.desktop file you just made. Repeat as necessary.

Simple Ruby Speed Benchmarks

  2015-11-30 04:14:00 PST

To show the speed differences in some ruby applications, I wrote a simple ceaser cipher in a few different ways, then timed how long they took to run. I thought the results were interesting enough to post here.

Big thanks to Alan Skorkin for the simple timing code.

The first way creates a string of A-Z, then add the lower case letters to it, then split each character out, making an array. This implementation isn't a one-line array creation like the second.

The second way uses a string that's already created with A-Za-z, and splits them into an array.

The third way uses a hash of a-z, then creates the mappings for A-Za-z.

The fourth way uses a full hash of A-Za-z.

chart_with_upwards_trend Let's post some graphs! chart_with_upwards_trend

I removed the outliers from the four trials and made some graphs. First up, the average for 92 trials:

As you can see, it looks like the full hash implementation is the clear winner here.

Next up is the 92 trials plotted out:

Here's the code if you would like to run your own analysis.

#!/usr/bin/env ruby

# There are lots of ways to do things in ruby. Some are faster than others.
# This ruby script outputs benchmarks in CSV format
# Thanks to Alan Skorkin for the simple timing code
#   http://www.skorks.com/2010/03/timing-ruby-code-it-is-easy-with-benchmark/

require "benchmark"

print "HalfArray,FullArray,HalfHash,FullHash\n"

100.times do
  # Half array manipulation
  def ceaser_cipher(string)
    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    alphabet += alphabet.downcase
    alphabet = alphabet.split(//)
    converted_string_array = []
    string.split(//).each do |l|
      if alphabet.include?(l)
        converted_string_array.push(alphabet[(alphabet.find_index(l) - 51).abs].swapcase)
      else
        converted_string_array.push(l)
      end
    end
    return converted_string_array.join
  end

  time = Benchmark.realtime do
    ceaser_cipher("ABC abc")
  end
  print (time * 1000)
  print ","

  # Full array manipulation
  def ceaser_cipher(string)
    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(//)
    converted_string_array = []
    string.split(//).each do |l|
      if alphabet.include?(l)
        converted_string_array.push(alphabet[(alphabet.find_index(l) - 51).abs].swapcase)
      else
        converted_string_array.push(l)
      end
    end
    return converted_string_array.join
  end

  time = Benchmark.realtime do
    ceaser_cipher("ABC abc")
  end
  print (time * 1000)
  print ","

  # Half hash dictionary
  def ceaser_cipher(string)
    initial_dictionary = Hash[
      "a" => "z",
      "b" => "y",
      "c" => "x",
      "d" => "w",
      "e" => "v",
      "f" => "u",
      "g" => "t",
      "h" => "s",
      "i" => "r",
      "j" => "q",
      "k" => "p",
      "l" => "o",
      "m" => "n",
      "n" => "m",
      "o" => "l",
      "p" => "k",
      "q" => "j",
      "r" => "i",
      "s" => "h",
      "t" => "g",
      "u" => "f",
      "v" => "e",
      "w" => "d",
      "x" => "c",
      "y" => "b",
      "z" => "a"
    ]
    dictionary = {}
    initial_dictionary.each do |original, reversed|
      dictionary[original] = reversed
      dictionary[original.upcase] = reversed.upcase
    end
    converted_string_array = []
    string.split(//).each do |l|
      if dictionary.include?(l)
        converted_string_array.push(dictionary[l])
      else
        converted_string_array.push(l)
      end
    end
    return converted_string_array.join
  end

  time = Benchmark.realtime do
    ceaser_cipher("ABC abc")
  end
  print (time * 1000)
  print ","

  # Full hash dictionary
  def ceaser_cipher(string)
     dictionary = Hash[
      "A" => "Z",
      "B" => "Y",
      "C" => "X",
      "D" => "W",
      "E" => "V",
      "F" => "U",
      "G" => "T",
      "H" => "S",
      "I" => "R",
      "J" => "Q",
      "K" => "P",
      "L" => "O",
      "M" => "N",
      "N" => "M",
      "O" => "L",
      "P" => "K",
      "Q" => "J",
      "R" => "I",
      "S" => "H",
      "T" => "G",
      "U" => "F",
      "V" => "E",
      "W" => "D",
      "X" => "C",
      "Y" => "B",
      "Z" => "A",
      "a" => "z",
      "b" => "y",
      "c" => "x",
      "d" => "w",
      "e" => "v",
      "f" => "u",
      "g" => "t",
      "h" => "s",
      "i" => "r",
      "j" => "q",
      "k" => "p",
      "l" => "o",
      "m" => "n",
      "n" => "m",
      "o" => "l",
      "p" => "k",
      "q" => "j",
      "r" => "i",
      "s" => "h",
      "t" => "g",
      "u" => "f",
      "v" => "e",
      "w" => "d",
      "x" => "c",
      "y" => "b",
      "z" => "a"
    ]
    converted_string_array = []
    string.split(//).each do |l|
      if dictionary.include?(l)
        converted_string_array.push(dictionary[l])
      else
        converted_string_array.push(l)
      end
    end
    return converted_string_array.join
  end

  time = Benchmark.realtime do
    ceaser_cipher("ABC abc")
  end
  print (time * 1000)
  print "\n"
end

I'm not entirely familiar with low low level ruby, so I can't offer any grand insights, but I thought it was some decent code and a nice set of graphs.

PSA: Time Variables

  2015-11-25 16:19:00 PST

This is a public service announcement about naming variables dealing with amounts of time. I've had the misfortune of dealing with some code recently that didn't have properly named variables for different time-sensitive functions. What resulted is some confusion about why certain functions would never fire, even after the elapsed time.

The majority of the time variables in this application were in miliseconds, as is common in most of the code I work with. Unfortunately, miliseconds were not the only measure of time used in variables. There were integer variables that used seconds and even one that used hours. With no call out, comments, or specific names to differentiate them. What was set to 3600000 miliseconds was actually a variable for number of hours. Instead of firing every hour, as planned, because of the inspecific variable name and mixing of time units without comments, that event would fire once every ~411 days.

If you're going to use variables for time, keep these things in mind:

  1. Only use one unit of time across your project, stick to seconds or miliseconds for everything. Call this out in the comments or readme. If you want to be really nice, you can use #2 as well.

  2. Call out the unit in all variable names. Yes, this can get tedious, but it really helps people looking at your code figure out your intent for the variable. Maybe making everything use seconds as the unit is too big, maybe you need something smaller, but settling for miliseconds across every value is kinda crazy, seeing as you want to use hours in a couple places. Why not socket_timeout_in_miliseconds or auto_backup_time_in_hours?

The only wrong answer is mixing units and leaving them a mystery to the next developer to pick up your code.

Page: 5 of 31