Two big releases in just a few days! First there was BlowPass 0.60 and now my “secret project” is unveiled!
I give you, OurUNO.com! It’s a semi-socially edited site for UNO students to share reviews, news and generally help each other out. It’s a bit crippled in this first “beta” release, but I expect to get it in tip-top shape in no time as the core is very fleshed out.
Go take a look!
Just finished up BlowPass 0.60. This was a major overhaul of the system, and there are very few similarities between the 0.50 and 0.60. Here’s a quick roundup of every change (Or at least those I could remember.)
New Domain
That’s right, BlowPass now has it’s own domain, BlowPass.com Now you can get there quick, none of this sub-domain garbage anymore. This isn’t really a code change, but it’s still a nice feature.
Installer!
Just kidding that’s not done yet.
New Logo

Sexy new reflected logo. It can only be beat by…
New Layout
After months of market research we have a new layout.
It’s clean, it fits in an 800×600 screen and it’s very blue. Plus…
The Log Is Optional
If you don’t want to see the technobabble, don’t open it.
Partial JSON
Smaller responses mean faster loads. Hopefully I’ll get around to moving it all into JSON and then we’ll be even faster.
Compressed Libraries
Everything has been squashed by the DoJo thingy. (Or will be soon.)
Prototype 1.5
Because hipness matters.
Sorting
You can now sort your items by last modified date, name, or…
Item Type
There are now several item types, “Network Account”, “System Account” are active by default, and if you think there should be another, let me know!
Okay, wasn’t that exciting? Here’s something even more exciting, the planned changes for V0.70.
Cleaner Code
There are a lot of repetitive chunks that need making into function calls.
JSON
More JSON for transmission, less delimited strings. Also, switch JSON to native when we get to PHP 5.2
SSL
This kind of service really needs SSL, but I don’t have the $189 to get that done at this point. If you really want to be secure, do what I do, run it on your home machine with your own SSL cert.
Delete Functionality
Finally add the ‘delete’ button for items now that we’re using PHP sessions.
Create New Types
User created item types should be done soon too.
We’ll see how it goes from here, could be a few months before the next release.
It’s a momentous occasion! Today, as of 1/25/07, I am the top-ranked page on Google for the search terms “expired mayonnaise“.
All because of this little post: Expired Mayonnaise Really Doesn’t Taste All That Different. My mother would be so proud. I think I’m going to make a little tracker to see how long I can stay in spot #1. It will be a grand experiment in SEO.
I just scratched an itch I’ve had for a long time. I always hate how on my category pages and my archive pages the little “More Posts” box would display even if there were no posts. Also, I could never check and see if there were no “Newer” or no “Older” posts so I could still print the words out in non-link form.
I finally did something about it today. I started by looking through the codex, and finding nothing. So I started digging through the WP code looking for the posts_nav_link() which sorta did what I wanted, but just echoed to the page instead of returning. I found it in wp-includes/template-functions-links.php and started chopping it up.
In the end I came up with three functions for my ‘my-hacks.php’ file. I didn’t want to spend the time making it into a plugin since it’s not that big a deal. They aren’t terribly efficient, but they work and thats what matters. Also, I pre-pended jh to the function names so there wouldn’t be any chance of collisions.
Returns true if there are more posts, newer or older.
function jh_more_posts() {
global $paged, $result, $request, $posts_per_page, $wpdb, $max_num_pages;
if ( isset($max_num_pages) ) {
$max_page = $max_num_pages;
} else {
preg_match('#FROM\s(.*)\sGROUP BY#siU', $request, $matches);
$fromwhere = $matches[1];
$numposts = $wpdb->get_var("SELECT COUNT(DISTINCT ID) FROM $fromwhere");
$max_page = $max_num_pages = ceil($numposts / $posts_per_page);
}
if( !$paged )
$paged = 1;
if($paged == 1 && $paged == $max_page)
return false;
else
return true;
}
Returns true if there are more ‘older’ posts.
function jh_more_old() {
global $paged;
if( !$paged || $paged == 1)
return true;
else
return false;
}
Returns true if there are more ‘newer’ posts.
function jh_more_new() {
global $paged, $result, $request, $posts_per_page, $wpdb, $max_num_pages;
if ( isset($max_num_pages) ) {
$max_page = $max_num_pages;
} else {
preg_match('#FROM\s(.*)\sGROUP BY#siU', $request, $matches);
$fromwhere = $matches[1];
$numposts = $wpdb->get_var("SELECT COUNT(DISTINCT ID) FROM $fromwhere");
$max_page = $max_num_pages = ceil($numposts / $posts_per_page);
}
if( !$paged )
$paged = 1;
if($paged == $max_page)
return true;
else
return false;
}
Whoa! Post 100 for this little blog. Although at times it’s been a little weak on content, I think there have been enough good ones to outweigh them. Besides, this site is more for me than for anyone else.
As this is post 100, I’m required by a dubious interpretation of a little known Norwegian law to list my favorite posts so far. So here they are, slightly categorized.
Mildly Useful
http://www.velvetcache.org/2006/09/28/usb-apps/
http://www.velvetcache.org/2006/09/17/firefox-plugins/
http://www.velvetcache.org/2006/10/02/simple-php-caching/
http://www.velvetcache.org/2007/01/19/cleaning-up-e-books/
http://www.velvetcache.org/2007/01/08/renaming-your-the-folders/
http://www.velvetcache.org/2007/01/08/pop-can-bookmarkers/
Wordy And Thoughtful
http://www.velvetcache.org/2006/09/15/i-cant-be-your-john-cusack/
http://www.velvetcache.org/2006/11/01/rediscovery/
http://www.velvetcache.org/2006/09/19/complexity-vs-redundancy/
http://www.velvetcache.org/2006/09/20/linux-on-the-desktop/
http://www.velvetcache.org/2006/09/07/facebook-apis/
http://www.velvetcache.org/2006/10/03/moniker-junkie/
Now to the meat of this post!
When I was first hired at UNO I was given the transfer articulation site as a project. What they basically do is keep track from year to year what each class at a number of schools is equivalent to here at UNO. I wrote it pretty quick, and they’ve been slowly adding data by hand for a few months now.
It’s a lot of data to enter too. So far they only have one year of one school done. The old system was a series of static HTML pages, so they didn’t think they could load it into the new system. I didn’t agree fully, because although the pages were poorly written and differed from year to year, they had a standard table layout on each one. I got to work on the idea of extracting the old data and loading it into the new database.
The first thing to do was create a syntactically correct file, here’s a sample of part of one of the files:
...
Max.
Transfer Hours
Allowed
|
Comments
|
ARCH1300
|
Architectural Desktop I
...
Nasty, all-caps and they didn’t even close the tags. Ugly, ugly.
Luckily I knew of a secret weapon, HTML Tidy!
When run through with the appropriate flags I got this lovely version of the code:
...
Comments
|
|
ARCH1300
|
Architectural Desktop I
|
....
Okay, so running the tidy command on every file one at a time would be crazy, so I wrote up a short batch file to hit every single .html file with the tidy love. Please excuse the nasty one-lined-ness of it.
FOR %%f IN ("*.html") DO tidy %%f --char-encoding utf8 --clean yes --doctype strict --escape-cdata yes --indent auto --indent-attributes no --join-classes yes --output-xhtml yes --show-errors 99 --tidy-mark no --wrap 0 -m "%%f"
Okay, so now that we’ve got that beautified file, we need to parse it. To make life easier I stripped all the other tags out except for the table tags with PHP’s strip_tags(). I then regexed out anything that wasn’t inside the <table> tags and created my SimpleXML object with what was left over.
$filename = $_REQUEST['dir'].'/'.$_REQUEST['file'];
// Remove the space in fopen, it's a WordPress thing. :(
$handle = f open($filename, "r");
$contents = fread($handle, filesize($filename));
fclose($handle);
$contents = strip_tags($contents,'
');
if(preg_match('/([.\r\n]*)<\/table>/si', $contents, $matches)) {
print 'Will attempt to load. ';
$contents = $matches[0];
$xml = new SimpleXMLElement($contents);
if(!$xml) {
print 'Error! XML Didn\'t read right.';
exit();
}
print 'Load complete. Checking for expected structure. ';
if(trim($xml->tr[0]->td[0]) != 'Course') {
print 'Error! Structure not as expected. Dumping. ';
var_dump($xml);
exit();
}
}
A few loops and a whole lot of boring processing later and it’s all in the DB. But that’s the gist of the system and it’s frickin tight.
|