Thursday, September 2, 2010

Reading Web Pages From the Android SD Card

Android 1.6 (Donut) tries to make it impossible to read web pages from the SD memory card. Fortunately there is a flaw in their security that lets a user create a specially formatted URL that allows access. This technique may work for other versions of Android but I've only tested it on 1.6.

This is an easy hack. The only skill required is the ability to drag and drop files from the computer to the phone and to connect to this web page via the Android.

Terminology

For the sake of simplicity the Android based phone is just going to be called the Android. It reads easier.

Local files are the files on the Android SD card. Any references to "the card" mean the Android SD card.

The Desktop is the computer that will be used to edit files and drag and drop the files to and from the Android.

"The browser" is the browser on the Android.

Overview

A web page is created on a computer and moved to an arbitrary, but known spot on the Android SD card. A special URL is entered in the Android browser which points to the page. The page is made into a book mark by bypassing the bookmark editor. The web page can then be edited to point to any other location on the SD card.

The Direct Way

This way is direct, but it involves a bit of typing on the Android keyboard. Most people find the longer way easier to get correct.

Put a web page the SD card. This example will use the file webpages/index.html.

Open the browser and type in the URL content://com.android.htmlfileprovider/sdcard/webpages/index.html.

If index.html shows up in the browser, go to the section "Saving as a Book Mark". If not, check the URL spelling and file location. If the problem can't be solved, use the longer way.

The Longer But Less Fussy Way

This way requires creating a web page on the desktop and the ability to drag a file from the desktop to the Android.

Open an editor ("notepad" will do) and paste the following text:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
<title>Found the sd card!</title>
</head>
<body>
<h1>It worked!</h1>
<ul>
<li><a href="content://com.android.htmlfileprovider/sdcard/foo.html">Self reference.</a></li>
<li><a href="webpages/index.html">Relative links work also.</a></li>
<li><a href="http://upcracky.blogspot.com">An external link.</a></li>
</ul>
</body>
</html>


Save the file as "foo.html". This is just a temporary file and the name has to be "foo.html" or the rest of the steps won't work.

Copy foo.html to the top level directory of the SD card.

Unhook the Android from the Desktop.

Connect to this blog entry via the Android browser and click on this URL. foo.html should be displayed in the browser.

Saving the Bookmark

While display the web page in the browser, press the menu key. Select "Bookmarks". Select "History". Select "Today". Find the entry for "Found the SD Card!" and click on the star symbol on the right. The bookmark will be added to the browser with no further intervention.

Do not use the "Edit bookmark" option. Just opening the book mark editor with this book mark may corrupt the link and it will stop working.

Changing the Name of the Bookmark

Since the bookmark can't be directly edited, some cleverness is required to move the SD web page and/or change the name of the bookmark.

First create a new web page and install it on the SD card in any arbitrary folder. Edit foo.html and add a link to the new page relative to this page. Bring up foo.html via the previous book mark. Click on the link to the new page. Bookmark the new file.

Once the new page is safely bookmarked, foo.html and it's bookmark can be deleted.

Limitations

The one quirk that hasn't been figured out is how to jump to the middle of a local web page. Links such as bar.html work fine. Links such as bar.html#middle give an error.

Sunday, August 29, 2010

Thursday, July 22, 2010

Beyond Help.

I'm a big fan of open source software. I do most of my work on Linux and most of my programming is done using Perl. I believe that open software has value and the more open our infrastructure is, the better it is for the world as a whole.

As programmers go, I'm pretty good at what I do. That gives me certain obligations, one of which is to give back to the open software movement when I can.

I was given an opportunity today, but I don't think I'll be giving back in this case.

As I mentioned before, I do a lot of programming in Perl. Sometimes I need to create windows and buttons to make my programs pretty. Enter GTK2. It's a really nice package. For what I do it's simple, reasonably clean and you can usually find an example out there that will give you a good head start. Therein lies the rub.

The example that I found was part of the GTK2-Perl Frequently Asked Question (FAQ) list. I copied it over and tried to run it. No go. The example was using an older version of the library and it had a typo. If only there were a programmer in the house!

Hey! I'm a programmer! And I'm in the house! It took me less that 15 minutes to get it up and running. Yay me!

Now comes the obligation part. I'm using public code, so therefore I'm obligated to send the fixes in to the GTK2-Perl folk so the next person who comes along doesn't have to figure it out. I connect to their bug tracker and try to enter a bug report, including the fix.

No dice! If you want the privilege of submitting a bug to them, you have to sign up to their web site. That's stupid but I'll bite the bullet for betterment of open sourceyness. I'm quite the patriot.

Nope. You not only have to sign up, but you have to give them an email address. Oh, and they'll publish your email address guaranteeing that you'll get spammed off the planet! It gets worse. They suggest creating a throwaway account to handle the spamming. What? Why would I set up an account just to throw it away?

In theory this is supposed to discourage spamming. Is spamming in bug reports really that big a marketing vector? Hey, my program is crashing, maybe penis enhancement will help!

I know that people want an automated system here. One that will block all spam without human intervention. These people are idiots. You have 2 choices. Get casual bug reports that will do wonders for enhancing your project while dealing with the reality of spamming, or set up barriers that will keep most spam out and will do wonders for causing inbreeding on your project.

I'll admit I don't have a lot of patience for this nonsense. I'm not jumping through hoops to help you. Besides, a better solution is trivial.

Any bug report sent via the "outside" gets put in a queue until someone who's trusted takes a look at it. Spam bug reports are rare and there are more than enough regulars on any project who will do the few seconds of grunt work for you.

You could also use a one time key. I connect to your bug tracker. You email me a tracker-putter-inner-key. You don't keep my email address, you just use it once to send me the key. I then use that key to submit the bug report. If I need to add comments to that report, then I use the number again. If I loose the number and want to add more comments then I have to sign up for an account and I become a regular user.


As for the moral obligation to open source? Here it is:

In the GTK2-Perl FAQ, question 5.3, "Show me a simple example for Drag-n-Drop" you need to make 4 changes to get it to work under Perl, v5.10.0 and GTK2 version 1:1.221-4.

  1. Replace "Gtk2::Ex::Simple::List" with "Gtk2::SimpleList". It occurs in 3 places, all near the top.
  2. In the function "_move_from_to", change "for my $i (0 .. $#{ @{$fromlist->{data}}) {" to "for my $i (0 .. $#{$fromlist->{data}}) {".
  3. Enjoy!

If someone wants to send this to the GTK2-Perl bug site, feel free, but watch out for the spam.

Sunday, May 23, 2010

Gators and Nautilus and DAVs, Oh My!

If you're here to get WebDAV working with Nautilus for HostGator, then just jump to the end of this article. The solution is trivial.

If you wish to bask in my purple prose, read on:

Introduction

I'm setting up a site on HostGator, which is a host provider of good repute. It's starting as place to put some of my little code snippets that don't warrant a full blown project. Who knows what it will turn in to.

So far it's been basically a positive experience, but it's not without its shortcomings. I'm trying to keep notes on dealing with HostGator so other people don't fall in to the same traps I've tripped.

One thing I ran into was getting WebDAV working with Linux. Specifically Ubunto's "Karmic Kaola" under Gnome, using the Nautilus file manager.

Of DAVs and Nautali

The first problem I ran into is that HostGator gives it's version of WebDAV the name "Web Disk".

I don't mind them trying to make web interfaces seem a bit easier to deal with, but somewhere on the page they really should tell us that "Web Disk" is really just another name for WebDAV.

Once you get that under your belt tracking down problems becomes a little easier.

The next problem I ran into is, well, I'm trying to use Nautilus.

Nautilus is the Gnome file manager. For many users it's the entire interface to the disk. It should, above all other things, be reasonably fast, accurate and reliable. All else follows from that.

Unfortunately Nautilus is notorious for running down rat holes while not getting the basics done right. It has improved a lot in the last 2 years, but it still plays amateur night a few times too often. This was one of those times.

I went to the HostGator site and navigated down to the "Web Disk" page. I selected Nautilus and followed its suggestions. They wanted me to connect to the location "https://foo.com:2078".

I did and I got "Could not display 'https://foo.com:2078'."

Crud.

I had no idea where to proceed from here. Is it the instructions, or is my account screwed up, or maybe Nautilus is broke?

Just to add to the confusion, HostGator has you create a user name when you create an account with them. No big deal, I chose "wiles". What they don't really make clear is that this user name isn't your domain user name. If you register the domain "foo.com" and want mail to come to "wiles@foo.com" then you need to set up another account called "wiles@foo.com". When I connect with Nautilus, should I use "wiles" or "wiles@foo.com"? The correct answer is neither, but that part's not HostGator's fault. More on that later.

So now I have and unknown protocol, with an untrusted browser connecting to a possibly mis-configured account using an unknown user name. You have to admit, it's kind of a challenge. Right?

I Prefer the Term "Challanged"

I'm not one to back down from a geek challenge, so into the fray I went. I ended up spending over an hour chopping around the Internet tubes trying to figure out what's going on. I got bits and pieces, but nothing I could really sink my teeth into.

I also wasn't sure of the format of the URL. For most services you can load in your user name into the URL and you don't have to type it in each time. For example, if you're using File Transfer Protocol (ftp), and the URL is ftp://foo.com, then you can include your user name with ftp://wiles@foo.com.

Does that work with "Web Disk"? What if I'm supposed to be using wiles@foo.com. Is it ftp://wiles@foo.com@foo.com or ftp://wiles%40foo.com@foo.com.

"%" is the HTML escape character and "40" is is ASCII code for "@" in hexadecimal. You knew that didn't you? I think it's a real sign of progress when connecting to a web site only requires knowledge of arcane character encoding and 2 number bases.

How about if I just create a bookmark in Nautilus, and then edit each variable separately and see if I can get anywhere? Nautilus will handle the details right? If you watch slasher moves there is always a part where some idiot says "lets split up!" The music they play at that point belongs here.

Scooby Do Takes and Ax to the Forehead

First, I'm not going to get anywhere until I figure out the real protocol being used. "Web Disk" criminy! Why not just call it "Disk Huggy Bunny" and be done with it.

I went back to the HostGator page. It listed a few other OSes and other browsers. The Mac options were mysterious. The Window options were baroque. It's not looking good. My last hope: Under Linux there was the option to use Nautilus's arch enemy "Konqueror". I selected it and it offered a download for my system. Anonymous downloads makes my toes itch, so instead I sent the file directly to a text editor to check it out.

There, large as life, is the line "URL=webdavs://foo.com:2078".

I now knew the protocol. We were moving forward.

I created the bookmark in Nautilus, set my user name, picked "Secure WebDAV (HTTPS)", and set the port.

I'm not sure about the start folder. Is it "/" or "/home/wiles" or "/public_html/wiles@foo.com"? I held my nose and left it blank.

I clicked connect and I'll be darned! I got a password prompt! Kewl. I typed in my password and crossed my fingers.

The error I got is "Could not display 'davs://wiles@foo.com:2078/'. Error: Not a WebDAV enabled share. Please select another view and try again."

This is a truly beautiful error message. First, it did *not* connect using "davs://wiles@foo.com:2078/" (more on that later). Second, the share is, in fact, a WebDav enabled share. And third, "Please select another view and try again." gives me absolutely no useful information. It was a perfect storm of rotten interface.

At this point I was pretty frustrated, and lets not kid ourselves, at this point most people have already given up. Fortunately I'm not most people. I'm a hard core uber-geek and I eat bad interfaces for breakfast! Snort!

I start creating bookmarks like they're going out of style. I try every combination I can think of. It's slow, it's tedious, it's everything a computer shouldn't be, but alas, are, and in the end, it was futile. I could not get Nautilus to connect to my HostGator site.

Nautilus: A Weasel in Drag

Hmmmm. Do I trust Nautilus? Would I lend it $10 if it asked? No. No I would not. Then why would I believe that its rotten bookmarks are doing what they say their doing? It's time to go back to first principals and start over again.

I knew, with reasonable confidence, that I'm trying to make a WebDav connection. I also think that the "s" in WebDavs" stands for "secure", as in a Secure Socket Layer (SSL) connection. When you drop the SSL requirement at HostGator, the socket number changes from 2078 to 2077. That was enough for me to make another try.

I fired up Nautilus, and in the "Location" bar I typed "webdav://wiles@foo.com:2077". I got back "Nautilus cannot handle 'webdav' locations." Wow. What a nice, simple and useful error message. Are we sure this is Nautilus talking?

"WebDAV" isn't going to work, but I've also heard it called just "dav". I tried that.

With "dav://wiles@foo.com:2077" I got the password pop up! I also got the "select another view" error message. Arg!

Blinky the Wonder Idiot

Then the dawn came. Does anyone else see the huge blinking "Dale is an idiot!" sign in the previous paragraph? It took me a while to see it.

Even though it's the standard, and Nautilus is reacting to it, do I really know that the "wiles@" part of the URL is kosher? What happens if I don't use it?

Into the breach with "dav://foo.com:2077". This time the pop up asked for user name and password. I used "wiles" again and typed in my password.

I connected like a 13 year old with an evangelist. Son of a ...

I had spent more than 4 hours trying to get this to work, and it all comes down to this one sentence. It really doesn't make HostGator or Gnome/Linux look good does it?

I wasn't where I want to be yet, so I kept pressing forward. I was going to get SSL working.

"davs://foo.com:2078". Yup. I was in. Sort of anticlimactic isn't it.

One last thing. I really wanted to be able to connect to HostGator by clicking on a shortcut on my desktop.

The solution is trivial. Right click on the desktop and select "create launcher". Give it a name, and in the "Command" field type "nautilus davs://foo.com:2078" or "nautilus dav://foo.com:2077", depending on whether you want to use SSL or not. (You do, unless it you can't get it working.)

That's it.

I'm sending this URL to HostGator so they can fix their documentation, but until they do, enjoy updating your HostGator sight via Nautilus.

Sunday, October 18, 2009

Android Phone Home

Getting Started

As some of you know, I've been playing with a new toy.

Android is a new operating system from Google. It's designed for cell phones and other small computers. I've been learning to program it.

For the first couple of months I was mostly working with the Android Software Development Kit (SDK) and the Android emulator. With the emulator you can write and test Android applications (Aps) from the comfort of your computer. As learning Android is like drinking from a fire hose, I wasn't going to invest any money on hardware until I knew I could get something done with it.

I'm at the stage now where I can generate simple programs and I have some definite ideas where to go, so I decided to bite the bullet and buy an Android developer phone.

I ordered my phone and a very few days it showed up. Good job Google!

I fired it up. It munches away for a few seconds, then it tells me "No SIM" and just sits there. Wha?

I know what a SIM is. It's a Subscriber Identity Module, which is a little piece of plastic that modern cell phones use to keep track of who you are. Take a SIM out of one phone and put it into another, and the new phone now has the old phone's number. Neat huh?

I'm using this as a development platform. I don't want to use it to make calls, so I don't need a SIM for it, right? I'm sure that Google has provided an easy work around for this. I'll just check the Internet tubes and find it. Oy! 2 days later I had real access to my phone.

The rest of this blog is designed to save the next poor swine the aggravation I went through in registering my phone.

After checking around I found out that Google not only wants you to have a SIM card, but you also need a data plan on that SIM card! I don't want a data plan, I don't need a data plan, And, at the rate the phone company rapes at, I can't afford a data plan!

Then it just gets silly. You only need the data plan for about 5 minutes, just long enough to connect to Google and register your phone. After that you can chuck it out the window. Oh, did I mention that the phone has WiFi?

You need a data plan to register a phone to get to the WiFi, which you could use, if you could get to it, to register your phone! You're killing me Google. Your just killing me.

Fortunately, if you have a regular SIM card (say from your current phone) and you're already running the Android SDK then it's not too hard to fire up WiFi on your phone and bypass the data plan requirement.

Away We Go!

First we'll get your Linux box to see the phone via the USB cable. I'm running CentOS 5, which is like Red Hat 5. There are other guides out there for Windows and Ubuntu. This guide is for CentOS.

First install the Android SDK on your system. Look around on the Internet for instructions. You don't need everything under the sun, but you do need the "adb" (Android Debug Bridge) command.

Plug your USB cable into your computer and your phone.

Open a root shell on your computer.

After a couple of seconds type "lsusb". You should see a list of the devices attached via USB to your computer. Somewhere in the list should be an entry for "High Tech Computer Corp." "High Tech Computer" is HTC. HTC makes your phone. If you see it then you know that USB is up and running and can see your phone.

The next question is does it see it as a phone or just a very expensive jump drive?

Type "adb devices". If you see an entry that begins with "HT" followed by a bunch of characters and the word "device", then skip to the next section. If adb can't see your phone, then we need to tweak the USB daemon so that it does.

This part took me a long time to get working. Apparently CentOS is using an older version of udevd, which is the program that scans the computer looking for new USB toys being plugged in.

Go in to /etc/udev/rules.d and look for a file named something like "90-android.rules". The leading number varies. It probably isn't there. No problem. You need to create/edit it until it looks like this. Make sure it has the same permissions as the other files in the directory.

# This file lets Linux recognise my Android Developer Phone in
# a way that the adb command can handle.
# Uncomment one of the lines below and run:
# udevcontrol reload_rules
# adb devices
# If it lists your phone, you're done. If not comment out the
# current line, uncomment the next line and run udevcontrol again.
#
# The 3rd line (usb_device) was the charm for me.
#
SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666"
# SUBSYSTEM=="usb", SYSFS{idVendor}=="0bb4", MODE="0666"
# SUBSYSTEM=="usb_device", SYSFS{idVendor}=="0bb4", MODE="0666"

Follow the instructions in "90-android.rules" and you should end up with a visible Android phone.

Connecting to the Phone

From the command line type: adb shell

After a moment or two you should get a "$" prompt. This means that you're in the phone talking as a regular user.

Type "su".

If the prompt changes from "$" to "#", then you're in as root.

Type "exit" to return to a regular user.

Bypassing the SIM check

There are two ways to do this:

The first, and easiest, is to plug in a SIM card. It doesn't matter that it doesn't have a data plan. This is just to get past the check.

The second, and I haven't tried this myself, is to fool the phone into thinking it passed the check. Check out http://forum.xda-developers.com/showthread.php?t=452316 for instructions.

Note, for the second technique, if you have a developer phone then you don't need to root break it. Just type "su" at the adb shell prompt and you're root.

Registering with out the Data Plan

At this point your phone should be at the registration screen.

From adb, as a regular user, type:

am start -a android.intent.action.MAIN -n com.android.settings/.Settings

In a couple of seconds the "settings" screen should pop up on your phone.

Set up your WiFi and hit the back arrow. You're back at the registration, which you can now do via WiFi.

If for some reason the settings screen doesn't pop up, try

setprop persist.service.adb.enable 1

and then try the settings command again.

Once you're registered you may want to go to the Android market place and pull down an ap called "APNdroid". It screws with the data plan APN so that your phone can't connect no matter how hard it tries. Bite me AT&T.

Using your Phone as a Jump Drive

One last thing, did you notice that your computer can see your phone as a jump drive but can't access it? That's easy to fix.

When you plug in your phone via USB, you'll notice a little USB forky type icon shows up in the upper left hand of the phone screen. This is the notification area. Pull it down with your finger. Click on the USB notification and then click on "mount". You're good to go!

Monday, September 7, 2009

Spanking Dawkins's Weasel

One of the problems with learning a new programming language is coming up with interesting "beginner" programs. Most beginning programs do something exciting like printing out "Howdy, Howdy, Howdy, Joe". Heart stopping stuff ain't it?

To ease this a bit, whenever I come up with an interesting idea for a beginner program, I'll write it up and you can give it a shot.

My hands down favorite simple program is something called Dawkins's Weasel.

Richard Dawkins is a evolutionary biologist from Oxford. He wanted to come up with a program to show the difference between a random mutation and a random mutation with selection. The result is a simple, straight forward program called "Dawkins's Weasel".

Note: Whenever I say "letter" below, I mean letters and/or spaces. Saying letter and/or space all over the place makes for a tedious read.

First we start with a target sentence, which we'll call "Target". This is what all good little sentences want to be when they grow up. Dawkins used "methinks it is like a weasel" and so will we.

Next we create a parent sentence called "Parent". This is a gibberish sentence of random letters that is the same length as Target. "y ksqmjwepqtgtyylmfexstvktpa" will work, as will "aaaaaaaaaaaaaaaaaaaaaaaaaaaa".

Our goal is going to be to evolve Parent into Target.

Parent will produce a litter of children. The fittest of the litter will then become the next parent. This continues until we produce a Parent that equals Target. It's survival of the fittest and all that jazz.

Unfortunately the sex life of a sentence is pretty dull. The way a sentence has a baby sentence is by copying itself and then changing a single letter at random. Not exactly the stuff of pornos. We'll call the baby sentence "Child".

As for who's the fittest? We'll use something simple. We'll count the number of letters in Child that match Target. For example, the sentence "aaaaaaaaaaaaaaaaaaaaaaaaaaa" would score a 2. "methinks it is like a measel" would score 27. If there is more than one pick of the litter, choose one. It doesn't matter how.

That's pretty much it. The only real variable you get to play with is the size of the litter. If you start with a litter of 50 then you tend to finish in less that 100 generations. Once you get the code working, starting dialing playing with the litter size to see how it effects the generation count.

I'll try to keep my eye out for other interesting algorithms worthy of posting. If you know of any that are fun, the add a comment.

Monday, July 20, 2009

Back to (Paranoia) High School

Whelp, I'm back from vacation and all in one piece. I'm a bit shell shocked, but all in all it was a good time.

I'm not one of those people who really gos on vacation. I more survive them. My home life is driven from project to project so when I hit a vacation that I can't spend in front of the computer I'm kind of at a loss.

However, my dearly beloved explained to me that my mother in-law put a lot of work into setting up this vacation, so my other option was to be in kind of a wheelchair, so vacate I did.

The big problem was, we vacated to a dead zone. No phones, no lights no motorcars, and no Internet. That means no real way to do any writing.

I hate writing with a pen. My hand writing is a scrawl and it's sooo slow! And once I'm back amongst the living, I have to transcribe it back into the computer.

With writing on mashed up trees as a failure, I tried using a small laptop. That kind of dominates the landscape and emphasized how much I'm ignoring my family. Not smart for this wheelchair phobic. I needed something sneaker.

How about my phone? It's got a 2 gig chip, supports text messaging and can hide in my hand. Could I use that?

Nope! My phone does allow memos, but they have to be less than 100 characters. Let me repeat that. My crappy phone, with 2 gig available, won't even let you save a memo as long as a Twitter "tweet"! Thrilling.

I know! I could use it as a voice recorder! Yea, I could do that. When I write I tend to talk out what I'm writing anyway. I'll just talk into my phone and record everything!

Unfortunately, with my current phone I have to shout to be heard. Every time inspiration hit, my in-laws would hear me shouting to my invisible friend who hides in my hand.

Now my in-laws think I'm nuts.

I can live with that, but I also got to play with writer's block. Such fun.

Actually, it a weird sort of way I don't mind writer's block. At least I don't mind having it once I've overcome it. It's kind of like the old saw about smacking yourself with a hammer because it feels so good once you stop. I sorta go through that.

As you may or may not know, I used to write for a comic strip called "Paranoia High" (Check it out.) It was a lot of fun and Dave (the artist) is a friend of mine.

After a while Dave took over the writing and I went on to fame as a geek blogger on them Internet tubes.

To make a long story short, we fade the mics and queue the organ and it's a year or so later and I'm back to writing the strip. Huzzah! The only problem is, can I still write the strip? Not May I, Can I?

Ya see, when Dave consolidated the strip, I gave him a list of the ideas I had at the time. No big deal, I have the list around somewhere and Dave has it too. But old ideas aren't enough. Can I come up with new ones?

I could feel the tightening grip of initial dread. What if my last creative idea was really my LAST CREATIVE IDEA!?!? You civilians don't savvy the pain we creative types go through when we birth forth art and stuff.

How can I explain it? It's like Paris Hilton waking up and finding out her butt has run off and joined the Peace Corps. No tush? No job! Writing is like that, except Paris's butt is our ideas.

Hopefully that image will help you develop an appreciation for the written word.

That analogy would have worked much better if it were a breast joke, but I couldn't think of any famous current women who are know for their big racks. Maybe Micheal Jackson, but he's dead.

Ms Proust is know for her rack, but she's a character in "Paranoia High". You really should check it out. (Note the reoccurring motif, that's the art baby!)

So I started running through ideas. Film strips? I think that's from the old list. Standardized tests? Nope, the old list. How about exploding frogs? Damn! School Principal Mike Ducacus? Whoa! Wrong decade!

It was looking pretty bleak for new strips, but I stayed with it. Football? Feral students? Sentient lunch meat? Damn! Damn! Damn! How about Hall Monitors?

Hall Monitors? Not on the old list. Hmm. Uniforms, Tazers, RoboCop, Juntas? Yea. Add "Hall Monitor" to the new list.

After that things started to roll. Walmart vs the school store? New! Texting NORAD? Brand spanking new! "Shakespeare: The Musical!" Oh yea baby. We're back in action!

Why are the in-laws looking at me?

Oh yea, I'm shouting at my fist.

They really think I'm nuts.

I gotta get a new phone.