Android SDK – $25 and an hour later January 1, 2010 1 Comment


If you’ve ever had an inkling to get into mobile software development, now is your time. Google has drastically narrowed the gap for wanna-be mobile developers to get into this arena with their opensource and free Android SDK (Software Development Kit). Exciting new phones such as the, HTC “Google Phone”, Motorola Droid, Motorola Cliq and MyTouch are making a splash and diverting attention away from the all-consuming iPhone market.

Android does have a bit of an identity crisis going on, no doubt because of the openness of the platform and the freedom it provides to developers hoping to capitalize on it. The marketing buzz surrounding different phones and software like Droid, MyTouch, G1, Google Phone, MOTOBLUR, Android, etc. seem to have a lot of people disoriented and on the surface, it is a bit confusing. All of these products are really only variously branded versions of a base Android OS running on a phone with some custom apps pre-installed. Android apps that you write will generally work on all of these. Here’s a breakdown:

Common Name Platform OS
Verizon Droid Motorola phone with some custom apps Android 2.0/2.1
Google Phone HTC Hero phone with some Google apps Android 2.0/2.1
T-Mobile MyTouch 3G HTC phone with some Google apps Android 1.5/1.6
T-Mobile Cliq Motorola M200 with some Motorola “MOTOBLUR” apps Android 1.5/1.6


Motorola has written “MOTOBLUR” as an application layer for Android 1.5/1.6 on the Cliq that allows corporate Exchange sync and other stuff that lets you consolidate your different accounts from Facebook, etc. Droid is a more generic version of Android 2.0 which has Exchange syncing built-in along with built-in apps for integration to Google services. It seems likely that Motorola will upgrade “MOTOBLUR” to be Android 2.0 and sideline MOTOBLUR in the future as there is a bit of overlap between what Android 2.0 and MOTOBLUR try to accomplish.

The Android SDK is available for free to download and so is Eclipse and Java. The Android OS is based on a Linux kernel and the Android GUI and API are written in Java. You can get the development environment running under MacOS X, Windows and Linux and the included documentation is excellent. Java is what enables the Android application packages (.apk files) to be installed on any architecture phone. A comprehensive development environment built on top of Eclipse allows you to visually draw the layout for your Android app, then fill in the blanks with a mix of more Java and XML. A variety of libraries built into the Android API such as Apache HTTP libs make interacting with web-based services over cell networks very easy. Also unlike Apple, a complete “service” infrastructure allows you to write daemons/services that run in the background with ease. Android incorporates the lightweight opensource database system SQLite to deal with local data storage and includes a basic library much like a registry for storing application preferences and restoring previous states of apps.

public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);	   	   
  TextView tv = new TextView(this);
 
  tv.setText("sun3.org says hello!");
  setContentView(tv);
 
  // Start my custom service, if it is not running already
  startService(new Intent(this, AndroidConnectService.class));
  }

Within the SDK, you first need to become familiar with the terminology. For example, the GUI that you write is called an “Activity”, “Intents” are actions along with data (calls to activities/services) and the presentation/screen is a “Layout”, etc. Once you get familiar with the basic terminology of the Android SDK and poke around a little, a design philosophy in Android emerges regarding the sharing of access to your interfaces and services. The entire platform is designed to be very modular and to allow other developers to use your Activities and Services.

You don’t even need an Android phone to start your development, as the SDK comes with a complete emulator that lets you test your apps without the pain of installing your software on actual Android hardware every time you make a change. Incidentally, this is also a great way to test-drive Android without buying a phone or borrowing your friend’s phone.

Once you are ready to test out your app on a real phone, you’ll find that the Android OS allows you to download and install your .apk file directly from a web URL. Unlike Apple, the philosophy around Android app development is one of un-restricted access. Apple has a more restrictive App Store, and hackers need to “jail break” their phones before they can install non Apple-approved apps. Apple is only making it harder to jail break their phones. Presumably, Apple is trying to save people from themselves and their own distaste. Google has a different philosophy for Android, whereby they make the SDK components, the OS and source for the whole platform freely available and open to tinkering. It’s surprisingly easy to get an app working, tested and installed on your off-the-shelf Android phone. I had their included “helloworld” example running within about an hour, including downloading the SDK/Java JRE, poking around, compiling, testing on their emulator and installing on my regular phone.

So now you’re wondering where the $25 dollars comes in? The Android Marketplace asks $25 for you to become an official developer. This includes the ability to both upload and sell applications in the official Android Marketplace, which is akin to the Apple AppStore. Unlike Apple, there is little to no review (read “censoring”) of the apps that you sell at the Google Android Marketplace. The $25 is just to keep the spammers away. So, what are you waiting for? =)

praux.com API October 28, 2009 1 Comment

praux.com
If you havn’t seen praux.com’s fancy API, you should definitely have a look. Here’s an interface I put together that uses the API to display praux-hosted resumes on your own site. Praux is a new site that allows you to assemble, maintain and share your resume with others. The REST design and personal URLs at Praux allow you to reference, export and display your resume in many different ways. Here’s some code that uses the YAML feed of your praux.com resume, to render it on your own site. You will need the spyc YAML parser to use the below script. Have fun!

<?
require_once("spyc.php");
$data = file_get_contents("http://your.url.praux.com/yaml/");
 
$resume = spyc_load_file($data);
 
echo "<b>" . $resume[name] . "</b><br>";
echo "<b>" . $resume[email] . "</b><br>";
echo "<b>" . $resume[phone] . "</b><br><br>";
 
$sections = $resume[sections];
 
function recurse_child($child,$level=0,$lastout=false,$subsection=0) {
    $level++;   
    if ($lastout==false) {
        $level--;
        }
    if (is_array($child)) {
        foreach ($child as $itemid => $item) {
            if (is_array($item[content_items]))  {
                if ($item[content_items][0][body]) {
                    echo "<span style='display:inline;position:relative;left:120px;'>";
                    echo str_repeat("&nbsp;",$level*8);
                    echo "</span>";
                    echo "<div style='display:inline;position:relative;left:135px;'>";
                    echo "<span style='position:absolute;left:-15px;font-size:1.0em;'>";
                    echo "&bull;";
                    echo "</span>";
                    echo trim($item[content_items][0][body]);
                    echo "</div>";
                    echo "<br>\n";
                    $lastout=true;
                    }
                if ($item[content_items][0][date_range]) {
                    if ($subsection > 0) {
                        echo "<br>";                
                        }
                    $subsection++;
 
                    echo $item[content_items][0][date_range] . " &nbsp;&nbsp;&nbsp;";
                    echo "<span style='position:absolute;left:120px;'>";
                    if ($item[content_items][0][organization]) {
                        echo "<b><i>" . $item[content_items][0][organization] . "</i></b>, ";
                        }
                    else {
                        echo "<b><i>" . $item[content_items][0][title] . "</i></b>, ";                
                        }                
                    echo $item[content_items][0][locality];
                    echo "</span><br>";
                    echo "<span style='position:absolute;left:120px;'>";
                    echo $item[content_items][0][title];
                    echo "</span><br>";
                    }            
                if (is_array($item[children]))
                    {
                    recurse_child($item[children],$level,$lastout,$subsection);
                    }
                }
            }
        }    
    }
 
echo "<div style='position:absolute;width:600px;'>";
foreach ($resume[sections] as $sectionid => $section) {
    foreach ($section[content_blocks] as $blockid => $block) {
        echo "<span style='font-size:1.5em;'>" . $block[content_items][0][body] . "</span>";
        echo "<span style='position:relative;'><hr></span><br>\n";
            foreach ($block as $childid => $child) {
            recurse_child($child);
            }
        echo "<br>";
        }
    }
echo "</div>";
 
?>

Ubuntu (Dapper) on the PC Engines Alix 3D1 October 25, 2009 5 Comments

alix-3D1
The Alix 3D1 is a small PC with an LX700 AMD Geode cpu. It costs $75 USD and can, with enough patience, run just about any mainstream Linux OS that you can think of. That is thanks to the AMD Geode processor, which is i386/x86 compatible, so you won’t need any special ARM distributions or the like to get the thing going.

This is a tutorial on installing specifically the Ubuntu Dapper distro on the Alix 3D1 with the help of a Windows PC. 

For some reason mainstream Ubuntu installs after Dapper have issues completing the installation procedure and will likely cause problem for you. If you are able to install something released after Dapper, please let me know!

Where to buy an Alix 3D1

First of all, I’ll post some info about where to get the Alix 3D1. It is made by a company called PC Engines and there are 3 different versions of the board. The cheapest is the 3D1 ($75).

This tutorial also should apply to the 3D2 model. The 3D3 model has an Award BIOS and a VGA port, so things might be a little different with that one (and likely easier). Available distributors:

What you need to get with the Alix 3D1

The 3D1 comes in a cardboard box with nothing but the motherboard and some anti-static packaging, so you’re going to need to order a few accessories with it too:

  • A power supply
  • An enclosure. You can’t go wrong with the metal waterproof one, it’s very nice.
  • If you’re planning on doing 802.11, you’ll want the type-N coaxial pigtails for any NICs you are adding to the 3D1’s 2 miniPCI slots.
  • A Compact Flash (CF) card preferably about 4GB or larger

Total cost for the Alix 3D1, power supply, waterproof closure with mounts and 2 type-N 802.11 pigtails was only $146.90 USD.

Accessing the Serial Console

putty
First thing you will need to do is to get access to the console on the 3D1. I’m using Windows, so the best terminal program out there (AFAIK) is PuTTY. You can download PuTTY from:

After you have PuTTY installed, you will need a serial cable with a null-modem adapter. Connect the serial cable with null-modem to the 3D1 to your Windows PC and start up PuTTY. Select ‘Serial’ for connection type and put the baud rate at 38400 and type in the COM port (COM[1-X]). 38400 is the default baud rate of the 3D1.

PC Engines ALIX.3 v0.99
640 KB Base Memory
130048 KB Extended Memory
 
01F0 Master 848A SAMSUNG CF/ATA
Phys C/H/S 992/16/32 Log C/H/S 992/16/32

Booting Ubuntu (Dapper) via PXE

ubuntulittleThe best way I’ve found to load a Linux distro on the box is to use the built-in PXE boot functionality of the BIOS. When the BIOS on the 3D1 boots, it does a DHCP broadcast to find any available PXE boot servers out there. You don’t have to worry about other DHCP servers on your network responding unless they are especially setup to do PXE. PXE uses your specialized DHCP server + TFTP (setup below) to bootstrap the device. If everything is setup correctly below, your DHCP server responds and provides an image for the device to download and run (bootstrap). After the image is downloaded and executed, then the fun begins.

This seems like a lot of stuff to get configured to do this, but luckily, there is some software that makes this pretty straight foward. The best utility I’ve found to do this a Windows program called TFTPD32:

You will first need to prepare a directory on your Windows PC for the TFTP server to serve out a kernel and a boot image. Create a directory on your windows machine for the files. I called mine C:\tftpd.

Downloading and preparing Ubuntu Dapper netboot.tar.gz

Download the following package to your C:\tftpd directory:

tftp-settingsYou will need a program to unzip .gz and extrat .tar files. A great one for Windows is 7-Zip, which is available here:

After the archive is in the directory, extract the .gz, then the .tar underneath the c:\tftpd directory. After this is done, you’re ready to prepare your TFTP and DHCP servers.

Setting up TFTPD32

You will need to setup your TFTPD32 application as follows. You are going to need to enable ‘PXE Compatibility‘ as well as make sure that DHCP and TFTPD servers are enabled. Also, be sure to set the path correctly for your ‘base directory‘ as shown, as well as setup your new DHCP server to give normal addresses on your network. The DHCP server that you setup here will serve up the correct boot image when an address is given out to the 3D1. There is an area to to input what image you want to provide to new DHCP hosts. In this textbox under the DHCP tab of TFTPD32, enter ‘pxelinux.0‘. Make sure that your default gateway, actual DNS server, subnet and IP ranges all make sense in the configuration. If you have problems getting PXE booting to work, be sure to look at your logs tabs. They are invaluable for debugging what is wrong.
tftp6

Starting up the Alix 3D1!

When you first startup the 3D1, you are going to need to modify the BIOS config to allow PXE booting. To do this, type ‘S’ when the 3D1 is testing memory. This should bring up a menu of options. To toggle PXE booting, type ‘N’, then save the configuration to the BIOS.

PC Engines ALIX.3 v0.99
640 KB Base Memory
130048 KB Extended Memory
 
01F0 Master 848A SAMSUNG CF/ATA
Phys C/H/S 992/16/32 Log C/H/S 992/16/32
 
BIOS setup:
 
(9) 9600 baud (2) 19200 baud *3* 38400 baud (5) 57600 baud (1) 115200 baud
*C* CHS mode (L) LBA mode (W) HDD wait (V) HDD slave (U) UDMA enable
(M) MFGPT workaround
(P) late PCI init
*R* Serial console enable
*E* PXE boot enable
(X) Xmodem upload
(Q) Quit
 
Save changes Y/N ?
Writing setup to flash...

When the 3D1 boots back up it, should start checking for a DHCP server, see the TFTPD services you have running, grab an available IP address from your DHCP server and start to load the kernel.

PC Engines ALIX.3 v0.99
640 KB Base Memory
130048 KB Extended Memory
 
01F0 Master 848A SAMSUNG CF/ATA
Phys C/H/S 992/16/32 Log C/H/S 992/16/32
 
Intel UNDI, PXE-2.0 (build 082)
Copyright (C) 1997,1998,1999  Intel Corporation
VIA Rhine III Management Adapter v2.43 (2005/12/15)
 
CLIENT MAC ADDR: 00 0D B9 13 CD 7C
CLIENT IP: 192.169.0.20  MASK: 255.255.255.0  DHCP IP: 192.169.0.250
GATEWAY IP: 192.169.0.1

Monitoring the TFTPD32 Logs

You should now see some activity in the TFTPD32 logs. The following would be a good sign:

Read request for file <pxelinux.cfg/default>. Mode octet [25/10 17:20:35.078]
OACK: <tsize=1821,> [25/10 17:20:35.078]
Using local port 2360 [25/10 17:20:35.078]
<pxelinux.cfg\default>: sent 4 blks, 1821 bytes in 0 s. 0 blk resent [25/10 17:20:35.140]
Connection received from 192.169.0.20 on port 57099 [25/10 17:20:35.140]
Read request for file <ubuntu-installer/i386/boot-screens/boot.txt>. Mode octet [25/10 17:20:35.140]
OACK: <tsize=301,> [25/10 17:20:35.156]
Using local port 2361 [25/10 17:20:35.156]
Connection received from 192.169.0.20 on port 57100 [25/10 17:20:35.234]
<ubuntu-installer\i386\boot-screens\boot.txt>: sent 1 blk, 301 bytes in 0 s. 0 blk resent [25/10 17:20:35.234]
Read request for file <ubuntu-installer/i386/boot-screens/splash.rle>. Mode octet [25/10 17:20:35.250]
OACK: <tsize=8023,> [25/10 17:20:35.250]
Using local port 2362 [25/10 17:20:35.250]
TIMEOUT waiting for Ack block #0  [25/10 17:20:50.343]

Ok, here’s the tricky part

Ubuntu will by default try and send the console output to a VGA source. Since there is not a VGA source on the 3D1, you are going to have to do tell it to send the console to the serial port. Problem is, you cannot see that it is currently at a boot prompt asking you what to do. In the TFTPD server logs, you should be able to see that it has grabbed the pxelinux.0 file and is waiting on something. This is your queue!. Type into PuTTY the following (you will not be able to see the output of your typing):

linux console=ttyS0,38400

..and hit Enter.
ubuntu
Within about 10 seconds, you should see the console outputting to your PuTTY window and the kernel booting. Your 3C1 should now have a valid IP, Netmask, router and DNS server configuration and it should continue to install Ubuntu from the Ubuntu network archives server. The rest is a piece of cake!

Credits

The following site(s) were very helpful in creating this tutorial

GroupWise 6.5 to Zimbra AddressBook August 22, 2009 No Comments

Here is some code to translate a GroupWise 6.5 address book into a format that Zimbra can understand.

nab2zimbra.php

<?php
function get_value_by_mapi($zimbraid, $nabid,$nabvalues,$nabfields)
    {
    if ($nabid == "")
        {
        return  "";
        }
    for ($i=0;$i<sizeof($nabfields);$i++)
        {
        if ($nabfields[$i][mapitag] == $nabid)
            {
            return $nabvalues[$i];
            }
        }
    }
 
if (count($argv) < 2)
    {
    echo "Usage: php nab2zimbra.php <input_file.nab> \n";
    }
else
    {
    $inputfile = trim($argv[1]);
    if (file_exists($inputfile))
        {
        $row = 1;
        $handle = fopen($inputfile, "r");
 
        /* 
        :::TAGMAP:::0FFE0003:***,
        3001001E:Name,
        3A08001E:Office Phone Number,
        3A18001E:Department,
        3A23001E:Fax Number,
        3003001E:E-Mail Address,
        3A06001E:First Name,
        3A11001E:Last Name,
        3A17001E:Title,
        3A29001E:Address,
        3A27001E:City,
        3A28001E:State,
        3A26001E:Country,
        3A2A001E:ZIP Code,
        3002001E:E-Mail Type,
        3A19001E:Mailstop,
        3A09001E:Home Phone Number,
        3A1C001E:Cellular Phone Number,
        3A21001E:Pager Number,
        3A1A001E:Phone Number,
        600B001E:Greeting,
        600F001E:Owner,
        3A16001E:Organization,
        3004001E:Comments,
        3A00001E:User ID,
        6604001E:Domain,
        6609001E:Additional Routing,
        6605001E:Post Office,
        6603001E:GUID,
        6607001E:eDirectory Distinguished Name,
        6608001E:Network ID,
        660D001E:Internet Domain,
        660E001E:AIM/IM Screen Name,
        3A45001E:Prefix,
        3A44001E:Middle Name,
        3A05001E:Generation,
        3A5D001E:Home Address,
        3A59001E:Home City,
        3A5C001E:Home State,
        3A5B001E:Home ZIP,
        3A5A001E:Home Country,
        3A50001E:Personal Web Site,
        3A51001E:Office Web Site,
        6612001E:Resource Type,
        6615001E:Primary Contact Name
        */        
 
        // First go through the input file and load an associative array with mapped MAPI tags        
 
 
 
        $fields = array();
 
        while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
            {
            if ($row==1)
                {
                $num = count($data);
                $row++;
                // This should be the header line
                $fieldmap = array();
                for ($c=0; $c < $num; $c++) 
                    {
                    $thismapitag = "";
                    $exploded = explode(":",$data[$c]);
                    $thismapitag = $exploded[0];                     
                    $fieldmap[$c][value] = $exploded[1];
                    $fieldmap[$c][mapitag] = $thismapitag;
                    }
                }
            else
                {                
                $num = count($data);
                $row++;
                for ($c=0; $c < $num; $c++) 
                    {
                    // Zimbra mapping
                    /*
                    birthday	
                    company	= 3A16001E
                    department = 3A18001E
                    dlist	
                    email	= 3003001E
                    email2	
                    email3	
                    fileAs = 1,2,3	
                    firstName	= 3A06001E
                    fullName = 3001001E
                    homeCity = 3A59001E
                    homeCountry	= 3A5A001E
                    homeFax	= 
                    homePhone	= 3A09001E
                    homePhone2	
                    homePostalCode = 3A5B001E
                    homeState	= 3A5C001E
                    homeStreet = 3A5D001E
                    homeURL	= 3A50001E
                    initials	
                    jobTitle = 3A17001E
                    lastName = 3A11001E
                    middleName = 3A44001E
                    mobilePhone	= 3A1C001E
                    nickname	
                    notes	= 3004001E
                    pager	= 3A21001E
                    type	
                    workCity = 3A27001E
                    workFax	= 3A23001E
                    workPhone	= 3A08001E
                    workPhone2	
                    workPostalCode = 3A2A001E	
                    workState	= 3A28001E
                    workStreet = 3A29001E
                    workURL = 3A51001E
                    */
                    $fields[$row][$c] = $data[$c];
                    }
                }
            }
        fclose($handle);
 
        // Ok, now build the header row:
        $zimbraheader = array("birthday","company","department","dlist","email","email2","email3","fileAs","firstName",
        "fullName","homeCity","homeCountry","homeFax","homePhone","homePhone2","homePostalCode","homeState","homeStreet","homeURL","initials","jobTitle","lastName","middleName","mobilePhone",
        "nickname","notes","pager","type","workCity","workFax","workPhone","workPhone2","workPostalCode","workState","workStreet","workURL");
 
        for ($i=0;$i<sizeof($zimbraheader);$i++)
            {
            echo $zimbraheader[$i] . ",";
            }
 
        echo "\n";
 
        // Loop through all the input rows
        foreach ($fields as $key => $val)
            {
            $nabfields = $fieldmap;
            $nabvalues = $fields[$key];
 
            // Only import people objects, not company objects.
            if ($nabvalues[0] == "U")
                {
                echo get_value_by_mapi("birthday", "",$nabvalues,$nabfields) . ",";            
                echo get_value_by_mapi("company", "3A16001E",$nabvalues,$nabfields) . ",";                                                                 
                echo get_value_by_mapi("department", "3A18001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("dlist", "",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("email", "3003001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("email2", "",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("email3", "",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("fileAs", "",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("firstName", "3A06001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("fullName", "3001001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("homeCity", "3A59001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("homeCountry", "3A5A001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("homeFax", "",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("homePhone", "3A09001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("homePhone2", "",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("homePostalCode", "3A5B001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("homeState", "3A5C001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("homeStreet", "3A5D001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("homeURL", "3A50001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("initials", "",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("jobTitle", "3A17001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("lastName", "3A11001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("middleName", "3A44001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("mobilePhone", "3A1C001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("nickname", "",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("notes", "3004001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("pager", "3A21001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("type", "",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("workCity", "3A27001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("workFax", "3A23001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("workPhone", "3A08001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("workPhone2", "",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("workPostalCode", "3A2A001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("workState", "3A28001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("workStreet", "3A29001E",$nabvalues,$nabfields) . ",";
                echo get_value_by_mapi("workURL", "3A51001E",$nabvalues,$nabfields) . ",";
 
                echo "\n";
                }
            }
 
 
        }
    else
        {
        echo "Could not find input file: " . $inputfile . " \n";
        }
    }    
?>

Favorite EBay Searches January 19, 2009 No Comments

EBay is a place that lacks description. It is a staple of the Internet, and is often criticized for being a hodge-podge outlet that resembles a dollar store. However, there are treasures that can be found on EBay that extend well beyond what can be purchased at your local store. Now, I know you can probably find lots of crazy things for sale at specialized Internet stores.. But really, where else but EBay can you find 100’s of vendors selling them in an atmosphere of free market competition? Here are a few of my favorite EBay searches and some information about them.

Ancient Roman Stuff

Ancient Roman artifacts are plentiful on Ebay. The Roman empire lasted nearly 1200 years and encompassed, at its peak, nearly 2.3 million square miles of what is now the general area known as Europe. 88 million people called Rome their capital, at the peak. The peak of the Roman civilization lasted from 27 BC – AD 476, that’s a minimum 1,533 years ago. Museums are filled with the best of Roman stuff. So much so, that they rarely accept new artifacts, unless they are exceptional. What that means for you is that you can have an incredible piece of history for almost nothing. One of the common pieces of Roman history sold on EBay are ancient roman coins. These coins come in a variety of states and conditions. They are often sold “uncleaned”, which means that the people who found them (often with a metal detector in “hordes”), have not stripped the corrosion from their surface. However, you can be quite assured that they have kept any pieces that are gold or silver.

About a year ago, I got mildly curious about these coins and ordered a set of 20 or so un-cleaned Roman coins. After following the detailed directions for cleaning that came with the coins, I found about 1/4 of them cleaned reasonably well. Here is a detail of one of these coins. I have no idea who/from where the militant looking guy or lady is on the surface, but it was a lot of fun for about $10 bucks.

A Roman coin that I cleaned
unknown


Search ‘Ancient Roman’ on Ebay

Surgical Supplies

You simply cannot find some treasures at your local retail outlets, or anywhere else for that matter. This includes stuff like surgical sutures. You or someone you know has probably been in situation where you were far away from medical help and needed it quickly. Unfortunately, many medical establishments, especially those in the US figure that you are an absolute idiot and can’t tend to your own body or that of someone else, without a 10 year degree. With a little bit of You Tube training, you can easily suture an open wound and maybe save someone from disfigurement or death from loss of blood. The only problem is that you can’t buy the basic supplies needed to tie a suture, a med school 101 procedure. At least in the US, your local pharmacy doesn’t carry this stuff. But on EBay, it’s a click away.

suture

Search ’suture’ on EBay

Well, that’s it for now. I’ll be sure to be back with more EBay treasures soon =)

iCAMView Pro November 27, 2008 No Comments

If you’ve ever searched on eBay or Google for IP-based camera security things, you’ve undoubtedly seen advertisements for these little plastic USB camera servers called the iCAMView. I finally got curious about these things and ordered one off eBay. I’ll admit, they’re really impressive. One of the downfalls of many IP-based cameras and camera servers is always the software. In general, you get what you pay for in this regard. However, the iCAMView device software is excellent.

The one thing that grabbed my attention about the iCAMView is that they recently released a new version of the device called the “iCAMView Pro”, which can use higher resolution USB cameras. Image resolution is one of my pet peeves and largely why I generally choose to stay away USB-based camera servers.

iCAMViewPro

http://icamview.com/

Once I started testing the device, a few things caught my eye. First, there is an option to automatically reboot the device at a specified interval. Most manufacturers of these things have some ridiculous idea that their devices will stay running indefinitely, without rebooting. I’ve tested many IP camera devices and they universally eventually lock up or start running slow. At least the iCAMView people were humble enough to add this option.

Secondly, you can plug a USB storage device into the thing for local storage. It even manages old files and deletes them when the storage hits a user-specified limit. This is another thing they added to the software to make the device a “set it and forget it” camera server.

Third, it’s fast! I don’t know how they manage to put a full web server packed with features such as motion detection in such as small package, but it’s amazing how responsive the web interface is, even when it’s actively capturing photographs.

Fourth, it supports many wireless USB dongles and even supports WEP encryption/keys.

Overall, the device is very impressive and well worth a look. It has user upgradable firmware and I’ll soon be testing the higher resolution USB cameras with it.

Cheap Computing: The “DecTop” August 24, 2008 No Comments

Do you remember AMD’s effort to populate the world with cheap PCs? Well, AMD ultimately stopped manufacturing their “PIC” (a.k.a the Personal Internet Communicator) machine themselves, but handed the right to sell that device to Data Evolution Corporation in late 2006 who is now selling it as the “DecTop”.

pic

Data Evolution’s DecTop (Can be had is small quantity for $88 shipped)

The machine itself was designed to be an effort in the production of cheap computers. It is still very cheap at qty 1 ($99) and can be purchased directly from Data Evolution Corp online. In fact, they now are offering a “4 for 3″ deal, which brings the individual cost down to around $88 shipped if you can split the cost between friends. The shipping costs are outlandish, but it still ends up a good deal.

It features a 366MHz AMD geode processor and a full size 3.5″ hard drive. The ram is a single 128MB 200pin SO-DIMM which can be upgraded to 512MB. I had a need for 2 such minimalist machines. One for a simple SSH gateway and the other for an MP3 player. So I figured I’d give these things a try. The site doesn’t give very much information about them, but there are some good resources out there regarding this thing. One of the unfortunate things about them is that they don’t have USB 2.0 ports, which would have made them a great choice for a NAS device. Strangely, it comes with a USB ethernet adapter. You’d think that something originally called an “Internet Communicator” would at least have that built-in. It does however have a built-in modem =).

One of the ways they keep the cost down is to use commodity parts such as the upgradable 10GB 3.5″ IDE (old style) hard drive. These drives are probably bought for almost nothing and likely avoid the higher cost of SSDs, 200GB+ SATA HDs, 2.5″ laptop drives and other flash-based disk that tend to make their way into “cheap” computers nowadays. I think there is a fairly huge market for cheap, small embedded-style PCs (emphasizing cheap first). Unfortunately, the embedded PC/Linux market hasn’t really tapped this yet, as when everything is said and done, you usually will end up paying much more for small embedded machines than you would a full-sized desktop. The DecTop is a clear exception to this rule.

Some companies have seen good success selling more expensive “tinker” devices like Bug Labs, who sells a modular embedded system called the “Bug” for hobbyist geeks/dorks like myself. Still, the Bug is not nearly as cheap as the DecTop and sells for ~$350, just for the base system. It’s got the right spirit, just not the price to make it a cheap machine.

bug

Bug Labs “Bug” (retails for $350+)

A better option than the Bug for a cheap machine is the Norhtec MicroClient JrSx. This machine is a slimmed down version of its brother the MicroClient Jr. It has a slightly more substantial list of features than the DecTop and comes with a CF slot and USB 2.0. However, it does not come with a hard drive . You are expected to either install a 2.5″ IDE disk or a CF card for your OS. It does optionally come with a mini-PCI slot so that you can add on nice things like wi-fi or other controllers. The CPU is an all-in-one 486SX running at 300MHz, a bit slower than the DecTop and with slower bus speed. Nohrtec advertises 128MB of on-board ram which does not appear to be expandable. Like the DecTop, shipping is completely unreasonable @ ~$53, however the base price for the machine is only $85 ($93 with mini-PCI or HD connector), bringing the cost of this base machine to ~$138-$146 shipped, a bit more than the DecTop, but still easily in the league of cheap machines.

microclient

Nohrtec MicroClient JrSX (retails for $138 shipped)

With all these efforts at cheap machines, it seems like fast, pluggable I/O and expandable RAM seem to be lacking. All this makes me wonder if there is a perfect cheap PC? It seems as though this could be accomplished by:

  • 1 PC-on-a-chip
  • 1 1Gb Ethernet Port
  • 1 SO-DIMM slot
  • 2 USB 2.0 ports
  • 1 CF Slot
  • 1 VGA port

This is fairly close to the Nohrtec box except for the SO-DIMM slot. In fact, a base system with no ram should be cheaper. I’d bet this could be marketed and sold at a profit for around $100 or less given what I’ve seen so far. Sure, there would plenty of people who would whine about absence of HDMI, FireWire, 802.11, etc., but what do they want for $100? I think it would score big, at least with people like me =)

More on High Resolution Security Cameras June 22, 2008 No Comments

If you read my previous article on high resolution security cameras and are interested in more options, you may want to look at “Trail Cameras”. These devices are designed for hunters, something which I am not into at all, but hunting does (rather symbolically) describe what I was trying to accomplish.

These cameras are designed from the ground up to be:

  • Independent (no connections needed)
  • Provide high resolution photographs
  • Triggered by motion

As far as the manufacturers of these cameras are concerned, their customers consist of people who get excited by images of roaming “bucks” and other wildlife that may happen to pass by their trail camera. I’m not yet sure what hunters intend to do with these photographs, but some of the images captured by these trail cameras are very cool. I won’t pretend to understand the market at all, but I do understand what these devices are intended to do and it fits the application of “high resolution security” perfectly.

There are several manufacturers of these cameras (among quite a few):

I am currently playing with one made by Moultrie and have found it to be fairly reliable. The addition of an “Eye-Fi” card makes it so that the captured images can be automatically transferred to a either an online destination of your choice such as a web-based photo sharing service or your PC. I’ll be sure to update with more information soon.

Bash Shell: Find Nano or Pico May 2, 2008 No Comments

It’s amazing how little things make all the difference when doing your day-to-day sysadmin tasks. I tend to use the same .profile on lots of *NIX boxes, but have always found it frustrating to find a sane editor in different environments. My editor of choice in Nano/Pico (I’m not ashamed), but this is not always in the path. I finally got around to adding functionality in my default bash .profile that looks in different places for Nano or Pico and adds an alias to the full-path binary, sets my EDITOR and VISUAL env variables and aliases one to the other if it can find one. I’ve tested this script on Solaris, Darwin and Linux platforms. If you like Nano/Pico and are frustrated with not having a consistent editor on different machines, you may find this useful to add to your .profile.

You should just be able to cut-n-paste this into your .profile. The only thing you may need to change is the EDITOR_LOCATIONS array, to add locations to where these binaries are commonly found on different systems that you work with.

 
#######
#######
### Begin: Nano/Pico search: Look for NANO or PICO in common locations, add a full path location as an alias to both or one-of them.
###                          Also, make my environment variable EDITOR and VISUAL equal to the pico/nano binary if one exists
#######
#######
 
PROFILE_VERSION=0.1
PROFILE_STRING="[Bash Profile v$PROFILE_VERSION]"
 
NANO_LOCATION=`which nano 2>&1`
PICO_LOCATION=`which pico 2>&1`
 
NANO_LOC_FIRSTCHAR=${NANO_LOCATION:0:1}
PICO_LOC_FIRSTCHAR=${PICO_LOCATION:0:1}
 
if [[ "$NANO_LOC_FIRSTCHAR" != "/" && "$PICO_LOC_FIRSTCHAR" != "/"  ]]; then
   EDITOR_LOCATIONS=(/bin/ /var/ /usr/bin/ /usr/local/bin/ /opt/bin/ /opt/local/bin/ /sbin/)
   EDITOR_DIR=""
 
   for ((i=0;i<${#EDITOR_LOCATIONS};i++)); do
      if [ -x ${EDITOR_LOCATIONS[${i}]}/nano ]; then
         NANO_LOCATION=${EDITOR_LOCATIONS[${i}]}nano
         NANO_LOC_FIRSTCHAR=${NANO_LOCATION:0:1}
         EDITOR_DIR=${EDITOR_LOCATIONS[${i}]}
         echo "$PROFILE_STRING Found nano in ${EDITOR_DIR} !" >&2
      fi
   done
 
   for ((i=0;i<${#EDITOR_LOCATIONS};i++)); do
      if [ -x ${EDITOR_LOCATIONS[${i}]}/pico ]; then
         PICO_LOCATION=${EDITOR_LOCATIONS[${i}]}pico
         PICO_LOC_FIRSTCHAR=${PICO_LOCATION:0:1}
         EDITOR_DIR=${EDITOR_LOCATIONS[${i}]}
         echo "$PROFILE_STRING Found pico in ${EDITOR_DIR} !" >&2
      fi
   done
fi
 
if [[ "$NANO_LOC_FIRSTCHAR" != "/" && "$PICO_LOC_FIRSTCHAR" == "/"  ]]; then
   echo "$PROFILE_STRING Only pico found ($PICO_LOCATION), adding alias for nano."
        alias pico=$PICO_LOCATION
        alias nano=$PICO_LOCATION
        export EDITOR=$PICO_LOCATION
        export VISUAL=$PICO_LOCATION
fi
if [[ "$NANO_LOC_FIRSTCHAR" == "/" && "$PICO_LOC_FIRSTCHAR" != "/"  ]]; then
        echo "$PROFILE_STRING Only nano found ($NANO_LOCATION), adding alias for pico."
        alias pico=$NANO_LOCATION
        alias nano=$NANO_LOCATION
        export EDITOR=$NANO_LOCATION
        export VISUAL=$NANO_LOCATION
fi
if [[ "$NANO_LOC_FIRSTCHAR" == "/" && "$PICO_LOC_FIRSTCHAR" == "/"  ]]; then
        echo "$PROFILE_STRING Nano and Pico already in path (nano in $NANO_LOCATION; pico in $PICO_LOCATION)."
        alias pico=$NANO_LOCATION
        alias nano=$PICO_LOCATION
        export EDITOR=$NANO_LOCATION
        export VISUAL=$NANO_LOCATION
fi
if [[ "$NANO_LOC_FIRSTCHAR" != "/" && "$PICO_LOC_FIRSTCHAR" != "/"  ]]; then
        echo "Nano or pico not found. Yuck."
        export EDITOR=vi
        export VISUAL=vi
fi
 
#######
#######
### End: Nano/pico search
#######
#######

Output

[0931][rob@machine:~]$ source ./.profile
[Bash Profile v0.1] Found pico in /opt/bin/ !
[Bash Profile v0.1] Only pico found (/opt/bin/pico), adding alias for nano.
[0931][rob@machine:~]$

Zimbra on a VPS: Step-by-Step April 16, 2008 No Comments

Here is a step-by-step how-to for getting Zimbra Collaboration Suite installed on a XEN-based virtual machine/virtual private server running on Linux with limited resources. I am going to use a hosted VPS from Linode for this example. Based on the forum discussions at Zimbra.com, depending on the setup, running Zimbra on a VPS/VM can sometimes cause problems, especially with libc calls. But, this setup seems to have worked fine for me for about 5 months so far and I figured I share.

BTW: I have no relation to Zimbra/Yahoo. So, it should be noted that neither Zimbra or myself directly support Zimbra in the open source variety. In short: I hope this helps, and good luck!

Pre-Installation Checklist

 • $30
 • A few hours
 • Some familiarity with UNIX
 • A domain name, for which you have control of an ‘A’ and MX DNS record.

Step 1: Set your DNS forward records

Before getting too into the VM setup, you will need to establish a domain name to use both as your web front-end and as your mail delivery host (MX). First, modify a forward DNS record for your domain to point toward your Linode IP. This step is accomplished at the site of whoever either manages your DNS or at the DNS server that serves your domain name. This forward DNS record will become the DNS name of your Zimbra front-end. The A record can be anything you like, such as mail.mydomain.com. Create an ‘A’ DNS record for your domain to point toward the IP address of your new Linode. Then, also modify the MX record for your domain to also point toward this IP. Point your MX record toward the name you chose for the A record. I.e. A=mail.mydomain.com=[your linode ip], MX=mail.mydomain.com.

In this example, I have used the domain name ‘mail.develo.com’ for both my ‘A’ and ‘MX’ DNS records.

Step 2: Setting up your Linode

The Linode 540 seems to be sized just right for a minimum install. Once you have completed the VPS purchase, and have a login to the linode site, you should see a screen in your account called ‘dashboard’ that looks like:

empty_linode

Select a Debian 4.0 distribution, then provision your disk so that you have a 1000MB swap, and use the rest for the main root partition. Zimbra will certainly eat all of your 540MB of ram (even with scaling down) and may potentially eat up some swap space too, so it is good to have this a bit big. Next set the password that will be become your root password.

linode_debian_install

Wait for your installation to be built (a few minutes), then click ‘Boot’

linode_debian_install_after

Step 3: Set a reverse DNS pointer for your new IP

In the Linode ‘members’ area, there is a tab called ‘utilities’. Click on the reverse DNS manager and put in the host name that matches your A/MX record that you set above. The linode.com site needs to see a forward record that is pointing to your IP for this step to work, so it may take a while for your DNS changes made above to propagate and for the Linode to pick up the changes. Until the forward DNS changes are viewable by the Linode.com DNS servers, Linode will not allow you to complete this step.

linode_reverse_dns_manager

Step 4: Connect to your Linode

Now connect to your Linode IP address using an SSH client. If you do not have an SSH client, here is a good one for Windows:

http://www.chiark.greenend.org.uk/~sgtatham/putty/

Connect as user ‘root’, using the password that you specified while creating your Debian distribution.

Step 5: Change your Linode hostname

After you are connected via SSH, the first order of business will be to change the hostname to match your DNS record, here, I’m using the example domain ‘mail.develo.com’. To change your host name, simple do the 2 command below. The first writes the name of the machine to a file, the second sets the name.

li11-170:~/zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307# echo 'mail.develo.com' > /etc/hostname
li11-170:~/zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307# /etc/init.d/hostname.sh start
Setting hostname to 'mail.develo.com'...done.

Step 6: Reboot your Linode

Now, let’s reboot the Linode to verify that the hostname change is in-place at boot-up. You may need to go back to your linode.com dashboard to start your linode if it does not come back automatically.

li11-170:~/zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307# sync
li11-170:~/zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307# reboot

Step 7: Update your package sources

Update your Debian package sources with the command ‘apt-get update’

mail:~/zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307/util# apt-get update
Get:1 http://ftp.us.debian.org stable Release.gpg [378B]
Get:2 http://ftp.us.debian.org stable Release [58.2kB]
Get:3 http://security.debian.org stable/updates Release.gpg [189B]
Get:4 http://security.debian.org stable/updates Release [37.6kB]
Ign http://ftp.us.debian.org stable/main Packages/DiffIndex
Ign http://ftp.us.debian.org stable/main Sources/DiffIndex
Get:5 http://ftp.us.debian.org stable/main Packages [4280kB]
Ign http://security.debian.org stable/updates/main Packages/DiffIndex
Get:6 http://security.debian.org stable/updates/main Packages [257kB]
Get:7 http://ftp.us.debian.org stable/main Sources [1214kB]
Fetched 5848kB in 6s (959kB/s)
Reading package lists... Done
mail:~/zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307/util#

Step 8: Upgrade your packages

This command will upgrade your Linux distribution to have current versions of all libraries and programs. You may be asked to restart a few daemons such as ssh, continue with the defaults if asked.

mail:~/zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307/util# apt-get upgrade
Reading package lists... Done
Building dependency tree... Done
The following packages will be upgraded:
  bsdutils cpio debconf debconf-i18n debian-archive-keyring e2fslibs e2fsprogs findutils libblkid1 libcomerr2 libkrb53 libpam-modules
  libpam-runtime libpam0g libpcre3 libss2 libssl0.9.7 libssl0.9.8 libuuid1 lsb-base mount nano tar tzdata util-linux
25 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 10.1MB of archives.
After unpacking 1163kB disk space will be freed.
Do you want to continue [Y/n]? y
Get:1 http://ftp.us.debian.org stable/main bsdutils 1:2.12r-19etch1 [68.5kB]
Get:2 http://ftp.us.debian.org stable/main e2fslibs 1.39+1.40-WIP-2006.11.14+dfsg-2etch1 [87.2kB]
Get:3 http://security.debian.org stable/updates/main libkrb53 1.4.4-7etch5 [408kB]
...
...

Step 9: Install packages required by Zimbra

Install these packages (with libc6-xen last) using the apt-get command as follows:

mail:~# apt-get install file
...
mail:~# apt-get install sudo
...
mail:~# apt-get install fetchmail
...
mail:~# apt-get install libgmp3c2
...
mail:~# apt-get install libxml2
...
mail:~# apt-get install libexpat1
...
mail:~# apt-get install openssl
...
mail:~# apt-get install libltdl3
...
mail:~# apt-get install perl5
...
mail:~# apt-get install libc6-xen
...

Step 10: Stop the default Debian email daemon

The Debian package at Linode.com comes with a default email daemon (exim). This runs by default and will conflict with Zimbra unless disabled before installation. To disable exim, comment out the the line that starts with ’smtp’ in /etc/inetd.conf using an editor such as vi or pico (i.e.: ‘pico -w /etc/inetd.conf’).

#:MAIL: Mail, news and uucp services.
#smtp            stream  tcp     nowait  mail    /usr/sbin/exim exim -bs

Now, restart the inetd daemon by issuing the command below:

mail:~# /etc/init.d/openbsd-inetd restart
Restarting internet superserver: inetd.

Step 11: Download Zimbra to your Linode

Find the HTTP link for ‘Debian 4 x86′ version of Open Source Zimbra at: http://www.zimbra.com/community/downloads.html. Save the link location, SSH into your Linode as root and use wget to grab the distribution using the link that you copied. Then ‘gunzip’ the distribution and ‘untar’ the tarball as shown.

mail:~# wget http://files.zimbra.com/downloads/5.0.4_GA/zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307.tgz
...
...
mail:~# gunzip ./zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307.tgz
mail:~# tar -xvf ./zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307.tar
zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307/
zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307/packages/
zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307/packages/zimbra-mta_5.0.4_GA_2101.DEBIAN4.0_i386.deb
zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307/packages/zimbra-spell_5.0.4_GA_2101.DEBIAN4.0_i386.deb
...
...

Step 12: Start the installer

The Zimbra installer is very easy, but has alot of output, so I’ve only included the steps that require input:

mail:~# cd zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307
mail:~/zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307# ./install.sh
...
...
Install zimbra-ldap [Y]
Install zimbra-logger [Y]
Install zimbra-mta [Y]
Install zimbra-snmp [Y]
Install zimbra-store [Y]
Install zimbra-apache [Y]
Install zimbra-spell [Y]
Install zimbra-proxy [N]
...
...
The system will be modified.  Continue? [N] y
...
...
Address unconfigured (**) items  (? - help) 3
...
...
Select, or 'r' for previous menu [r] 4
...
Password for admin@mail.develo.com (min 6 characters): [Kj77DUf9]
...
...
Select, or 'r' for previous menu [r] r
...
...
*** CONFIGURATION COMPLETE - press 'a' to apply
Select from menu, or press 'a' to apply config (? - help) a
Save configuration data to a file? [Yes]
Save config in file: [/opt/zimbra/config.5961]
...
...
The system will be modified - continue? [No] yes
...
...
Notify Zimbra of your installation? [Yes]
...
...
Configuration complete - press return to exit
mail:~/zcs-5.0.4_GA_2101.DEBIAN4.0.20080321134307#

Step 13: Congrats!: Zimbra should now be running!

http://yourdomain.com

login

To get to the administration URL goto:

https://yourdomain.com:7071

There are tons of great people and lots of reference material here: http://www.zimbra.com/forums/

Next see: Zimbra on a VPS: Tuning to reduce the memory footprint consumed by your Zimbra install