CCCKC: Hack-o-Lanterns revisited

Since I already made my own Life Glider Hack-O-Lantern, I didn't participate, but several people brought pumpkins down to the CCCKC Hackerspace last night to carve out their geeky designs. I left before most of them were completed, but I noticed they showed up in the CCCKC flickr pool this morning. Some of these are pretty nifty! I particularly enjoyed the LED-illuminated Hack-o-Lanterns. Check out that microprocessor-driven Cylon!

There are more geeky jack-o-lanterns over at Geeks Are Sexy. Also: Some tips for hosting a Halloween party.


Twitter Lists = all the @SecurityTwits in one place!

Twitter rolled out lists to everyone today. The thing I'm most excited about is the ability to follow all of the Security Twits with a single click. I already follow quite a few of them, probably more than half, since I primarily use Twitter for security news and interacting with people of that mindset. SecurityTwits also created lists for Security Companies, Blogs & Research (of which HiR is included), Media, and Events.

HiR even has a list of our authors!

You are able to make lists to share with others, too. All of the Twitter accounts from your local 2600 group or hackerspace, your fantasy football pals, or comedy troupe, for example. Also, like SecurityTwits, there are already a bunch of public Twitter lists out there that you might be interested in following. Mashable has a good catalog of lists started.

Related: Roll your own hive-mind

Humor (kind of): Hardened OpenBSD installation

So my buddy James a.k.a. n0b0d4 a.k.a. Genesyswave who you may know best for his posts on SecurityCatalyst, decides to be funny. Or maybe he was being serious. A few hours after mentioning the OAMP post, he asked if I had a post about installing OpenBSD securely.

Well, not as such...

So, here's a walk-through:

  1. Insert CD. You can download the ISO for free.
  2. Boot from it. You might need to tweak your boot settings.
  3. Follow the prompts.
See the OpenBSD 4.6 installation article for some helpful screen shots.

Voila. You have a hardened, secure OpenBSD install. If you want a really secure installation, I recommend not enabling X11 or SSH. hah.

update: In my fanboy-induced haze, I must admit that I didn't even think to mention patching. There are already three reliability (potential DOS/Crash) fixes for OpenBSD as of writing, and it's not even been out for but a week or so. It goes without saying that no one is perfect. OpenBSD has patches, just like every other operating system.

Patching OpenBSD is not nearly as easy as it is on most popular Linux distributions, but the OpenBSD FAQ covers patching better than I could cover it here. To tell the truth, the patching process is one of my big gripes. To patch OpenBSD, go to the OpenBSD 4.6 Errata (patches) page and download the patches. Read the comments and follow the instructions. Note: you'll almost always need a full source tree to patch OpenBSD.



Earlier this week, my wife and I carved pumpkins. Lacking any semblance of artistic skill, I traced a circular object nine times onto the face of my pumpkin, carved out five holes, and ran a dremel around the other four. My wife's handiwork on the left is more aesthetically pleasing.

The Glider is one of the smallest moving self-perpetuating patterns in Conway's Game Of Life, which is a zero-player game that functions as a demonstration of cellular automation. It has a few very simple rules. In 2003, Eric S. Raymond proposed that hackers adopt the glider as their emblem. Read his Hacker Emblem FAQ to figure out why he thinks it's a good emblem. I agree with most of it, and I'm completely fascinated by Conway's Game Of Life. So this is just plain cool to me on many levels. Here's a java implementation of Life for you to tinker with.

Let's see your pumpkins!

OAMP: OpenBSD 4.6 + Chroot Apache + MySQL + PHP

I'm combining the OAMP howto with chroot from the start this time because it's really the proper and secure thing to do. You can read more about how chroot works in my last article about it, but the premise is that chrooting Apache limits the amount of damage that can be caused by vulnerabilities in web applications. Keep in mind that we'll be accessing MySQL from within the chroot in this article, so all content within MySQL is potentially at risk if you're serving up SQLi-vulnerable content. The best things the average sysadmin can do to protect the server is to keep webapps and system patches up-to-date, and to perform periodic database dumps and system-wide backups.

I will walk through the commands here without showing the output they generate. You can reference my OAMP walk-through from OpenBSD 4.4 if you want to see example output, which should look similar for OpenBSD 4.6. The output shouldn't matter much, because I'll walk you through everything here.

To start off, I make sure that a user-level admin account has access to run anything as root from sudo. Note: all the administrative commands in this post begin with "sudo" for a reason. To do this, I add my admin account to the wheel group. You can do this during the adduser process or with usermod, but if you created a non-root admin user during the OpenBSD 4.6 installation process, that user will be in the wheel group by default. All you need to do is add a sudo rule for the wheel group. It's commented out in /etc/sudoers.

$ su -
# visudo
... or use whatever editor you want on /etc/sudoers. Not recommended.

Find the line that grants access to the wheel group, and uncomment it. It's about 35-40 lines down in the default configuration. Optionally, there's a NOPASSWD version of the same, a few lines down. I don't recommend using this option on a production server, but it may make system management more friendly on your development servers and workstations.

-- or --

I also set up the path for pkg_add by adding these lines to my user-level account's .profile, then logging out and back in to reload the profile. I usually use an OpenBSD mirror, like ftp5.usa.openbsd.org instead of the main FTP site. You can also use any of the http mirrors in this path.
vi .profile

export PKG_PATH
Installing Packages
Installing php5-mysql and mysql-server will fetch all of the dependencies for OAMP. This particular version of PHP comes pre-compiled with the suhosin hardened PHP patches in place, which is a nice touch! This process may take a while depending on your connection speed. There are eight or nine packages in total, including php5-core and some perl modules that MySQL depends on for its management tools.
sudo pkg_add php5-mysql mysql-server
Next, copy the PHP + MySQL sample files into place
sudo cp /var/www/conf/modules.sample/php5.conf \

sudo cp /var/www/conf/php5.sample/mysql.ini \
Run the script to get the default MySQL database installed, start MySQL and set a MySQL root password.
sudo /usr/local/bin/mysql_install_db

sudo /usr/local/share/mysql/mysql.server start

sudo /usr/local/bin/mysqladmin \
-u root password 'your-password'
At this point, both MySQL and PHP are installed and set up with a default configuration that will probably work fine for most applications.

Chroot Setup
Most AMP packages only need somewhere to store Session information and a way to get to the MySQL socket. Since the real /tmp contains information that is not needed for Apache, we'll just create a new tmp directory specifically for Apache within /var/www and make it world-writable with the "sticky bit" set (exactly like the real /tmp)
sudo mkdir /var/www/tmp
sudo chmod 1777 /var/www/tmp
Next, reproduce the directory structure for the MySQL socket under /var/www.
sudo mkdir -p /var/www/var/run/mysql  # -p creates subdirs as needed
Start Apache and MySQL at boot
Set apache to start on boot by editing /etc/rc.conf. Find the httpd_flags line in the file, change NO to "" -- literally, two double quotes as shown below.
sudo vi /etc/rc.conf
# use -u to disable chroot, see httpd(8)
httpd_flags="-u" #disables chroot. You can if you want.
Then, make sure that MySQL starts at boot and that the real mysql.sock file gets hard linked into the new directory by editing /etc/rc.local. I also added a line to remove the old hard link before starting MySQL. The end of my /etc/rc.local looks like this:

rm /var/www/var/run/mysql/mysql.sock
/usr/local/share/mysql/mysql.server start
ln /var/run/mysql/mysql.sock /var/www/var/run/mysql/mysql.sock

After getting all of the services set up to start automatically, I usually reboot to make sure everything starts up as expected.

sudo reboot

Once the system comes back online, the most basic test of Apache and PHP is to create a phpinfo script. This can be done with one line of shell-fu, which will launch "tee" with root permissions to write the phpinfo.php file.

echo "<?php phpinfo(); ?>" | sudo tee /var/www/htdocs/phpinfo.php

Then, navigate to http://your.openbsd.ip.address/phpinfo.php in your web browser. It should load a nice-looking document containing details about PHP's configuration. In particular, check for MySQL.

To really put our fresh chrooted OAMP installation through its paces, I downloaded the latest version of Wordpress, then followed the instructions using "the famous 5-minute install", which is way beyond the scope of this article. It's as simple as creating a database, setting up a privileged user for that database, editing a configuration file and copying wordpress into /var/www/htdocs (or a subdirectory) before accessing the control panel to finish up.

The wordpress install worked without changing anything from the instructions, and it's all running under chroot without any problems!

If you find that things are not working well with a particular AMP application, check file permissions, and copy or create hard links to files or directories that are needed. Example: sometimes you need a fake /etc/password file, some tools from /usr/bin or a /dev structure to be replicated within the chroot environment. Add these only as needed.


Installing OpenBSD 4.6, Virtual machine snapshots

OpenBSD's install process changed for the first time in a very long time with the release of 4.6.

For the most part, I feel like the changes are for the better. The install script asks fewer questions, and one can almost accept all the default options without worrying about much of anything. I've already installed it on a few of my systems, but in preparation for my upcoming article on getting OpenBSD, Apache, MySQL and PHP playing together nicely in a chroot environment, I decided to install it in VirtualBox.

Here you can see a new feature towards the top of the screen shot. OpenBSD now asks if you wish to create an initial non-root user. This user will be automatically placed in the wheel group, which has certain administrative abilities in OpenBSD.

At the bottom of this screen shot you can see the partitioning setup. This is similar to the old manual disk partitioning from pre-4.6 installs. It's worth reading up on the OpenBSD installation FAQ, which has a detailed section on setting up disks. Notice that I'm doing a fresh install over OpenBSD 4.5, so the partition table is laid out in OpenBSD's "Whole Disk" mode already. Your partition table may look different.

After that, you get the disklabel, which now has an "auto" option by default for setting up the slices, similar to FreeBSD. I just pressed enter and watched as the filesystems were created.

The installation set selection changed aesthetically, but it's the same as before, there's just not one item per line anymore.

When I test things out, I like the ability to use snapshots in a virtual machine environment. This isn't a unique feature to VirtualBox. I know VMWare can do it as well. I shut down the VM and made a pristine snapshot right after installation, then I started the VM, logged in, got some things configured the way I want (sudo, bash, and PKG_PATH) and made another snapshot after shutting down one more time.

In preparing another OAMP article, snapshots are nice because as I try to get OAMP working, I usually run into snags. Snapshots enable the VM to go back to a previous state and start over from a specific point in time without doing a fresh installation.

Once I think I have the installation procedure down solid, I can revert to the base install one more time and make sure my instructions work. Obviously, virtual machine snapshots have many great uses for both desktop and server instances alike. This is a look into one way I utilize them. For servers, this is a life-saver for backing out of a change gone bad, but it's no substitute for testing changes properly before deploying them to production. Think of snapshots as bookmarks to a virtual machine's past:

One of our readers has already tried the instructions for OpenBSD 4.5 on his new OpenBSD 4.6 installation with some problems. I'll see if I can reproduce the issue and come up with instructions to work through them. Look for an OAMP Chroot article for OpenBSD 4.6 coming soon!


Giving OpenSolaris another shot

I've got Planet Solaris in my RSS reader, as you probably see some of the content from there in the semi-frequent Delicious Links RSS entries (or on the sidebar). I also follow a few of the Planet Solaris folks on twitter. As such, I read a lot about OpenSolaris.

I've tried it before, in a Parallels VM on my MacBook, but never really gave it a go of things on a decent desktop system until tonight. The system I'm using isn't wired, so I was pleased to see that OpenSolaris picked up my USB WiFi adapter and had no problems connecting to my encrypted network (although there's that network manager annoyance where you, for some reason, have to type in your network key TWICE).

I'm currently running it in Live CD mode, and it's pretty responsive. Granted, I'm running it on 2GB of RAM, so that probably helps a great deal. When I get a chance to swap out hard drives, I'll likely install it permanently to see how it goes.

Daily, I use Solaris, AIX, Windows XP, and Linux. The gnome desktop environment within OpenSolaris is familiar, with a very Ubuntu-inspired default configuration. It's certainly much different than my Solaris 10 "Java Desktop" interface at the office. The default theme is pretty slick, and doesn't make me want to search for ways to cast out the demons of angry fruit salad.

I'll have another update in a while after I settle in with OpenSolaris a little more.


Quick Steampunk Book Review: Boneshaker

Cherie Priest has done something in Boneshaker I once thought foolhardy and absurd. She has given Steampunkers the world over a good reason to wear googles.

In Priest's alternate history world the Blight has caused the citizens in early Seattle to don elaborate headgear and rock the hell out while running from roving hoards of the rotting undead. The Blight also gives Priest a good reason to have airship pirates, mad scientists and mysterious Chinamen running the streets in a wasted urban landscape. In a strange parallel, she also has a tough lady as a retro-mechanical version of Gibson's Ratz from Neuromancer as bartender in the ex-patriot bar Maynard's.

Overall I liked this book, but I absolutely loved how Priest didn't go over the top with the Steam-ification of things. Not a single person went around with brass watch gears sewn to the lapels of their great coat! Top hats with random gears? NONE! This book is about the nitty gritty of life in an alternate history and these people don't have the time for silly and useless glommifications that seem to be substituting for style in the modern Steampunk fashion trends. Priest has done something I thought was almost impossible and thankfully skipped right over the silly parts of the genre. Until I read Boneshaker I thought Steampunk goggles were among the worst parts of it, right down there with the airship pirate theme. She has lifted them from the depths of absurdity and made them a necessary and believable part of the landscape for the book. Inside the novel is also her own version of a BFG, and the effects of the Blight give it a good reason to exist. None of the characters use silly little raygun pistols and I'm pretty sure I never read the word aether in the book.

Thanks, Ms. Priest! You've redeemed Steampunk from the downward spiral of mindless fashion trends and useless gizmos.


Dissecting a Simplex lock

Some guys at CCCKC brought part of an old-school Simplex lock down to the cave. I've always wondered exactly how they work and what kinds of vulnerabilities they have.

Pushbutton locks like this (and older designs with the buttons arranged in a pentagon shape) have been around for ages, but I've never had one in my hands before. I have always guessed that:
  1. They are 100% mechanical (requiring no electricity)
  2. The order doesn't matter.
  3. Any combination from 1-5 digits would be viable
  4. Each button can only be pressed once
I'll explain how these hypotheses work out as I go along.

Starting out, you can see where the inner door knob will attach on the other side of the wall. The nub at the top (or, to the left in this photo) is strange to me. As it turns out, it's used to reset the combination.

Once open, the lock mechanism inside is covered by a metal shroud. Some pivoting arms can be seen.

Here, I have swung the arm going to the combination mechanism out of the way, and I'm pulling the shield away. There's no power in here, so hypothesis #1 is true.

Here, I've re-attached the arm with the shield removed. Every time a button is pressed, the pawl associated with it rotates a little. The bar seen across the top of them will increment any of the lower numbers at the same time. If you press "1", only the first pawl moves. If you press "3", then pawls 1, 2, and 3 move at the same time. This means that the order in which buttons are pressed DOES matter. Hypothesis #2 is false.

Here is the other side of the combination mechanics. Visible is a gate with 5 fingers. When the outer knob is turned and the gate can't fit into the pawls (wrong combination) the furthest left bar (vertical in this photo) stays upright. The pivoting arm buckles, and the inner knob does not turn. The bolt work (not visible) is not withdrawn.

When the gate is aligned, the pivoting arms are allowed to swing up a bit (angled left a bit in this photo), and the inner knob is caught. The bolt is withdrawn and the door is allowed to open.

To reset the combination:
  1. Enter the current combo
  2. Activate the combination reset. I'm activating it with my finger in the above photo, but twisting that nub in the first photo does the same thing. It should "click" when you get it pressed. You do not need to hold the button.
  3. Turn the door knob to clear the combination.
  4. Enter the desired combination.
  5. Turn the door knob again.
  6. Test the new combination. You don't want to get locked out!

So what about hypotheses #3 and #4?

I got a few surprises:
  • If you accidentally turn the knob twice during a combination reset, you end up completely clearing the combination. If this happens, the door will open without you entering anything. Obviously, if you DO enter something in this state, it'll be wrong and won't open.
  • More than one button can be pressed at a time, and it's part of the combination. You can require any combination of keys to be pressed simultaneously, up to and including all five at once. 2/3, 1, 4, 5 is a valid combo, and you can't press 2, 3, 1, 4, 5 or 3, 2, 1, 4, 5 to make it work.
#3 was incorrect on a technicality. Any combination of 0-5 keypresses is valid.

#4 is correct. Once a button's been pressed, pressing it again does nothing, but you CAN press multiple at once to increase the complexity of the combination.

All in all, this was a fun little way to spend an hour or so at the cave. I was happy to finally get to learn how these fascinating relics work. As with any combination lock, once you can see the mechanics of it while you mess with it, it's pretty easy to get it to pop open.

The sheer reliability and simplicity of the mechanics leaves me in awe. It's no wonder you can still see these in airports, hospitals, post offices and elsewhere. This is certainly one of the more clever locks I've dealt with.

Props to Rob K for helping me get some higher quality shots of the combination mechanics.


Viral marketing

As seen in my Facebook notifications. Facebook apps in general are shady business, but this just seems downright predatory.

For those who don't know, any application you add potentially gives the author carte blanche access to anything you can see on Facebook. Friends' updates, list of friends' friends, not to mention almost anything you've bothered to fill out about yourself. Think about that before you go handing the keys to the kingdom over to LivingSocial or any of the other application developers.


2600 Article: Roll Your Own Hive-Mind

Editorial comment: This initially showed up in the Autumn 2009 issue of 2600: The Hacker Quarterly,Volume 26 Number 3, which is on stands now! I wrote it almost a year ago. Today, I would say that Google Reader's new options make it a very important part of my personal hive-mind, allowing me to crowd-source my news by hand-picking a relatively small group of people who reliably share and comment on things that I find pertinent, urgent or fascinating -- often near real-time. At the time of writing, sharing with people in Google Reader wasn't nearly as intuitive so it got a lot less play. In the past few months, though, it has grown up to become far more than just an online RSS aggregator and a web filter evasion tool to me.

While I don't feel like this is my best work, I do make a habit of publishing all of my printed articles here after they've hit the newsstand.

There's no doubt that social networking is all the rage on the Internet these days. Places like MySpace and Facebook have become ubiquitous social hubs that start out as a circle of your real-life friends. Eventually, others join in that you've probably never met and might never meet in your lifetime. Your reasons for befriending them may be many: interesting photos or content, similar interests, or simply because they're a friend of a friend (of a friend of a friend). Maybe, you just like to compete in the popularity contest to see how many e-friends you can collect.

LinkedIn has a business focus. Maybe that's where you keep all of your professional contacts or hunt for job opportunities. Brightkite is a location-aware microblog with photo hosting ability; Like Twitter on steroids. Maybe that's how you find out who hangs out at your favorite local places to try to find new friends. Friendfeed can aggregate most content from your other social network accounts. Maybe that's where you go to get your 50,000 foot view of your online social sphere.

What if you wanted to craft a specialized hive-mind, though? I'm interested in security, and I've found that online, quite a few security geeks have blogs, twitter accounts, facebook profiles and the like.

Instead of just looking for your existing friends online, you can leverage microblogging services like Twitter to find and follow like-minded strangers. Obviously, self-described social media addicts have no problem finding their cliques, but everyone from World of Warcraft Gamers to Bacon-lovers can find a niche in most social networks. Security nerds like me have SecurityTwits.

The people you follow will frequently ask or answer questions of other folks. You can follow them as well, and pretty soon you end up with a news-feed of data you're interested in. Assuming enough of them follow you back, you will have a powerful hive mind at your fingertips: This collective will give input on ideas from within itself. It will refine, disprove, or validate answers given to questions within the collective. It will link to fascinating content elsewhere on the web that other members might not otherwise find. It will challenge you to participate by giving as much as you get.

I've found that this hive-mind functionality works best on lightweight services like the aforementioned Twitter, or with link-sharing tools like Delicious, Digg, and Google Reader. Facebook and MySpace are far too cumbersome and broad-sweeping in their content to be used efficiently. Plus, most of the services I mentioned have easy-to-use RSS feeds that can be indexed, processed, aggregated, and searched later.

Of course, if you want people in your niche to acknowledge your existence on these social networks, you need to establish your presence with relevant content that's as equally interesting to them as their content is to you. Jumping onto Twitter and following every single member of SecurityTwits, for example, won't immediately integrate you into the hive. By lurking, however, you can learn a lot.


OpenBSD 4.6 is released

Normally, OpenBSD is released every May 1 and November 1. The team was really trying to push 4.6 out the door by October 1, but problems with the CDs held it back. Still, they managed to ship the CDs early, and decided to release OpenBSD 4.6 today. I've been offline almost all day, so I just now saw it.

As always, the new release brings more hardware support and improved functionality. Check out the release notes for details. Order your 3-CD set, or hit the mirrors to download installation media images.


On cloud computing

It seems everyone is blaming a general failure of cloud computing for the massive data loss that hit Danger, Microsoft and T-Mobile over the weekend.

From what I've read, a failed storage upgrade occurred without a good, solid backup in place. That sounds a lot more like a failure in backup, planning and design than a failure of cloud computing to me. Had the storage folks at my office made the same mistakes, that's what would have been said -- right before the human resources folks came to "have a talk" with the team.

It just so happens that T-Mobile's sidekick phones rely on a lot of back-end storage, so there's the whole "cloud" element to things. I'm not familiar enough with the Danger platform to know how easy it is to back up your own data, but I'd hope it's possible.

I think it goes for any service where you've entrusted storage of your data to someone else: make sure you back it up yourself, if you think it's important. The difference with the Danger/T-Mo disaster, I think, is that it was a lot less obvious to end-users that the data wasn't all stored permanently on the phone. Clearly, "cloud computing" was collateral damage in the wake of a much more mundane failure. The fact that it was completely avoidable offers little comfort for those affected.

Shifting gears: Along comes this piece on how e-mail is becoming less and less relevant.
The thing that separates e-mail as we know it from other messaging platforms is the fact that e-mail is decentralized. Using information stored in DNS, all Internet-facing e-mail servers can properly send mail to the correct server for a given address. IRC is another decentralized communication protocol. The days of decentralized infrastructure are fading fast, though, being replaced by walled gardens that want your constant attention, and many of them requiring a separate account and password. These walled gardens are supposed to be "the new way" of communicating.

You can't easily backup everything you've received through Twitter or Facebook, and the people who communicate with you there have to have accounts. Sure, anyone can get an account. What about Google Wave? Very few of the people I REALLY want to collaborate with have an account. So, while I do see a lot of value in these services for certain things, I don't think that any of them are quite ready to fill the roll that e-mail currently provides. Chiefly: if I have a local e-mail client running on my system, I don't need to suckle at the teat of the Interwebs in order to rifle through my data. It's right there, on my computer. Web mail has indeed blurred the line, but the good web-mail providers still offer mechanisms to back-up your data or use an offline mail client such as Thunderbird.

OpenID somewhat fixes the need to have multiple accounts and passwords scattered all over the web, but shifting authentication "into the cloud" just means that each OpenID account we have will be more catastrophic if compromised. OpenID is tantamount to using the same username and password everywhere, and we know how well that works for security.

How do you backup your cloud data? Well, for starters, you can try a native-client RSS aggregator such as Liferea. One thing that "Cloud" is doing is making syndication possible through ubiquitous RSS feeds. Backups won't work perfectly on every site, for example: you won't actually download all of the photos from Flickr with RSS, you'll only get links to them. It will nicely archive text content, though. This is good for things such as blog posts, twitter conversations and the like.


Solving transit questions with PHP

When I saw Visualmotive's "Walk or Bus?" chart, I was fascinated. I love stuff like this! It answers the question of "If I have to be somewhere, is it going to be faster to wait for a bus, or just start hiking?"

I am a multi-mode commuter. I often use my bike combined with the bus to get myself downtown. Sometimes, I also need to get around the city. I almost always do this on my bike unless it's somewhere really close. Still, I felt compelled to create a chart that included bicycling, as well as walking.

The top header is how long you'll have to wait for the bus.Where there's a gray bus icon, it's faster to wait for the bus. Where there's a blue bicycle, it's faster to hop on the bike and ride. The yellow jogging man represents a brisk walking pace and the green foot represents trudging along with an average gait. I extended the chart out to 4.0 miles, which is about how far one can get on a bicycle in an urban setting within half an hour at 8 MPH. These are just guidelines, of course. Some people are considerably faster on bicycles. Others are slower. Same with walking and the bus, actually.

Click for big:

I ended up making a quick program in PHP to draw the main part of the above chart for me. I sourced the icons from the same place Visualmotive did (icons.mysitemyway.com) but opted to modify their icon colors, then added the headers manually in GIMP. I'll upload a .zip file (and link to it) later, with the icons.

The algorithm is pretty straightforward. Urban buses probably average 15 MPH with all their stops included, or about 4 minutes for every mile. Most people can get around on a bicycle at an average speed of 8 MPH (7:30) and so on and so forth as commented in the code below.

The code is pretty simple and very ugly. Not only did I use tables (ew) but I also barf out HTML with PHP. This is why I say there's a massive difference between programmers (like me) and developers (who code for a living).

<html><head><title>Walk, Bike, or Bus?</title></head><body>
<TABLE cellpadding='0' cellspacing='0'><TR>
<!-- Model View Controller what? -->
=.2; # .2 Miles. Just walk it. Jeez.
while ($Miles <= 4.0){
$TravelTime['Bus'] = $Miles * 4; # Bus ! 15 MPH (4:00 mile)
$TravelTime['Bike'] = $Miles * 7.5; # Bike ~ 8 MPH (7:30 mile)
$TravelTime['Brisk'] = $Miles * 15; # Brisk walk ~ 4 MPH (15:00)
$TravelTime['Walk'] = $Miles * 20; # Walk ~ 3 MPH (20:00)
while (
$Mins < 30){
if (
$Mins >= $TravelTime['Walk'])
"<IMG WIDTH='45' SRC='img/iconwalk.png'>";}
elseif (
$Mins >= $TravelTime['Brisk'])
"<IMG WIDTH='45' SRC='img/iconbrisk.png'>";}
elseif (
$Mins >= $TravelTime['Bike'])
"<IMG WIDTH='45' SRC='img/iconbike.png'>";}
"<IMG WIDTH='45' SRC='img/iconbus.png'>";}
"</TR>"; #I know you're not supposed to print HTML. Byte Me.

So, what started as a desire to have a cool chart to share with other bicycling/pedestrian friends of mine turned into an exercise in algorithms last night, with a little bit of PHP programming tossed into the mix. This is yet another example of a quick-n-dirty program I wrote for something simple.