I want a monopoly.

I really enjoy The Week Magazine. Every Monday I'm provided with an amusing overview of world events collated from often opposing editorials of the various news outlets worldwide. A filtered "best of the best" -- or -- to quote the byline: "All you need to know about everything that matters" ... It is an easy read, and is not blatantly skewed left or right. It usually gets 'my blood boiling' to see the editorials and articles nationwide ... The "Only in America" notes are especially embarassing.

My most recent fit of 'outrage' prompted by the Week was their coverage of the FCC Hearing in Boston. Comcast, with it's infinite collective intellect, paid "line standers" to hold places in line prior to the meeting happening. This was done to "allow Comcast employees interested in Net Neutrality" that were unable to get time off work to attend the meeting ... But it turns out the line holders were merely a mini "sleeper cell", most of whom had no interest in the hearing anyway -- riveting testimony -- to the point of boredom, and eventually slumber.

This is my proverbial straw. I call Comcast a monopoly. In my area, there is one cable service provider and one telephone service provider (who handles DSL and phone service). I have two choices: internet, or not. But I work from home in the tech industry, so going without internet isn't really a choice. I don't watch television, but am unable to have high-speed internet without "basic" digital cable -- I pay an additional $45 monthly with no choice in the matter, for a service I do not use. The same applies to Embarq, ultimately. In order to have DSL service, I would need local phone service -- something I am wholly uninterested (being one of the many who communicate exclusively via cellular) in, the minimum being somewhere around $35 monthly.

I'm okay with the money. I have come to terms with paying $90 monthly for internet connectivity (advertised as "always on internet") with the side effect of having moving pictures on the various televisions in my house. Unfortunately, the service is far from "always on" ... My most recent experience involved the service running for 5 minutes, and stopping for 2, then restarting. Just long enough for anything running relying on a connection to drop.

It happened for two days in a row, at which point I broke down and called support, asking for help. They believed me at the time, they were unable to ping my modem. They agreed to send a service tech "this afternoon". I called at 7am. Issues persist, though seemingly fixed at some point during the day. They called me asking if my service was okay, and I responded "yes, for now, but I still need a tech to come out -- there is something wrong with the signal or my modem, so please have the tech bring a spare and tester" ... The problems reappeared intermittently throughout the rest of the day. Finally, at 6pm, as I am about to leave for dinner, they call again verifying I'd like a tech to visit. "yes" ... The tech shows up at the door with no spare modem and no testing equipment whatsoever. When asked, the response was akin to "yah - we don't believe you are having trouble, and it wasn't worth carrying it in" ... I was immediately irritated.

Long story short, the tech ended up having to make two trips to the truck, which amused me because the extra trips up three flights of steps could have been avoided had they just brought the damn tester initially. I ended up with a new modem and an extensive lesson on signal strength tolerances. I was right, the signal was bad. My whole day wasted due to shotty service and dis-believing techs. What ever happened to "the customer is always right"? Just bring the bloody tester if I've taken the time to call, sit on hold listening to an annoying lady repeat new channel lineups, wondering all the while what a "friendful customer" is. (She says: "For friendful customers, our lineup has changed ... " ) ... This particular voice is like fingernails on a chalkboard, especially when you realize you've been on hold for 20 minutes and know "SportsSouthwest has been added on channel 23" because of the ten times she'd mentioned it prior.

Overall: I loathe having to call Comcast for anything. I am tolerant of short-lived outages (usually no more than 30 minutes at a time). One month, the service was out so often, I wrote a script to run on a local machine pinging various hosts on an interval to track "to the minute" how much service I had received. Thankfully, after _serveral_ calls and various requests to speak to supervisors, I convinced them to credit my account for a whole month of service, as my logs indicated I was working with around 25% uptime. Unfortunately, the credit never showed up on a bill, and my blatant refusal to actually pay them caused every subsequent bill to show up as "past due", at which point I would call them, verify the credit, and make sure I wasn't going to get a service shutoff. It took four months for the credit to go through and return me to a normal billing cycle.

Then we get into the traffic shaping going on, and all hell breaks loose. I get exceptional upspeeds for the first 10 seconds of any transfer. I can see progress go from 400k/s and immediately drop to 30k after 10 seconds. It seems any activity on BitTorrent ports causes a vast decrease in overall throughput, both up and down. My router showing 10 open connections, nothing excessive, and no explanation for why my connectivity is shot. Why would you even tolerate this kind of stuff, as a consumer? I pay for my service, and have done so on this same account for the past 5 years.

The newest, most fun experience: They don't believe I am me. I am now unable to modify, upgrade, downgrade, or cancel my service. For the past five years, It has not been an issue. Magically, a few days ago, I was asked to verify the last four digits of my social security number ... A question I don't usually get wrong ... unfortunately, somehow, someway, the SSN on file at Comcast is no longer mine, and because of which, I am unable to even ask about the account. They will accept payments from anyone, but require the SSN as an identifier (which if I'm not mistaken is illegal, but out of the scope of this discussion, there is probably some stipulation going on with account numbers, etc).

I decided not to act on it. It would be a waste of my time to go jump through the hoops required to prove my identity to them (which involves a trip to the office with an old bill, ID, and Social Security card in hand, and likely lots of waiting around). It simply isn't worth it to me. I've not modified the account in any meaningful way in years. When I finally do decide to dump Comcast (I've seriously considered getting a t1 or the likes directly, they are getting very cheap), I will have to have it shutoff for non-payment, which isn't an issue to me because it's not my social security number they will be sending the non-payment notification to. I told them it was their issue, and they should restore their records to the SSN that actually signed up the account. They claim there is no log of any change, but their logs "only go back so far" ... The have zero legal recourse should I, the individual paying the bill for the last 5 years, decide not to pay anymore. They can call me on the phone number listed in the account, but will be able to verify my Social Security Number. The worst they can do is turn off my service, which isn't really "always on" to being with.

If I had a choice, I would not use Comcast at all. Please support Net Neutrality -- The last thing I want is for my monopoly the dictate which points on the internet get priority throughput.

Google Analytics after onLoad

update: This was written during Dojo 1.1, and is outdated. The current documentation can be found at http://docs.dojocampus.org/dojox/analytics/Urchin, as some things have changed regarding parameters and setup since this blog post.

You've all seen it, especially in the Ajax world. The page is stalled, waiting to render, the status bar woefully proclaims "waiting for google-analytics.com ... " The culprit being the ever popular urchin tracker, and the [synchronous] script tags placed
at the bottom of your webpage:

 
<script type="text/javascript">
    var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
    document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
    var pageTracker = _gat._getTracker("UA-123456-7");
    pageTracker._initData();
    pageTracker._trackPageview();
</script>
 

This is usually before the body tag is closed, which causes [at least] Dojo's addOnLoad() function to wait until after ga.js has been loaded, and executed. I notice it most on the SitePen Dojo QuickStart guide. The whole guide is sent as valid HTML and CSS, then enhanced to break major sections into a custom tabbed view, with simple navigation. Unfortunately, all the code to do that is run from within an addOnLoad function, and my poor pitiful ethernets here in Tennessee make ga.js take upwards of five seconds to load. Long story short, sometimes I'm presented with a nasty jolt of rendering as the navigation is added, and the unselected chapters go hidden.

I decided it was a safe bet I could just append a script tag to my head element, and run that onLoad, allowing the rest of the code to execute as soon as the Dom was ready, regardless of Google being ready. This should work with any page that uses Dojo >= 0.9 ... I'm going to test it on this site for a while before considering making it another utility of the Toolkit. It's working so far, let's see if it picks up my traffic (the Analytics dashboard said it was getting data, but I just started it today, so I won't know until tomorrow).

This is just plain JavaScript, with some fancy scope magic for convenience. It uses Dojo because I do.

 
dojo.provide("dojox.analytics.ga");
dojo.mixin(dojox.analytics.ga, {
	// _acct: String
	//		your GA urchin tracker account numbers.
	_acct: dojo.config.urchin || "",
 
	// _loadInterval: Integer
	// 		time in ms to wait between checking again
	_loadInterval: 420,
 
	_loadGA: function(){
		// summary: load the ga.js file and begin initialization process
		var gaHost = ("https:" == document.location.protocol) ? "https://ssl." : "http://www.";
		var s = dojo.doc.createElement('script');
		s.src = gaHost + "google-analytics.com/ga.js";
		dojo.doc.getElementsByTagName("head")[0].appendChild(s);
		setTimeout(dojo.hitch(this, "_checkGA"), this._loadInterval);
	},
 
	_checkGA: function(){
		// summary: sniff the global _gat variable Google defines.
		// 		if it exists, run _gotGA, otherwise, do another interval
		setTimeout(dojo.hitch(this, window['_gat'] ? "_gotGA" : "_checkGA"), this._loadInterval);
	},
 
	_gotGA: function(){
		// summary: initialize the tracker, we've got ga.js loaded
		var ga = this._tracker = dojo.hitch(_gat, "_getTracker", this._acct)();
		ga._initData();
		ga._trackPageview();
		this.GAonLoad.apply(this, arguments);
	},
 
	GAonLoad: function(){
		// stub function to fire when urchin is complete
		// you also have access in this function to this._tracker, which is the
		// root tracker instance you called _initData() on
	}
 
}); 
 
// start it all up after body is ready:
dojo.addOnLoad(dojox.analytics.ga,"_loadGA");
 

I've hard-coded my UA-# into the code, but you would be able to define it as part of your djConfig variable, either before dojo.js is loaded:

 
<script type="text/javascript">
    var djConfig = { parseOnLoad:true, urchin:"UA-123456-7" };
</script>
 

or directly on the script tag:

 
<script src="dojo/dojo.js" djConfig="urchin: UA-123456-7, parseOnLoad:true"></script>
 

you can see the file is namespaced dojox.analytics.ga in the example. If the file were actually located there, you would be able to simply dojo.require("dojox.analytics.ga"); to include analytics tracking on any Dojo-enabled page.

update: It works! (or at least seems to.) All of yesterday's traffic apparently was tracked, and showed up in my analytics dashboard this morning.

update 2: This is now in trunk, as of revision [14006], and is known to work with 1.1 without issue. 1.0 is untested. It will be released with 1.2.

Ajax just got easier

This morning, Andi Gutman broke some very exiting news: The Zend Framework will be integrating Dojo 1.x! I am glad to be directly involved in the effort. It's a big win for both communities. Zend Framework users will have built-in Ajax support courtesy the Dojo Toolkit -- the easiest, most feature complete, liberally licensed JavaScript library available today. This integration is a perfect example of how a server-side technology and client-side goodness can work together to provide the best possible experience for developers maintaining projects, and the end users consuming them.

Sortable object

To follow up of Wolfram's blog about sorting an object hash by values, I thought i'd make a simple function to work on most single key-pair objects, the JavaScript version of an associative array:

 
var obj = {
	car: 300, bike:60, motorbike:200, airplane:1000,
	helicopter: 500, rocket: 8*60*60
};
 
function sortObj(theObj, idx){
	// summary: sort an object hash by a numerical value
	var sortable = [];
	for(var i in theObj){
		sortable.push([i, theObj[i]]);
	}
 
	sortable.sort(function(a,b){
		return a[idx] - b[idx];
	});
 
	var newObj = {};
	dojo.forEach(dojo.map(sortable,function(elm){
		return elm[0];
	}), function(elm){
		newObj[elm] = theObj[elm];
	});
	return newObj;
}
 
console.log(sortObj(obj,1));
 

Branching for IE

I'm working on a really cool demo, and it really pushes the limits of what our current offering of web browsers are capable of doing via JavaScript animations (yes, it's one of those flash-like UI's I recreated in DHTML with surprisingly good results) ... Anyway, it uses a lot of images, and they ALL have png alpha channels, making IE6 display this horrible pale green/blue outlay border we all know and love.

So I'm faced with an interesting twist on a common problem, and I think I found a solution I am happy with: Branch for IE6. This is no ordinary branch, mind you, this is the magical forced upgrade branch. Technically one line of javascript, a function, fired onLoad based on browser sniffing:

 
var newp = function(){
 // IE6 branch of this demo
 window.location.href = "http://" +
  (confirm("Is it 2008?") ?
   "webkit.org" : "mozilla.org") +
  "/";
}
 
// setup our branch launch:
dojo.addOnLoad((dojo.isIE < 7 ? newp : init));
 

I found humour in it ... It performs a whole lot better than 188 filter: directives, and really, I have no desire to put that burden on anyone's PC. It's 2008 folks, don't test out hot demos using Internet Explorer 6, you will usually be disappointed (when compared to the likes of Safari 3 and even IE7)

Please, Microsoft, for the love of jebus --- end of life IE6 so we, as innovators of the web, can push forward and stop wasting time supporting a near deceased browser anyway, which still has the highest percentage of market share due to your unwillingness to force people up to IE7 ... What version of IE will be out when you finally DO end-of-life it? 9? 10?

I have actually kind of grown to love ie7 -- minus some quirks (solved by dojo sniffing and css sniffing) and poor png support, it actually performs very well, and better than FF2 in some cases. (Granted ff3 picks up any slack ff2 left off, but that's the whole point of these "browser wars" anyway. keep pushing forward ... ) To that end, I reiterate: Microsoft, for the love of jebus ...

update: I've put the demo online.