Sean’s Obsessions

Sean Walberg’s blog

Upgrading Legacy Fedora Boxen for the DST Time Change

There’s lots of documents out there on how to download the latest time zone data and apply it manually. In the interests of proper management though, I like using RPM to do pretty much everything. The problem is that Fedora Legacy has disbanded, so I can’t get patches for my FC1 and FC4 systems. The solution is to rebuild the FC6 packages and apply them to the legacy systems. (It’s entirely possible that they may apply directly since it’s noarch, but my local mirror didn’t seem to have the package)

[root@sergeant root]# zdump -v /etc/localtime | grep 2007
/etc/localtime Sun Apr 1 07:59:59 2007 UTC = Sun Apr 1 01:59:59 2007 CST isdst=0 gmtoff=-21600
/etc/localtime Sun Apr 1 08:00:00 2007 UTC = Sun Apr 1 03:00:00 2007 CDT isdst=1 gmtoff=-18000
/etc/localtime Sun Oct 28 07:59:59 2007 UTC = Sun Oct 28 02:59:59 2007 CDT isdst=1 gmtoff=-18000
/etc/localtime Sun Oct 28 08:00:00 2007 UTC = Sun Oct 28 02:00:00 2007 CST isdst=0 gmtoff=-21600

[root@sergeant root]# wget http://www.muug.mb.ca/pub/fedora/linux/core/updates/6/SRPMS/tzdata-2007c-1.fc6.src.rpm
–08:31:20– http://www.muug.mb.ca/pub/fedora/linux/core/updates/6/SRPMS/tzdata-2007c-1.fc6.src.rpm
=> `tzdata-2007c-1.fc6.src.rpm’
Resolving www.muug.mb.ca… done.
Connecting to www.muug.mb.ca[130.179.31.46]:80… connected.
HTTP request sent, awaiting response… 200 OK
Length: 366,378 [application/x-rpm]

100%[====================================>] 366,378 494.87K/s ETA 00:00

08:31:21 (494.87 KB/s) - `tzdata-2007c-1.fc6.src.rpm’ saved [366378/366378]

[root@sergeant root]# rpmbuild –rebuild tzdata-2007c-1.fc6.src.rpm
Installing tzdata-2007c-1.fc6.src.rpm

Wrote: /usr/src/redhat/RPMS/noarch/tzdata-2007c-1.noarch.rpm

[root@sergeant root]# rpm -Uvh /usr/src/redhat/RPMS/noarch/tzdata-2007c-1.noarch.rpm

Preparing… ########################################### [100%]
1:tzdata ########################################### [100%]

For some reason /etc/localtime was a file instead of a symlink
[root@sergeant root]# rm /etc/localtime
rm: remove regular file `/etc/localtime’? y
[root@sergeant root]# ln -s /usr/share/zoneinfo/CST6CDT /etc/localtime
[root@sergeant root]# !zdump
zdump -v /etc/localtime | grep 2007
/etc/localtime Sun Mar 11 07:59:59 2007 UTC = Sun Mar 11 01:59:59 2007 CST isdst=0 gmtoff=-21600
/etc/localtime Sun Mar 11 08:00:00 2007 UTC = Sun Mar 11 03:00:00 2007 CDT isdst=1 gmtoff=-18000
/etc/localtime Sun Nov 4 06:59:59 2007 UTC = Sun Nov 4 01:59:59 2007 CDT isdst=1 gmtoff=-18000
/etc/localtime Sun Nov 4 07:00:00 2007 UTC = Sun Nov 4 01:00:00 2007 CST isdst=0 gmtoff=-21600

Simple Trickle Charger for a Cordless Drill

I’ve got a couple of cheap cordless drills, one’s a 9.6 volt and the other is 18.2 volts. They work well, but the annoying thing is the charger isn’t “smart”. By smart, I mean that it will continue to charge the battery even after it’s been charged. With NiCad batteries this means that the batteries become damaged after time and stop holding a charge.

I had started to build my own smart charger but made one major mistake with the MOSFETs so I threw out that design and went simpler. I converted the chargers that came with the batteries to trickle chargers based on some advice from a coworker who pointed out that more often than not, I just want a charged drill when I need it, and rarely will need to charge the battery quickly.

Rechargable batteries are rated in terms of Amp-Hours (AH) or milliamp Hours (mAh). Theoretically, a battery rated at 1AH can deliver 1A of current for 1 hour, or 2A for 1/2 hour, or 1/2A for 2 hours, and so forth.

The product of Amps and time is the Coulomb, so the capacity of the battery is sometimes written as C. To charge the battery one must put back the number of coulombs that were taken out (plus some for transfer loss). Charge rates are usually expressed as a rate of C. Most cheap drills I’ve run into have battery packs rated at 1200mAh. To charge the drill I could do 1.2A for 1 hr (which would be a rate of C), or .6A for 2 hrs (C/2), or 2.4A for 1/2 hr (2C). Practically speaking though, the cheap batteries need a lower charge rate for a longer time, such as C/2 or C/4.

The chargers that come with the drills are actually just a transformer to limit the current. The only electronics are a transistor, a resistor, and an LED to indicate the current is flowing. The transformer limits the current, so if you have a 300mA transformer you need 4-5 hours of charging at C/4. Leave it any longer at that rate, and you’ll be hurting your batteries.

Drop the rate really low, to C/20 (~60mA) and you can keep the current on indefinately. It will take a long time to charge (20-24 hours), but you never have to worry about pulling the drill off. This is how most smart chargers work, they give the battery a high charge until it’s done (ie at C, or C/2), and then drop to a low charge like C/20 to keep the battery topped off.

Converting an existing charger to a trickle charger is actually very simple. There is a part called the LM117 that’s an ajustable 3 terminal regulator. Normally the LM117 is used to provide a constant voltage given a variable input, but it can do other things. The circuit I used is even in the datasheet, it makes the device a 50mA constant current source. That is, no matter what voltage you put in, the LM117 will pump out that voltage at 50mA. You have to apply 24 ohms across terminals 1 and 2 (read the datasheet for which pin is which), for which I used two 47ohm resistors in parallel soldered directly to the lm117. Throw that in between the battery and the source, and you’ve got a constant current source.

100_1243.JPG

The parts are easily available and should cost no more than a few dollars. You might even be able to order the LM117s as samples, or go to a local hobby shop to get it. Glitchbuster is a great place to order stuff from too.

Be careful when working with batteries. This only works for NiCad and possibly NiMH, and not LiON, and certainly not alkeline.

Random Thoughts on LinkedIn

I like LinkedIn. It’s a handy way of keeping in touch with old friends. Often I’ll see one of my contacts add another contact who I know from a long time ago, which leads me to getting back in touch. I like it better than other services I’ve tried.

I downloaded the Outlook Toolbar for LinkedIn which let me search my contacts for people who are already members which worked well. It also shows me when someone I’m corresponding with is already a member. It’s really a good feature.

A couple of things annoy me about the site, though. The first is the answers section. People can ask questions and other members can answer them. However it’s mostly crap. Recruiters looking for people, a bunch of stupid questions, and a crappy interface.

The second thing is that some people treat it as if you get something for having more connections. I often get requests from people I’ve never met. Usually we worked for the same company, or one sharing the same name, but the fact remains I’VE NEVER MET YOU. I thought the connections were supposed to be trusted in some sense. My litmus test for this is, if I called you up, would you know who I was?

Part of me is resistant to using the service. My profile has some of the stuff I do on the side (mostly writing and consulting) and I’m often hesitant to make that publicly known. On the other hand, I am who I am.

View Sean Walberg's profile on LinkedIn

Update: I didn’t realize the answers service can be directed only to your trusted contacts. I just received a query from a contact looking for writers, and I thought that was an excellent use. So my comments above should be limited to the public question area.

Unit Testing PHP Using Apache-Test

After being reminded that Debugging sucks, Testing rocks I thought I’d go back to some PHP stuff I was working on and develop some unit tests. I looked around at a few testing packages including PHPUnit2 as recommended by Jack Herrington in PHP Hacks, but the overhead and complexity of creating classes to encapsulate my test was too much. Plus, I wanted to be able to test on PHP 4 and 5. Finding examples was also difficult, everyone seemed to be showing off a class that simply adds two numbers which to me is fairly useless. I wanted a real world example of someone testing code as ugly as mine.

Trying to compare different methods led me to Power PHP Testing which is a good description of testing in PHP and the various methods, and also showed me about Apache-Test.

Apache-Test is a project by the Apache foundation that will create a local instance of a web server for hosting the tests, and also uses the “Test Anything Protocol” that I was familiar with from Perl. Each test spits out something like “OK” which makes collecting and generating a simple unit test easy. The documentation on Apache-Test was quite extensive, but still it was difficult to get started with a “Hello World!” type of test to make sure everything is running. To start off I installed Apache::Test from CPAN (perl -MCPAN -e ‘install Apache::Test’)

Assume the app is in /var/www/html, and we want to test get.php which gets a web page using cURL.


function get($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}

?>

The basic tests I’d like to run on this are to make sure get.php compiles, to get a simple web page, and then to introduce a few error conditions and see what happens. (Note the latter ones will probably fail because there is no error checking, defining the tests beforehand is an advantage then to ensure I don’t forget something)

To implement the testing environment:

mkdir -p t/response/TestGet
cat > Makefile.pl
# don't worry about this file - you should not
# need to edit it at all.

use 5.00501;

use ExtUtils::MakeMaker;

use lib qw(lib);

use Apache::TestMM qw(test clean);
use Apache::TestRunPHP ();

Apache::TestMM::filter_args();

Apache::TestRunPHP->generate_script();

WriteMakefile(
NAME => 'perl-php',
VERSION => 'test',
);
^D
perl Makefile.PL

Each series of tests is a directory in the t/response directory with a name starting with Test. I’ve called the tests relating to get.php “Get”, so all my tests for get.php go in t/response/TestGet.

Before getting into the tests, you have to understand the environment you’ll be testing in. The test script will be running on a web server on a non standard port (8529 by default) with a document root of t/htdocs. Each testing directory (ie TestGet) has an Alias directive so that a request to /TestGet/foo will be mapped to t/response/TestGet/foo.

So the first test to make sure get.php loads fine is


require "test-more.php";
require "../../../get.php";

plan(1);

ok(1);

?>

Note that I needed to require get.php out of a parent directory. There are ways to modify the config files to change the php include_path but this is easy enough now.

The test-more.php file comes with Apache-Test and implements some testing functions that help. I started off with plan(1) which tells the testing harness that 1 tests are expected. The ok() function is a test, if whatever is inside the parenthesis is true the tests pass.

[sean@bob html]$ make test
/usr/bin/perl -Iblib/arch -Iblib/lib \
t/TEST -clean
[warning] setting ulimit to allow core files
ulimit -c unlimited; /usr/bin/perl /var/www/html/t/TEST -clean
APACHE_TEST_GROUP= APACHE_TEST_HTTPD= APACHE_TEST_PORT= APACHE_TEST_USER= APACHE_TEST_APXS= \
/usr/bin/perl -Iblib/arch -Iblib/lib \
t/TEST -bugreport -verbose=0
[warning] setting ulimit to allow core files
ulimit -c unlimited; /usr/bin/perl /var/www/html/t/TEST -bugreport -verbose=0
/usr/sbin/httpd -d /var/www/html/t -f /var/www/html/t/conf/httpd.conf -D APACHE2 -D PERL_USEITHREADS
using Apache/2.2.3 (prefork MPM)

waiting 60 seconds for server to start: ..
waiting 60 seconds for server to start: ok (waited 1 secs)
server localhost:8529 started
t/get/0_test....ok
All tests successful.
Files=1, Tests=1, 2 wallclock secs ( 1.78 cusr + 0.32 csys = 2.10 CPU)
[warning] server localhost:8529 shutdown

I’ll create another test to get two pages, one that exists and one that doesn’t. Apache-Test places an index.html in the docroot for testing which I’ll use.


require "test-more.php";
require "../../../get.php";

plan(2);

$result = get("http://localhost:8529/index.html");
like($result, "/welcome to/i");

$result = get("http://localhost:8529/idontexist.html");
is($result, NULL);

?>

Here I used two more testing functions. like() accepts a regular expression that gets passed to preg_match. If the regexp matches the string in the first parameter, the test passes. is() compares two values. Here I’d expect that if the page wasn’t found I’d get a NULL.

Then I run it again

[sean@bob html]$ make test
/usr/bin/perl -Iblib/arch -Iblib/lib \
t/TEST -clean
[warning] setting ulimit to allow core files
ulimit -c unlimited; /usr/bin/perl /var/www/html/t/TEST -clean
APACHE_TEST_GROUP= APACHE_TEST_HTTPD= APACHE_TEST_PORT= APACHE_TEST_USER= APACHE_TEST_APXS= \
/usr/bin/perl -Iblib/arch -Iblib/lib \
t/TEST -bugreport -verbose=0
[warning] setting ulimit to allow core files
ulimit -c unlimited; /usr/bin/perl /var/www/html/t/TEST -bugreport -verbose=0
/usr/sbin/httpd -d /var/www/html/t -f /var/www/html/t/conf/httpd.conf -D APACHE2 -D PERL_USEITHREADS
using Apache/2.2.3 (prefork MPM)

waiting 60 seconds for server to start: ...
waiting 60 seconds for server to start: ok (waited 2 secs)
server localhost:8529 started
t/get/0_test....ok
t/get/1_get.....FAILED test 2
Failed 1/2 tests, 50.00% okay
Failed Test Stat Wstat Total Fail List of Failed
-------------------------------------------------------------------------------
t/get/1_get.t 2 1 2
Failed 1/2 test scripts. 1/3 subtests failed.
Files=2, Tests=3, 5 wallclock secs ( 3.75 cusr + 0.64 csys = 4.39 CPU)
Failed 1/2 test programs. 1/3 subtests failed.
[warning] server localhost:8529 shutdown
[ error] error running tests (please examine t/logs/error_log)
make: *** [run_tests] Error 1

It looks like the second test failed… I
[sean@bob html]$ make test
/usr/bin/perl -Iblib/arch -Iblib/lib \
t/TEST -clean
[warning] setting ulimit to allow core files
ulimit -c unlimited; /usr/bin/perl /var/www/html/t/TEST -clean
APACHE_TEST_GROUP= APACHE_TEST_HTTPD= APACHE_TEST_PORT= APACHE_TEST_USER= APACHE_TEST_APXS= \
/usr/bin/perl -Iblib/arch -Iblib/lib \
t/TEST -bugreport -verbose=0
[warning] setting ulimit to allow core files
ulimit -c unlimited; /usr/bin/perl /var/www/html/t/TEST -bugreport -verbose=0
/usr/sbin/httpd -d /var/www/html/t -f /var/www/html/t/conf/httpd.conf -D APACHE2 -D PERL_USEITHREADS
using Apache/2.2.3 (prefork MPM)

waiting 60 seconds for server to start: …
waiting 60 seconds for server to start: ok (waited 2 secs)
server localhost:8529 started
t/get/0_test….ok
t/get/1_get…..FAILED test 2
Failed 1/2 tests, 50.00% okay
Failed Test Stat Wstat Total Fail List of Failed
——————————————————————————-
t/get/1_get.t 2 1 2
Failed 1/2 test scripts. 1/3 subtests failed.
Files=2, Tests=3, 5 wallclock secs ( 3.75 cusr + 0.64 csys = 4.39 CPU)
Failed 1/2 test programs. 1/3 subtests failed.
[warning] server localhost:8529 shutdown
[ error] error running tests (please examine t/logs/error_log)
make: *** [run_tests] Error 1

The final test of a missing page failed. I can enable more debug output with TEST_VERBOSE=1:

make test
...
t/get/1_get.....1..2
ok 1
not ok 2
# Failed test (t/response/TestGet/1_get.php at line 12)
# got: '

404 Not Found

Not Found

The requested URL /idontexist.html was not found on this server.



'
# expected: ''

# Looks like you failed 1 tests of 2.
FAILED test 2
...

So, the script returns the contents of the 404 page rather than the NULL. After fixing that up my tests pass.

Social Networking Meets Cooking

I like to cook. The other night I wanted to make some caramel corn so I started searching for recipes on the Internet. All I found was crap, or the same recipe rehashed (using 1 cup of butter, no less). I’ve also been on mailing lists where the same point gets debated, or the same question gets asked about tips or kitchen equipment.

This led me to start a digg like site for kitchen tips, recipes, and equipment. It’s called KitchenLackey.com. It uses Pligg, which is a great piece of software. I’ve only started configuring it.

Hacking PHP Hacks

I’ve had Jack Herrington’s PHP Hacks around for a while, always refering to it, but never getting around to using it. There were two hacks that really caught my eye, one made a DHTML graph that did a scatterplot of data letting you choose the X and Y axes, and the colour and size of the dots. The other showed how to use JSON to easily get data from a PHP structure to an AJAX application. After seeing both of them, I thought that integrating the two would be really helpful – pulling results in a PHP program and manipulating them through an AJAX application.

So, last night I sat down to do it. It wasn’t as easy as I had thought, largely because the graphing hack was fairly specific to the dataset he used. For example, the columns are predefined, and my code dynamically determines what the columns are. This isn’t so bad, but the way the selection boxes were done needed the data when the page was loaded, but because I’m doing the AJAX thing, it’s not available until after.

Still a bit of work to go but I think for the purpose I have in mind I don’t need to take it any further.

json_graph.tgz

Changing Jobs

I put in my two weeks notice at Ceridian on Friday. For reasons I’m keeping to myself, I haven’t told anyone where I’m going, what I’ll be doing, or where the job is. I have to admit, the rampant speculation is a great source of amusement! Quitting is always a pain because you’re comfortable where you are. But I’m looking forward to a clean inbox, no more Lotus Notes, a new set of people and a new set of projects.

I was at Ceridian for a little over 4 years and managed to learn a lot and meet some great people. However, the constant reorganization, complete lack of vision, and poor management are what drove me away.

To the folks at the other company I was interviewing at, thanks for taking the time to talk to me. I know you have high standards which is what drew me to you. I’m disappointed that I didn’t meet those standards. Even though I would have been junior compared to you, I think I would have made you proud. Even the long haired guy whose name I forgot who probably thinks I’m an idiot after interviewing me. I’m horrible with names but thanks Wade, Michelle, Scott, and especially Jason.

My Tax Dollars Go Where?

http://www.crtc.gc.ca/ENG/NEWS/SPEECHES/2006/s060929.htm

A local college radio station is being called to task for the following alleged infractions, committed over a year ago.

The examination also revealed shortfalls relating to the following three conditions of licence:

1. the licensee broadcast a level of 4.73% category 3 music instead of the weekly minimum of 5%;
2. the licensee broadcast a weekly level of 0.83% news instead of the weekly minimum of 4%; and
3. the absence of any formal educational programming despite its condition of licence to broadcast a minimum of two hours of such programming.

A hearing was called and people were flown in from all over the country to attend. All because a college radio station didn’t play some news and missed a few minutes of “category 3 music”.

I realize spectrum is a limited commodity, but gee-whiz, isn’t there a more efficient way of handling this?

Process Watchdog

I’m sure there’s a million variants out there, but I had a simple need to make sure a process was running and restart it if it isn’t. I’ve done this before using one off scripts, but then I figured I may as well do one that is generic:

watchdog.sh:

#!/bin/sh

# watchdog LOOKFOR SERVICE
# will restart SERVICE (/sbin/service SERVICE restart) when LOOKFOR doesn’t appear in the processlist

P=`echo $1 | sed ‘s/^\(.\)/[\1]/’` # enclose first char in brackets

ps -ef | grep -v $0 | grep -q “$P” # skip myself

if [ $? -eq 1 ]; then
/sbin/service $2 restart
fi

So,

/usr/local/sbin/watchdog.sh asterisk asterisk

will run /sbin/service asterisk if there are no asterisk processes running.