Sunday, December 29, 2013

I Hate Big Box ISP's

Sometimes I hate "big box" Internet service providers.  In this case, Comcast (or Xfinity, which ever name you'd prefer) is my target.

We had a power outage in this area a week and a half ago.  Normally, this is not an issue.  However, this was wide-spread enough that Comcast decided to add custom routes in the network, and hasn't figured out how to remove them.

What it means for me

I have to have Internet access for my job.  I need it to be accessible from both sides (public to the private network, and vice-versa).  However, I cannot ping the public IP address that they provide from the public side.  I can't connect to it from there, either.  Since I'm an idiot with some networking experience, I start looking at trace routes.  From the inside :

traceroute to virtualserver (XXX.XXX.XXX.XXX), 64 hops max, 52 byte packets
 1  router (  7.623 ms  1.502 ms  1.832 ms
 2  XXX.XXX.XXX.XXX (XXX.XXX.XXX.XXX)  10.849 ms  11.573 ms  11.102 ms
 3 (  11.262 ms  13.049 ms  11.200 ms
 4 (  11.564 ms (  15.901 ms *
 5 (  16.767 ms  14.778 ms  15.931 ms
 6 (  27.885 ms  28.708 ms  24.411 ms
 7 (  36.089 ms  246.011 ms  185.173 ms
 8 (  24.435 ms (  27.180 ms (  26.129 ms
 9 (  81.675 ms  82.868 ms  87.086 ms
10 (  89.675 ms  88.852 ms (  92.166 ms
11 (  124.252 ms  122.275 ms (  124.109 ms
12 (  122.540 ms  122.649 ms  123.540 ms
13  * * *
14  vpslinkrouter (XXX.XXX.XXX.XXX)  122.334 ms  124.073 ms  127.955 ms
15  virtualserver (XXX.XXX.XXX.XXX)  121.408 ms  121.116 ms *

From the outside looking back to that IP address :

traceroute to XXX.XXX.XXX.XXX (XXX.XXX.XXX.XXX), 30 hops max, 40 byte packets
 1  vpslinkrouter (XXX.XXX.XXX.XXX)  0.063 ms  0.082 ms  0.073 ms
 2 (  0.297 ms  0.392 ms  6.757 ms
 3 (  0.232 ms  0.259 ms  0.316 ms
 4 (  0.654 ms  1.991 ms  1.971 ms
 5 (  6.401 ms (  6.502 ms  6.519 ms
 6 (  6.563 ms  6.502 ms  6.400 ms
 7 (  8.090 ms (  7.971 ms (  6.892 ms
 8 (  57.804 ms  57.789 ms  57.833 ms
 9 (  61.152 ms (  58.932 ms  58.892 ms
10 (  77.619 ms  77.642 ms  77.613 ms
11 (  100.511 ms  100.459 ms  100.443 ms
12 (  109.087 ms  112.585 ms  111.537 ms
13 (  111.017 ms  109.492 ms  111.080 ms
14 (  110.072 ms  108.898 ms  110.121 ms
15  * * *
16  * * *
17  * * *
18  * * *
19  * * *
20  * * *
21  * * *
22  * * *
23  * * *
24  * * *
25  * * *
26  * * *
27  * * *
28  * * *
29  * * *
30  * * *

Outbound traffic was routed from SLC, UT, USA to Denver, CO, USA.  In Denver, things take a different path than the inbound traffic.  In fact, inbound traffic is getting routed through New York City, NY, USA.  Even with THAT, it should be easy to pin point the problem.

Why I hate "Big Box" ISP's

So, I jump on the phone with them.  2 hours and 25 minutes (yes, I tried for this long), 8 transfers (3 times at the same group, too), 9 "that's beyond what I can do for you", and two online chat sessions later, my phone battery dies.  Not one idiot works for Comcast that knew that when I talked about an IP address in Denver that was their router, I wasn't meaning my home network router.  When this contract is over (if I can find a good ISP), kiss Comcast good bye.  If someone wants to pitch in to buy me a fiber connection, I'd be one happy camper!  But, in the mean time, I have to deal with big box idiots that associate "router" with "in house wireless" rather than a nice Foundry device sitting at their Denver office.

Wednesday, December 11, 2013

It's a Dangerous World Out There

The Honda Civic has been giving me fits again - it has a really loud rattle at idle, and it's been getting worse.  Sure, I'd love to be able to work on the vette again - to try and get back to the electrical, but it's not going to happen until I have a stable method of transportation.  I borrowed what is called a "mechanics stethoscope" - it's a mutation off of a doctors stethoscope, but instead of the diaphragm at the bottom (the thing you put on your back), it has a loose rod.

Here's how it works.  You put the usual binaural "ear pieces" where they'd normally go (if you put them elsewhere, I do NOT want to ever use your mechanics stethoscope).  Then, when the rattle is happening on the car, you simply place the rod onto various parts of the engine or components - making absolute certainty that you do NOT get it stuck in moving parts such as fans or belts.  You will hear a slightly amplified form of the rattle depending on how close to the rattling part you really are.

Here's my experience.  I went out with this to check the loud rattle on the civic.  Since it was cold (14 degrees), I put the ear pieces to my ears before I went out to the car so I could also put on the balaclava.  I'd suggest NOT doing this - every time I bumped the bottom end of the stethoscope, there was a really loud "thump" that seemed to cause pain.  Once I had the car started and the hood up, I began methodically setting the rod onto various components.  The engine block was first (new engine, wanted to make sure it was okay), transmission was next (wanted to make sure there wasn't a bad bearing or torque converter going on, or a stripped gear), and then the usual suspects.  It all stopped with the alternator.  It seemed to be the loudest.  The tool seems like it worked well.  I needed to remove the alternator to get it checked.

Here's the result.  I titled this post "It's a Dangerous World Out There".  So where was the danger?  Aside from not getting the thing caught in any moving parts, what could possibly have happened?  Well, I identified the alternator as a potential problem (and then saw the pulley on the alternator sitting at a bad angle).  So, I decided to remove it.  While I was laying underneath the car, clothing starting to stick to the concrete beneath me, with a large wrench to remove the alternator bolts, and not having much feeling due to the cold at this point, I dropped the wrench.  Normally this is not a problem.  However, I've been in the cold for a bit so the bridge of my nose is numb (right where the wrench hit), and I'm already frustrated.  Luckily, I was wearing glasses, which broke the fall of the wrench.  I rolled out from underneath the car, bent the glasses back to shape, felt kind of odd about my nose (no blood from the inside, so it's not broken), and went back to work.

Every time I stood up, I felt a little weird.  When I finished up as much as I could (the alternator is still there and needs to be disconnected), I went inside to console my sweet wife (another failure).  Looking in the mirror later that weekend told me I did break the skin.  Apparently, it's hard to take me seriously when I've been hit right between the eyes.

Friday, November 1, 2013

Steering Column ... Tilt / Telescopic Reassembled

Disclaimer : I am not Jim Shea - I do not have his understanding of steering columns, nor could I possibly pretend to do so.  If anyone is looking at GM steering columns from the mid-60's to the late 70's, I'd strongly suggest a visit to, since Jim Shea provided many hours of work to the public.  I believe he worked for Saginaw (the company that built the steering columns for GM during that period), and his hours of labor back then paid off big dividends for the rest of the Corvette community (or anyone rebuilding a GM column for that matter).

Since you are still reading, you are probably wondering what my problem was.  Obviously, it was in the steering column.  On my C3 Corvette, I took the steering wheel off to clean it, realized I had a horn contact retainer broken, and had to dismantle the column to get down to there.  While I was there, I had a lock cylinder to replace (I am re-keying the car as I go), so I had to take things a little bit further apart.  On the way into the dismantling, I thought I'd clean some of the components up, including a "sticking" turn signal.  The turn signal repair resulted in a separate post, and I started to put things back together again.  Unfortunately, after installing the lock cylinder, I couldn't get the key out.  The key-release was failing to allow everything to disengage.  Checking online, a 1977 Corvette steering column is not available.  I can order columns from others that don't match up, but should be close, but that was a $975 price tag I couldn't swallow.

Enter Jim Shea.  His documentation goes well beyond the factory installation manual, well beyond the factory service manual, and so far beyond the depth of the Haynes/Chiltons manuals that it's not even funny.  I knew I had to dismantle it, find what I thought was a broken part, and reassemble the column.  I tore it down to the tilt mechanism :

First, a few things.  In the above photo, you can see the tilt joint for the column.  I had to remove everything on the outside.  You can also see the key-release lever on the right side of the column.  This is simply a rotating (axis is down the centerline of the column, not perpendicular to the column), and it connects to the ignition rod on the left side of the column.  The joint sits in the actual column, with an external piece of plastic called the lower "bowl".

On the left side, inside the bowl but the outside of the column sleeve, is the ignition switch joint.  There are three pieces here, the shaft that connects to the actual ignition switch on top of the steering column (farther down the column), a guide (the ignition rod guide), and a key-like thing (the ignition rack).

So, I looked, and realized that (when I was making a silicon mold almost 10 years ago) I ended up getting silicon into the lower bowl housing, where the key release bar slid - and it was binding everything.  I grabbed my small files and cleaned it out, slapped some WD-40 into there, and ensure it rotated as needed.  Just a word of caution - the telescopic shaft comes right out.  If you don't need it, be very careful with it, you don't want grease all over your carpet.

I reassembled it, and tested (still no telescopic hardware installed, just the tilt, the upper bowl (where the turn signal switch sits) and everything below that.  The key release now works, and the turn signal works, everything is almost installed to the point I can install the telescopic parts of the steering column.  After finishing the telescopic, it's just a matter of cleaning up the steering wheel and putting it back on.  Looking good!

Tuesday, October 15, 2013

Catching TrendNet "End-Of-Motion" Signals

Anyone using a CGI to grab notifications from a TrendNet IP camera will know that the TrendNet doesn't send a signal when all is clear - it simply sends repetitive "motion" signals.  It makes it difficult to receive an "all clear" without doing some fancy "touches", and you won't get it in any sort of real-time status.  So, how can you grab an "All Clear", and have it happen when the camera stops recording (meaning that you can configure a camera to record an extra 30 seconds, then get the "all clear" when the recording stops) ?  Well, it turns out it's simple, if you are using Samba.  Here's how I did it.

Configure Samba :

The later versions of Samba (e.g. 3.x) include "VFS" modules - or "Virtual File System" modules - which allow Samba to handle virtual tasks such as translating new lines on-the-fly, or checking new files for virus or malware.  There is are two included VFS module for auditing, and one will log messages when a file is closed.  The VFS module is the one we need.  It's included, so we simply need to enable it.  Open your /etc/samba/smb.conf, and in the [global] section :
    vfs objects = full_audit
    full_audit:prefix = %u|%I|%m|%S
    full_audit:success = close
    full_audit:failure = none
    full_audit:facility = local6
    full_audit:priority = DEBUG
If the priority is NOTICE, you will get the messages into /var/log/messages, so beware of your config.  I went with DEBUG, so that I can then restrict that to one destination (I'll talk about that later).

The secret is in the "full_audit:success" and "full_audit:failure" parameters.  These allow you to configure what system calls you want logged, either on failure or on success.  In the above configuration, I log nothing on failures, and I log "close" on successes.  This means that the syslog configuration will get a log message for every time a file is closed (whether being written to or just read from).  The log messages look like :
    Oct 15 22:44:01 localhost smbd[20487]: anne||mediacenter|movies|close|ok|disney/the_little_mermaid.mp4
    Oct 15 22:44:02 localhost smbd[20487]: secuser||tv-ip322p-0015f|camerashares|close|ok|path_to_storage/20131015/22/224315.mp4
So, since we will end up with all closings, you want to ensure either the username ("secuser" in the above messages) doing the writing or the hostname (tv-ip322p-0015f) that is writing to the Samba share is unique and you can filter out the rest of the stuff.  In my case, the host is "tv-ip322p-0015f", so I can easily just watch for those messages for closings from the camera(s) in question through logcheck, and have an instantaneous notification via e-mail when each camera clears itself and stops recording.  However, since we want the notification to enter our event server (e.g. Nagios), and... since full_audit already runs through syslog, it's simply a matter of setting up a named-pipe.

Named Pipe Creation :
  1. Create the named-pipe :

    mkdir /etc/syslog.pipes
    mknod /etc/syslog.pipes/sambaEvents p
    chmod 600 /etc/syslog.pipes/sambaEvents
  2. Next, configure syslog to write to that named pipe.  In your syslog config (e.g. /etc/rsyslog.conf), add a line such as (make sure it matches your customizations) :

    local6.* |/etc/syslog.pipes/sambaEvents
  3. Then, restart syslog :

    /etc/init.d/rsyslog restart
  4. Finally, you will have to write a tool that reads from your named-pipe.  In my case, I'm setting up an eventserver, and I'm using a plugin for that one.  For anyone else, you can do a cron (example such as :

    * * * * * /usr/local/bin/ < /etc/syslog.pipes/sambaEvents

    That will run the job once a second looking for messages from the queue, and then e-mail them out if they match my tv-ip322p.
SELinux note :
    Oct 16 08:30:21 cottonwoodheights rsyslogd-2039: Could not open output pipe '/etc/syslog.pipes/sambaEvents' [try ]
    Oct 16 08:30:24 cottonwoodheights setroubleshoot: SELinux is preventing /sbin/rsyslogd from 'read, write' accesses on the fifo_file sambaEvents. For complete SELinux messages. run sealert -l 0f6ad628-c737-452f-a4a2-fbf240519594
If you are running SELinux, you will probably see something like the above.  Simply run the sealert command it names, and follow the directions the command provides.  You may also find more messages in there for the script that reads from the named pipe.

Added Notifications :

Just a note, if you want other functions (for example, if the camera you are using doesn't have a "motion detected" notification method but does capture only the motion video, you can add the "open" to the full_audit:success line such as "full_audit:success = open,close"), I grabbed a list from the vfs_full_audit.c source, so these are things you can monitor if you really want, but beware things like "pwrite" are called multiple times in a file write, not just once for the entire file, so you could have a log inundated with verbose messages.

Wednesday, October 9, 2013

Alarm Switch Installed

Well, it's amazing what you can accomplish when you have a little time.  I was able to install the alarm lock cylinder into the fender (wires, lock retainer, and gasket), and I was able to get the hood hinges in place and connected to the body and the hood.

I need to figure out how to adjust the hood at this point, and then I can install the hood support (which I received - thanks, Corvette Central!), and then finish plumbing the carburetor.  That would leave simply the headlights, steering column reassembly, electrical testing, door glass adjustment (need to get the battery in place to do the adjustment, which is also why I needed to get the electrical tested, which is why I needed the alarm switch functional and installed).

So, here's my to-do list (yes, it has gotten to the point that it is very specific) :
  • Reassemble the Turn Signal Switch and Ignition Switch
  • Install the Tilt/Tele Steering Wheel Components
  • Have Someone Clean the Steering Wheel Leather (Not sure how expensive)
  • Install the Steering Wheel
  • Hood Adjustment
  • Plumb the Fuel-Filter-to-Carburetor Lines
  • Headlights
    • Obtain Ford Probe Headlight Motors (model year 1993 to 1997, about $60 for the set)
    • Wire up a Headlight Control Relay (from Napa, EC23 $15 and BK3007884 $9)
    • Manufacture a Bracket to Hold the Probe Headlight Motors (not sure how much this will cost)
    • Assemble the Electric Headlight System
    • Get the Headlight Bezels and Lids Painted to Match (at $300 a pint for the color coat alone)
    • Install Headlights Themselves
  • Probe Electrical Connections (before Adjusting the Door Glass)
  • Connect the Battery
  • Adjust the Door Glass
  • Disconnect the Battery
  • Install Door Panels
  • Ensure Interior Light Bulbs are in Working Order
  • Complete Air Ducts
  • Install the Drivers' Dash Panel
  • Obtain a Map Pocket ($85) for the Passengers' Side and Install (with Springs)
  • Install the Passengers' Side  Dash Panel
  • Bolt Down the Center Console
  • Bolt Down the Parking Brake Cover
  • Install Transmission Tunnel Covers
  • Bolt Down the Seats and Test
  • Connect the Battery and Test All Electrical Components (EXCEPT FOR STARTER)
  • Fill with coolant
  • Add Oil and Prime the Oil Pump
  • Add a LITTLE Gasoline to the Tank
  • Add Gear Oil to the Tremec TKO II
  • Add Windshield Washer Fluid
  • Lift Rear Wheels into the Air (don't want to have the transmission fail to disengage)
  • Connect the Battery
  • Put some Gasoline in a Glass cup in Preparation to Test Fire
  • Test Fire
  • Stop Engine
  • Engage Wheels with the Ground
  • Start, and Drive a Short Distance (less than a mile)
  • Return and Check the Oil
  • Raise the Back End
  • Run the Car in Gears for 20 Minutes Each (Transmission Break In)
  • Drop the Car
  • Check the Oil

Tuesday, October 8, 2013

CentOS 6 and Standard X ScreenSavers

I use CentOS as a desktop, primarily because I need to be able to work on scripts and ensure they work on the servers before I throw the things over to the servers for production runs.  However, the default number (and style) of screensavers for Gnome are pitiful.  Popart, the insecure "photos", and some weird "gnome feet" screen saver.  Because of this, I needed to have the original X screen savers.

I'm using CentOS 6.4, and due to previous histories, I knew I needed packages named with the following :
    gnome-screensaver (already installed)
I loaded up (way better than, and tracked down RedHat EL6 RPM URL's.  Then threw them into the following command :
    yum install \ \ \ \ \
This gave me a requirement for a package that was missing with the following error :
    Error: Package: 1:xscreensaver-base-5.11-7.el6.respin1.x86_64 (/xscreensaver-base-5.11-7.el6.respin1.x86_64)
               Requires: xorg-x11-resutils
     You could try using --skip-broken to work around the problem
     You could try running: rpm -Va --nofiles --nodigest

I found the missing package that was required (news to me), and fired off the command :

    yum install \ \ \ \ \ \

Success!  Note that you will have TWO screen saver options.  If you use gnome-screen saver and hot keys to lock your workstation, you should continue to use that one (your new screensavers will show up in it's configuration pane).  If you open the first one and it says it needs to stop the gnome screen saver, cancel that, close that preferences pane, and open the other one.

Sunday, October 6, 2013

Steering Column - Coming Together

With some bad engineering drawings, a bad memory, and some skill with Tetris from growing up, I finally figured out how the steering column's Tilt/Telescopic components fit together.  There were a few steps to get me to a point that the Chevrolet manuals talked about :

  1. Find out how the light dimmer switch shaft sets into the housing.
  2. Find out how the turn signal switch connects to the dimmer switch (hint - it uses a plastic carrier that sets into a plastic shell that the tilt/telescopic lever runs through).
  3. Understand how the wiring fits into the wiper/turn signal switch carrier housing (that also houses the ignition lock cylinder)
  4. Locate a suitable pivot pin for the wiper/turn signal switch that connects the switch to the housing.
  5. Put that all together in one fell swoop (you kind of have to do this - without the housing, the parts will fall out, and without the parts in the right place, the housing won't connect.
For the pivot pin, I had lost mine, and found out that no one sells a replacement.  Goofing off, I realized that my Honda Civic (metric) had six bolts for the timing belt cover, and (since I had replaced the engine this year) I had the old bolts laying around.  Those bolts fit into the threads for the housing, and the shoulder on the bolt had a slightly larger diameter (that's a good thing) than what it should be (it wouldn't fit into the switch).  I grabbed my drill, slapped the bolt into the chuck, and grabbed a file.  I basically turned the shoulder without a lathe until it was the right size.

Then I ran out to grab the ratchet to install it..... and found the old pivot bolt still in the socket from nine months ago!  I compared them, and they were almost identical, the original had an extra pivot pin on the end (e.g. two shoulders of different sizes with a threaded section sandwiched in between).  The "replacement" would have still worked, but I opted for the original (anyone wonder why?).

I set about installing everything, and had success in getting those parts completely installed (complete with a new ignition lock cylinder).  Next up, finishing the rest of the assembly, which I can now use the AIM for (the assembly instruction/engineering diagrams at the factory).

Wednesday, October 2, 2013

Bluetooth USB Desktop with VOIP

I'm running as a guinea pig for the corporate office, helping to set up a software-based phone (no VoIP hardware).  That means that I needed to set up a wireless headseat, which forced an interaction with Bluetooth on my CentOS workstation.  I bought a Sabrent BT-USBT 2.0 adapter (small, which is good, you can find one on's website).

I got the adapter fairly quickly, and plugged it into the workstation, and did an lsusb to see what I had :
    [username@hostname video]$ lsusb|grep -i bluetooth
    Bus 003 Device 040: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
    [username@hostname video]$
It looks like it's a re-badged device, but that also means that it it can communicate with the USB system.

In preparation, ensure you have the right tools for this :
    yum install bluez-alsa bluez bluez-compat
You will first need to enable the bluetooth services.  The first thing to do (before you forget) is to enable the bluetooth service at startup (the first command following this paragraph).  The second thing is to actually start the bluetooth service.  The commands :
    [root@hostname video]# chkconfig bluetooth on
    [root@hostname video]# service bluetooth start
    Enabling Bluetooth devices:
    [root@hostname video]#
Next, you will need to pair a device to your new bluetooth connection.  This is done fairly easily through the GUI (if you needed this faster than a crazed admin with a site down).  In gnome, click "System" from your menu, then "Preferences", then "Bluetooth". e.g. :

This should present a window with courses of action - a check box entitled "Make computer discoverable", and a button to "Set up new device".  The "Make computer discoverable" is to use the computer as the peripheral device, while the other will add a device to your computer.

For a bluetooth wireless device, click on "Set up new device".

However, I never work through the GUI unless it is imperative.  The tool for you command-line folks to use is "hcitool".  First, run an "hcitool scan" (to look for your device), followed by an "hcitool info" (get more information on the specific device) :
    [root@hostname video]# hcitool scan
    Scanning ...
     60:33:4B:07:15:49 appletv
     50:3D:E5:7D:62:FD CP-8945
    [root@hostname video]# hcitool info 60:33:4B:07:15:49
    Requesting information ...
     BD Address:  60:33:4B:07:15:49
     OUI Company: Apple, Inc. (60-33-4B)
     Device Name: appletv
     LMP Version: 2.1 (0x4) LMP Subversion: 0x422a
     Manufacturer: Broadcom Corporation (15)
     Features page 0: 0xff 0xff 0xcf 0xfe 0x9b 0xff 0x79 0x83
     Features page 1: 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
    [root@hostname video]#
This should give you most basic information, but to pair it up, simply run (where XX:XX:XX:XX:XX:XX is the device hardware address from above) :
    hidd --connect XX:XX:XX:XX:XX:XX
For example :
    [root@hostname video]# hidd --connect 60:33:4B:07:15:49
    [root@hostname video]#
And then you can configure the device as needed through the normal methods.

Monday, September 23, 2013

Arduino Helps in Auto Resto

I started trying to re-assemble the steering column, but didn't get anywhere.  Well, maybe I did.  I started checking the wiper switch, found that it wasn't working as the wiring diagram said it should, and started looking for new ones.  I failed to find one I could buy.

Over the weekend, I was chatting with my father, who asked me, "well, why not just rebuild your switch?  You've just about rebuilt everything else without knowing how it was engineered!"

It took a few days for that to fully sink in, and this morning, I asked myself, "why not?"

I took the switch completely out of the housing (just down to the plastic/contact pieces), and grabbed a drill bit (had to be the right size).  I started to drill the rivets (where you don't drill all the way through, you simply drill far enough into the rivet for it to separate), and used a pocket knife (great edge, not flimsy like an x-acto knife, perfect for prying apart without breaking the surrounding plastics).  That got my contacts off of the plastic frame for the switch.  Other than paint that had gotten into the switch and a wire that someone had cut, my switch was actually in great shape.

I used a wire brush to clean the contacts.

Before installing things, I thought it would be easier to solder in a new chunk of wire in the one that had been clipped.  I broke out the soldering iron, solder, heat shrink tubing, and slapped that puppy back together.  I added the contacts back to the switch frame, placed the eyelets, grabbed the rivets, and popped it all back together.

I needed to test it, but, since my voltmeter was not working (translation: I was too lazy to go buy a new 9v battery), I opted to get a better visual test for this.  I ran down and grabbed my Arduino Nano, connected the common point for the switch connector to ground, and slapped a modified button code onto it that defaulted with a pull-up resistor on three inputs, and three outputs to LED's.  This way, if the wire wasn't connected to ground, the LED would light up.  If it was connected to ground, the LED would turn off.

It gave me a great visual way to ensure that it was connected properly.  Now I can start to figure out the entire reassembly.  It will take some time, but once I get it, I'll have the steering column put back together fairly quickly, and then I can finally do the electrical test before connecting the battery to adjust the windows.  Getting one small step closer!

Back to the Corvette - The Steering Column

I started trying to re-assemble the steering column, but didn't get anywhere.  Well, maybe I did.  I started checking the wiper switch, found that it wasn't working as the wiring diagram said it should, and started looking for new ones.  I failed to find one I could buy.

Over the weekend, I was chatting with my father, who asked me, "well, why not just rebuild your switch?  You've just about rebuilt everything else without knowing how it was engineered!"

It took a few days for that to fully sink in, and this morning, I asked myself, "why not?"

I took the switch completely out of the housing (just down to the plastic/contact pieces), and grabbed a drill bit (had to be the right size).  I started to drill the rivets (where you don't drill all the way through, you simply drill far enough into the rivet for it to separate), and used a pocket knife (great edge, not flimsy like an x-acto knife, perfect for prying apart without breaking the surrounding plastics).  That got my contacts off of the plastic frame for the switch.  Other than paint that had gotten into the switch and a wire that someone had cut, my switch was actually in great shape.

I used a wire brush to clean the contacts.

Before installing things, I thought it would be easier to solder in a new chunk of wire in the one that had been clipped.  I broke out the soldering iron, solder, heat shrink tubing, and slapped that puppy back together.  I added the contacts back to the switch frame, placed the eyelets, grabbed the rivets, and popped it all back together.

I needed to test it, but, since my voltmeter was not working (translation: I was too lazy to go buy a new 9v battery), I opted to get a better visual test for this.  I ran down and grabbed my Arduino Nano, connected the common point for the switch connector to ground, and slapped a modified button code onto it that defaulted with a pull-up resistor on three inputs, and three outputs to LED's.  This way, if the wire wasn't connected to ground, the LED would light up.  If it was connected to ground, the LED would turn off.

It gave me a great visual way to ensure that it was connected properly.  Now I can start to figure out the entire reassembly.  It will take some time, but once I get it, I'll have the steering column put back together fairly quickly, and then I can finally do the electrical test before connecting the battery to adjust the windows.  Getting one small step closer!

Friday, August 30, 2013

CIVIC: Almost Alive

Well, the Civic is almost alive.  It runs, and I've driven it almost 20 miles since the swap.  However, it's only legal right now because I have a permit on it.  The reality is - it failed the safety and the emissions checks.

Emissions Inspection :

When I finally snuck it in to get it inspected, I had completely forgotten that if you disconnect the battery for any extended period, the computer's memory completely resets, and all of the emissions equipment settles into a "Not Ready" state until you have enough regular driving conditions on the car for it to figure out how it is doing.  So, it failed the emissions because everything was in a "not ready" state.

Safety Inspection :

The safety inspection wasn't as bad as it could have been.  Shoot, the last time it was inspected, I was surprised it passed because the tires were so worn out.  I didn't expect them to pass this time, and wasn't shocked when that didn't happen.  I'll get it to Les Schwab in the next few days and then get it registered.

Result :

Today's drive was a good, longer than 9 months of driving kind of drive.  I put 15 miles on it in a half hour, but none was freeway.  I have a 15 day period to get the good driving results in, and get it registered.  Then I'll be completely back on my feet.  It was good city driving, and the car didn't want to move as easily at first, but slowly started to loosen up again.  I think it will be back to normal within a week with my driving habits.

That said, it's allowed me to work on the Corvette a little bit - and I was able to get that alarm key set up, and duplicated.  Now, I just need to install the switch and wiring, and then hit the electrical with some probes to ensure things are lined up in the right places.  Perhaps after a good day of work on it on Monday can get me feeling better about it.  I might be able to get the steering column put back together.  Hooray!

Wednesday, August 28, 2013

Corvette - Alarm Key Working

So, I had purchased an alarm switch off of eBay a while back for the Corvette (while working on the Civic).  I finally got around to having a lock smith take a look at the switch (I had no key, and it was advertised as "filling a hole" and was in "rough shape" according to the photos).  I had held the thing in my hand numerous times, and I've been wondering if it's possible to restore it to functionality.

Well, I finally overcame my fear and headed to the lock smith.  $26 later, I had the following :

  • A functional key to fit the switch - I needed to have them re-key, but didn't have that key with me.
  • Electrical testing operates as designed.
  • A feel good "That's the cleanest set of tumblers I've ever seen on something that old - I think they just never used it."
I'd install it, but I have one thing left to do - get it re-keyed to match the new ignition keys. Once that is done, it's time to install it, check the electrical, and then connect a battery so that I can get the window glass adjusted and the door and dash panels installed.  One small step, but it's been a hurdle.

Wednesday, August 21, 2013

MisicBrainz Picard (and FFMpeg and Chromaprint) in CentOS

I had some unidentified tracks that I wanted to identify.  I knew that there were apps that would "listen" on the microphone of a phone to a song to identify it, and that lead me to believe that there would be a webservice out there I could call with the MP3's to identify them.

A quick Google search turned up a program called "Picard", by "MusicBrainz".  They even had a "Linux" interface for it.

For those who are impatient and want to install this, there are two dependencies - ffmpeg development packages (a result of the next dependency) and chromaprint.  Here's how to install everything :

  1. Install ffmpeg by doing :
    1. Using RPMForge, follow the instructions at :
    2. Then, install ffmpeg and libraries :
      yum install ffmpeg ffmpeg-devel
  2. Install chromaprint (download, extract, and CD into the directory - remember, we installed ffmpeg to an odd directory above, tweak if this is in a normal place) :

      make install
  3. Ensure you have the libraries for chromaprint installed :
    all chromaprint (download, extract, and CD into the directory - remember, we installed ffmpeg to an odd directory above, tweak if this is in a normal place) :

      ldconfig -p|grep chroma

    If nothing shows up, add /usr/lobal/lib to /etc/ and run "ldconfig" again.
  4. Install picard by grabbing the code from, extract it, cd into it, and run :

      python install

    This should install it for you.  Run it using the command picard.
For those that want to know how I got to this point, this is how I got it installed, and tried it.

First, I grabbed it from (using the Linux source as I didn't want to deal with cross-distribution RPM's).  Pulling it down, I found it to be a python based installation (not the usual "./configure && make && make install").  I checked the INSTALL.txt and found what I needed.  Once inside the source directory, run :
    python install
This will install the code for you.  I also ran into a few issues with missing python modules.  The ones I had problems with are PyQt4.x86_64 and mutagen

So, in order to get the interface to launch, I had to run :
    yum install PyQt4.x86_64 python-mutagen.noarch
This allowed the interface to run, but I was getting :
    Fingerprint calculator failed error = No such file or directory (0)
This is a result of not having chromaprint's "fpcalc" program (the packages fingerprint calculator, which is actually sent to the web service and used to find the song information from an accoustic perspective).  In trying to get that one installed, I ran into the following error :
    FFTW3 lib not found. Set FFTW3_DIR to find it.
    CMake Error at CMakeLists.txt:114 (message):
      Neither FFmpeg with avfft.h nor FFTW3 found
Hrmmmm.  I need FFMpeg for the encoding, and it must apparently be the development.  That package starts to become a little "extreme" for a few people, but I was actually stunned that I hadn't installed it myself (it's usually one of the first things I install).  So, I had to install it.  It's a matter of following (standard instructions), and then :

yum install ffmpeg ffmpeg-devel
    yum install ffmpeg ffmpeg-devel
I had some conflict errors, so had to throw in a few "--disablerepo dag --disablerepo rpmforge" options and manually install a package, but got ffmpeg installed.  Next, I had to compile and install chromaprint :
    make install
It tossed /usr/local/bin/fpcalc onto the filesystem, and this time, we got :
    Network request error for Error downloading - server replied: BAD REQUEST (QT code 299, HTTP code 400)
    Fingerprint lookup failed: u'invalid fingerprint'
THEN I figured out the "scan" wasn't the right thing to do - invalid fingerprinting.  I was supposed to be using "locate", not "scan".  Cool!

Tuesday, August 13, 2013

Civic Status: running, SRS/CEL both clean

Okay, after breaking the valve cover bolt, I had to drill the bolt without touching the valve train/head, and then back it out.  I was successfully able to do that, dropped in the replacement bolt, tightened things down (very carefully, this time), and then crossed my fingers.....

... the car started, no CEL (not even the SRS, this time, either), and it seemed to be running much better.  Next up - grease the bearings on the wheels, pull a lug bolt and replace it, and go get it registered.  I don't know if the tires will pass an inspection, but if they don't, that would be it to be back on the road.  An A/C recharge would be next on the list, but it's workable without it.  So, three things to do before I can get back to the Corvette :
  1. Lug bolt/nuts
  2. Tires replaced
  3. Recharge/oil the A/C lines
This is phenomenal news!

Monday, August 5, 2013

Simple TCP Server in C - Republish

Security Note

If you need to set up a command server, there are a few issues. The first and foremost is security, though in the contexts of this document we will fore go the security issues. In this document we will discuss the ability to set up and create a simple server using unix and C/C++, leaving the discussion of securing a simple command server to a different document.

First, please be aware that running the resulting server as a root account could cause potential damage to the system (via hackers). So, this is only documented as research, with no liabilities held by the authors, consultants, or companies holding this code specifically as such.

Constructing the Program

First, we need to understand how a TCP/IP server even works. When a message is sent from a client to a server, it is encoded with an ID number, or a port as commonly referred to. Some port numbers are associated with a name, such as www (80), telnet (21), ssh (23), and SMTP/Mail (25). These are referred to as "common" ports. We need to identify the best port (preferrably one that is not used in any circumstances). I like to use the port 666 for software like this as it can be a real devil to secure. You will note that, in unix systems, one must be the root user in order to use privileged ports (ports under 1000), just to ensure the safety and well being of the "common" ports.

On the server itself, a piece of software called a daemon is running, and listening for connections that have the specified ID/port. When one comes in, it can then accept these connections, and recieve and transmit data to/from the other end of the connection (client).

An endpoint for TCP/IP communication is called a socket. The header file is called "sys/socket.h" (except in MS Windows where it is "winsock.h"). We will create a socket handle, using the socket function. Rather than opening the socket (a client will do this), bind to the socket, listen for incoming connections, and then accept them.

socket : This creates an endpoint, or a socket, to communicate with a client or a server on the network. It's use is :

int socket(int domain, int type, int protocol);

The integer returned is the handle to our socket.

bind : bind assigns the local port and server address to the socket. When a socket is created with the above socket command, it is classed only as a family (TCP is the AF_INET family, or internet type of socket). This can be used to request that a specific IP address will be listened to, or any IP address on the machine. The code :

int bind(int s, const struct sockaddr *addr, socklen_t addrlen);

listen : listen tells the program that incoming connections will be used. It also allows you to set things like queue limits for connections that clients have requested.

int listen(int s, int queued_connections);

accept : Once a socket has been created, assigned a port, and is listening for connections, you must call accept. Accept will block (meaning that it will wait until a connection request is made).

int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

Creating the Source Code

We'll save the topic for creating a Makefile for a completely different discussion, as this can get extremely complex. In the mean time, use the following :
    # Makefile for a simple TCP Server
    PROGRAM =tcp_server
    CC      =gcc
    CCF     =-c
    LINKER  =ld
    LINKERF =-lc /usr/lib/crt1.o
    SRCS    =\
    OBJS    =
    CCSRCS  =
    .for SRC in $(SRCS)
      OBJS += $(SRC).o
    all: compile link
    $(SRCS) :
            $(CC) $(CCF) $@.c -o $@.o
    compile: $(SRCS)
            $(LINKER) $(LINKERF) $(OBJS) -o $(PROGRAM)
    rmproper: clean
            @rm *.o
            @rm $(PROGRAM)
Now, with this Makefile, all we will ever need to be worried about is adding source modules to the SRCS parameter (which already has a tcp and a main). The backslash is an escape method of saying "we're still adding stuff to the variable using the next line of information".

Okay, we need to have a 'main' function. The purpose of a 'main' function is to provide a uniform method for all C programs to be compiled. So, we create our function, and make it call our server code. If you want to add the ability to use command line options as you'll find on most tcp servers, this is the function you would add the code to. But, since all we need to do is start our TCP server, our function will be short :
    int main(void) {
            start_server(); /* start the tcp server */
            return 0;       /* return "success" to the shell */
Nice and simple, eh? In fact, if you commented out that start_server(); line, and replace it with a printf("Hello, World!");, and you've got yourself the infamous "Hello, World!" program that is taught as the first step in C Programming.

But that's not what we're after. We are going to assemble a simple TCP command server. So, we leave the start_server(); line in place, and add a function called start_server(). It should take no parameters, because our example program is purely designed to be as simple as can be.

Prior to performing any socket operations, we will need to make sure we've got the right headers. Of we don't, compiling will fail the program. The headers we'll need are :
      #include <sys/types.h>
      #include <sys/socket.h>
      #include <netinet/in.h>
      #include <netdb.h>
Once you've got those, the following functions should be okay.

Inside of the function, we will need to create and prepare our socket. First, we create the socket handle (which is an integer) by creating an integer variable and assigning to it the result of calling the socket(AF_INET,SOCK_STREAM,getprotobyname("tcp")). The AF_INET declaration is specifically for the Internet, and the SOCK_STREAM number for the type is required for TCP data. We can typecast the return value of the getprotobyname to int just to keep from getting a lot of warning messages. But, here in our example, we'll just use 0 for that.

Once we have the socket handle created and initialized, we then bind the socket address information to our new socket handle. We first fill out the socket information, setting the address to the IP we are going to bind to (INADDR_ANY if we want to open up to any IP address), and also set the socket's family (the AF_INET is used twice, once for the operating system using the connect function call, and once for the socket information itself). We then push these parameters into the socket information using the bind() function, as in :

bind(our_socket_handle,(struct sockaddr *)&socket_info,sizeof(socket_info)).

Now, before proceding, I MUST hit on a key programming factor. ALWAYS check the status of a function if it returns it. The last thing you need to do is try a function call on an already defunct socket handle. So, PLEASE check the status of the bind function.
    int start_server(void) {
     int                  our_socket_handle,status;
     struct sockaddr_in   socket_info;
     our_socket_handle = socket(AF_INET,SOCK_STREAM,0);
     if (our_socket_handle == -1) {
      perror("Creating socket()");
     socket_info.sin_family      = AF_INET;              /* Internet TCP/IP              */
     socket_info.sin_addr.s_addr = htonl(INADDR_ANY);    /* listen on any IP address     */
     socket_info.sin_port        = htons(5000);          /* 5000 is an unprivileged port */
     status = bind(our_socket_handle,(struct sockaddr *)&socket_info,sizeof(struct sockaddr));
     if (status) {
      fprintf(stderr,"Cannot bind() to the socket");
Now, we've bound the socket's information to it, so we need to listen() and accept() connections. Here's how we do that.

Listen is a straight forward function. All it is designed to do is tell the operating system that we are waiting for connections on the socket. We also include the number of back logged, or queued connections that we will allow to wait for our program (in this example, we'' listen for 5 connections), e.g. :

status = listen(our_socket_handle,5);.

Then we put a loop function around the accept() function. This allows us to retrieve an unlimited number of connections (though still at one at a time). But, since this is a simple tutorial, we will NOT put the accept in a loop. All we will do is retrieve the information that is sent, send it back, and exit. It's primarily a simple procedure to test with.

This accept() function is designed to recieve a connection. It will block until a connection is recieved, then proceed to the next line of code. It initializes a socket structure with the clients connection, and then releases you to work. Don't forget that the return variable, client_socket_handle, needs to be declared in the variables at the top. We also add the client_socket_info structure, and we're ready to implement it. Also, don't forget to close the sockets :
    status = listen(our_socket_handle,5); if (status) { fprintf(stderr,"Cannot listen() to socket"); exit(1); } client_socket_handle = accept(our_socket_handle,(struct sockaddr *)&client_socket_info,sizeof(struct sockaddr)); write(client_socket_handle,"Hello, World!",strlen("Hello, World!")); close(client_socket_handle); close(our_socket_handle);
Now, with this entire program, if you were to run it, it should not give you the command prompt back. Now, open up another telnet window, and go to the server you are running this on, at port 5000, and you should get an immediate close of the connection, but it should have printed the "Hello, World!" string before closing. Pretty snazzy, eh? Using a combination of the send() and recv() functions, you can build an effective communication tool to do nearly anything you need. Effectively, here is our main.c file :
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    int main(void) {
     start_server(); /* start the tcp server */
     return 0; /* return "success" to the shell */
    int start_server(void) {
     int                  our_socket_handle,client_socket_handle,socket_size,status;
     struct sockaddr_in   socket_info;
     struct sockaddr_in   client_socket_info;
     our_socket_handle = socket(AF_INET,SOCK_STREAM,0); //(int)getprotobyname("tcp"));
     if (our_socket_handle == -1) {
      perror("Cannot create the socket : ");
     socket_info.sin_family = AF_INET;
     socket_info.sin_addr.s_addr = htonl(INADDR_ANY);
     socket_info.sin_port = htons(5000);
     status = bind(our_socket_handle,(struct sockaddr*)&socket_info,sizeof(struct sockaddr));
     if (status == -1) {
      perror("Cannot bind() to socket : ");
     status = listen(our_socket_handle,5);
     if (status == -1) {
      fprintf(stderr,"Cannot listen() to socket");
     socket_size = sizeof(struct sockaddr);
     client_socket_handle = accept(our_socket_handle,(struct sockaddr *)&client_socket_info,&socket_size);
     write(client_socket_handle,"HELLO, WORLD!",strlen("HELLO, WORLD!"));

Saturday, July 27, 2013

Civic Timing Belt Gear Differences

So, with the P0171 (or flash code 54 on the CEL/Check Engine Light method), I suddenly realized the fluctuation sensor (CFK) on the civic needed teeth closer to it, and didn't have them.  I knew I had to tear into the engine, thinking I'd put the timing gear/pulley on backwards, and took it all apart.  When I pulled the gear off, I knew why I was having problems - they weren't even the same.  I called the dealership (who kept telling me "I've never seen one of these fail before" and trying to convince me I didn't need one), and $77 later, I had the part to compare.

Wow, that is much more like it.  The one on the left is what came with the replacement engine.  The one on the right is the one that came from the dealership.

Though the engine block was identical, it was still a Japanese-spec'd engine, meaning it met Japanese specifications - and their computers probably didn't care about the fluctuations on the crank sensor, and (I think) didn't even have the sensor in there.  The one on the right has what looks like a bicycle sprocket on one end, and that is the difference.  Things looked much better with the new gear in place, but I am still unable to test it as I snapped one of the valve cover bolts off in the head trying to get it tightened down so that it wouldn't leak oil like it did before.  We'll see how it works when I can drill it out and tap it for a new one.

Friday, July 26, 2013

Power Supply Pinouts

Voltages and Funtions
Wire ColorVoltage/Function
Connector Color Scheme
(looking at the connector with the wires pointed away)

Apache Module Config Merge

An example apache module merge routine :
    static void *mod_gzip_merge_dconfig(
    apr_pool_t *p,
    void *parent_conf,
    void *newloc_conf
     mod_gzip_conf *merged_config = (mod_gzip_conf *) apr_pcalloc(p, sizeof(mod_gzip_conf));
     mod_gzip_conf *pconf         = (mod_gzip_conf *) parent_conf;
     mod_gzip_conf *nconf         = (mod_gzip_conf *) newloc_conf;
     ( apr_pool_t    * ) p,
     ( mod_gzip_conf * ) merged_config,
     ( mod_gzip_conf * ) pconf,
     ( mod_gzip_conf * ) nconf
    static int mod_gzip_handler( request_rec *r ) {
     mod_gzip_conf *mgc; /* Location/Directory configuration */
     mgc = ( mod_gzip_conf * )
     ap_get_module_config( r->per_dir_config, &gzip_module );
    register_hooks() {
      ap_hook_insert_filter( mod_gzip_insert_output_filter, NULL, NULL, APR_HOOK_MIDDLE );
     ap_register_output_filter( mod_gzip_filter_name, mod_gzip_output_filter, AP_FTYPE_CONTENT );

PerlMagick Tutorial - Re-Published

I wrote this tutorial years ago, and it has been a popular little page.  As a result, with me closing down one website and moving to a blog-oriented online presence, I thought I'd better get it out there again for people to see.  Hence, a re-publish ensues.

Congratulations on taking a look at PerlMagick!  I am positive that you will find a system of image manipulation routines that are both powerful and easy to implement.  PerlMagick is a set of perl commands and routines that allows a developer or administrator the ease of using perl, but the power of using ImageMagick.  The tools are impressive on how they can be used in creating dynamic images, whether for business use in charting, or even just in CGI development.

In this tutorial, I will walk you through creating some of the tools typically used, and some of the simple methods.  We will discuss the following, respectively :
    Compiling ImageMagick and PerlMagick  This is where we discuss the "How's" of installing ImageMagick and PerlMagick.  There are a couple of quirks that occur when compiling, and we discuss why they occur.  
    Command-Line Tools  Once installed, I'll introduce you to some simple command line functions to use the tools that come with ImageMagick.  Once we understand these better, we can proceed to implement PerlMagick.  
    PerlMagick  A good understanding of ImageMagick, or even image manipulation is key to implementing the PerlMagick interface.  Here, we'll take a solid look at constructing a simple PerlMagick script.  
    File Reading and Writing  Reading and writing images the key to any image manipulation tool.  Because of that, we'll discuss the basic methods for reading and writing images, plus take a look at some quirks of working with files in a CGI environment.  
    Creating Images from Scratch  If developing a dynamic image utility, often we'll need to create images, without having a previous image to work from.  Here's how we do that.  
    Drawing Primitives  Adding lines, squares, circles, or other "primitives" using PerlMagick is often not discussed, and it's difficult to find sources on it.  I'll teach you how to draw primitives onto your images.  
    Writing on the Image  This is where we can get tricky.  Writing on images is a key principle of image manipulation.  
    Adding Transparency  Some image formats (such as .gif, and .png) allow transparency.  These formats are most often used in web design, allowing the image to properly show background colors and creating more seamless integration of HTML and graphics.  
    Creating Animations  Want to use the PerlMagick interface for handling logo creation?  I'll walk you through a quick example, plus describe a few of the required attributes and their effects on the resulting animation.  

Compiling ImageMagick and PerlMagick

If you can install from a package, do it.  Whomever has created the package has done some homework on setting it up properly for the specific operating system.  However, it may become apparent that a package is not available.  If this is the case, the procedure is simple and straight forward, and you don't need to be a programmer to do it.  Here's how :

First, download the source code (from  Save this to the computer you wish to install ImageMagick on.  You will need to uncompress the file and open all of the source code, and change into the newly created directory.  This is done with the following commands (in bold) :
    [/tmp] $ tar -xzf ImageMagick-5.5.7-15.tar.gz
    [/tmp] $ cd ImageMagick-5.5.7
One of the pitfalls of compiling ImageMagick and PerlMagick is in the unification of the two packages.  When you download (from the source code for ImageMagick, it includes the PerlMagick code as well.  But, in order to compile and install the Perl::Magick (the perl library name), the ImageMagick libraries must already be installed.  This can be done by configuring the entire package without PerlMagick, compiling and installing, and then re-configuring the entire package with PerlMagick.  Then you just have to compile the PerlMagick code and install that.  For example :
    [/tmp/ImageMagick-5.5.7] $ ./configure --without-perl --without-x \
    configuring ImageMagick 5.5.7
    checking build system type... i686-pc-linux-gnu
    [... lots more output ...]
    LIBS     = -ltiff -lfreetype -ljpeg -lpng -lbz2 -lz -lpthread -lm
    [/tmp/ImageMagick-5.5.7] $ make && make install
    Making all in coders
    make[1]: Entering directory `/tmp/ImageMagick/ImageMagick-5.5.7/coders'
    if /bin/sh ../libtool --silent --mode=compile gcc -DHAVE_CONFIG_H -I../ -I. -I. -I../magick
    -I.. -I.. -I../magick -I/usr/include/freetype2 -D_FILE_OFFSET_BITS=64 -D_REENTRANT -g -O2
    -Wall -MT art.lo -MD -MP -MF ".deps/art.Tpo" -c -o art.lo art.c; \
    then mv -f ".deps/art.Tpo" ".deps/art.Plo"; else rm -f ".deps/art.Tpo"; exit 1; fi
    [... lots more output ...]
    /usr/bin/install -c -m 644 QuickStart.txt /usr/local/share/ImageMagick-5.5.7/QuickStart.txt
    make[2]: Leaving directory `/tmp/ImageMagick/ImageMagick-5.5.7'
    make[1]: Leaving directory `/tmp/ImageMagick/ImageMagick-5.5.7'
    [/tmp/ImageMagick-5.5.7] $ ./configure --with-perl --without-x \
    checking build system type... i686-pc-linux-gnu
    [... lots more output ...]
    LIBS     = -ltiff -lfreetype -ljpeg -lpng -lbz2 -lz -lpthread -lm
    [/tmp/ImageMagick-5.5.7] $ cd PerlMagick
    [/tmp/ImageMagick-5.5.7/PerlMagick] $ perl Makefile.PL
    Checking if your kit is complete...
    Looks good
    Writing Makefile for Image::Magick
    [/tmp/ImageMagick-5.5.7/PerlMagick] $ make && make install 
    cp blib/lib/Image/
    AutoSplitting blib/lib/Image/ (blib/lib/auto/Image/Magick)
    [... lots more output ...]
    Writing /usr/lib/perl5/site_perl/5.6.1/i386-linux/auto/Image/Magick/.packlist
    Appending installation info to /usr/lib/perl5/5.6.1/i386-linux/perllocal.pod
Now, we'd better take a more in depth look at the configure commands.  You will note that we specified a --with-windows-font-dir=/usr/share/fonts/defaults/TrueType and a --without-x.  These two configure options are vital to both using TrueType fonts and also running on a machine that does not have XWindows installed (typically servers).

First, we configure the software to not use the PerlMagick stuff, by specifying the --without-perl configure option.  Then, we run the make command (in BSD, gmake may be a better option), and then make install.  The make install command still uses the make command to copy the libraries into the proper places.

Then, we reconfigure the software to use PerlMagick, by replacing the --without-perl with the --with-perl.  Once reconfigured (this resets the PerlMagick stuff up), we step into the PerlMagick directory, and create the new make file.  This is done by executing a perl script located in that directory, called Makefile.PL, and then run the make and make install commands again.  This installs the proper Perl::Magick libraries for perl into their proper places so that we can use them.

Command-Line Tools

When it comes to command line tools, it really depends on what you need to do, as to which tool.  The list is :
    animate Assembling images into an animation.
    composite Merging images.
    conjure The Magick scripting language (MSL) will primarily benefit those that want to accomplish custom image processing tasks but do not wish to program, or those that do not have access to a Perl interpreter or a compiler.  The interpreter is called conjure.
    convert Converting images from one format to another.
    display Display the image(s) on the XWindows display.
    identify This command is used to determine image characteristics, from format, to palette/RGB colorspace.
    import This tool reads an image from any visible window on an X server and outputs it as an image file. You can capture a single window, the entire screen, or any rectangular portion of the screen.
    mogrify Mogrify  transforms  an image or a sequence of images. These transforms include image scaling, image rotation, color reduction, and others. Each transmogrified image overwrites the corresponding original  image, unless an option such as -format causes the output filename to be different from the input filename.  Make changes to the image, such as blurs, sharpens, etc.
    montage montage  creates  a composite image by combining several separate images. The images are tiled on the composite image with the name of the image optionally appearing just below the individual tile.
Examples of calling the functions can be obtained by typing "man {functionname}", such as man convert.  Still, if you need to create a JPG thumbnail of an image that is 100 by 100 pixels, or change from an MIFF (Magick Image File Format) to a Sun Raster format :
    [/tmp] $ convert -size 120x120 filename.jpg -resize 120x120 +profile "*" filename-thumbnail.jpg
    [/tmp] $ convert cockatoo.miff sun:cockatoo.ras


As a brief introduction to using PerlMagick, you should be familiar with perl in general, and using the object oriented methods associated with perl.  As with each perl program, we must specify the introductory line :
Then, we ensure that the module objects are there :
    use Image::Magick;
Simply, we just declare a new Image::Magick object.  This can be done in two forms.  I will show you both forms, but suggest the latter one, just in case you have implemented a new function :
    my $imgs = new Image::Magick;
    my $imgs = Image::Magick->new();
Now, the most commonly functions are Set(), Get(), Read(), and Write().  These functions are used to read and write images, and also to retrieve and set attributes of images in memory.  These functions are usually written as associated with our image object :
    $imgs->Set(variable name=>variable value);
Now, we can get into the nitty gritty of handling images.

File Reading and Writing

To read an image from a disk, or to write one is simple.  but, rather than delving deep into the system calls implemented by the functions, we just simply need to understand what we do.  Now, we can read in multiple images, and this will create an array object, or it's also used in creating animations, but we'll discuss that later on.  In the mean time, a simple "multi-image" read statement is just passed an array of images to read.  The two examples are (one single image, and one multi-image) :
Writing is similar, except in cases of multiple images.  A multi-image write call must either specify the image to write, or it will write the entire image as an animation.  For example :
The first example is for writing a standard image to a file, and the second example is for writing a single image in a multi-image to a file.

But, how does writing to a browser work in terms of CGI?  Here's where it gets tricky.  When a browser makes a request, the browser expects to see HEADERS back from the webserver that is running the CGI.  At least one header is required, and that is Content-Type.  In addition, the file streams work a bit differently, because we can't write to "a file", per se.  So, we print the Content-Type header, and a blank line so the browser knows that we're done printing headers, and then print the image.  We put the output stream into binary mode before writing the image, just so we get the proper image.  It works like this :
    use Image::Magick;
    my $imgs = Image::Magick->new();
    print "Content-Type: image/gif\n\n";
    binmode STDOUT;
The above script should read in the image, write the proper content type to the web browser, then convert the output stream to binary mode.  After converting the output stream, we dump the image that we've read.  This example would be better served to be rewritten using basic perl commands, but it will act as a starting point for you to read and write images.

Now, if you've got the image saved with a .jpg extension, but it's really just a .gif file, you can add a format specifier to the filename by preceding the filename with the format and a colon.  For example :
This works for both the Read() and the Write() functions, which means you can also change formats for the image (converting from .jpg to .gif).

Creating Images from Scratch

Creating images from scratch is complex in thought, yet simple in implementation.  Rather than creating the image object, resizing the image, and filling a square with a color (still works), one could simply use the read command.  If you use the read command, and read a file format of type "xc" followed by a filename that is equivelent to the X color, i.e. :
Prior to calling this read command, you might want to resize the image to how big you want it.  This is done with the Set() function call, using a variable name of "size" and a value of "{width}x{height}".  For example, creating a new image that is 60 pixels by 30 pixels with a blue color :

Drawing Primitives

Drawing primitives isn't discussed very often at all.  This is not because it can't be done, but because there is no real reason to do so, as most primitives can be created with other software.  In other words, if you are really just trying to create a chart system, you might be better off using the GD package or GIFGraph.  Still, there are instances where you want to do this.  I've run across a couple of situations where having two libraries just isn't a good idea.  So, I've used PerlMagick to implement the "primitives".  The basic core of drawing primitives is the Draw() function.  This function requires at least two parameters, a "primitive" and a "points".  The value of the primitive variable is the type of primitive being drawn.  For example, to draw a red rectangle, one would use the command :
    $mage->Draw(fill=>'red', primitive=>'rectangle', points=>'20,20 100,100');
The points value depends on the primitive you are trying to draw.  The following guidelines apply :
    PrimitivePoints Format
    arc{x-center},{y-center} {x-endpoint-1},{y-endpoint-1} {x-endpoint-2},{y-endpoint-2}"
    bezier{x-end-1},{y-end-1}, {x-end-2},{y-end-2}[, {x-end-n},{y-end-n}]
    ellipse{x-center},{y-center} {x-radius-1},{y-radius-1} {x-radius-2},{y-radius-2}
    line{x-start},{y-start} {x-end},{y-end}
    path*too complex for writing
    polygon{x-corner-1},{y-corner-1} {x-corner-2},{y-corner-2}
    polyline{x-endpoint-1},{y-endpoint-1} {x-endpoint-2},{y-endpoint-2} [{x-endpoint-3},{y-endpoint-3}]
    rectangle{x-upper-left},{y-upper-left} {x-lower-right},{y-lower-right}
    text{x},{y} "{what text}"
The primitives are relatively straight forward.  For example, to create a circle, we'd use the following command :
    $imgs->Draw(stroke=>'blue', primitive=>'circle', points=>'20,20 15,15');

Writing on the Image

There are actually two different methods that we can use to write on an image.  First, we can use the primitive function.  The problem with doing the primitive function is we get only one font, and it is very basic.  We can also make a call to the Annotate() function.  First, the primitive :
    $imgs->Draw(primitive=>'text',points=>'15,15 "awesome"',stroke=>green);
will give us a green "awesome".  Note the font and it's quality.  Very poor.  So, we'll opt to use the Annotate function in the following way :
    $imgs->Annotate(font=>'cour.ttf', pointsize=>40, fill=>'green', text=>"awesome");
If you have the Courier TrueType font available, you will get "awesome" in green, but done in a 40 point size, plus using the Courier font.  You can specify locations using the x and y variables, and also add a "gravity" variable.  Gravity means that the text will be centered on the x,y position, or southwest, or northeast, or right, etc.  This means you can create right justified text by specifying the upper left hand corner, and using a southwest gravity :
Play around with the settings, and you'll find a rather potent arsenal of font and image writing capabilities.

Adding Transparency

Transparency is a nice effect when it comes to different formats.  Of particular note is Internet graphics and transparencies, where the choices become very limited.  For example, PNG (Portable Network Graphics) are displayed by most browsers, but some browsers (e.g. Internet Explorer) just won't display any transparency at all - just white color.  GIF (Graphic Interchange Format) uses a "solid" transparency, which means no semi-transparent colors.  That drop-shadow fade you are trying to accomplish just won't work very well over the Internet.  However, most current browsers DO support the PNG format, so if you don't mind requiring visitors to have the lastest, go with PNG (animations are not supported with PNG, either).

Here, though, since we are ultimately creating a logo, we'll be doing so with GIF, because we want it to be animated.  So, with a GIF format, we first ensure that the colorspace is for transparency.  Once we've gotten the proper colorspace, we'll then set which "color" we want to be transparent.
In the above to images, we've got a single picture (the one in black), that we're going to convert to have a transparent background.  To accomplish this, we'd use the following code :
The result is the image on the right, or the one with a transparent background.  Simple, and straight forward.  Now, with GIF's, we really don't need to set the colorspace prior to the Transparent() command, but just do it anyway to ensure the habits of proper handling so you don't shoot yourself in the foot down the road.

Creating Animations

Remember the good old days when we'd sit in elementary school with a notebook, and draw the stick figures on each page?  Then we'd flip through the pages, and it gave the appearance of true motion?  Well, that's what we need to do.  We get all of the images together, and then combine them into a series of pages, each one being called a "frame".

Animated logo's have become a novelty that is often either overdone, or done too simply.  But, what is the process that is used?  I've actually used a few different methods for creating nice 3 dimensional logo's, but the one I prefer is this :
  1. Ray-trace a 3 dimensional definition into a series of images.
  2. Assemble each "frame" into one big sequence of frames, using ImageMagick
  3. Set any transparency properties, again using ImageMagick
  4. Write the image out
This gives some very nice effects (such as my sharktooth logo, or the firebird logo).  I name the images sequentially (such as firebird-00.gif, firebird-01.gif, etc.), then call a script.  This script creates the ImageMagick object, reads in the images in alphabetical order, sets the transparency, and then writes it out.  Since we've already discussed how to set transparency, this becomes easier.  I'll walk you through the details of what the commands do after showing the script snippets :
    my $imgs = Image::Magick->new();
    # the animation stuff
    #set the animation characteristics
    # write the animation out
Now, for the description.  First, we Read() an array of images (my example has the filenames provided on the commandline and sorts them into ascending order).  This will turn the $imgs object into an array reference rather than a single object.  We then make adjustments by Set()-ting the delay (in miliseconds) between frames, set an endless loop (if non-zero, the animation will loop that many times and then stop), and the refresh (termed as dispose) method between frames, and Write() it out.  So, according to the above example, we'll end up with an endless loop, with 1/100th of a second between each picture.  The result is seen to your left.

There are actually four different dispose methods.  The first (0), is for NO refresh method.  The second (1) is for repainting the background, and the third (2) refreshes from the previous frame.  Did I say there were four disposal methods?  Yes, I did.  The fourth (3) is a valid option, but is really an undefined action - in other words, don't use this one.


We've covered some rather basic things, but also covered some fairly complex thoughts.  As you've seen, the ImageMagick suite of image manipulation software is both easy to use and powerful in it's functionality.  We've talked a little of command-line tools, and gotten heavily into perl scripting with the ImageMagick library.

It is an obvious choice as to a good software suite to use in scripting or dynamic images, as the possibilities are endless.  Play around with the scripts or tools, and explore the world of image manipulation.