↓ Twitter is updated more often, so read it! ↓

SVN is so WordPress 2.0: Updating your git-controlled WordPress

A couple of months ago, I wrote an article entitled SVN is so WordPress 2.0: Using git to manage a WordPress 3.0 installation. This article explained how to migrate an existing WordPress installation to a git-managed installation, much like using Subversion to manage it.

That post detailed how to migrate and the instructions could very easily be adapted to create a new installation. This post details how to upgrade to the latest release of WordPress whenever it is released.

Unfortunately, I’ve found that the WordPress team, perhaps git-svn, doesn’t import svn tags, so we need to do some sleuthing to find out exactly which tag to use.

The first stop is finding out the last svn revision used for the tag. Use this command to do so. Replace the version number with the one applicable to the upgrade you wish to perform.

svn log -v -q --stop-on-copy http://svn.automattic.com/wordpress/tags/3.0.1/ | less

The output of that for me is this:

------------------------------------------------------------------------
r15479 | nacin | 2010-07-29 17:57:26 -0400 (Thu, 29 Jul 2010)
Changed paths:
   M /tags/3.0.1/wp-includes/capabilities.php
   M /tags/3.0.1/wp-includes/version.php
------------------------------------------------------------------------
r15477 | ryan | 2010-07-29 17:09:29 -0400 (Thu, 29 Jul 2010)
Changed paths:
   A /tags/3.0.1 (from /branches/3.0:15476)
------------------------------------------------------------------------

Looking at the revisions, I’m looking for a revision 15479 or shortly there after.

Next, I use the WordPress Codex entry for the release to find what date it was released. Version 3.0.1 was released July 29, 2010, so that gives me a pretty good approximate date for the last commit. The svn log above also shows this date, but I figured there might be some lag between the final commit and when the release came out. You could probably skip this step. Don’t judge me.

I then go to WordPress’s Github’s commit history on its master branch and look for a commit on the date above. There are two: 20812cf38b99a40a0e3c1d3dd5c2b3d20fb893b5 and 2f27661e1afffe16ecfbaf7a5b02db8f47e46482. Looking at the log for each, I see this line:

git-svn-id: http://core.svn.wordpress.org/trunk@15480 1a063a9b-81f0-0310-95a4-ce76da25c4cd

Revision 15480 is approximately right at the above, and looking at the changeset shows that this is probably what I want.

I do wish there was a commit which was right on, though.

So, now that I know the commit id, I can use it with git.

The rest is easy! Well, sorta. For the love of $deity, back up your blog, both the files and the database, before you do anything past here.

Once I’m in my git-versioned WordPress directory, I had a little bit of cleanup to do. I’d inadvertently added some files in wp-content/cache, so I had to manually remove them with git rm and also update my sitemap.xml and sitemap.xml.gz with git add sitemap.xml* and git commit.

Then, I could proceed.

git fetch gh
git merge 2f27661e1afffe16ecfbaf7a5b02db8f47e46482

Remember that you really only need to use enough of the commit id hash to uniquely identify the commit. If I recall correctly, seven characters is usually enough, and git will warn you if your choice is ambiguous. I used the full one because I copied and pasted.

Here’s my transcript from these commands so you know what it should look like:

[colin@convoy blog]$ git fetch gh
remote: Counting objects: 860, done.
remote: Compressing objects: 100% (591/591), done.
remote: Total 749 (delta 568), reused 202 (delta 155)
Receiving objects: 100% (749/749), 312.70 KiB, done.
Resolving deltas: 100% (568/568), completed with 104 local objects.
From git://github.com/wordpress/wordpress
   c39484b..6e44120  master     -> gh/master
[colin@convoy blog]$ git status
# On branch master
nothing to commit (working directory clean)
[colin@convoy blog]$ git merge 2f27661e1afffe16ecfbaf7a5b02db8f47e46482
Auto-merged readme.html
Merge made by recursive.
 readme.html                                        |    2 +-
 wp-activate.php                                    |    2 +-
 wp-admin/admin-ajax.php                            |   22 +-
 wp-admin/admin.php                                 |   12 +-
 wp-admin/edit-attachment-rows.php                  |    4 +-
 wp-admin/edit-tags.php                             |    7 +
 wp-admin/edit.php                                  |   11 +-
 wp-admin/export.php                                |   12 +-
 wp-admin/import.php                                |    2 +-
 wp-admin/includes/bookmark.php                     |    4 +-
 wp-admin/includes/class-wp-importer.php            |    5 +-
 wp-admin/includes/class-wp-upgrader.php            |   33 ++-
 wp-admin/includes/dashboard.php                    |    4 +-
 wp-admin/includes/deprecated.php                   |   10 +-
 wp-admin/includes/export.php                       |    2 +-
 wp-admin/includes/media.php                        |    2 +-
 wp-admin/includes/meta-boxes.php                   |    4 +-
 wp-admin/includes/ms.php                           |   48 ++--
 wp-admin/includes/nav-menu.php                     |    2 +-
 wp-admin/includes/plugin-install.php               |   13 +-
 wp-admin/includes/plugin.php                       |    3 +-
 wp-admin/includes/post.php                         |   20 +-
 wp-admin/includes/schema.php                       |    9 +-
 wp-admin/includes/template.php                     |  288 ++++++++---------
 wp-admin/includes/theme.php                        |    6 +-
 wp-admin/includes/update.php                       |    6 +-
 wp-admin/includes/upgrade.php                      |   12 +-
 wp-admin/includes/user.php                         |    8 +-
 wp-admin/install-helper.php                        |   10 +-
 wp-admin/install.php                               |    2 +-
 wp-admin/menu.php                                  |    4 +-
 wp-admin/ms-edit.php                               |   13 +-
 wp-admin/ms-sites.php                              |    5 +-
 wp-admin/nav-menus.php                             |   15 +-
 wp-admin/options-discussion.php                    |    2 +-
 wp-admin/options-permalink.php                     |   51 +---
 wp-admin/plugins.php                               |   23 +-
 wp-admin/press-this.php                            |    2 +-
 wp-admin/update-core.php                           |    4 +-
 wp-admin/user-new.php                              |    4 +-
 wp-app.php                                         |    2 +-
 wp-content/themes/twentyten/attachment.php         |   12 +-
 wp-content/themes/twentyten/editor-style.css       |    8 +-
 wp-content/themes/twentyten/functions.php          |   58 ----
 wp-content/themes/twentyten/header.php             |   16 +-
 .../themes/twentyten/languages/twentyten.pot       |  123 ++++----
 wp-content/themes/twentyten/loop.php               |   33 +-
 wp-content/themes/twentyten/page.php               |    8 +-
 wp-content/themes/twentyten/style.css              |  340 +++++++++-----------
 wp-includes/canonical.php                          |   14 +-
 wp-includes/capabilities.php                       |   12 +-
 wp-includes/category-template.php                  |    4 +-
 wp-includes/class-http.php                         |   54 ++--
 wp-includes/classes.php                            |    2 +-
 wp-includes/comment-template.php                   |   46 +++-
 wp-includes/cron.php                               |    8 +-
 wp-includes/default-filters.php                    |    2 +-
 wp-includes/default-widgets.php                    |    2 +
 wp-includes/deprecated.php                         |   19 +-
 wp-includes/feed.php                               |    2 +-
 wp-includes/formatting.php                         |   14 +-
 wp-includes/functions.php                          |   15 +-
 wp-includes/general-template.php                   |   11 +-
 wp-includes/kses.php                               |    4 +-
 wp-includes/link-template.php                      |    6 +-
 wp-includes/media.php                              |    2 +-
 wp-includes/meta.php                               |    2 +-
 wp-includes/ms-blogs.php                           |   20 +-
 wp-includes/ms-deprecated.php                      |   14 +-
 wp-includes/ms-functions.php                       |   27 +-
 wp-includes/ms-load.php                            |    7 +-
 wp-includes/nav-menu-template.php                  |   35 ++-
 wp-includes/nav-menu.php                           |   17 +
 wp-includes/post-thumbnail-template.php            |    2 +-
 wp-includes/post.php                               |   26 +-
 wp-includes/query.php                              |    3 +-
 wp-includes/taxonomy.php                           |   34 +-
 wp-includes/theme.php                              |    4 +-
 wp-includes/update.php                             |   47 ++--
 wp-includes/user.php                               |    4 +-
 wp-includes/version.php                            |    4 +-
 wp-includes/wp-db.php                              |    9 +-
 wp-signup.php                                      |    5 +-
 xmlrpc.php                                         |   10 +-
 84 files changed, 903 insertions(+), 872 deletions(-)
[colin@convoy blog]$ git status
# On branch master
nothing to commit (working directory clean)

The last thing to do is go to /wp-admin/upgrade.php in your browser. You’ll likely be redirected there when you hit the admin panel anyway, so it’s likely easier simply to do that.

Is managing the installation with git easier than managing it with svn? So far, not really. Subversion’s svn switch and WordPress’s use of SVN tags makes using git with it a little frustrating. If WordPress were ever to switch to git for real, then they’d likely use tags and all this searching would be moot. One could just switch branches and be done with it.

Got an easier way? Tell me in the comments.

Tonight’s dinner: chicken and sun-dried tomato pasta

plated. this is one of the most delicious meals I've made.

I went into tonight’s dinner primarily wanting chicken alfredo. After discovering that my jar of alfredo was a little, well, old, I decided to search the cupboards for alternative ingredients to match the chicken.

The result will go down in history as one of the most delicious dishes I’ve ever concocted. Now, I’m sure someone has done this at some point, but I’ll humor my ego and continue thinking that I’m somewhat original.

Has the picture already activated your salivary glands? It should have. Huzzah.

Here’s my recipe:

  • 1/2 pound diced, pre-cooked filet chicken
  • 1 can of olives
  • 1/2 – 3/4 cup of crumbled feta cheese
  • 1 cup of sliced/diced sun-dried tomatoes in olive oil and basil (I got it at Costco)
  • ~1/4 pound of pasta (I used capellini, but farfalle or fettuccine would work well, too)
  • 1 tablespoon of olive oil

Cook the pasta and drain it separately. You’ll eventually mix it with the rest.

Heat the chicken over medium heat in a large skillet until it’s fairly hot, then add the olive oil. Adjust the temperature slightly higher, but no so high that the olive oil fries the chicken. Add the tomatoes. Stir. Add the olives, crushing them by hand as you drop them into the skillet. Stir. Add the feta cheese. Stir. Heat for ~5 minutes until feta is slightly melted, stirring occasionally.

Taste it here to see if you want to add more tomatoes or oil or basil. I didn’t.

this chicken and sun dried tomato dish is looking soooo good

Once it’s sufficiently hot, mix with the noodles however you’d like. I mixed my capellini in the skillet, but the chicken mix could also be served on top of the noodles.

If you mix in the pasta, stir it thoroughly to coat it in oil and melted feta. Serve! I have enough to two large portions.

It’s probably quite possible to add some pine nuts, spinach, parmesean cheese, and/or additional basil.

As for a beverage pairing, stick to a berry fruit juice, lighter beer, or white wine. I had a Cerveza SOL (wp) with mine. It wasn’t ideal, but it sufficed.

If you try out this recipe, let me know in the comments how it goes.

New milestone: the longest I’ve lived anywhere

I realized today that as of yesterday, I’ve lived in my current dwelling longer than I’ve lived anywhere outside of my parents’ house. As of today, I’ve lived here in Regent Square for 368 days. I lived in Forest Hills for 366 days.

This is a little freaky for me, as I’ve moved around a lot since graduating high school, including a new dorm or apartment every year of college (not unusual, I know).

I’ll probably stay here at least until Brigette finishes school, but probably until a month or two after. Then, who knows?

VLC 1.1.0 released with GPU decoding

VLC 1.1.0 was just released few hours ago. VLC is a fantastic media player and I use it on all of the operating systems I use (Ubuntu Linux, Mac OS X, Windows 7). It’ll play just about any format and do it wonderfully. It’s easier to use than Rhythmbox, Quicktime, or Windows Media Player for watching movies or iTunes for quick listening of an audio file.

Anyway, among new features are VP8 support (Google’s newly open sourced video format), lossless MPEG-4 support, AMR-NB support for audio in cellphone video, CDDB/CDTEXT on Windows when listening to CDs, and lots more.

A big feature in this release of VLC is the ability to decode video using the computer’s graphics card. You’ll need an nVidia graphics card to really benefit from it, though.

I decided to give it a quick test myself before upgrading from VLC 1.0.5 on my Windows 7 box. I played back a 720p HD rip of Adventureland and Back to the Future 3. Both were encoded with 23.97 fps H264 for video. Adventureland used DTSfor audio, while Back to the Future 3 used a52. I watched about 5 minutes of each and watched the Task Manager. For both movies, the CPU usage stayed between 15% and 30%, while memory usage stayed around 92,000 kilobytes.

Then, I upgraded to VLC 1.1.0 and enabled GPU support in the preferences. I watched the same parts. Both videos used the slightly less CPU, but less memory.

“What gives?” I thought. So, I did some research. I found the wiki article on VLC GPU Decoding and found that a video card using VP2 or newer is required. There’s a link to a table on Wikipedia showing the version of PureVideo support in each video card. Unfortunately, my 8800 GTX doesn’t support VP2.

Oh well, I guess I get to wait for the next video card I buy. However, if you own a video card made in the last 3 years, you probably have support for it, so go forth and enjoy low CPU usage when you’re watching videos.

SVN is so WordPress 2.0: Using git to manage a WordPress 3.0 installation

Using Subversion to manage my WordPress installation was convenient and mindless. Whenever there was a new release of the blog software, I could hop to a terminal, back up my filesystem and database, and run svn sw http://svn.automattic.com/wordpress/tags/(new.version.number).

This worked great all through WordPress 2.x. However, when I tried to switch from 2.9.2 to 3.0, things broke. As in, “white screen with PHP failure message” broken. I hit the dreaded is_multisite error because something didn’t come in right or I’d accidentally modified something or maybe even the tag was out of date.

Regardless, I decided that in order to fix the problem, I needed to wipe out every file or directory which began with wp in my /blog directory and copy over from a fresh download of the package.

I mindlessly did this, then realized: “Oh crap, now I can’t upgrade with Subversion any more.”

I queried Twitter, asking So I went and deleted all of the .svn directories in my wp install. Is there a way I can put it back on svn without having to recopy stuff?. @steveklabnik quickly replied, jokingly, @colindean yeah, you just run ‘git init .’ ;) .

A troubleshooting conversation ensued, and then I found that WordPress maintains a GitHub repository.

Then it hit me: maintaining my WordPress installation with Subversion is so…WordPress 2.0. I’m on WordPress 3.0 now, it’s time to embrace modern distributed version control systems and use Git!

Steve, being an intrepid Rubyist friend and Git user, suggested how I could version my existing blog directory and add a git remote, then fetch and rebase, thereby syncronizing my local installation with an easy to use versioning system!

However, because it’s a development repository without any “tags”, I’ll have to remember to look for a specific commit whenever I upgrade.

I changed things up a bit and corrected order of things. Here’s what I did to get it working. Note that I’m a git newb and very open to suggestions if there’s a more succinct or overall better way to do this.

Note that I used git protocol for the repository (Github’s HTTP git seems to have problems completing transfers to my server).

Initialize the local repo and add what you have already:

git init
git add .
git commit

Add the remote, fetch and rebase:

git remote add gh git://github.com/wordpress/wordpress.git
git fetch gh
git rebase gh/master

At this point, I was informed that I had some files in wp-content/cache which needed to be deleted/updated. A quick git status showed that I’d versioned these cache files. Oops! You’ll have to do git rm <filename> for each of those, or just do git rm wp-content/cache.

Next, I added a few directories to .gitignore using my text editor of choice:

wp-content/cache/*
wp-content/uploads/*
wp-content/plugins/*
wp-content/themes/*

Then, I needed to merge in the 3.0 commit.

git merge 7cee95b6bba8bc867023ae0831e7538a8419a9f5

There were a few conflicts, but all were easily resolved. Use git add on each file needing resolved, then git commmit to finalize your changes. Once you commit, you’ll be up-to-date and merged with that version.

I’ll update this post or make another when the next release of WordPress is out to report how well the actual upgrade goes.

June mission update: walking to work daily [in progress]

I have so far kept up the mission. The first week, I walked to work every day.

The following week, I was in DC on a business trip, but I still walked from my hotel to the job site every day. It was closer—approximately 3/4 mile instead of the 1.6 miles from my apartment to the office, but I think I made up for it in the amount of walking I did every night after work. I didn’t use my car at all that week!

This past week, though, I hit an exception condition: “At some point during the day, I must leave work to go to something to which I cannot reasonably walk.” I had a package to send, and it was too heavy for me to reasonably carry it. I drove to work, returned, and went for a nice walk near dark.

What have I noticed? I’m certainly not as tired when I arrive at work as I was when I first started this. I’d get to work and be completely and utterly exhausted, and drenched in sweat. Three weeks in, I’m able to make it to work without being debilitated. I have a little more energy than I did before I started walking. I still need a jolt in the morning, usually getting a cup of coffee or tea around 10:30.

There are essentially two weeks remaining in the month. This next week is a normal week, while the following will be once again spent in DC. My hotel for this upcoming trip is considerably closer—one block away, so I’ll have to offset that with some walking around the monuments and Smithsonian. I didn’t make it to the Jefferson Memorial last time, so I’ll have to make sure I get there this time!

Oh, and if you’ve not seen them, check out my DC pictures.

National World War II Memorial [Mid-June 2010]

June mission: walk to work daily

For too long, I’ve put regular exercise in a priority below the various activities which follow work. I’ve favored hurrying home to watch a movie, write a review, or work on my coding projects to a healthy exercise regimen.

No movie, work, or project is more important than my health. I realized this a few months ago and have finally resolved to do something about it.

Somehow, I need to lose weight. I’ve not maintained my weight since Thanksgiving and Christmas were not kind to my attempted diet. I already eat fairly healthily, so the missing link is exercise.

I recognize that I could join a gym or something, but that costs money I’d rather not surrender and a time commitment which doesn’t fit into my schedule. How can I exercise without sacrificing too much time or money?

Regent Square to Squirrel Hill

Just an approximation, you stalker you

I believe I’ve found an acceptable exercise method: I will walk to and from work daily through June.

The trip normally takes approximately 15 minutes, including about 5 minutes of walking from where I normally park to my office building. It can reach half an hour on bad traffic days. Google Maps says that the trip is 1.6 miles and will take approximately 33 minutes. Fair enough.

In walking, I can get some exercise and savings perhaps a quarter per day in gas. I suppose when compounded through the month, I could save up to…$5.50 by walking. Maybe I’ll buy a beer to celebrate when the month is finished.

However, I recognize that there are certain times when walking will be a great inconvenience to me or my coworkers. I am permitted to drive under these very few conditions:

  • An injury sustained during the month makes the journey unbearable.
  • It is raining with such ferocity that an umbrella or rainsuit would be useless.
  • I awaken or would otherwise leave too late to arrive by 9:30.
  • At some point during the day, I must leave work to go to something to which I cannot reasonably walk.
  • I must go somewhere immediately after work and could not walk home in time to get my car and get to my destination.

If any of these conditions occur, I must go for at least a 30 minute walk after work in order to make up for it, unless it is unsafe for me to do so. If I am unable to walk for the day, there is no repercussion, as I can’t really think of anything to make up for it.

I tried this for the first time today. I was exhausted by the time I got to work, and I probably left my apartment just a little too late. I carried in my backpack a towel and an extra shirt. It was raining lightly, so I stopped at my car to get an umbrella. The journey back was far more pleasant, and I actually typed the majority of this blog post on my phone using WordPress for Android.

For future travels, I’ll likely wear my Jaybird bluetooth stereo headset and enjoy some tunes or audiobooks. The latter would likely help me power through some books I’ve been wanting to read, but have not found the time to read, such as Freakonomics: A Rogue Economist Explores the Hidden Side of Everything.

I don’t know if I’ll log my weight loss during the month, but I intend as of this moment to post again in a month’s time on this subject and hopefully report positive results.

Please help me on this, and help keep me to this. Thanks.

Letter to the Editor: Be fair about FairTax

Update 2010-06-03: This was letter was published in the Tribune-Review on Wednesday, June 2, 2010.

Sent via email 14 May 2010 to USAToday, Pittsburgh Post-Gazette, Pittsburgh Tribune-Review, Beaver County Times, New Castle News, and the Sharon Herald

Recently, nationally funded ads have mislead Pennsylvanians about the FairTax. These ads claim that the FairTax will add 23% to the cost of everything. This is true, but the ads omit the most important part of the tax reform plan.

What these ads irresponsibly fail to address is that the FairTax would fully rid citizens and businesses of income taxes, federal payroll taxes, inheritance and estate taxes, capital gains tax, social security and pension taxes, and the “marriage penality”. Additionally, it fails to mention a key provision: the prebate, a pre-refund of all taxes paid up to the poverty level, which amounts to $500 per month to a family of four.

Personally, I’d pay about 5% less tax with FairTax.

FactCheck, a nonprofit and non-partisan information verification agency set up by UPenn, agrees, calling these ads “false and misleading“.

While I appreciate the attention to the FairTax, it’s important that people know the facts and realize that they’d have more money to spend because they wouldn’t have any income tax taken out of their paychecks, plus the prebate gives another $500 per month, enough for food, or perhaps a car payment, or an iPad, whichever they deem fiscally responsible for their own needs.


Spongetech ($SPNG) executives arrested for securities fraud

It’s all over the stock world today that top executives, accountants, and others related to Spongetech Delivery Systems (SPNG) were arrested by the SEC, charged with securities fraud.

The top executives of Spongetech Delivery Systems Inc. (SPNG) were arrested and charged Wednesday in an alleged scheme to defraud investors by reporting falsely and grossly overstated sales figures.

According to a criminal complaint filed Wednesday, Michael Metter, Spongetech’s chief executive and president, and Steven Moskowitz, the New York pre-soaped sponge maker’s chief operating officer and chief financial officer, were charged with conspiracy to commit securities fraud and obstruction of justice. They each face up to five years in prison on the conspiracy charge.

The article, and others, go on to reveal that SPNG overstated its sales by up to 99%, the percentage of which its sales were to entities which don’t even exist.

SPNG down 83% on news its execs were arrested for securities fraud

SPNG ended the trading day today at .0069, an 83% drop.

I rode SPNG through the pump-and-dump scheme last June (SPNG dropped 27.66% yesterday, or how I learned many lessons about the stock market, Out of SPNG, 7% profit, back in and holding).

I bought back in shortly after and have been holding since. I added a small position in November, bringing my average from .15 to .095. I bought a tiny position today for $75, bringing my average to .08. I somewhat regret this decision, as I probably could have bought and sold more intraday if I had more cash in my account.

Timothy Sykes has a fantastic article on the mess: The Biggest Penny Stock Pump & Dump Ever? Possibly $250+ Million, SEC Alleges SpongeTech Scheme Sold 2.5 Billion Shares, Suckering Sports Fans Everywhere, What Do You Think?

If what the SEC alleges is proven true and SPNG executives did sell 2.5 billion shares, this may go down as the largest penny stock pump and dump in history (the stock rose from under a penny/share to 30 cents/share so you gotta figure an average selling price of 10-20 cents/share would yield $250-$500 million in allegedly illegal profits)…pretty amazing considering SPNG is getting sued by half a dozen sports teams like The NY Mets, NY Islanders, Chicago Bears & NY Giants as The NY Post recently pointed out (nope, they didn’t ask me for my opinion, I am simply linking to a published article FYI) for mere six figures (where did all the money go from these 2.5 billion share sales?)

I, to this day, which that I had listened to @_TheDean when he warned me the morning of June 12 that he thought SPNG was a pump and dump and that I should take my profits (~99%) and run. Considering my goal of stock trading is to risk a little bit of extra, unplanned income to help pay off my student loans, I’d have been more than 2/3 of the way there had I followed his advice (and perhaps that of Sykes).

Live and learn. Risk is risk.

Anyway, worst case scenario is that I lose the couple thousand dollars I have in SPNG and get to perhaps partake in a shareholder lawsuit. Best case scenario? Current execs serve their time and someone else comes in, and takes this .0069 dollar stock to a 1.00 dollar stock in a few years. No matter what, I’m in for the ride. Profits or bust on this one.

Ironically, I just watched Wall Street last night.

Decomposing, manipulating, and recomposing URLs in Javascript

I recently had a need to decompose a URL, do some stuff with the parameters, and reassemble it. I later had a need to take another URL and create a form on the fly, because using GET could overrun the URL character limit imposed by Internet Explorer.

Here’s my code for a decomposition and composition pair, plus the code to create a form dynamically using the output of the url_decompose() function.

/**
 * @param String url the URL to be decomposed
 * @return Object with full path in .path, params in arrays in .params
**/
function url_decompose(url){
    if(url.indexOf('?') == -1){ return {path: url, params: {} }; }
    path = url.substring(0, url.indexOf('?'));//get the path before the ?
    qs = url.substring(url.indexOf('?')+1);
    qsa = qs.split('&');
    params = new Object();
    for (var kv in qsa) {
        var kva = qsa[kv].split('=');
        var k = kva[0];
        var v = kva.slice(1, kva.length).join("=");
        params[k] = params[k] || new Array();
        params[k].push(v);
    }
    return {path: path, params: params};
}
/**
 * @param Object output of url_decompose()
 * @return String reassembled URL
**/
function url_compose(urlObject){
    if(!urlObject.path){return urlObject;}
    var urlString = '';
    var params = [];
    for (var kv in urlObject.params){
        if(kv.length > 0){
            params.push(
                encodeURIComponent(kv) +
                '=' +
                encodeURIComponent(urlObject.params[kv][0]));
        }
    }
    urlString = urlObject.path +
                    (params.length > 0 ? '?' + params.join('&') : '');
    return urlString;
}
/**
 * @param String path the path to be accessed
 * @param Array params associative array or object w/ params in key/value pairs
 * @param String method null for post or whatever method the form should use
**/
function do_post(path, params, method) {
    method = method || "post";
    var form = document.createElement("form");
    form.setAttribute("method", method);
    form.setAttribute("action", path);

    for(var key in params) {
      for(var idx in params[key]){
        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("type", "hidden");
        hiddenField.setAttribute("name", key);
        hiddenField.setAttribute("value", params[key][idx]);
        form.appendChild(hiddenField);
      }
    }
    document.body.appendChild(form);
    form.submit();
}

If I’ve omitted an edge case, please do let me know and I’ll amend my code. I really do need to get one of those code highlighter plugins installed now that I’m doing more code examples.