// このプログラムの著作権はオカタケにあります。
// グローバルオブジェクト
var global = this;
// 名前空間の管理 //
var jsutil_namespace="namespace.jsutil";
// 名前空間の追加
function addNamespace(object,namespace) {
	if(!(typeof namespace == "string"))throw Error("argument error");
	if(object[namespace] == undefined)
		object[namespace] = new Object;
	return object[namespace];
}

// クラス操作 //
// CSSのクラスを検索、追加または除去します。
function addClass(element,className) {
	removeClass(element,className);
	element.className += (getSeparater() + className);
	function getSeparater() {
		if(/\S/.test(element.className))
			return " ";
		else
			return "";
	}
}
function removeClass(element,className) {
	// クラス名は空白系文字で区切るが、使用可能な文字は規定されていない。
	var regExp = new RegExp("\\s*\\b" + className + "\\b\\s*");
	var matchStr = element.className.match(regExp);
	element.className = element.className.replace(regExp,getSeparater());
	function getSeparater() {
		if(matchStr == null) return "";
		if(element.className.indexOf(matchStr) == 0
		|| element.className.lastIndexOf(matchStr) == 0)
			return "";
		else
			return " ";
	}
}
function hasClass(element,className) {
	// クラス名は空白系文字で区切るが、使用可能な文字は規定されていない。
	var regExp = new RegExp("\\s*\\b" + className + "\\b\\s*");
	return regExp.test(element.className);
}

// << ブラウザ周辺部 >> //
var bw = new Object; // BrowserWrapper
void function() {
	// << ブラウザ判別と環境情報の設定 >> //
	bw.env = {};// 環境情報
	// DOM2.0完全対応か確認し環境情報を設定
	function _setDOMInfo() {
		with(document.implementation)
			return bw.env.dom = hasFeature("Core","2.0") && hasFeature("XML","2.0") && hasFeature("HTML","2.0")
			&& hasFeature("Views","2.0") && hasFeature("StyleSheets","2.0") && hasFeature("CSS","2.0") && hasFeature("CSS2","2.0")
			&& hasFeature("Events","2.0") && hasFeature("UIEvents","2.0") && hasFeature("MouseEvents","2.0")
			&& hasFeature("MutationEvents","2.0") && hasFeature("HTMLEvents","2.0")
			&& hasFeature("Range","2.0") && hasFeature("Traversal","2.0");
	}
	// Geckoベースか確認し環境情報を設定
	function _setGeckoInfo() {
		bw.env.gk = false;
		// マイルストーン形式は古すぎるので考慮しない。
		var productToken = navigator.userAgent.match(/(Gecko)\/(\d{8})/);
		var releaseVersion = navigator.userAgent.match(/rv:([^;,\s\(\)]*)/);
		if(productToken == null || releaseVersion == null)return false;
		bw.env.gk = true;
		bw.env.ua = productToken[1];
		bw.env.buildId = productToken[2];
		bw.env.cmpVer = (new BetaVerComparator(releaseVersion[1])).compare;
		return true;
	}
	// Operaか確認し環境情報を設定
	function _setOperaInfo() {
		bw.env.op = false;
		if(window.opera == undefined || window.opera.version == undefined)return false;
		bw.env.op = true;
		bw.env.ua = "Opera";
		bw.env.cmpVer = (new VerComparator(window.opera.version())).compare;
		bw.env.css1 = !document.compatMode == "BackCompat"
		/* Opera7用 */ && !document.compatMode == "QuirksMode";
		return true;
	}
	// IEベースか確認し環境情報を設定
	function _setIEInfo() {
		bw.env.ie = false;
		var productToken = navigator.userAgent.match(/(MSIE) (\d+.\d+)/);
		if(productToken == null)return false;
		/*@cc_on bw.env.ie = true;
		bw.env.ua = productToken[1];
		bw.env.cmpVer = (new VerComparator(productToken[2])).compare;
		bw.env.css1 = !(document.compatMode == "BackCompat");
		return true; @*/
		return false;
	}
	// 一般的なバージョン文字列を比較します。
	bw.VerComparator = VerComparator;
	function VerComparator(baseVer) {
		var This = this;
		this.compare = function(compVer) {
			var baseSubs = baseVer.split('.'), compSubs = compVer.split('.');
			var context = {};
			for(var i=0;i<Math.min(baseSubs.length,compSubs.length);i++) {
				context.index = i;
				context.baseLength = baseSubs.length;
				context.compLength = compSubs.length;
				var result = This.compareSub(context,baseSubs[i],compSubs[i]);
				if(result != 0)return result;
			}
			return baseSubs.length - compSubs.length;
		};
	}
	VerComparator.prototype.compareSub = function(context,baseVer,compVer) {
		if(!/^\d*$/.test(compVer))throw Error("argument error"); 
		if(!/^\d*$/.test(baseVer))return +1; 
		return (context.index==0?compAsInt:compAsFloat)(baseVer,compVer);
	};
	// ベータバージョンの可能性のあるバージョン文字列を比較します。
	bw.BetaVerComparator = BetaVerComparator;
	chainPrototype(BetaVerComparator,VerComparator);
	function BetaVerComparator(baseVer) {
		VerComparator.call(this,baseVer);
	}
	BetaVerComparator.prototype.compareSub = function(context,baseVer,compVer) {
		var baseParam = baseVer.match(/^(\d*)(b?)$/);
		var compParam = compVer.match(/^(\d*)(b?)$/);
		if(compParam == null)throw Error("argument error");
		if(baseParam == null)return +1;
		return VerComparator.prototype.compareSub(context,baseParam[1],compParam[1]) ||
			verPostfixCompare(baseParam[2],compParam[2]);
	};
	function compAsInt(baseVer,compVer) { return parseInt(baseVer)-parseInt(compVer); };
	function compAsFloat(baseVer,compVer) { return parseFloat("0."+baseVer)-parseFloat("0."+compVer); };
	function verPostfixCompare(baseVer,compVer) { return compVer.length - baseVer.length; }
	// 判別と環境情報の設定(確実な順から設定)
	bw.env.unknown = !(_setOperaInfo() || _setIEInfo() || _setGeckoInfo() || _setDOMInfo());
	// << ブラウザ依存部吸収用メソッド等 >> //
	// 文書の表示オブジェクトを取得
	bw.defaultView = !bw.env.ie?
		function(document) {return document.defaultView;}:
		function(document) {return document.parentWindow;};
	// 要素OBJECT内の文書を取得
	bw.contentDocument =!bw.env.ie?
		function(obj) {return obj.contentDocument;}:
		function(obj) {return obj.object;};
	// 関連するオブジェクトを削除する。
	bw.deleteRelatedObject = function(htmlElement) {
		// SCRIPT要素でFOR属性を持つ場合
		var scripts = document.getElementsByTagName("SCRIPT");
		for(var i=0;i<scripts.length;i++) {
			var script = scripts[i];
			if(script.htmlFor == htmlElement.id)
				script.parentNode.removeChild(script);
		}
	};
	// 最終的なスタイルを取得。
	// 返値の暗黙的なプロパティに短縮名でアクセスする事でスタイルを取得可能。
	// DOMでは返値のgetPropertyValueメソッドにスタイルの完全名を渡しても良い。
	// 注意:borderWidth等はgeckoでは計算されたピクセルに、IEではmidium等の値。
	bw.getComputedStyle = !bw.env.ie?
		function(element) {return document.defaultView.getComputedStyle(element,null);}:
		function(element) {return element.currentStyle;};
	// テキストの選択を解除する。
	bw.selectionRemove
		= _isDefineRmoveAllRanges()? function(){window.getSelection().removeAllRanges();}
		: _isDefineSelectionEmpty()? function(){document.selection.empty();}
		: function(){}; // Opera8は未対応
	function _isDefineRmoveAllRanges() { // gecko等
		return window.getSelection != undefined
			&& window.getSelection().removeAllRanges != undefined;
	};
	function _isDefineSelectionEmpty() { // IE等
		return document.selection != undefined
			&& document.selection.empty != undefined
	};
	// ブラウザ固有のドラッグ動作を抑止
	bw.preventDrag = !bw.env.ie?function(element) {
			bw.addEventListener(element,"mousedown",function(event){event.preventDefault();});
		}:function(element) {
			bw.addEventListener(element,"drag",function(){window.event.returnValue = false;});
		};
	// イベントオブジェクトの生成
	bw.createEvent = function(eventType) {
		var event = !bw.env.ie?
			document.createEvent(eventType):
			document.createEventObject();
		switch(eventType) {
		case "MouseEvents": return new bw.MouseEvent(event);
		default: return new bw.Event(event);
		}
	};
	// イベントオブジェクトの発火
	bw.dispatchEvent = !bw.env.ie?
		function(htmlElement,event) {
			var event = event.getEvent();
			return htmlElement.dispatchEvent(event);
		}:
		function(htmlElement,event) {
			event.preDispatch(htmlElement);
			var event = event.getEvent();
			return htmlElement.fireEvent("on"+event.type,event);
		};
	// イベントの取得
	bw.getEvent = function(event) {
		var _event = event || window.event;
		switch(_event.type) {
			case "click": case "mousedown": case "mouseup":
			case "mouseover": case "mousemove": case "mouseout":
				return new bw.MouseEvent(_event);
			default:
				return new bw.Event(_event);
		}
	};
	// 基本イベント
	bw.Event = function(event) {
		this.getEvent = function() {return event};
	};
	copy(bw.Event.prototype, {
		getType : function() { return this.getEvent().type; },
		getTarget : function() { return this.getEvent().target; },
		getCurrentTarget : function() { return this.getEvent().currentTarget; },
		stopPropagation : function() { this.getEvent().stopPropagation(); },
		preventDefault : function() { this.getEvent().preventDefault(); },
		// バブルやキャンセル可能性については変更不可能なIEに合わせる。
		initEvent : function(type) {
			with(_eventDefaults[type])
				this.getEvent().initEvent(type,canBubble,cancelable);
		}
	});
	if(bw.env.ie) copy(bw.Event.prototype, {
		getTarget : function() { return this.getEvent().srcElement; },
		getCurrentTarget : function() { return _currentTarget; },
		stopPropagation : function() { this.getEvent().cancelBubble = true; },
		preventDefault : function() { this.getEvent().returnValue = false; },
		// 発火時の参照用:type等はfireEventで無視される。
		// preDispatchはマウスイベントで発火前の前処理用。
		initEvent : function(type) { 
			this.getEvent().type = type;
			this.preDispatch = function(htmlElement) { delete this.preDispatch; };
		}
	});
	// IE用のcurrentTarget置き場
	var _currentTarget = null;
	// マウスイベント
	bw.MouseEvent = function(event) {
		bw.Event.call(this,event);
	};
	chainPrototype(bw.MouseEvent,bw.Event);
	copy(bw.MouseEvent.prototype, {
		// relatedTargetはAREA要素付近の挙動が統一出来ていないので注意！
		getScreenX : function() { return this.getEvent().screenX; },
		getScreenY : function() { return this.getEvent().screenY; },
		getClientX : function() { return this.getEvent().clientX; },
		getClientY : function() { return this.getEvent().clientY; },
		getCtrlKey : function() { return this.getEvent().ctrlKey; },
		getShiftKey : function() { return this.getEvent().shiftKey; },
		getAltKey : function() { return this.getEvent().altKey; },
		getRelatedTarget : function() { return this.getEvent().relatedTarget; },
		getButton : function() { return this.getEvent().button; },
		// バブルやキャンセル可能性については変更不可能なIEに合わせる。
		// view,metaKeyはIEに該当するプロパティが存在しません。
		initMouseEvent : function(type,detail,screenX,screenY,clientX,clientY,
				ctrlKey,altKey,shiftKey,button,relatedTarget) {
			this.getEvent().initMouseEvent(
				type,_eventDefaults[type].canBubble,_eventDefaults[type].cancelable,
				window,detail,screenX,screenY,clientX,clientY,
				ctrlKey,altKey,shiftKey,false,button,relatedTarget);
		}
	});
	if(bw.env.ie) copy(bw.MouseEvent.prototype, {
		getRelatedTarget : function() {
			switch(this.getEvent().type) {
			case "mouseover":return this.getEvent().fromElement;
			case "mouseout":return this.getEvent().toElement;
			default:return null;
			}
		},
		getButton : function() {
			switch(this.getEvent().type) {
			case "click":case "mousedown":case "mouseup":
			if(this.getEvent().button & 0x2)return 2;// 右
			if(this.getEvent().button & 0x1)return 0;// 左
			if(this.getEvent().button & 0x4)return 1;// 中央
			default:return new Number;
			}
		},
		initMouseEvent : function(
				type,detail,screenX,screenY,clientX,clientY,
				ctrlKey,altKey,shiftKey,button,relatedTarget) {
			var event = this.getEvent();
			event.type = type; // 発火時の参照用
			event.screenX = screenX;
			event.screenY = screenY;
			event.clientX = clientX;
			event.clientY = clientY;
			event.ctrlKey = ctrlKey;
			event.altKey = altKey;
			event.shiftKey = shiftKey;
			event.button = (button==0)?1:(button==1)?4:(button==2)?2:new Number;
			event.fromElement = event.toElement = null;
			// fromElementとtoElementの設定(逆方向はdispatchEventで対象が提供されるまで保留)
			if(type == "mouseover")event.fromElement = relatedTarget;
			if(type == "mouseout")event.toElement = relatedTarget;
			this.preDispatch = function(htmlElement) {
				delete this.preDispatch;
				if(type == "mouseover")event.toElement = htmlElement;
				if(type == "mouseout")event.fromElement = htmlElement;
			};
		}
	});
	// イベントリスナの登録
	bw.addEventListener = 
		// [IE Bug KB890900]対策
		(bw.env.ie && bw.env.cmpVer("7.0") < 0) ? function(element,eventName,handler) {
			var isFirst = _addEventForIE(element,eventName,handler);
			if(!isFirst) return;
			else if(element != window) element.removerId = element.addBehavior("remover.htc");
			else window.attachEvent("onunload",_cleanupWindow);
		}:
		// IE7以上
		bw.env.ie ? function(element,eventName,handler) {
			_addEventForIE(element,eventName,handler);
		}:
		// [Bugzilla Bug 174320],[Bugzilla Bug 241518]対策
		(bw.env.gk && bw.env.cmpVer("1.8.1") < 0) ? function(element,eventName,handler,capture) {
			var funcSet = _reserveFuncSet(element,eventName);
			if(funcSet.empty())
				element.addEventListener(eventName,_listenerForGeckoWithBug,capture);
			funcSet.set(handler);
		}:
		// DOM標準
		function(element,eventName,handler,capture) {
			element.addEventListener(eventName,handler,capture);
		};
	// イベントリスナの削除
	bw.removeEventListener = 
		(bw.env.ie && bw.env.cmpVer("7.0") < 0) ? function(element,eventName,handler) {
			var isLast = _removeEventForIE(element,eventName,handler);
			if(!isLast)return;
			else if(element != window) element.removeBehavior(element.removerId);
			else window.detachEvent("onunload",_cleanupWindow);
		}: 
		bw.env.ie ? function(element,eventName,handler) {
			_removeEventForIE(element,eventName,handler);
		}:
		(bw.env.gk && bw.env.cmpVer("1.8.1") < 0) ? function(element,eventName,handler,capture) {
			var funcSet = _getFuncSet(element,eventName);
			if(funcSet == undefined)return;
			funcSet.remove(handler);
			if(funcSet.empty())
				element.removeEventListener(eventName,_listenerForGeckoWithBug,capture);
		}:
		function(element,eventName,handler,capture) {
			element.removeEventListener(eventName,handler,capture);
		};
	function _reserveFuncSet(element,eventName,capture) {
		var jsutilElement = addNamespace(element,jsutil_namespace);
		if(!jsutilElement.bubbles)jsutilElement.bubbles = {};
		if(!jsutilElement.captures)jsutilElement.captures = {};
		var handlers = capture?jsutilElement.captures:jsutilElement.bubbles;
		if(!handlers[eventName])handlers[eventName] = new jsutil.FuncSet;
		return handlers[eventName];
	}
	function _getFuncSet(element,eventName,capture) {
		var jsutilElement = addNamespace(element,jsutil_namespace);
		var handlers = capture?jsutilElement.captures:jsutilElement.bubbles;
		if(!handlers)return undefined;
		return handlers[eventName];
	}
	function _listenerForGeckoWithBug(event) {
		with(event) {
			var funcSet = _getFuncSet(currentTarget,type);
			funcSet.exec(currentTarget,arguments);
		}
	}
	function _addEventForIE(element,eventName,handler) {
		var funcSet = _reserveFuncSet(element,eventName);
		var isEmpty = funcSet.empty();
		if(isEmpty) {
			element.attachEvent("on" + eventName,funcSet.thisCall);
			funcSet.preExec = function() { _currentTarget = element; };
		}
		funcSet.set(handler);
		return isEmpty;
	}
	function _removeEventForIE(element,eventName,handler) {
		var funcSet = _getFuncSet(element,eventName);
		if(funcSet == undefined)return false;
		funcSet.remove(handler);
		var isLast = funcSet.empty();
		if(isLast)
			element.detachEvent("on"+eventName,funcSet.thisCall);
		return isLast;
	}
	function _cleanupWindow() {
		bw.cleanup(window);
	}
	// 要素のクリーンアップ
	bw.cleanup = function(element) {
		var jsutilElement = addNamespace(element,jsutil_namespace);
		var eventNames = new Array;
		// 登録されているイベント名の記録
		for(var eventName in jsutilElement.handlers)
		if(jsutilElement.handlers.hasOwnProperty(eventName))
			eventNames.push(eventName);
		for(var i=0;i<eventNames.length;i++) {
			var funcSet = _getFuncSet(element,eventNames[i]);
			if(funcSet == undefined)continue;
			element.detachEvent("on"+eventNames[i],funcSet.thisCall);
			jsutilElement.handlers[eventNames[i]] = null;
		}
	};
	// マウスイベントをウィンドウ外で追跡
	bw.setCapture = (document.documentElement.setCapture != undefined)? // IE
		function() { document.documentElement.setCapture(); }:bw.env.gk? // gecko系
		function() { 
			bw.addEventListener(document.documentElement,"mousemove",_mousemove,true);
			bw.addEventListener(document.documentElement,"mouseout",_mouseout,true);
		}:
		function(){}; // Opera未対応
	bw.releaseCapture = (document.documentElement.releaseCapture != undefined)? // IE
		function() { document.documentElement.releaseCapture(); }:bw.env.gk? // gecko系
		function() {
			bw.removeEventListener(document.documentElement,"mousemove",_mousemove,true);
			bw.removeEventListener(document.documentElement,"mouseout",_mouseout,true);
		}:
		function(){};// Opera未対応
	// AJAX
	bw.newXMLHttpRequest = window.XMLHttpRequest? function(){ 
			return new XMLHttpRequest(); 
		}: window.ActiveXObject? function() {
			var xObjects = ["Msxml2.XMLHTTP","Microsoft.XMLHTTP"];
			for(var i=0;i<xObjects.length;i++) try {
				return new ActiveXObject(xObjects[i]);
			} catch(e) { }
			return null;
		}: function() {return null};
	// XML
	bw.importNode = !bw.env.ie?
		function(docTo, node, deep) { return docTo.importNode(node, deep); }:
		function(docTo, node, deep) {
			var docFrom = node.ownerDocument;
			var toHTML = _isHTML(docTo), fromHTML = _isHTML(docFrom);
			return (!toHTML && !fromHTML)?
				node.cloneNode(deep):_convertDoc(docTo, node, deep);
		};
	// private //
	var _lastMouseEvent = null;
	function _mousemove(event) {
		_lastMouseEvent = event;
	}
	function _mouseout(event) {
		if(event.relatedTarget != null)return;
		var dumyMouseUpEvent = document.createEvent('MouseEvents');
		dumyMouseUpEvent.initMouseEvent('mouseup',
			// bubles,cancelable,view,detail
			true, true, window, 1, 
			_lastMouseEvent.screenX, // screenX
			_lastMouseEvent.screenY, // screenY
			_lastMouseEvent.clientX, // clientX
			_lastMouseEvent.clientY, // clientY
			// ctrlKey,altKey,shiftKey,metaKey,button,relatedTarget
			false, false, false, false, 0, null);
		 document.documentElement.dispatchEvent(dumyMouseUpEvent);
	}
	// 各イベントのデフォルトパラメタ
	// IEとDOMで挙動が違う物、abort,error,select,change,submit,reset,scrollには未対応
	var _eventDefaults = { 
		"click":new _EventDefault(true,true),
		"mousedown":new _EventDefault(true,true),
		"mouseup":new _EventDefault(true,true),
		"mouseover":new _EventDefault(true,true),
		"mousemove":new _EventDefault(true,false),
		"mouseout":new _EventDefault(true,true),
		"load":new _EventDefault(false,false),
		"unload":new _EventDefault(false,false),
		"focus":new _EventDefault(false,false),
		"blur":new _EventDefault(false,false),
		"resize":new _EventDefault(false,false)
	};
	function _EventDefault(canBubble,cancelable) {
		this.canBubble = canBubble;
		this.cancelable = cancelable;
	}
	function _convertDoc(docTo, node, deep) {
		switch(node.nodeType) {
		case 1: // ELEMENT_NODE
			if(_isHTML(docTo)) {
				var temp = docTo.createElement("div");
				var copyNode = deep?node:node.cloneNode(false);
				temp.innerHTML = copyNode.xml || copyNode.outerHTML;
				return temp.removeChild(temp.firstChild);
			} else {
				var newNode = docTo.createElement(node.tagName);
				var attributes = node.attributes;
				for (var i=0,I=attributes.length; i < I; i++)
					if (attributes[i].specified)
						newNode.setAttributeNode(arguments.callee(docTo, attributes[i], true));
				if(deep) importChildNodes(newNode, node);
				return newNode;
			}
		case 2: // ATTRIBUTE_NODE
			var newNode = docTo.createAttribute (node.name);
			newNode.value = node.value;
			return newNode;
		case 3: // TEXT_NODE
			return docTo.createTextNode(node.data);
		case 4: // CDATA_SECTION_NODE
			return docTo.createCDATASection(node.data);
		case 5: // ENTITY_REFERENCE_NODE
			return docTo.createEntityReference(node.nodeName);
		case 8: // COMMENT_NODE
			return docTo.createComment(node.data);
		case 11: // DOCUMENT_FRAGMENT_NODE
			var newNode = docTo.createDocumentFragment();
			if(deep) importChildNodes(newNode, node);
			return newNode;
		default: throw Error("not supported");
		}
		function importChildNodes(newNode, node) {
			var childNodes = node.childNodes;
			for (var i=0,I=childNodes.length;i<I;i++)
				newNode.appendChild(convertDoc(docTo, childNodes[i], true));
		}
	}
	function _isHTML(doc) {
		return doc.body != undefined;
	}
}();

// << EcmaScriptユーティリティ >> //
// プロトタイプ継承をコンストラクタの副作用無しに実現する。
/*
	普通、プロトタイプ継承は派生側のプロトタイプに基底側のインスタンスを
	指定する事で実現される。そのため、インスタンス作成による副作用を伴う。
	EcmaScript3rdEditionはオブジェクトの生成後にその継承元(プロトタイプ)
	を変更できない。(ただし、JavaScript1.3は__proto__で可能。)
*/
function chainPrototype(DerivedConstructor,BaseConstructor) {
	// 副作用の無い空のコンストラクタを生成する。
	var Empty = function(){};
	// プロトタイプを統一。これでinstanceof演算子は両者を同一とみなす。
	Empty.prototype = BaseConstructor.prototype;
	// 派生側のプロトタイプを指定。
	DerivedConstructor.prototype = new Empty;
	// コンストラクタを復元
	DerivedConstructor.prototype.constructor = DerivedConstructor;
}

// 配列の要素を引数にしてnew演算子を呼び出す。
function newApply(Constructor,argumentsArray) {
	// 副作用の無い空のコンストラクタを生成する。
	var Empty = function(){};
	// プロトタイプを統一。これでinstanceof演算子は両者を同一とみなす。
	Empty.prototype = Constructor.prototype;
	// 仮のインスタンスを生成
	var instance = new Empty;
	// applyを呼び出しnew演算子をエミュレートする。
	Constructor.apply(instance,argumentsArray);
	return instance;
}

// 残余引数を配列で取得します。
function getRestArguments(callerArguments) {
	var	expectedCount = callerArguments.callee.length;
	var actualCount = callerArguments.length;
	var restArguments = new Array(actualCount - expectedCount);
	for(var i=0;i<restArguments.length;i++)
		restArguments[i] = callerArguments[expectedCount+i];
	return restArguments;
}

// オーバライドが必要な関数のデフォルト値
function notOverrided() { throw Error("Not overrided."); }
// 何もしない関数
function nothingTodo() {};

void function() { with(global.jsutil = {}) {
	var myPackadge = new Packadge;
	var $set = myPackadge.setPackadge;
	var $reserve = myPackadge.reservePackadge;
	var $ = myPackadge.getPackadge;
// マップ
jsutil.Map = function() {
	if(arguments.length > 0)throw Error("argument error");
	var _this = $set(this);
	// ハッシュによりget,setの高速化。
	_this.hash = {};
	// リストによる走査の提供。
	_this.list = new List;
};
copy(jsutil.Map.prototype, {
	get : function(key) {
		with(new _EntryList($(this).hash,key))
			return search()?get().value:undefined;
	},
	/* * キー:keyに値:valueを設定します。
	 * 値が未指定の場合はキーと同じ値が使われます。
	 * */
	set : function(key,value) { with($(this)) {
		var isNewEntry,entry;
		with(new _EntryList(hash,key)) {
			isNewEntry = make();
			entry = get();
			entry.value = (value!=undefined)?value:key;
		}
		// リストに対する処理
		if(!isNewEntry)return;
		$(entry).listEntry = list.getEnd().addPrev(entry);
	} },
	remove : function(key) { with($(this)) {
		var _entry;
		with(new _EntryList(hash,key)) {
			if(!search())return;
			_entry = $(get());
			remove();
		}
		// リストに対する処理
		_entry.listEntry.remove();
	} },
	getLength : function() {
		return $(this).list.getLength();
	},
	iterator : function() { // ★一番最初のMapEntryを返してるだけ…★ //
		var listFirst = $(this).list.getFirst();
		return listFirst?listFirst.value:null;
	}
});
// エントリリストの管理用ヘルパ
function _EntryList(hash,key) {
	this.hash = hash;
	this.key = key;
	this.hashCode = jsutil.getHashCode(key);
	this.entryList = hash[this.hashCode];
	this.i=0;
}
copy(_EntryList.prototype, {
	search : function() { with(this) {
		if(entryList == undefined) return false;
		for(i=0;i<entryList.length;i++)
			if($(entryList[i]).key == key) return true;
		return false;
	} },
	make : function(value) { with(this) {
		if(entryList == undefined)
			entryList = hash[hashCode] = new Array;
		for(i=0;i<entryList.length;i++)
			if($(entryList[i]).key == key) return false;
		entryList.push(new MapEntry(key,null));
		return true;
	} },
	remove : function() { with(this) {
		entryList.splice(i,1);
		if(entryList.length == 0)
			delete hash[hashCode];
	} },
	get : function() { with(this) {
		return entryList[i];
	} }
});
// キーを読込専用にしたエントリ
jsutil.MapEntry = function(key,value) {
	var _this = $set(this);
	this.value = value;
	_this.key = key;
	_this.listEntry = null;
};
copy(MapEntry.prototype, {
	getKey : function() { return $(this).key; },
	getNext : function() {
		var nextListEntry = $(this).listEntry.getNext();
		return nextListEntry?nextListEntry.value:null;
	}
});
// リスト
jsutil.List = function() {
	var _this = $set(this);
	_this.start = new ListEntry(null,this);
	_this.end = new ListEntry(null,this);
	$(_this.start).next = _this.end;
	$(_this.end).prev = _this.start;
	_this.count = 0;
};
copy(List.prototype, {
	getLength : function() { return $(this).count; },
	getFirst : function() { return $(this).start.getNext(); },
	getLast : function() { return $(this).end.getPrev(); },
	getStart : function() { return $(this).start; },
	getEnd : function() { return $(this).end; }
});
// リストのエントリ
jsutil.ListEntry = function(value,list) {
	var _this = $set(this);
	this.value = value;
	_this.prev = _this.next = null;
	_this.list = list;
};
copy(ListEntry.prototype, {
	getPrev : function() { with($(this)) {
		return prev != $(list).start?prev:null;
	} },
	getNext : function() { with($(this)) {
		return next != $(list).end?next:null;
	} },
	addNext : function(value) { 
		if($(this).list.getEnd() == this)throw Error("argument error");
		return $(this).next.addPrev(value);
	},
	addPrev : function(value) { with($(this)) {
		if($(this).list.getStart() == this)throw Error("argument error");
		var entry = new ListEntry(value,list);
		$(entry).prev = prev;
		$(entry).next = this;
		$(list).count++;
		return prev = $(prev).next = entry;
	} },
	remove : function() { with($(this)) {
		if(!prev || !next)throw Error("argument error");
		$(prev).next = next;
		$(next).prev = prev;
		next = prev = null;
		$(list).count--;
	} }
});
// 関数の集合。
jsutil.FuncSet = function() {
	var This = this;
	$set(this).funcMap = new Map;
	/* * thisや引数を指定できない場面での正常な呼び出しを行う関数。 * */
	this.thisCall = function(){This.exec.call(This,this,arguments)};
};
copy(FuncSet.prototype, {
	/* * キー:keyに関数:fを設定します。
	 * 関数が未指定の場合キー自体を関数として扱います。
	 * */
	set : function(key,f) {
		$(this).funcMap.set(key,f);
	},
	remove : function(key) {
		$(this).funcMap.remove(key);
	},
	empty : function() {
		return $(this).funcMap.getLength()==0;
	},
	exec : function(thisArg,argumentsArg) {
		// 実行中の新たな追加や削除に備え現在のリストをコピー
		var funcMap = $(this).funcMap;
		functions = new Array;
		for(var i=funcMap.iterator();i!=null;i=i.getNext())
			functions.push(i.value);
		// 実行
		this.preExec();
		for(var i=0;i<functions.length;i++)
			functions[i].apply(thisArg,argumentsArg);
		this.afterExec();
	},
	preExec : nothingTodo,
	afterExec : nothingTodo 
});
// 値やオブジェクトのハッシュ値を得る。
jsutil.getHashCode = function(target) {
	var hashCode = target;
	if(target instanceof Object) {
		var _target = $reserve(target);
		if(!_target.hasOwnProperty("hashCode"))
			_target.hashCode = Math.random();
		hashCode = _target.hashCode;
	}
	return typeof target + ":" + hashCode;
};
} }();

function Packadge() {
	var This = this;
	this.setPackadge = function(obj) {
		var packValue = {};
		obj.getPackadge = function(key) {
			if(This != key)throw Error("access error");
			return packValue;
		};
		return packValue;
	};
	this.reservePackadge = function(obj) {
		return obj.getPackadge?obj.getPackadge(This):This.setPackadge(obj);
	};
	this.getPackadge = function(obj) {
		return obj.getPackadge(This);
	};
}

function copy(dist,source) {
	for(var i in source) dist[i] = source[i];
}
