function objShopUtils() {

	this.wins = {};
	this.IE = document.all?true:false;
	this.mouse_pos = {x:0,y:0};
	this.objID = Math.random();
	this.drag = null;

	// Simplify access from other scopes ...
	window[this.objID] = this;

	this.openPopWin = function(url, winName, winProps) {
		try { this.wins[winName].close(); } // Close any existing window with same name
		catch(e) { } // Don't react if there's no window object to close
		this.wins[winName] = window.open(url, winName, winProps);
	}

	this.trackMouse = function() {
		// Handler to handle scope issues when getCursorPosition called from document scope ...
		eval("this.getCursorPosHandler = function(e) { window[" + this.objID + "].getCursorPosition(e); }");
		if (!this.IE) document.captureEvents(Event.MOUSEMOVE)
		document.onmousemove = this.getCursorPosHandler;			
	}

	this.startDrag = function(el) {
		if(el.style) {
			var pos = this.getPosition(el);
			if(pos) {
				this.drag = {element:el};
				this.drag.x_offset = this.mouse_pos.x - pos.x;
				this.drag.y_offset = this.mouse_pos.y - pos.y;
				document.onstartdrag = function() { return false; }
				return true;
				// NB - return the inverse of this to cancel selection mode when dragging
			}
		}
		window.status = "Error: invalid element passed to startDrag()";
		return false;
	}

	this.getPosition = function(el) {
		try {
			var left = el.offsetLeft;
			var top  = el.offsetTop;
		} catch(e) {
			window.status = "Error: couldn't get element position";
			return false;
		}
		while (el = el.offsetParent){ // Iterate up to outer container
			left += el.offsetLeft;
			top  += el.offsetTop;
		}
		return {x:left, y:top};
	}

	this.stopDrag = function() {
		this.drag = null;
	}
 
	// Cross-browser quirks-mode-corrected cursor position ...
	this.getCursorPosition = function(e) {
		if(this.IE) {		
			this.mouse_pos.x = event.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
			this.mouse_pos.y = event.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
		} else {
			this.mouse_pos.x = e.pageX;
			this.mouse_pos.y = e.pageY;
		}
		if(this.drag) {
			this.drag.element.style.left = (this.mouse_pos.x - this.drag.x_offset) + 'px';
			this.drag.element.style.top = (this.mouse_pos.y - this.drag.y_offset) + 'px';
		}
		return this.mouse_pos;
	}

	// Hack to make CSS-based dynamic tree menus work in IE6
	// li:hover doesn't work in IE6 so all <li> elements need a mouseover instead ...
	// Call activate_menu with the ID of the top-level <ul> of each menu in page
	this.activate_menu = function(ul_name) {
		try {
			this.activate_ul(document.getElementById(ul_name));
		} catch(e) {
			window.status = "Error activating menu (" + ul_name + ") - check element name";
		}
	}
	this.activate_ul = function(obj_ul) {
		for (var i=0; i<obj_ul.childNodes.length; i++) {
			var node = obj_ul.childNodes[i];
			if(node.nodeName=="LI") {
				node.onmouseover = function() { this.className = "over"; }
		  		node.onmouseout = function() { this.className = this.className = ""; }
				for(var j=0; j<node.childNodes.length; j++) {
					var ch_node = node.childNodes[j];
					if(ch_node.nodeName == "UL") this.activate_ul(ch_node);
			  	}
		   	}
		}
	}

}