Somewhat Productive Weekend

I got a few things done this weekend since my post on Friday, just not most of what I’d planned (and really need) to do.

First off, I wrote an interface and pair of streams to replace Externalizable and ObjectOutput/InputStream. I had a bug at work where I’d implemented Externalizable but not specified the serialVersionUID and the versionUID changed without my custom serialization changing so suddenly my old data logs couldn’t be read. Basically I hadn’t realized how much metadata (serialVersionUID, class name, and probably some other stuff) was written to the stream, and working on this at home was my reaction to how inefficient Externalizable is for what I’m using it for. Anyways, the library I wrote this weekend typically sends exactly 1 byte of stream header information, and only sends the class name when the class hasn’t been written to the stream recently. After the header it sends exactly what you specify. Once I’m convinced it’s tested enough I may release it somewhere, but not yet.

Unfortunately, I designed the library to prevent a problem I’ve already solved at work, and since I was more concerned with recovering the ~500 GB of data I’d already recorded than having extremely lightweight serialization I can’t apply this there. I don’t even have a project of my own that uses networking currently, which makes it hard to really test the library. I’ll probably use the lessons learned at some point, but the most obvious application of this is in another part that’s already finished, tested, and working.

What I’d planned to do this weekend (same thing I’ve intended to do for the last several weekends) was take my car in to the shop for an oil change and to swap the winter tires off, as well as have them look at one of the back wheels to try to figure out why it rumbles (I’m guessing bearings from talking to people at work). Instead I slept till noon, and that late on a Saturday I expect to have to wait a while, so I put it off again. The idea is to get there not too long after they open and have a book so I can just sit in the waiting room till they’re done.

I did at least manage to make it to an auto parts place to buy new windshield wipers since the rubber part had mostly fallen off mine. I also tried to twist one of the wiper arms back to where it should be (it’s twisted such that the blade doesn’t meet the windshield at a right angle), but that wasn’t happening with the little pair of pliers I have. Wish I hadn’t left so many of my tools at my parents house, but that will be partially resolved in a few weeks after I go home for vacation.

I also finished with (not “finished”) a couple books. The first I read all the way through. It wasn’t bad, but between a couple rather graphic scenes and the way the world building was done it wasn’t quite what I prefer reading. The other one I got over half way through and had to ask myself why I was still reading it (at which point I promptly stopped). It was very much not the type story I prefer, and the overly heavy usage of the main character’s magic in nearly every situation just got old. I need to make another trip to the library soon, possibly to just wander till something catches my eye.

Rubik’s Cube Simulator

I’m planning to try to write a Rubik’s cube solver, or rather a few tools towards one. One goal is to have a program that can breadth-first search moves from a given arrangement to reach another arrangement. That’ll probably take a significant amount of optimization to allow it to run quickly and efficiently in memory, but to be able to get that working I need a computer model of a Rubik’s cube.

This weekend I put together a Rubik’s cube simulator and a command line interface to allow interaction:
Well, this was supposed to be where I pasted the log of console output of manipulating the cube, but the formatting depends on a uniform-width font and maintaining whitespace, neither of which actually worked when I pasted it. Here’s a screenshot:

It’s still having some issues, but the example sequence I chose doesn’t show them. I also only implemented (almost) the entire set of moves that are valid on a 2-cube, but didn’t try to use any 3-cube specific moves in that sequence. Once I’ve got the last few bugs worked out of that set extending it to n-cube size is just a matter of defining the moves for that size cube puzzle as an extension off the base 2-cube moves. I was planning to have that finished tonight, but I was distracted (see my previous post) and had to settle for just finding the test cases that it fails. Didn’t have time to put them in unit tests, but if they give me enough trouble I might bother with that.

In other news, I wish I’d looked up the problem of representing a Rubik’s cube as an object before I started. I couldn’t think of a way to represent the puzzle in a way that would make manipulating it easy, so I took the approach that I’d store the data in an easily extensible form (arrays of size n*n where n is the size of the cube) and put all the logic to make it work in the code that manipulates the puzzle. This approach (from 1986) flips it around, but the end solution looks a lot simpler than mine. The way I have mine written is easily extensible to larger cubes, but done right I think that approach could be also. Since mine is almost finished I’ll get it working on the 2- and 3-cubes, then I’ll probably put together a 2-cube using that approach and see if it’s actually as simple as it looks (I don’t know APL, but I know what it’s trying to do).

At least my interface is very similar, though there aren’t all that many reasonable ways to represent a cube in ascii, and my input accepts standard cube notation, unlike his. Looking at the other search results it’s surprising that the first Google hit exactly solved one of my problems (that I’d already worked around less elegantly) when all the rest are just software puzzles, not computer science.

Call Home Script

A year or two ago when I first set up my old laptop as a linux server I created a script that logged into my router, parsed the external ip address, checked that against the ip address it got last time, and emailed me if they were different. That worked great for the intended purpose (telling me when the address of my server changed), but I was thinking recently that I could rewrite it to tell me whenever the external ip address of the computer changes, such as if someone stole one of my linux computers and booted it far enough for my cron job to be able to fire. That depends on the computer being connected to the internet when the script runs, but updating the script was interesting enough to be worth doing even if there’s very little chance of it being overly useful.

I’m building off of code I wrote a while ago, so the parts that work won’t have much commentary on what it took to write them.

Calling Home

The first (and most important part) is the script to notify you when it decides it needs to. I chose email because I expected it to be pretty easy (it was) and because always having an email in my inbox that contained the ip address of my server seemed useful.

A quick search on “python send email” turned up a docs.python.org page with the basics, so that’s might have been where I started. I wanted a general script that I could call from other places, but I didn’t want to include the login info for the server every time so I ended up with this script.

The username, password, and email address are obviously not actually all ‘*’s, but I didn’t particularly want to post my gmail info. The smtpuser that my version of the script uses is everything before the @ in my gmail address, and the smtppass has to be a valid password for your account, though interestingly it was willing to accept my last password (my password changed after I wrote the script and it still worked). Giving it an invalid password raised an exception at session.login(smtpuser, smtppass) with a link to a gmail support page.

The documentation example I linked above used another library for setting up the body of the message, but joining the header lines I have with line breaks works too. The "", # extra line break comment is a required blank line for it to parse correctly as an email.

Checking your IP

Once your script can notify you, it has to be able to tell when it needs to. My original script logged onto my router (a linksys), opened the status page, and parsed the external ip. That obviously depends on your computer being at home where it’s able to log into the router. A more general solution is to check a website for the ip address it sees you connecting from.

Since I have web hosting and wasn’t sure that sites like whatismyip would like being called regularly from a script I looked up the php to display the external ip of the requesting computer. I don’t really want my site to be hit be any random person looking for a machine-friendly ip address site, so it’s in a passworded section of my site, but here’s the html of my getip.php file:

<html><body>
<?php echo $_SERVER['REMOTE_ADDR']; ?>
</body></html>

Note: All block code formatting and syntax highlighting is done through code2html.

Since I’m fetching the ip address from an html page behind a password I had to find a way to have python log in. I ended up using urllib2:

uri = "http://192.168.1.1/"
username = "********"
password = "********"
page = "http://192.168.1.1/Status_Router.asp"

def get_ip() :
	pass_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
	pass_mgr.add_password(None, uri, username, password)

	auth_handler = urllib2.HTTPBasicAuthHandler(pass_mgr)
	opener = urllib2.build_opener(auth_handler)
	urllib2.install_opener(opener)
	
	handle = urllib2.urlopen(page)
	site_text = handle.read()

	match = re.search("var wan_ip = \"([\d\.]+)\";", site_text)
	#print match.group(1)

	my_ip = match.group(1)

	return (time.asctime(), my_ip)

The uri and regex in that snippet are for my linksys router. For the php code earlier in this post I’m matching on "([\d\.]+)". The return statement gives the time the ip address was taken and the ip string. I keep a log file with that data pair so I can see when the ip address changed, but that’s just python file io, so I need the time at some point and making a tuple here was easiest.

The entire script (including the error handling I trimmed out of the snippet) is posted here.

Scheduling

No matter how fancy your script is, it’s useless if it doesn’t actually get run. Since I’m running it on linux cron seemed like the easiest way to go. Once the script was there to tell me if my ip address changed I didn’t want to run it too often, but I did want it to run regularly. I settled for running it once an hour, and I think I’ll stick with that:

# to deactivate (all cron jobs): crontab -r
# to activate : crontab ./cronip
MAILTO=*username*@localhost
0 * * * * /home/*username*/scripts/ipcheck.py

The *username* should be the login of the user who the script is to be run as. If I remember correctly any errors or other output from the script will be mailed to the specified local user. I think there is a way to mail to an external user, but it required more setup than just typing an email address.

For the path to the script I wrote out the full path, but a relative path from your home directory might also work. The script will be run from the home directory, so any file input and output will be done from there unless an absolute path is specified.