/**
 *	@filename		blades.js
 *	@charset		utf-8
 *	@author			COPYRIGHT (C) 2009 BLADES CO.,LTD. ALL RIGHTS RESERVED.
 *	@created		July 9, 2009
 *	@modified		July 9, 2009:VER. 1.0.0
 *					July 9, 2009:VER. 1.0.1
 *					July 10, 2009:VER. 1.0.2
 *					July 11, 2009:VER. 1.0.3
 *					July 13, 2009:VER. 1.0.4
 *					July 14, 2009:VER. 1.0.5
 *					July 15, 2009:VER. 1.0.6
 *					July 16, 2009:VER. 1.0.7
 *					July 17, 2009:VER. 1.0.8
 *					July 21, 2009:VER. 1.0.9
 *					July 22, 2009:VER. 1.1.0
 *					July 23, 2009:VER. 1.1.1
 *					July 28, 2009:VER. 1.1.2
 *					July 29, 2009:VER. 1.1.3
 *					July 31, 2009:VER. 1.1.4
 *					August 3, 2009:VER. 1.1.5
 *					August 6, 2009:VER. 1.1.6
 *					August 8, 2009:VER. 1.1.7
 *					August 11, 2009:VER. 1.1.8
 *					August 17, 2009:VER. 1.1.9
 *					August 18, 2009:VER. 1.2.0
 *					September 3, 2009:VER. 1.2.1
 *					October 2, 2009:VER. 1.2.2
 *					October 8, 2009:VER. 1.2.3
 *
 *	FOR MORE INFORMATION, VISIT OUR WEBSITE http://www.blades.co.jp/
 */
(function(){

var VERSION = "1.2.3";

var UNDEFINED;

//名前空間作成までのダミーオブジェクト作成
if(window.blades === UNDEFINED){
	window.blades = {};
}else{
	throw new Error("window.blades already exists!");
}

//当ファイル修正時にデバッグする場合のみ以下をtrueにしてください。
//他ファイル内でデバッグを行う場合はそのファイルの先頭でblades.debugModeをtrueにしてください。
blades.debugMode = true;

//
var PUBLIC = 1,
	INTERNAL = 2,
	PROTECTED = 3,
	PRIVATE = 4;

var ORIGINAL = "original",
	INHERITED = "inherited",
	OVERRIDDEN = "overridden",
	DEFINED_BY_INTERFACE = "defined by interface",
	ABSTRACT = "abstract";

var PROPERTY = "property",
	METHOD = "method";

var INTERFACE = "interface",
	CLASS = "class";

var createMemberList,
	createClass,
	createInterface,
	convertClass,
	createNamespace;

/**
 *	メンバリストを作成します。
 *
 *	メンバリストはインターフェイス及びクラスのメンバ情報（アクセス指定、final指定、abstract指定、その他）を管理します。
 *	このリストが管理するのはあくまでもメンバの有無とそのメンバの付随的な情報のみであり、プロパティの値やメソッドのコードは管理しません。
 *
 *	@return createMemberListオブジェクトを返します。
 *	@type Object
 */
createMemberList = function(){
	
	//リスト一覧
	var list = {};
	
	/**
	 *	メンバリストにメンバを登録します。
	 *
	 *	@param {String} name メンバ名
	 *
	 *	@return メンバ設定用のユーティリティー関数の一覧を返します。
	 *	@type Object
	 */
	var registerMember = function(name){
		
		//エラーチェック
		if(blades.debugMode && list[name]){
			throw new Error("ARGUMENT ERROR : createMemberList::registerMember : " + name + " already exists!");
		}
		
		//プロパティ一覧
		var access = 0;
		var isFinal = false;
		var isAbstract = false;
		var status = "";
		var type = "";
		var argLength = null;
		
		//メソッド一覧
		return{
			
			/**
			 *	アクセス指定設定用
			 *
			 *	@param {Number} val アクセス指定
			 */
			setAccess : function(val){
				
				//エラーチェック
				if(blades.debugMode){
					if(val !== PRIVATE && val !== PROTECTED && val !== INTERNAL && val !== PUBLIC){
						throw new Error("ARGUMENT ERROR : " + val);
					}
				}
				access = val;
			},
			
			/**
			 *	アクセス指定取得用
			 *	
			 *	@return アクセス指定
			 *	@type Number
			 */
			getAccess : function(){
				return access ? access : 0;
			},
			
			/**	
			 *	finalかどうかを真偽値で設定
			 *	
			 *	@param {Boolean} val メンバがfinalであるか
			 */
			setFinal : function(val){
				
				//エラーチェック
				if(blades.debugMode){
					if(val !== true && val !== false){
						throw new Error("ARGUMENT ERROR : " + val);
					}
				}
				isFinal = val;
			},
			
			/**	
			 *	finalかどうかを真偽値で取得
			 *	
			 *	@return メンバがfinalかどうかを真偽値で返します。
			 *	@type Boolean
			 */
			isFinal : function(){
				return isFinal;
			},
			
			/**
			 *	abstractかどうかを真偽値で設定
			 *	
			 *	@param {Boolean} メンバがabstractかどうかを真偽値で設定します。
			 */
			setAbstract : function(val){
				
				//エラーチェック
				if(blades.debugMode){
					if(val !== true && val !== false){
						throw new Error("ARGUMENT ERROR : " + val);
					}
				}
				isAbstract = val;
			},
			
			/**
			 *	abstractかどうかを真偽値で取得
			 *	
			 *	@return メンバがabstractかどうかを真偽値で返します。
			 *	@type Boolean
			 */
			isAbstract : function(){
				return isAbstract;
			},
			
			/**
			 *	メンバ情報を設定
			 *	
			 *	@param {String} val メンバ情報（"original", "inherited", "overridden"）を設定します。
			 */
			setStatus : function(val){
				
				//エラーチェック
				if(blades.debugMode){
					if(val !== ORIGINAL && val !== INHERITED && val !== OVERRIDDEN && val !== DEFINED_BY_INTERFACE){
						throw new Error("ARGUMENT ERROR : " + val);
					}
				}
				status = val;
			},
			
			/**
			 *	メンバ情報を取得
			 *	
			 *	@return メンバ情報（"original", "inherited", "overridden"）を返します。
			 *	@type String
			 */
			getStatus : function(){
				return status;
			},
			
			/**
			 *	メンバの種類を設定
			 *	
			 *	@param {String} val メンバの種類（PROPERTY : プロパティ, METHOD : メソッド）を設定します。
			 */
			setType : function(val){
				
				//	エラーチェック
				if(blades.debugMode){
					if(val !== PROPERTY && val !== METHOD){
						throw new Error("ARGUMENT ERROR : " + val);
					}
				}
				type = val;
			},
			
			/**
			 *	メンバの種類を取得
			 *	
			 *	@return メンバの種類（PROPERTY : プロパティ, METHOD : メソッド）を設定します。
			 *	@type String
			 */
			getType : function(){
				return type;
			},
			
			/**
			 *	メンバがメソッドの場合、引数の数を設定
			 *	
			 *	@param {Number} num 引数の数
			 */
			setArgLength : function(num){
				argLength = (num === UNDEFINED) ? null : num;
			},
			
			/**
			 *	メンバがメソッドの場合、引数の数を取得
			 *	
			 *	@return 引数の数を返します。
			 *	@type Number
			 */
			getArgLength : function(){
				return argLength;
			}
		};
	};
	
	return{
		
		/**
		 *	メンバリストにメンバを新規登録します。
		 *
		 *	@param {String} name メンバ名を設定します。
		 *	
		 *	@return registerMemberオブジェクトを返します。
		 *	@type Object
		 */
		register : function(name){
			list[name] = registerMember(name);
			return list[name];
		},
		
		/**
		 *	リストに任意のメンバが登録されているかを真偽値で返します。
		 *	
		 *	@param {String} name メンバ名を指定します。
		 *	
		 *	@return 指定されたメンバがメンバリストに存在するかを真偽値で返します。
		 *	@type Boolean
		 */
		has : function(name){
			if(list.hasOwnProperty(name)){
				return true;
			}else{
				return false;
			}
		},
		
		/**
		 *	リストに登録されているメンバのregisterMemberオブジェクトを取得します。
		 *	
		 *	@param {String} p メンバ名
		 *	
		 *	@return 指定したメンバのregisterMemberオブジェクトを返します。
		 *	@type Object
		 */
		get : function(p){
			return list[p];
		},
		
		/**
		 *	スーパークラスのメンバリストを継承します
		 *	(privateのメンバ情報は継承しません）
		 *
		 *	@param {Object} superList スーパークラスのcreateMemberListオブジェクトを指定します。
		 */
		extendsList : function(superList){
			superList.each(function(p){
				if(this.getAccess() < PRIVATE){
					
					//エラーチェック
					if(blades.debugMode && list[p]){
						throw new Error("ERROR : createMemberList::extendsList : " + p + " already exists!");
					}
					
					//メンバ新規登録
					list[p] = registerMember(p);
					
					//各プロパティをコピー
					list[p].setAccess(this.getAccess());
					list[p].setFinal(this.isFinal());
					list[p].setAbstract(this.isAbstract());
					list[p].setStatus(INHERITED);
					list[p].setType(this.getType());
					list[p].setArgLength(this.getArgLength());
				}
			});
		},
		
		/**	
		 *	インターフェイスのメンバリスト継承用
		 *	
		 *	@param {Object} superList implementするインターフェイスのcreateMemberListオブジェクトを指定します。
		 */
		implementsList : function(superList){
			superList.each(function(p){
				
				//implementsより先にextendsしてる場合にはlist[p]が存在している
				if(!list[p]){
					list[p] = registerMember(p);
					list[p].setStatus(DEFINED_BY_INTERFACE);
					list[p].setAccess(this.getAccess());
					list[p].setFinal(this.isFinal());
					list[p].setAbstract(this.isAbstract());
					list[p].setType(this.getType());
					list[p].setArgLength(this.getArgLength());
				}
			});
		},
		
		/**
		 *	メンバリストの各メンバ（registerMemberオブジェクト）へアクセスするためのIteratorです。
		 *
		 *	@param {function} func 各メンバに対して実行する関数を指定します。
		 *
		 *	・thisには各メンバ（registerMemberオブジェクト）がバインドされます。
		 *	・引数にはメンバ名が渡されます。
		 */
		each : function(func){
			for(var p in list){
				if(list.hasOwnProperty(p)){
					func.call(list[p], p);
				}
			}
		}
		/*
		_listUp : function(){
			var str = "listing...\n";
			for(var p in list){
				str += (p + "\n");
			}
			alert(str);
		}*/
	};
};



/**
 *	インターフェイスを作成します。
 *
 *	@return ユーティリティ関数の一覧を返します。
 *	@type Object
 */
createInterface = function(){
	
	//メンバリスト作成
	var memberList = createMemberList();
	
	//
	//	publicMembers
	//
	var publicMembers = {
		
		/**
		 *	インターフェイスにメソッドを定義します。
		 *	・メソッドのアクセス指定はpublicになります。
		 *	
		 *	@param {String} name メソッド名
		 */
		createMethod : function(name){
			var m = null;
			
			//新規登録
			m = memberList.register(name);
			
			//各プロパティ設定
			m.setAccess(PUBLIC);
			m.setStatus(DEFINED_BY_INTERFACE);
			m.setType(METHOD);
		},
		
		
		
		/**
		 *	インターフェイスを継承します。
		 *	
		 *	@param {Object} cSuperInterface 継承するインターフェイス（createInterfaceオブジェクト）を指定します。
		 *	
		 *	@return 自分自身（createInterfaceオブジェクト）をかえします。
		 *	@type Object
		 */
		extend : function(cSuperInterface){
			
			//エラーチェック
			if(blades.debugMode){
				if(cSuperInterface._util.getType() !== INTERFACE){
					throw new Error("ARGUMENT ERROR : createInterface::extend : " + cSuperInterface + " is not interface!");
				}
			}
			
			//memberListを継承(privateメンバの情報は継承されない）
			memberList.extendsList(cSuperInterface._util.getMemberList());
			
			//cSuperInterfaceは今後編集不可とする
			cSuperInterface._util.lock();
			
			return this;
		},
		
		
		
		/**
		 *	createClass/createInterface/createNamespaceインターフェイス内で使用されるユーティリティ関数の一覧です。
		 *	
		 *	@private
		 *	@type Object
		 */
		_util : {
			
			/**
			 *	createInterfaceオブジェクトかどうか
			 *
			 *	@return createInterfaceオブジェクトであることを示す文字列（INTERFACE）を返します。（createClassオブジェクトではCLASSを返します。）
			 *	@type String
			 */
			getType : function(){
				return INTERFACE;
			},
			
			/**
			 *	インターフェイスで定義されたメンバ情報（createMemberListオブジェクト）を取得します。
			 *
			 *	@return createMemberListオブジェクトを返します。
			 *	@type Object
			 */
			getMemberList : function(){
				return memberList;
			},
			
			/**
			 *	インターフェイス（createInterfaceオブジェクト）を編集不可にします。
			 */
			lock : function(){
				var newFunc = null;
				if(blades.debugMode){
					newFunc = function(){
						throw new Error("This interface object is LOCKED!");
					};
				}
				for(var p in publicMembers){
					if(publicMembers.hasOwnProperty(p)){
						if(p !== "_util"){
							publicMembers[p] = newFunc;
						}
					}
				}
			}
		}
	};
	return publicMembers;
};



/**
 *	クラスを作成します。
 *	
 *	これにより作成されるのはコンストラクタではありません。オブジェクト＆コンストラクタを内部に持つクロージャです。
 *	
 *	仕様：
 *		■コンストラクタ及びメソッド内でthis.変数名で宣言したメンバについて
 *			これらのメンバはメンバリスト管理の対象外です。
 *			アクセス指定はすべていかなる場合も（事実上）protectedになります。public/privateにすることはできません。
 *			publicとしてアクセスしたい場合はcreatePublicMethod()を用いてゲッタ／セッタを別途作成してください。
 *		
 *		■メソッドの作成について
 *			メソッドを0として作成した場合、そのメソッドはサブクラスで必ずオーバーライドされなければなりません。
 *			名前空間に追加時、オーバーライドされていない場合はエラーを投げます。
 *			
 *		■オーバーライドについて
 *		
 *		
 *		■継承について
 *			スーパークラスのコンストラクタは自動的に呼び出されます。
 *			例えば、以下のように継承している場合：
 *				Man → Monkey → Mammal
 *			呼び出される順番は 1)Mammalのコンストラクタ、2)Monkeyのコンストラクタ、3)Manのコンストラクタ となります。
 *			引数はインスタンス生成時の引数がそのまま渡されます。
 *			スーパークラスのコンストラクタ内でthis.変数名で宣言されたプロパティはそのスーパークラスのコンストラクタ実行時に宣言（＆値の代入）が行われます。
 *			よって、サブクラスのコンストラクタでは追加するプロパティをthis.変数名で宣言すればよいです。
 *			継承されたクラスはそれ以降createPublicMethod()などにより修正を加える（メソッド・プロパティの追加）ことはできません。
 *		
 *		■継承時のアクセス指定について
 *			継承時にはアクセス指定が必須です。
 *			privateで継承した場合は、public&protectedメソッド／静的メンバがprivateになります。
 *			protectedで継承した場合はpublicメソッド／静的メンバがprotectedになります。
 *			publicで継承した場合はアクセス指定に変更はありません。
 *			なお上述のとおり、this.変数名で宣言したメンバはprotectedのままとなります。
 *		
 *		■使用方法
 *			createClass()により作成したクラスは正確にはまだクラスではありません。
 *			名前空間のメソッドregisterClass()を使用しその名前空間に追加して初めて通常のクラスとして使用できます。
 *			名前空間に追加後はcreatePublicMethod()などによりそのクラスに対して修正を加える（メソッド・プロパティの追加）ことはできません。
 *			名前空間に追加後、継承された静的プロパティに値を代入すると内部の値と異なってしまいます。
 *			（これは静的プロパティの継承を「参照渡し」ではなく「値渡し」で行っているためです。）
 *	
 *	@param {function} code? コンストラクタ関数
 *	
 *	@return クラス作成用のユーティリティー関数の一覧を返します。
 *	@type Object
 */
createClass = function(code){
	
	//
	//	private properties
	//
	
	//実際のコンストラクタ
	//createPublicMethod等でメソッドを作成すると、このコンストラクタのprototypeにメソッドが追加される
	var realConstructor = function(){};
	
	//スーパークラスコンストラクタ
	//デフォルトでは空の配列だがextendsで他クラスを継承した場合、そのクラスのuserConstructorが代入される
	//var superUserConstructor = function(){};
	var superUserConstructors = [];
	
	//このクラスが任意のクラスを継承しているかどうかを表わす真偽値
	//extends()で他クラスを継承した場合にtrueが代入される
	var hasSuperClass = false;
	
	//このクラスがfinalかどうか
	var isFinal = false;
	
	//抽象クラスかどうか
	var isAbstract = false;
	
	//一番近いスーパークラスのメソッド一覧
	var superMethods = {};
	
	//ユーザーが記述したコンストラクタ + スーパークラスのユーザーが記述したコンストラクタ
	//スーパークラスのコンストラクタを先に実行する
	var userConstructor = function(){
		
		
		
		//自分自身のコンストラクタにはthis._constructorでアクセスできる
		this._constructor = arguments.callee;
		
		//スーパークラスのコンストラクタを自動呼出し
		//この際にthis._superが作成される
		//superUserConstructor.apply(this, arguments);
		for(var i=0, len=superUserConstructors.length; i<len; i++){
			superUserConstructors[i].apply(this, arguments);
		}
		
		//コンストラクタおよびメソッド内ではthis._super.メソッド名でスーパークラスのprotected/publicメソッドにアクセスできる
		var self = this;
		if(hasSuperClass){
			//this._superはスーパークラスのコンストラクタ実行時に生成されている可能性がある。
			if(!this._super || typeof this._super !== "object"){
				this._super = {};
			}
			for(var p in superMethods){
				if(superMethods.hasOwnProperty(p) && typeof superMethods[p] === "function"){
					this._super[p] = (function(p){
						return function(){
							return superMethods[p].apply(self, arguments);
						};
					})(p);
				}
			}
		}
		
		if(typeof code === "function"){
			code.apply(this, arguments);
		}
	};
	
	//createClassが返すオブジェクト
	//staticメンバはこのオブジェクトのプロパティとして追加されます。
	var createClassObject = {};
	
	//クラス作成用ユーティリティメソッド一覧
	//このオブジェクトのプロパティ(_util以外)はlockで使用不可となります。
	var createClassMethods = {};
	
	//メンバリスト作成
	var memberList = createMemberList();
	var staticMemberList = createMemberList();
	
	
	
	//
	//	private methods
	//
	
	/**
	 *	メソッドを作成します。
	 *	
	 *	@param {String} name メンバ名
	 *	@param {function} code メソッドの処理内容
	 *	@param {Number} access アクセス指定
	 *
	 *	@return メソッドをfinalにするためのasFinal()を返します。
	 *	@type Object
	 */
	var createMember = function(name, code, access, type, status){
		var m = null;
		var isAbstract = (status === ABSTRACT) ? true : false;
		
		if(memberList.has(name)){
			m = memberList.get(name);
			if(blades.debugMode){
				if(m.getStatus() !== DEFINED_BY_INTERFACE){
					if(m.getStatus() === INHERITED){
						throw new Error("ERROR : " + name + "() is inherited! Use override method!");
					}else{
						throw new Error("ERROR : " + name + "() is already defined!");
					}
				}
			}
		}else{
			//新規登録
			m = memberList.register(name);
		}
		
		//
		if(blades.debugMode && !isAbstract && typeof code !== "function"){
			throw new Error("You are creating method " + name + "(), but code is not function");
		}
		
		//各プロパティ設定
		m.setArgLength(code.length);
		m.setAccess(access);
		m.setStatus(ORIGINAL);
		m.setAbstract(isAbstract);
		m.setType(METHOD);
		
		//コンストラクタ設定
		realConstructor.prototype[name] = code;
			
		return {
			/**
			 *	メソッドをfinalとします。
			 */
			asFinal : function(){
				m.setFinal(true);
			}
		};
	};
	
	
	/**
	 *	静的メンバを作成します。
	 *
	 *	静的メンバは名前空間追加前はcreateClass()オブジェクトのプロパティとなります。
	 *	名前空間追加時、registerClass()で作成される疑似コンストラクタのプロパティとしてコピーされます。
	 *	この際、数値や文字列などは参照渡しではなく値渡しとなります。
	 *	よって、名前空間に追加後にこれらの静的プロパティに加えられた変更は内部の値（コピー元）と異なってしまいます。
	 *	以上の理由により静的メンバはconst、すなわち定数として扱ってください。
	 *
	 *	@param {String} name 静的メンバ名
	 *	@param {-} code 静的メンバの値
	 *	@param {Number} access アクセス指定
	 *	@param {String} type 静的メンバのタイプ（PROPERTY / METHOD）
	 *
	 *	@return メンバをfinalにするためのasFinal()を返します。
	 *	@type Object
	 */
	var createStaticMember = function(name, code, access, type){
		
		//エラーチェック
		if(blades.debugMode){
			if(staticMemberList.has(name) || createClassObject.hasOwnProperty(name)){
				throw new Error("ARGUMENT ERROR : createStaticMember : " + name + " is already defined!");
			}
			if(createClassMethods.hasOwnProperty(name)){
				throw new Error("ARGUMENT ERROR : createStaticMember : " + name + " is invalid!");
			}
			if(type === METHOD && typeof code !== "function"){
				throw new Error("ARGUMENT ERROR : createStaticMember : " + code + "() is not function!");
			}
		}
		
		//新規登録
		var m = staticMemberList.register(name);
		
		//各プロパティ設定
		m.setAccess(access);
		m.setStatus(ORIGINAL);
		m.setType(type);
		if(type === METHOD){
			m.setArgLength(code.length);
		}
		
		//静的メンバ設定
		createClassObject[name] = code;

		return {
			/**
			 *	メソッドをfinalとします。
			 */
			asFinal : function(){
				m.setFinal(true);
			}
		};
	};
	
	
	
	/**
	 *	スーパークラスのメソッドをオーバーライドします。
	 *	
	 *	@param {String} name メソッド名
	 *	@param {function} code メソッド内容
	 *	@param {Number} access アクセス指定
	 *
	 *	@return メンバをfinalにするためのasFinal()を返します。
	 *	@type Object
	 */
	var createMethodOverride = function(name, code, access){
		
		var m = memberList.get(name);
		
		//	エラーチェック
		if(blades.debugMode){
			
			//function出ない場合
			if(typeof code !== "function"){
				throw new Error(code + " is not function!");
			}
			
			//クラスを継承していない場合
			if(!hasSuperClass){
				throw new Error("Cannot override " + name + "()! This class extends no class!");
			}
			
			//メソッドが存在しない場合
			if(!m){
				throw new Error("Method : " + name + "() does not exist!");
			}
			
			//final指定の場合
			if(m.isFinal()){
				throw new Error("Cannot override " + name + "()! This method is final!");
			}
			
			//継承していないメソッドの場合（サブクラスで作成orオーバーライド済）
			if(m.getStatus() !== INHERITED){
				throw new Error("Cannot override " + name + "()! This method is " + m.getStatus() + " !");
			}
			
			//インターフェイスで定義されたメソッドの場合
			if(m.getStatus() === DEFINED_BY_INTERFACE){
				throw new Error("Cannot override " + name + "()! This method is " + m.getStatus() + " ! Use create[Access-here]Method()");
			}
			
			//アクセス指定子をチェック（protected をpublicにはできない等）
			if(m.getAccess() > access){
				throw new Error("Check access specifier! : You cannot override this method as " + access + "!");
			}
			
			//引数の数をチェック
			//メソッドがインターフェイスで定義された場合、もしくはabstractの場合、argLengthの値はデフォルトのnullである。
			var argLength = m.getArgLength();
			if(argLength !== null && argLength !== code.length){
				throw new Error("Check argument length! : " + name + "() has " + argLength + " argument(s), but new " + name + "() has " + code.length + "argument(s)!");
			}
		}
		
		//アクセス指定子を上書き
		m.setAccess(access);
		
		//オーバーライドされたのでabstractではない
		m.setAbstract(false);
		
		//ステータスを変更
		m.setStatus(OVERRIDDEN);
			
		//スーパークラスのメソッドを隠匿
		realConstructor.prototype[name] = code;
		
		return {
			/**
			 *	メソッドをfinalとします。
			 */
			asFinal : function(){
				m.setFinal(true);
			}
		};
	};
	
	/**
	 *	クラスを継承します。（内部用）
	 *	
	 *	@param {Object/function} cSuperClass createClassオブジェクト/コンストラクタ関数
	 *	@param {Number} access 継承時のアクセス指定
	 */
	var extend = function(cSuperClass, access){
		
		//blades.createClassオブジェクトでない場合は変換
		if(!cSuperClass._util){
			
			//すでに名前空間に追加されたクラスの場合
			if(cSuperClass.convert){
				cSuperClass = cSuperClass.convert();
				
			//通常のクラスの場合
			}else{
				cSuperClass = convertClass(cSuperClass);
			}
		}
		
		//エラーチェック
		if(blades.debugMode){
			//クラスかどうかチェック
			if(cSuperClass._util.getType() !== CLASS){
				throw new Error("ARGUMENT ERROR : createClass::extend : The argument is not class!");
			}
			
			//final指定をチェック
			if(cSuperClass._util.isFinal()){
				throw new Error("ARGUMENT ERROR : createClass::extend : Cannot extend final class!");
			}
		}
		
		//memberListを継承(privateメンバの情報は継承されない）
		memberList.extendsList(cSuperClass._util.getMemberList());
		
		//
		hasSuperClass = true;
		
		//スーパークラスのコンストラクターを設定
		//superUserConstructor = cSuperClass._util.getUserConstructor();
		superUserConstructors.push(cSuperClass._util.getUserConstructor());
		
		//prototypeをコピー
		var spr = cSuperClass._util.getRealConstructor();
		memberList.each(function(p){
			if(spr.prototype.hasOwnProperty(p)){
					
				//継承時のアクセス指定が元の指定よりも高い場合は上書き
				if(this.getAccess() < access){
					this.setAccess(access);
				}
				
				//メソッドをコピー
				realConstructor.prototype[p] = spr.prototype[p];
				
				//コンストラクタおよびメソッド内でthis._superで呼び出すためのメソッド登録
				superMethods[p] = spr.prototype[p];
			}
		});
		
		//staticMemberListを継承(privateメンバの情報は継承されない）
		staticMemberList.extendsList(cSuperClass._util.getStaticMemberList());
		
		//静的メンバをコピー
		staticMemberList.each(function(p){
			if(cSuperClass.hasOwnProperty(p)){
				
				//継承時のアクセス指定が元の指定よりも高い場合は上書き
				if(this.getAccess() < access){
					this.setAccess(access);
				}
				
				//メソッドをコピー
				createClassObject[p] = cSuperClass[p];
			}
		});
		
		//cSuperClassは今後編集不可とする
		cSuperClass._util.lock();
	};
	
	
	
	//
	//	createClassMethods
	//
	createClassMethods = {
		
		/**
		 *	静的private/protected/publicメソッドを作成します。
		 *	
		 *	@param {String} name メソッド名
		 *	@param {function} code メソッド内容
		 *
		 *	@return メンバをfinalにするためのasFinal()を返します。
		 *	@type Object
		 */
		createStaticPrivateMethod : function(name, code){
			return createStaticMember(name, code, PRIVATE, METHOD);
		},
		createStaticProtectedMethod : function(name, code){
			return createStaticMember(name, code, PROTECTED, METHOD);
		},
		createStaticPublicMethod : function(name, code){
			return createStaticMember(name, code, PUBLIC, METHOD);
		},
		
		/**
		 *	静的private/protected/publicプロパティを作成します。
		 *	
		 *	@param {String} name プロパティ名
		 *	@param {-} code 値
		 */
		createStaticPrivateProperty : function(name, val){
			createStaticMember(name, val, PRIVATE, PROPERTY);
		},
		createStaticProtectedProperty : function(name, val){
			createStaticMember(name, val, PROTECTED, PROPERTY);
		},
		createStaticPublicProperty : function(name, val){
			createStaticMember(name, val, PUBLIC, PROPERTY);
		},
		
		/**
		 *	private/protected/publicメソッドを作成します。
		 *	
		 *	@param {String} name メソッド名
		 *	@param {function} code メソッド内容
		 *
		 *	@return メソッドをfinalにするためのasFinal()を返します。
		 *	@type Object
		 */
		createPrivateMethod : function(name, code){
			return createMember(name, code, PRIVATE, METHOD);
		},
		createProtectedMethod : function(name, code){
			return createMember(name, code, PROTECTED, METHOD);
		},
		createPublicMethod : function(name, code){
			return createMember(name, code, PUBLIC, METHOD);
		},
		
		/**
		 *	protected/publicなabstractメソッドを作成します。
		 *	
		 *	@param {String} name メソッド名
		 *	@param {function} code メソッド内容
		 */
		createAbstractProtectedMethod : function(name){
			createMember(name, 0, PROTECTED, METHOD, ABSTRACT);
		},
		createAbstractPublicMethod : function(name){
			createMember(name, 0, PUBLIC, METHOD, ABSTRACT);
		},
		
		/**
		 *	スーパークラスのメソッドをprivate/protected/publicとしてオーバーライドします。
		 *	
		 *	@param {String} name メソッド名
		 *	@param {function} code メソッド内容
		 *
		 *	@return メソッドをfinalにするためのasFinal()を返します。
		 *	@type Object
		 */
		createPrivateMethodOverride : function(name, code){
			return createMethodOverride(name, code, PRIVATE);
		},
		createProtectedMethodOverride : function(name, code){
			return createMethodOverride(name, code, PROTECTED);
		},
		createPublicMethodOverride : function(name, code){
			return createMethodOverride(name, code, PUBLIC);
		},
		
		/**
		 *	任意のクラスをprivate/protected/publicで継承します。
		 *	
		 *	@param {Object/function} cSuperClass createClassオブジェクト/コンストラクタ関数
		 *	
		 *	@return カスケードを可能にするため自分自身（createClassオブジェクト）を返します。
		 *	@type Object
		 */
		extendsPrivate : function(cSuperClass){
			extend(cSuperClass, PRIVATE);
			return this;
		},
		extendsProtected : function(cSuperClass){
			extend(cSuperClass, PROTECTED);
			return this;
		},
		extendsPublic : function(cSuperClass){
			extend(cSuperClass, PUBLIC);
			return this;
		},
		
		/**
		 *	インターフェイスをimplementします。
		 *	
		 *	@param {Object} --- createInterfaceオブジェクト（複数指定可能）
		 *	
		 *	@return カスケードを可能にするため自分自身（createClassオブジェクト）を返します。
		 *	@type Object
		 */
		implement : function(){
			for(var i=0, len=arguments.length; i<len; i++){
				
				//エラーチェック
				if(blades.debugMode){
					
					//引数の型をチェック
					if(!arguments[i]._util || arguments[i]._util.getType() !== INTERFACE){
						throw new Error("ARGUMENT ERROR : createClass::implement : The argument is not interface!");
					}
				}
				
				//memberListを継承(privateメンバの情報は継承されない）
				memberList.implementsList(arguments[i]._util.getMemberList());
			}
			//createClassMethods.implement = null;
			return this;
		},
		
		/**
		 *	クラスをfinalとします。
		 *	
		 *	@return カスケードを可能にするため自分自身（createClassオブジェクト）を返します。
		 *	@type Object
		 */
		asFinal : function(){
			isFinal = true;
			return this;
		},
		
		/**
		 *	クラスをabstractとします。
		 *	
		 *	abstractクラスは名前空間に追加することはできません。
		 *	
		 *	@return カスケードを可能にするため自分自身（createClassオブジェクト）を返します。
		 *	@type Object
		 */
		asAbstract : function(){
			isAbstract = true;
			return this;
		},
		
		/**
		 *	createClass/createNamespaceオブジェクト内で使用されるユーティリティ関数の一覧です。
		 *	
		 *	@private
		 *	@type Object
		 */
		_util : {
			
			/**
			 *	createClassオブジェクトかどうか
			 *	
			 *	@return createClassオブジェクトであることを示す定数（CLASS）を返します。
			 *	@type String
			 */
			getType : function(){
				return CLASS;
			},
			
			/**
			 *	実際のコンストラクタを取得します。
			 *	
			 *	@return 実際のコンストラクタを返します。
			 *	@type function
			 */
			getRealConstructor : function(){
				return realConstructor;
			},
			
			/**
			 *	ユーザーが記述したコンストラクタを取得します。
			 *	
			 *	@return ユーザーが記述したコンストラクタを返します。
			 *	@type function
			 */
			getUserConstructor : function(){
				return userConstructor;
			},
			
			/**
			 *	メンバ情報一覧を取得します。
			 *	
			 *	@return createMemberListオブジェクトを返します。
			 *	@type Object
			 */
			getMemberList : function(){
				return memberList;
			},
			
			/**
			 *	静的メンバ情報一覧を取得します。
			 *	
			 *	@return createMemberListオブジェクトを返します。
			 *	@type Object
			 */
			getStaticMemberList : function(){
				return staticMemberList;
			},
			
			/**
			 *	クラスがfinalかどうかを真偽値で取得します。
			 *	
			 *	@return クラスがfinalかどうかを真偽値で返します。
			 *	@type Boolean
			 */
			isFinal : function(){
				return isFinal;
			},
			
			/**
			 *	クラスがabstractかどうかを真偽値で取得します。
			 *	
			 *	@return クラスがabstractかどうかを真偽値で返します。
			 *	@type Boolean
			 */
			isAbstract : function(){
				return isAbstract;
			},
			
			/**
			 *	クラスを編集不可とします。
			 */
			lock : function(){
				var newFunc = null;
				if(blades.debugMode){
					newFunc = function(){
						throw new Error("This class object is LOCKED!");
					};
				}
				for(var p in createClassMethods){
					if(createClassMethods.hasOwnProperty(p)){
						//if(p!=="_util" && !staticMemberList.has(p)){
						if(p!=="_util"){
							createClassMethods[p] = newFunc;
						}
					}
				}
			}
		}
	};
	
	//createClassObjectに直接静的メンバが宣言された場合にそれらと区別するため浅いコピーを作成。
	for(var p in createClassMethods){
		if(createClassMethods.hasOwnProperty(p)){
			createClassObject[p] = createClassMethods[p];
		}
	}
	return createClassObject;
};



/**
 *	通常のクラス（コンストラクタ関数）をcreateClassオブジェクトに変換します。
 *
 *	prototypeチェーン上のメソッドはすべてoriginalでpublicなメソッドとして登録されます。
 *	prototypeチェーン上のプロパティは無視されます。
 *	コンストラクタの静的メンバはすべてoriginalでpublicな静的メンバとして登録されます。
 *
 *	@param {function} klass コンストラクタ関数
 *
 *	@return createClassオブジェクト
 *	@type Object
 */
convertClass = function(klass){
	
	//エラーチェック
	if(blades.debugMode){
		if(typeof klass !== "function"){
			throw new Error("ARGUMENT ERROR : convertClass : " + klass + " is not a constructor!");
		}
	}
	
	var cKlass = createClass(klass);
	
	//静的メンバをpublicとして登録
	for(var p in klass){
		if(klass.hasOwnProperty(p)){
			if(typeof klass[p] === "function"){
				cKlass.createStaticPublicMethod(p, klass[p]);
			}else{
				cKlass.createStaticPublicProperty(p, klass[p]);
			}
		}
	}
	
	//prototypeチェーン上のメソッドをpublicメソッドとして登録
	//hasOwnPropertyはチェックしない
	for(var p2 in klass.prototype){
		if(typeof klass.prototype[p2] === "function"){
			cKlass.createPublicMethod(p2, klass.prototype[p2]);
		}
	}
	
	return cKlass;
};



/**
 *	@param {String} namespaceName 名前空間名(optional)
 *	@return {undefined/createInterfaceObject}
 *
 *	名前空間を作成します。
 *
 *	引数を省略することでprivateな名前空間を作成できます。
 *	その場合は機能がregisterClass()のみに制限されたcreateInterfaceオブジェクトを返します。
 */
createNamespace = function(namespaceName){
	var fullNamespaceName = "";
	namespaceName = namespaceName || "";
	
	if(namespaceName){
		//名前空間オブジェクトのメソッドとして呼び出された場合
		if(this.createNamespace && this.getFullNamespaceName){
			fullNamespaceName = [this.getFullNamespaceName(), ".", namespaceName].join("");
			
		//window.blades名前空間を作成する場合
		}else{
			fullNamespaceName = ["window.", namespaceName].join("");
		}
		
		//エラーチェック
		if(blades.debugMode){
			//var self = this === window ? window : this;
			//var self = this;
			//すでに同名のオブジェクトが存在していないか確認
			//if(self[namespaceName]){
			if(this!==window && this.hasOwnProperty(namespaceName)){
				throw new Error("ARGUMENT ERROR : " + fullNamespaceName + " already exists!");
			}
		}
	}
	
	//名前空間のユーティリティメソッド一覧
	var createNamespaceMethods = {
		
		//名前空間を作成します。
		createNamespace : arguments.callee,
		
		/**
		 *	名前空間名を取得します。
		 *
		 *	@return 名前空間名を返します。
		 *	@type String
		 */
		getFullNamespaceName : function(){
			return fullNamespaceName;
		},
		
		//通常のクラスをcreateClassオブジェクトに変換します。
		convertClass : convertClass,
		
		//createInterfaceオブジェクトを作成します。
		createInterface : createInterface,
		
		//インターフェイスを名前空間のプロパティとして追加します。
		registerInterface : function(interfaceName, interfaceObject){
			//エラーチェック
			if(blades.debugMode){
				//インスタンス作成時にはnewする必要はない（しても特に問題はないが）
				if(this[interfaceName]){
					throw new Error(interfaceName + " already exists!");
				}
			}
			
			var fullInterfaceName = fullNamespaceName + "." + interfaceName;
			
			interfaceObject._util.lock();
			this[interfaceName] = interfaceObject;
			this[interfaceName].toString = function(){
				return "[interface " + fullInterfaceName + "]";
			};
		},
		
		//createClassオブジェクトを作成します。
		createClass : createClass,
		
		/**
		 *	クラスを名前空間のプロパティとして追加します。
		 *	
		 *	@param {String} className 追加後のクラス名
		 *	@param {Object} cKlass 追加したいcreateClassオブジェクト
		 *	@param {Boolean} isSingleton?=false シングルトンクラスかどうか（オプション）
		 */
		registerClass : function(className, cKlass, isSingleton){
			
			//toStringが返す文字列用
			var fullClassName = fullNamespaceName + "." + className;
			
			//エラーチェック
			if(blades.debugMode){
				
				//抽象クラスかどうかをチェック
				if(cKlass._util.isAbstract()){
					throw new Error("Cannot register class " + fullClassName + " ! This class is abstract!");
				}
				
				//インスタンス作成時にはnewする必要はない（しても特に問題はないが）
				if(this[className]){
					throw new Error(className + " class/namespace already exists!");
				}
				
				//3つ目の引数をチェック
				if(arguments.length > 2){
					if(isSingleton !== true && isSingleton !== false){
						throw new Error("Invalis Argument :" + isSingleton + " 3rd argument must be Boolean!");
					}
				}
			}
			
			//疑似コンストラクタ作成に必要な要素を取得
			var realConstructor = cKlass._util.getRealConstructor();
			var userConstructor = cKlass._util.getUserConstructor();
			var memberList = cKlass._util.getMemberList();
			var staticMemberList = cKlass._util.getStaticMemberList();
			
			//エラーチェック2
			if(blades.debugMode){
				
				//メンバリスト一覧をチェック
				memberList.each(function(p){
					//abstractな関数がオーバーライドされずにある場合
					if(this.isAbstract()){
						throw new Error(p + "() is abstract function! Override this method in sub class!");
					}
					
					//インターフェイスで定義されたメソッドを作成していない場合
					if(this.getStatus() === DEFINED_BY_INTERFACE){
						throw new Error("You must define " +  p + "()! This method is " + DEFINED_BY_INTERFACE + ".");
					}
				});
			}
			
			/*
			 *	疑似コンストラクタ
			 *
			 *	registerClass()は以下の疑似コンストラクタを名前空間のプロパティとして追加します。
			 *	これはコンストラクタではありません。publicメンバの一覧オブジェクトを返す関数です。
			 *	実際のインスタンスを保護するクロージャでもあります。
			 *	よって使用時にnewする必要はありません。（newしても問題はないですが）
			 *	ただし通常のクラスと利用方法統一のため、newすることを推奨します。
			 *	
			 *	@return publicメンバの一覧を返します。
			 *	@type Object
			 */
			var pseudoConstructor = function(){
				
				//実際のコンストラクタ（空）でインスタンスを作成
				var instance = new realConstructor();
				
				//ユーザー指定のコンストラクタを実行（内部でスーパークラスのコンストラクタも実行される）
				userConstructor.apply(instance, arguments);
				
				//疑似コンストラクタが返すpublicメンバ一覧
				var publicMembers = {};
				
				/**
				 *	toString設定
				 *
				 *	@return クラス名を返します。
				 *	@type String
				 */
				publicMembers.toString = function(){
					return "[object " + fullClassName + "]";
				};
				
				//publicメソッドをpublicMembersにセット
				memberList.each(function(p){
					if(this.getAccess() === PUBLIC){
						publicMembers[p] = function(){
							var returnValue = realConstructor.prototype[p].apply(instance, arguments);
							//メソッド内でカスケーディング等のためにreturn thisをしていると本物のインスタンスを返してしまう。
							//よってその場合は代わりにpublicMembersを返す。
							//なお、return this.someMemberなどは考慮しない。
							if(returnValue === instance){
								returnValue = publicMembers;
							}
							return returnValue;
							//this.someMemberというプロパティがあってsomeMemberというpublicメソッドを作成すると以下はエラーになる
							//return instance[p].apply(instance, arguments);
						};
					}
				});
				
				return publicMembers;
			};
			
			//クラスメソッド（静的メソッド）を設定
			var setStaticMember = function(pseudoConstructor){
				staticMemberList.each(function(p){
					if(this.getAccess() === PUBLIC){
						
						//"getInstance"は予約語とした
						if(blades.debugMode && p === "getInstance"){
							throw new Error("You cannot create static member : getIinstance");
						}
						
						//メソッドの場合
						if(typeof cKlass[p] === "function"){
							pseudoConstructor[p] = function(){
								return cKlass[p].apply(null, arguments);
							};
							
						//プロパティの場合
						}else{
							pseudoConstructor[p] = cKlass[p];
						}
					}
				});
				
				/**
				 *	名前空間追加前のcreateClassオブジェクトに変換します。
				 *	
				 *	@return createClassオブジェクトを返します。
				 *	@type Object
				 */
				pseudoConstructor.convert = function(){
					return cKlass;
				};
			};
			
			/*
			 *	シングルトンクラス（isSingleton === true）の場合
			 *
			 *	シングルトンクラスの場合、疑似コンストラクタは関数ではなくオブジェクトになります。
			 *	これによりnewでインスタンスを生成しようとした場合はエラーが投げられるようになります。
			 *	インスタンスの参照を取得するには、自動的に宣言される静的メソッド、"getInstance()"を使用してください。
			 *	実際のコンストラクタのアクセス指定は"protected"となります。
			 *	シングルトンクラスを継承したクラスはシングルトンクラスにはなりません。
			 *	"getInstance()"はcreateClassオブジェクト内の静的メソッドのリストには含まれないため、継承されません。
			 *
			 */
			if(isSingleton === true){
				var instance;
				var singletonClass = {
					getInstance : function(args){
						if(instance){
							return instance;
						}else{
							return (instance = pseudoConstructor(args));//唯一のインスタンス作成（newは本当は必要ないのでしていない）
						}
					}
				};
				//静的メンバ追加
				setStaticMember(singletonClass);
				
				//名前空間にクラスを追加
				this[className] = singletonClass;
			}else{
				
				//静的メンバ追加
				setStaticMember(pseudoConstructor);
				
				//名前空間にクラスを追加
				this[className] = pseudoConstructor;
				
			}
			
			
			
			//編集不可とする
			cKlass._util.lock();
		}
	};
	
	//createNamespace()が返すオブジェクト
	var createNamespaceObject = {};
	
	//上書きによる汚染を防止するため浅いコピーを作成
	for(var p in createNamespaceMethods){
		if(createNamespaceMethods.hasOwnProperty(p)){
			createNamespaceObject[p] = createNamespaceMethods[p];
		}
	}
	
	//名前空間のメソッドとして呼び出された場合
	if(this.registerClass){
		
		//名前空間名が指定されない場合はオブジェクトを返す（internalな名前空間の作成を想定）。
		//ただし、その場合は機能をregisterClassのみに制限する。
		if(!namespaceName){
			for(var p2 in createNamespaceObject){
				if(createNamespaceObject.hasOwnProperty(p2) && p2 !== "registerClass"){
					if(blades.debugMode){
						createNamespaceObject[p2] = function(){
							throw new Error("This is an internal namespace. registerClass() is the only method available.");
						};
					}else{
						createNamespaceObject[p2] = null;
					}
				}
			}
			return createNamespaceObject;
		}else{
			this[namespaceName] = createNamespaceObject;
		}
		
	//window.blades名前空間作成時専用
	}else{
		return createNamespaceObject;
	}
};

//blades名前空間を作成
var temp = blades.debugMode;

/**
 *	bladesは blades.js 及びそのモジュールが利用する唯一のグローバルシンボルです。
 */
blades = createNamespace("blades");
blades.debugMode = temp;
temp = null;

})();

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

(function(){

var document = window.document;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

var iAggregate = blades.createInterface();
iAggregate.createMethod("each");

blades.registerInterface("iAggregate", iAggregate);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 *	@class		blades.Parameters
 *	@inherits	blades.Parameters → Object
 *	@implements	blades.iAggregate
 *	
 *	@param {String/Object} params 上記のような文字列／キーを値がペアとなった連想配列
 *	@param {String} equalizer? = "=" キーと値を連結する文字列
 *	@param {String} separator? = "&" キーと値のペア同士を連結する文字列
 *
 *	key1=val1&key2=val2&key3=val3 のようなパラメータを扱うクラスです。
 */
var cParameters = blades.createClass(function(params, equalizer, separator){
	equalizer = equalizer || "=";
	separator = separator || "&";
	
	//null/undefined/""等の場合（blades.URLクラス内で引数を省略してインスタンスを作成している。
	if(!params){
		this.params = {};
	
	//文字列の場合
	}else if(typeof params === "string" || (params.constructor && params.constructor === String)){
		this.params = this.parse(params, equalizer, separator);
		
	//Objectの場合
	}else if(typeof params === "object" && params.constructor === Object){
		this.params = params;
		
	//それ以外
	}else{
		throw new Error("INVALID ARGUMENT : " + params + typeof params);
	}
}).implement(blades.iAggregate);

/**
 *	@param {String} str 解析する文字列（例：key1=val1&key2=val2&key3=val3）
 *	@param {String} equalizer? = "=" キーと値を連結する文字列
 *	@param {String} separator? = "&" キーと値のペア同士を連結する文字列
 *
 *	@return {Object} parameters キーと値の連想配列
 *
 *	文字列として与えられたパラメータを解析し連想配列を作成します。
 *	文字列がnullと等価である場合には空のオブジェクトを生成します。
 */
cParameters.createPrivateMethod("parse", function(str, equalizer, separator){
	var pairs = [];
	var parameters = {};
	if(str){
		//キーと値のペアに分ける
		if(str.indexOf(separator) > -1){
			pairs = str.split(separator);
		}else{
			pairs[0] = str;
		}
		
		//連想配列にする
		for(var i=0, len=pairs.length, key, val; i<len; i++){
			if(pairs[i].indexOf(equalizer)>-1){
				key = pairs[i].split(equalizer)[0];
				key = key.replace(/^\s+/, "").replace(/\s+$/, "");
				val = pairs[i].split(equalizer)[1];
				val = val.replace(/^\s+/, "").replace(/\s+$/, "");
				if(val){
					parameters[key] = val;
				}
			}
		}
	}else{
		parameters = {};
	}
	return parameters;
});

/**
 *	@return {Object} 複製したハッシュオブジェクト
 *	
 *	内部で保持しているthis.paramsの浅いコピーを返します。
 */
cParameters.createProtectedMethod("copy", function(){
	var copy = {};
	for(var p in this.params){
		if(this.params.hasOwnProperty(p)){
			copy[p] = this.params[p];
		}
	}
	return copy;
});

/**
 *	@param {String} key キー名
 *	@param {String/Number/Boolean} val 値
 *	@return {blades.Prameters} 修正した新しいハッシュ
 *	
 *	現在のハッシュにキー名と値を設定し新しいハッシュ（blades.Parameters)を返します。
 *	すでに同名のキーが存在する場合は値が上書きされます。
 *	同名のキーが存在しない場合は新たに追加されます。
 *	値を省略するとキーが削除されます。
 */
cParameters.createPublicMethod("set", function(key, val){
	//コピーを作成
	var copy = this.copy();
	
	//valが指定された場合
	if(arguments.length > 1 && typeof val === "undefined"){
		copy[key] = val;
	
	//valが省略された場合値を削除
	}else{
		copy[key] = null;
		delete copy[key];
	}
	copy = new blades.Parameters(copy);
	return copy;
});

/**
 *	@param {String} key? キー名
 *	@return {any} キーに対応する値
 *
 *	任意のキー名に対応する値を返します。
 *	指定されたキー名が存在しない場合はnullを返します。
 */
cParameters.createPublicMethod("get", function(key){
	//キー名が指定された場合
	if(this.params.hasOwnProperty(key)){
		return this.params[key];
	}else{
		return null;
	}
});

/**	
 *	@param {String} key キー名
 *	@return {Boolean} 任意のキーの有無を真偽値で返します。
 */
cParameters.createPublicMethod("has", function(key){
	return this.params.hasOwnProperty(key);
});

//パラメータの有無を真偽値で取得
/*
cParameters.createPublicMethod("hasParameters", function(){
	if(this.params){
		return true;
	}else{
		return false;
	}
});
*/

/**
 *	@param {String} equalizer? = "=" キーと値を連結する文字列;
 *	@param {String} separator? = "&" キーと値のペア同士を連結する文字列;
 *	@return {Array} 解析したパラメータを文字列に変換して返します。
 */	
cParameters.createPublicMethod("join", function(equalizer, separator){
	equalizer = equalizer || "=";
	separator = separator || "&";
	var result = [];
	for(var p in this.params){
		if(this.params.hasOwnProperty(p)){
			result.push( [p, this.params[p]].join(equalizer) );
		}
	}
	result = result.join(separator);
	return result;
});

/**
 *	@param {Function} func コールバック関数
 *	@return {void}
 *
 *	Iteratorです。
 *	仕様では、call/applyでthisに文字列(typeof は "string")を渡すとcallback内でのthisはStringラッパーオブジェクトとなります Object(文字列)/new String(文字列)
 *	真偽値・数値に関しても同上です。
 *	よってこれまでcallbackのthisに値をバインドしていましたが、ハッシュオブジェクトをバインドする仕様に変更しました。
 */
cParameters.createPublicMethod("each", function(func){
	for(var p in this.params){
		if(this.params.hasOwnProperty(p)){
			//func.call(this.params[p], p);
			func.call(this.params, p);
		}
	}
});

blades.registerClass("Parameters", cParameters);

////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 *	@class		blades.URL
 *	@inherits	blades.URL → Object
 *	@implements	none
 *	
 *	@param {String} url URL文字列
 *
 *	URL文字列を解析するクラスです。
 */
var cURL = blades.createClass(function(url){
	var search = null, hash = null;
	this.search = new blades.Parameters();
	this.hash = new blades.Parameters();
	
	//絶対パスかどうかをチェック
	var a = url.match(/^([a-zA-Z]+):\/\/([^\/][\w.]+)(\/([\s\S]+)?)/);
	this.isAbsolute = !!(a);
	
	var remainder;
	if(this.isAbsolute){
		this.protocol = a[1];
		this.domain = a[2];
		//remainder can be undefined
		remainder = a[4];
		//alert("protocol: " + this.protocol);
		//alert("domain: " + this.domain);
	}else{
		remainder = url;
	}
	//alert("isAbsolute: " + this.isAbsolute);
	
	//プロトコル＆ドメイン部分以外を調査
	if(remainder){
		
		//パラメータ（?/#）で始まる文字列を取り除く
		this.path = remainder.split("?")[0].split("#")[0];
		//alert("path: " + this.path);
		
		//ディレクトリ部分とファイル名（らしき部分）を取得
		var b = this.path.match(/(([\s_\S]+\/)?)([^\/]+)$/);
		var possibleFileName;
		if(b){
			this.directories = b[1].split("/");
			possibleFileName = b[3];
		}else{
			this.directories = this.path.split("/");
		}
		
		//ファイル名（らしき部分）を検証
		if(possibleFileName && possibleFileName.indexOf(".") > -1){
			this.fileName = possibleFileName;
		}else{
			this.directories.push(possibleFileName);
		}
		
		//clean up　連続したスラッシュ、"."を取り除く
		var _directories = [];
		for(var i=0, len=this.directories.length; i<len; i++){
			if(this.directories[i] && this.directories[i]!="."){
				_directories.push(this.directories[i]);
			}
		}
		this.directories = _directories;
		
		//alert("directories: " + this.directories);
		//alert("fileName: " + this.fileName);
		
		//locationプロパティ（現在位置）
		if(this.isAbsolute){
			this.location = this.protocol + "://" + this.domain + "/" + this.directories.join("/");
		}else{
			this.location = this.directories.join("/");
		}
		if(this.directories.length>0){
			this.location += "/";
		}
		
		//拡張子を取得
		if(this.fileName){
			this.fileType = this.fileName.match(/.(\w+)$/)[1];
		}
		//alert("fileType: " + this.fileType);

		//パラメータ部分を解析
		if(url.indexOf("?") > -1){
			search = url.split("?")[1].replace(/#\S*/,"");
			this.search = new blades.Parameters(search, "=", "&");
		}
		if(url.indexOf("#") > -1){
			hash = url.split("#")[1].replace(/\?\S*/, "");
			this.hash = new blades.Parameters(hash, "=", "&");
		}
	}
});

/**
 *	@return {String} プロトコル部分の文字列を返します。
 */
cURL.createPublicMethod("getProtocol", function(){
	return this.protocol;
});

/**
 *	@return {String} ドメイン部分の文字列を返します。
 */
cURL.createPublicMethod("getDomain", function(){
	return this.domain;
});

/**
 *	@return {String} パス部分の文字列を返します。
 */
cURL.createPublicMethod("getPath", function(){
	return this.path;
});

/**
 *	@return {Array} ディレクトリ名の配列を返します。
 */
cURL.createPublicMethod("getDirectories", function(){
	return this.directories;
});

/**
 *	@return {String} ファイル名を返します。
 */
cURL.createPublicMethod("getFileName", function(){
	return this.fileName;
});

/**
 *	@return {String} 拡張子を返します。
 */
cURL.createPublicMethod("getFileType", function(){
	return this.fileType;
});

/**
 *	@return {String} locationを返します。
 */
cURL.createPublicMethod("getLocation", function(){
	return this.location;
});

/**
 *	@return {blades.Parameters}	?パラメータを返します。
 */
cURL.createPublicMethod("getSearch", function(){
	return this.search;
});

/**
 *	@return {blades.Parameters} #パラメータを返します。
 */
cURL.createPublicMethod("getHash", function(){
	return this.hash;
});

blades.registerClass("URL", cURL);

////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 *	@class		blades.Script
 *	@inherits	blades.Script → Object
 *	@implements	none
 *	
 *	@param {String} fileName?
 *	
 *	スクリプトタグを扱うクラスです。jsの読み込み機能を提供します。
 */
var cScript = blades.createClass(function(fileName){
	this.objs = this.get(fileName);

	//DOMでスクリプトタグを挿入する際に挿入先の目印として利用
	this.lastScriptInserted = this.objs;
	
	this.magic();
});

/**
 *	@param {String} fileName?
 *	@return {Element} 
 *
 *	scriptタグを取得します。ファイル名が指定されない場合はその時点でノードリストの最後にあるタグ(※1)を返します。
 *	通常(※1)はインスタンスが生成されたjsファイルを指しますが、インスタンス生成以前に同ファイル内で動的にscriptタグを挿入した場合等、期待した結果が得られない場合が考えられます。
 */
cScript.createPrivateMethod("get", function(fileName){
	var scripts = document.getElementsByTagName("script");
	if(fileName){
		var src;
		for(var i=0, len=scripts.length; i<len; i++){
			src = new blades.URL(scripts[i].getAttribute("src"));
			if( src.getFileName()==fileName ){
				this.src = src;
				return scripts[i];
			}
		}
		throw new Error("REQUESTED FILE:" + fileName + " NOT FOUND");
	}else{
		this.src = new blades.URL(scripts[scripts.length-1].getAttribute("src"));
		return scripts[scripts.length-1];
	}
});

/**
 *	@return {void}
 *
 *	headタグ内でscriptタグのノードリストのlengthにアクセスした場合、bodyタグ内に入るまでscriptタグのノードリストの内容が更新されない問題が確認されています。
 *	この問題を解決するためにダミーのscriptタグを挿入／削除します。
 */
cScript.createPrivateMethod("magic", function(){
	var dummy = document.createElement("script");
	this.objs.parentNode.appendChild(dummy);
	this.objs.parentNode.removeChild(dummy);
	dummy = null;
});

/**
 *	@param {String} fileName
 *	@param {String} charset?
 *	@return {void}
 *	
 *	絶対パスで指定されたjsファイルをdocument.write()により動的に書き出します。
 */
cScript.createPublicMethod("includeGlobal", function(fileName, charset){
	var _charset = charset ? (" charset=\"" + charset + "\"") : "";
	document.write(unescape("%3Cscr" + "ipt type=\"text\/javascript\" src=\"" + fileName + "\"" + _charset + "%3E%3C/script%3E"));
});

/**
 *	@param {String} fileName
 *	@param {String} charset?
 *	@return {void}
 *	
 *	絶対パスで指定されたjsファイルをDOMにより動的に挿入します。
 */
cScript.createPublicMethod("includeGlobal2", function(fileName, charset){
	var scriptTag = document.createElement("script");
	scriptTag.setAttribute("src", fileName);
	if(charset){
		scriptTag.setAttribute("charset", charset);
	}
	scriptTag.setAttribute("type", "text/javascript");
	
	this.objs.parentNode.insertBefore(scriptTag, this.lastScriptInserted.nextSibling);
	this.lastScriptInserted = scriptTag;
});

/**
 *	@param {String} fileName
 *	@param {String} charset?
 *	@return {void}
 *	
 *	相対パスで指定されたjsファイルをdocument.write()により動的に書き出します。
 *	パスの基準はインスタンス生成時に取得したjsファイルのパスです。
 */
cScript.createPublicMethod("includeLocal", function(fileName, charset){
	this.includeGlobal((this.src.getLocation() + fileName), charset);
});

/**
 *	@param {String} fileName
 *	@param {String} charset?
 *	@return {void}
 *	
 *	相対パスで指定されたjsファイルをDOMにより動的に挿入します。
 *	パスの基準はインスタンス生成時に取得したjsファイルのパスです。
 */
cScript.createPublicMethod("includeLocal2", function(fileName, charset){
	this.includeGlobal2((this.src.getLocation() + fileName), charset);
});

/**
 *	@return {blades.URL} this.src取得用ゲッタです。
 */
cScript.createPublicMethod("getSrc", function(){
	return this.src;
});

blades.registerClass("Script", cScript);

////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 *	@class 		blades.Cookie
 *	@inherits	blades.Cookie → Object
 *	@implements	none
 *
 *	@param {Object} options? オプションをハッシュで指定します
 *
 *	クッキーを扱うクラスです。
 */
var cCookie = blades.createClass(function(options){
	if(options){
		this.domain = options.domain;
		this.path = options.path;
		this.maxAge = options.maxAge;
		this.expires = options.expires;
		this.secure = options.secure;
	}
});

/**
 *	@param {String} key
 *	@return {String/null} keyに対応する値を返します。
 *
 *	指定されたキーに対応する値を返します。
 */
cCookie.createPublicMethod("get", function(key){
	var cookie = new blades.Parameters(document.cookie, "=", ";");
	if(cookie.get(key)){
		return decodeURIComponent(cookie.get(key));
	}else{
		return null;
	}
});

/**
 *	@param {String} key
 *	@param {String} val
 *	@return {void}
 *
 *	クッキーにキーと値を設定します。
 */
cCookie.createPublicMethod("set", function(key, val){
	document.cookie = key + "=" + encodeURIComponent(val) + this.getOptions();
});

/**
 *	@param {String} key?
 *	@return {void}
 *
 *	クッキーからキーを削除します。
 *	キーが指定されない場合は全てのクッキーを削除します。
 */
cCookie.createPublicMethod("remove", function(key){
	if(key){
		document.cookie = key + "=" + this.getOptions(0);
	}else{
		var cookie = new blades.Parameters(document.cookie, "=", ";");
		for(var p in cookie){
			if(cookie.hasOwnProperty(p)){
				document.cookie = p + "=" + this.getOptions(0);
			}
		}
		cookie = null;
	}
});

/**
 *	@param {GMTString} expires
 *	@return {String}
 */
cCookie.createPrivateMethod("getOptions", function(expires){
	var str = "";
	if(this.domain){
		str+= ("; domain=" + this.domain);
	}
	if(this.path){
		str+= ("; path=" + this.path);
	}
	if(this.maxAge){
		str+= ("; max-age=" + this.maxAge);
	}
	if(this.expires){
		var a = (expires===0) ? 0 : this.expires;
		str+= ("; expires=" + a);
	}
	if(this.secure){
		str+= ("; secure=" + this.secure);
	}
	return str;
});

/**
 *	@return {Boolean} クッキーが有効かどうかを真偽値で返します。
 */
cCookie.createPrivateMethod("isEnabled", function(){
	if(navigator.cookieEnabled){
		return true;
	}else{
		this.set("dyhshgw357heg", "khi3w53w786");
		if(this.get("dyhshgw357heg") == "khi3w53w786"){
			return true;
		}
	}
	return false;
});

blades.registerClass("Cookie", cCookie);

////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 *	@class		internal.Handler
 *	@inherits	internal.Handler → Object
 *	@implements	none
 *	
 *	blades.EventDispatcher内で使用されるクラスです。
 */
var cHandlers = blades.createClass(function(){
	this.list = [];
});

/**
 *	@param {function} func
 *	@return {Boolean} 任意のハンドラーが既に登録されているかを真偽値で返します。
 */
cHandlers.createPrivateMethod("has", function(func){
	for(var i=0, len=this.list.length; i<len; i++){
		if(this.list[i]===func){
			return true;
		}
	}
	return false;
});

/**
 *	@param {funcion} func
 *	@return {void}
 *	
 *	ハンドラーを登録します。（同一のハンドラーを複数回登録することはできません。
 */
cHandlers.createPublicMethod("add", function(func){
	if(typeof func==="function" && !this.has(func)){
		this.list.push(func);
	}
});

/**
 *	@param {function} func 
 *	@return {void}
 *	
 *	ハンドラーを削除します。
 */
cHandlers.createPublicMethod("remove", function(func){
	if(typeof func==="function"){
		for(var i=0, len=this.list.length; i<len; i++){
			if(this.list[i]===func){
				this.list[i] = null;
			}
		}
	}
});

/**
 *	@param {any} evt ハンドラーに引数として渡すイベントオブジェクトを指定します。
 *	@return {void}
 *	
 *	登録されているハンドラーを一括して実行します。
 */
cHandlers.createPublicMethod("execute", function(evt){
	for(var i=0, len=this.list.length; i<len; i++){
		if(typeof this.list[i] === "function"){
			//(this.list[i])(evt);
			this.list[i].apply(null, evt);
		}
	}
});

var internal = blades.createNamespace();
internal.registerClass("Handlers", cHandlers);

////////////////////////////////////////////////////////////////////////////////////////////////////

var iEventListener = blades.createInterface();
iEventListener.createMethod("addListener");
iEventListener.createMethod("removeListener");

blades.registerInterface("iEventListener", iEventListener);

////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 *	@class		blades.EventDispatcher
 *	@inherits	blades.EventDispatcher → Object
 *	@implements	blades.iEventListener
 *	@subClasses	blades.FontSizeEvent, blades.Loader
 *	
 *	独自のイベント登録／削除／発火の機能を提供するクラスです。
 */
var cEventDispatcher = blades.createClass(function(){
	this.handlers = {};
	this.nonrecursiveEvents = {};
}).implement(blades.iEventListener);

/**
 *	@param {String} eventName
 *	@param {Boolean} nonrecursive? = false イベントが非再帰性かどうかを真偽値で指定します。trueに指定した場合、すでに発火したイベントに対してリスナーを追加すると即実行されます。
 *	@return {void}
 *	
 *	独自のイベントを作成します。
 */
cEventDispatcher.createProtectedMethod("createEvent", function(eventName, nonrecursive){
	if(this.handlers.hasOwnProperty(eventName)){
		throw new Error("Event name -" + eventName + "- already exsits!");
	}else{
		this.handlers[eventName] = new internal.Handlers();
		if(nonrecursive === true){
			this.nonrecursiveEvents[eventName] = {
				args : null,
				dispatched : false
			};
		}
	}
});

/**
 *	@param {String} eventName
 *	@param {arguments} args? ハンドラーに渡される引数
 *	@return {void}
 *	
 *	独自のイベントを発火します。
 *	指定されたイベントが非再帰性の場合イベント発火後にそのイベントに登録されたハンドラーが削除されます。
 *	非再帰性のイベントは複数回発火することはできません。
 */
cEventDispatcher.createProtectedMethod("dispatchEvent", function(eventName, args){
	//IEでargsが指定されない場合にエラーが出る。
	//args = args || [];
	args = [].concat(args);
	if(this.handlers.hasOwnProperty(eventName)){
		//this.handlers[eventName].execute.apply(null, args);
		this.handlers[eventName].execute(args);
		
		if( this.nonrecursiveEvents.hasOwnProperty(eventName) ){
			this.nonrecursiveEvents[eventName] = {
				args : args,
				dispatched : true
			};
			this.handlers[eventName] = null;
			delete this.handlers[eventName];
		}
	}else{
		throw new Error("Event name -" + eventName + "- is invalid!");
	}
});

/**
 *	@param {String} eventName
 *	@return {Boolean} イベントリスナーが存在するかを真偽値で取得します。
 */
cEventDispatcher.createPublicMethod("hasListener", function(eventName){
	if(this.handlers.hasOwnProperty(eventName)){
		return true;
	}else{
		return false;
	}
});

/**
 *	@param {String} eventName
 *	@param {function} handler
 *	@return {void}
 *	
 *	イベントリスナーを追加します。
 *	指定されたイベントが非再起性の場合、即ハンドラーが実行されます。引数には前回（=初回)に指定された引数が再度渡されます。
 */
cEventDispatcher.createPublicMethod("addListener", function(eventName, handler){
	if(this.nonrecursiveEvents.hasOwnProperty(eventName) && this.nonrecursiveEvents[eventName].dispatched){
		handler.apply(null, this.nonrecursiveEvents[eventName].args);
		handler = null;
	}else if(this.handlers.hasOwnProperty(eventName)){
		this.handlers[eventName].add(handler);
	}else{
		throw new Error("Event name -" + eventName + "- is invalid!");
	}
});

/**
 *	@param {String} eventName
 *	@param {function} handler
 *	@return {void}
 *	
 *	イベントリスナーを削除します。
 */
cEventDispatcher.createPublicMethod("removeListener", function(eventName, handler){
	if(this.handlers.hasOwnProperty(eventName)){
		this.handlers[eventName].remove(handler);
	}else{
		throw new Error("Event name -" + eventName + "- is invalid!");
	}
});

blades.registerClass("EventDispatcher", cEventDispatcher);

////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 *	@class		blades.DOM
 *	@inherits	blades.DOM → Object
 *	@implements	blades.iEventListener, blades.iAggregate
 *
 *	@param {any} arg 以下を参照
 *		#idName
 *		tagName
 *		tagName.className
 *		element
 *		elementList
 *
 *
 *	DOM要素を扱うクラスです。
 *	・id名、クラス名、タグ名を指定し要素／ノードリストを取得
 *	・イベント挿入、クラス名の追加／削除
 */
var cDOM = blades.createClass(function(arg){
	
	//protected properties
	this.parentElement = document;
	this.objs = [];
	
	if(arg){
		this.addElements(arg, this.parentElement);
	}
}).implement(blades.iEventListener, blades.iAggregate);

/**
 *	@param {any} arg
 *	@return {Boolean}
 *
 *	引数が配列かどうかを真偽値で返します。
 */
cDOM.createStaticPrivateMethod("isArray", function(arg){
	return ( arg && typeof arg === "object" && cDOM.isNumber(arg.length) && typeof arg.splice === "function" && !(arg.propertyIsEnumerable("length")) );
});

/**
 *	@param {any} arg
 *	@return {array}
 *
 *	引数を配列に変換します。
 */
cDOM.createStaticPrivateMethod("toArray", function(arg){
	var array = [];
	
	//配列の場合
	if(cDOM.isArray(arg)){
		return arg;
		
	//formタグ,windowはlengthプロパティを持っている
	}else if(cDOM.isElement(arg) || cDOM.isWindow(arg)){
		return array.concat(arg);
		
	//ノードリストやarguments
	}else if(cDOM.isNumber(arg.length)){
		try{
			array = Array.prototype.slice.call(arg);
		}catch(e){
			for(var i=0, len=arg.length; i<len; i++){
				array.push(arg[i]);
			}
		}
		return array;
	}else{
		return array.concat(arg);
	}
});

/**
 *	@param {any} arg
 *	@return {Boolean}
 *
 *	引数がノードリストかどうかを真偽値で返します。
 */
cDOM.createStaticPrivateMethod("isNodeList", function(arg){
	return (arg[0] && arg[0].getAttribute);
});

/**
 *	@param {any} arg
 *	@return {Boolean}
 *
 *	引数がwindowかどうかを真偽値で返します。
 */
cDOM.createStaticPrivateMethod("isWindow", function(arg){
	return !!(arg.setTimeout);
});

/**
 *	@param {any} arg
 *	@return {Boolean}
 *
 *	引数がdocumentかどうかを真偽値で返します。
 */
cDOM.createStaticPrivateMethod("isDocument", function(arg){
	return !!(arg.getElementById);
});

/**
 *	@param {any} arg
 *	@return {Boolean}
 *
 *	引数がbodyかどうかを真偽値で返します。
 */
cDOM.createStaticPrivateMethod("isBody", function(arg){
	return (arg===document.body);
});

/**
 *	@param {any} arg
 *	@return {Boolean}
 *
 *	引数がDOM要素かどうかを真偽値で返します。
 */
cDOM.createStaticPrivateMethod("isElement", function(arg){
	return !!(arg.getAttribute);
});

/**
 *	@param {any} arg
 *	@return {Boolean}
 *	
 *	引数が文字列（もしくはそのラッパーオブジェクト）かどうかを真偽値で返します。
 */
cDOM.createStaticPrivateMethod("isString", function(arg){
	return (typeof arg === "string" || (typeof arg === "object" && arg.constructor === String));
});

/**
 *	@param {any} arg
 *	@return {Boolean}
 *
 *	引数が数値（もしくはそのラッパーオブジェクト）かどうかを真偽値で返します。
 */
cDOM.createStaticPrivateMethod("isNumber", function(arg){
	return (typeof arg === "number");
});



/**
 * @param {any} obj 以下を参照
 *		#idName
 *		tagName
 *		tagName.className
 *		element
 *		elementList
 *	@param {Element} parentElement? = document
 *	@return {Array}
 *
 *	要素を取得し、配列に格納して返します。
 */
cDOM.createStaticPrivateMethod("getElements", function(obj, parentElement){
	var result = null;
	
	parentElement = parentElement || document;
	//対象要素が複数かどうかを表わす真偽値
	//this.isElements = false;
	
	//
	if(!obj){
		throw new Error("ArgumentError : blades.DOM() : ARGUMENT IS NULL");
		
	//文字列の場合
	}else if(cDOM.isString(obj)){
		//alert("string");
		result = cDOM.parse(obj, parentElement);
		
	//windowの場合
	//}else if(obj === window && obj.setTimeout){
	}else if(cDOM.isWindow(obj)){
		//alert(["2341", "window!!"]);
		result = obj;
		
		
	//documentの場合
	//}else if(obj === document && obj.getElementById){
	}else if(cDOM.isDocument(obj)){
		result = obj;
		
	//要素の場合
	}else if(cDOM.isElement(obj)){
		result = obj;
		
	//配列の場合
	}else if(cDOM.isArray(obj)){
		var objs = [];
		for(var i=0, len=obj.length; i<len; i++){
			
			//文字列の場合
			if(cDOM.isString(obj[i])){
				var a = cDOM.parse(obj[i], parentElement);
				if(a){
					if(a.getAttribute){//要素単体
						objs.push(a);
					}else if(cDOM.isArray(a)){//要素の配列
						objs = objs.concat(a);
					}else if(cDOM.isNodeList(a)){//ノードリスト
						objs = objs.concat(cDOM.toArray(a));
					}
					a = null;
				}
			
			//要素の場合
			}else if(cDOM.isElement(obj[i])){
				objs.push(obj[i]);
				
			//windowの場合
			}else if(cDOM.isWindow(obj[i])){
				objs.push(obj[i]);
			}
		}
		//this.isElements = true;
		result = objs;
		objs = null;
		
	//ノードリストの場合
	}else if(cDOM.isNodeList(obj)){
		result = cDOM.toArray(obj);
		//this.isElements = true;
	}
	if(!result){
		throw new Error("CANNOT FIND ELEMENTS: " + typeof obj + " : " + obj.constructor + " : " + obj);
	}
	return cDOM.toArray(result);
});



/**
 *	@param {Element/Elements/String} childElementExp 取得する要素（の文字列）
 *	@param {Element/Elements/String} parentElementExp? = document 取得する要素の親要素（の文字列）
 *	@return {instance} インスタンス自身
 *
 *	要素を取得し、内部リストに追加します。
 */
cDOM.createPublicMethod("addElements", function(childElementExp, parentElementExp){
	parentElementExp = cDOM.getElements(parentElementExp)[0];
	this.objs = this.objs.concat(cDOM.getElements(childElementExp, parentElementExp));
	return this;
});



/**
 *	@param {String/Element/ElementList/Array} str
 *	@param {element} parentElement
 *	@return {any} ノード／ノードリスト／ノードの配列を返します。
 */
cDOM.createStaticPrivateMethod("parse", function(str, parentElement){
	var obj = null;
	var exp, tagName, className, tags;
	var i, len;
	
	/*
	var spacePos = str.indexOf(" ");
	if(spacePos > 0){
		alert("-" + str.substring(0, spacePos) + "-");
		parentElement = this.getElements(str.substring(0, spacePos));
		alert(parentElement);
		alert(str.substring(spacePos + 1));
		str = str.substring(spacePos + 1);
	}*/
	
	//ID名の場合
	if(str.match(/^([a-zA-Z_\-0-9\$]+)?\#([a-zA-Z_\-0-9\$]+)$/)){
		//alert("id: " + RegExp.$2);
		
		//parentElementがdocumentオブジェクトの場合
		if(cDOM.isDocument(parentElement)){
			obj = parentElement.getElementById(RegExp.$2);
		}else{
			obj = document.getElementById(RegExp.$2);
		}
		//alert("id : " + RegExp.$2 + " = " + obj)
		if(!obj){
			throw new Error("blades.DOM(): ID NAME " + RegExp.$2 + " SEEMS TO BE INCORRECT");
		}
	
	//タグ名＋クラス名の場合
	}else if(str.match(/^((?:[a-zA-Z_\-0-9\$]+)|\*)\.([a-zA-Z_\-0-9\$]+)$/)){
		//alert("tagName: " + RegExp.$1 + ", class: " + RegExp.$2);
		tagName = RegExp.$1;
		className = RegExp.$2;
		tags = parentElement.getElementsByTagName(tagName);
		if(tags.length===0){
			throw new Error("blades.DOM(): TAG NAME " + tagName + "SEEMS TO BE INCORRECT");
		}
		obj = [];
		for(i=0, len = tags.length; i<len; i++){
			exp = new RegExp("\\b" + className + "\\b");
			if(tags[i].className.match(exp)){
				obj.push(tags[i]);
			}
		}
		if(obj.length===0){
			throw new Error("blades.DOM(): CLASS NAME " + className + "SEEMS TO BE INCORRECT");
		}
		
	//クラス名の場合
	}else if(str.match(/^\.([a-zA-Z_\-0-9\$]+)$/)){
		//alert("class: " + RegExp.$1);
		className = RegExp.$1;
		tags = parentElement.getElementsByTagName("*");
		obj=[];
		for(i=0, len = tags.length; i<len; i++){
			exp = new RegExp("\\b" + className + "\\b");
			if(tags[i].className.match(exp)){
				obj.push(tags[i]);
			}
		}
		//clear from memory
		tags = null;
		if(obj.length===0){
			throw new Error("blades.DOM(): CLASS NAME " + className + "SEEMS TO BE INCORRECT");
		}
		
	//タグ名の場合
	}else if(str.match(/^((?:[a-zA-Z_\-0-9\$]+)|\*)$/)){
		obj = parentElement.getElementsByTagName(RegExp.$1);
		if(!obj){
			throw new Error("blades.DOM(): CLASS NAME " + RegExp.$1 + "SEEMS TO BE INCORRECT");
		}
	}
	exp = null;
	return obj;
});

/**
 *	@param {Element} obj ノード
 *	@param {String} className クラス名
 *	@return {void}
 *
 *	ノードにクラス名を追加します。
 */
cDOM.createProtectedMethod("_addClass", function(obj, className){
	var exp = new RegExp("\\b" + className + "\\b");
	if(obj.className===""){
		obj.className += className;
	}else if(!obj.className.match(exp)){
		obj.className += (" " + className);
	}
	exp = null;
});

/**
 *	@param {Element} obj ノード
 *	@param {String} className クラス名
 *	@return {void}
 *
 *	ノードからクラス名を除去します。
 */
cDOM.createProtectedMethod("_removeClass", function(obj, className){
	var exp = new RegExp("\\b" + className + "\\b", "g");
	if(obj.className!==null){
		obj.className = obj.className.replace(exp, "");
	}
	exp = null;
});

/**
 *	@param {Element} obj ノード
 *	@param {String} eventName イベント名
 *	@param {function} handler イベントハンドラ
 *	@return {void}
 *
 *	ノードにイベントハンドラを登録します。
 *	thisにはノードがバインドされます。
 *	イベントハンドラがfalseを返した場合はデフォルトアクションを抑止します。
 */
cDOM.createProtectedMethod("_addListener", function(obj, eventName, handler){
	var returnValue;
	var d, w;
	try{
		obj.addEventListener(eventName, function(evt){
			returnValue = handler.call(obj, evt);
			if(returnValue === false){
				evt.preventDefault();
			}
			return returnValue;
		}, false);
	}catch(e){
		var newHandler = function(evt){
			returnValue =  handler.call(obj, evt);
			if(returnValue === false){
				evt.returnValue = false;
			}
			return returnValue;
		};
		obj.attachEvent("on"+eventName, newHandler);
		
		/* IE メモリリーク対策 */
		//d = obj.document || obj;
		//w = d.parentWindow;
		w = window;
		w.attachEvent("onunload", function(){
			obj.detachEvent("on"+eventName, newHandler);
			obj = null;
			handler = null;
			newHandler = null;
		});
		d = w = null;
	}
});

/**
 *	@param {Element} obj ノード
 *	@param {String} eventName イベント名
 *	@param {function} handler イベントハンドラ
 *	@return {void}
 *
 *	ノードからイベントハンドラを削除します。
 */
cDOM.createProtectedMethod("_removeListener", function(obj, eventName, handler){
	var returnValue;
	try{
		obj.removeEventListener(eventName, function(evt){
			returnValue = handler.call(obj, evt);
			if(returnValue === false){
				evt.preventDefault();
			}
			return returnValue;
		}, false);
	}catch(e){
		var newHandler = function(evt){
			returnValue =  handler.call(obj, evt);
			if(returnValue === false){
				evt.returnValue = false;
			}
			return returnValue;
		};
		obj.detachEvent("on"+eventName, newHandler);
	}
});

/**
 *	@param {Number} num?
 *	@return {Element/Elements} ノード／ノードの配列を返します。
 *	
 *	引数が指定された場合にはノードの配列の引数+1番目の要素を返します。
 *	引数が指定されない場合はノードの配列をそのまま返します。
 */
cDOM.createPublicMethod("get", function(num){
	if(!isNaN(num)){
		return this.objs[parseInt(num, 10)];
	}else{
		return this.objs;
	}
});

/**
 *	@param {String} className クラス名
 *	@return {void}
 *
 *	ノード／ノードリスト／ノードの配列の全要素にクラス名を追加します。
 */
cDOM.createPublicMethod("addClass", function(className){
	var self = this;
	this.each(function(){
		self._addClass(this, className);
	});
	self = null;
});

/**
 *	@param {String} className クラス名
 *	@return {void}
 *
 *	ノード／ノードリスト／ノードの配列の全要素からクラス名を除去します。
 */
cDOM.createPublicMethod("removeClass", function(className){
	var self = this;
	this.each(function(){
		self._removeClass(this, className);
	});
	self = null;
});

/**
 *	@param {String} eventName イベント名
 *	@param {function} handler イベントハンドラ
 *	@return {void}
 *
 *	ノード／ノードリスト／ノードの配列の全要素にイベントハンドラを登録します。
 *	thisにはノードがバインドされます。
 *	イベントハンドラがfalseを返した場合はデフォルトアクションを抑止します。
 */
cDOM.createPublicMethod("addListener", function(eventName, handler){
	var self = this;
	this.each(function(){
		self._addListener(this, eventName, handler);
	});
	self = null;
});

/**
 *	@param {String} eventName イベント名
 *	@param {function} handler イベントハンドラ
 *	@return {void}
 *
 *	ノード／ノードリスト／ノードの配列の全要素からイベントハンドラを削除します。
 */
cDOM.createPublicMethod("removeListener", function(eventName, handler){
	var self = this;
	this.each(function(){
		self._removeListener(this, eventName, handler);
	});
	self = null;
});

/**
 *	@param {function} func 
 *	@return {void}
 *
 *	ノード／ノードリスト／ノードの配列の全要素に対してfuncを実行します。
 *	thisにはノードがバインドされます。
 */
cDOM.createPublicMethod("each", function(func){
	
	//ノードリストor要素の配列の場合
	//if(this.isElements){
		for(var i=0, len=this.objs.length; i<len; i++){
			func.call(this.objs[i], null);
		}
		
	//要素の場合
	//}else{
	//	func.call(this.objs, null);
	//}
});

/**
 *	@param {Element} 高さを取得する対象要素
 *	@return {Number}
 *	
 *	要素の高さを返します。
 */
cDOM.createStaticPrivateMethod("getHeight", function(obj){
	//alert(["2781 : ", obj, cDOM.isWindow(obj)]);
	if(cDOM.isWindow(obj)){
		//alert("2782 : isWindow");
		//var wh = window.innerHeight;//fx,opera,chrome,safari,netscapeはOK![ie6 & ie7はundefined]
		//var wh = new blades.DOM("html").get(0).clientHeight;//fx,ie8,safari,chromeはOK! [ダメ:operaはwindowではなく中身の高さを返す, ie6,netscapeは0]
		//var wh = document.body.clientHeight;//ie6,opera,netscapeはwindow内の高さを返す。[fx,ie7,chrome,safariはちゃんと中の高さを返す]
		//if(_DEBUG_)alert(wh);
		/*
		//window高さを取得
		var wh = window.innerHeight;
		if(document.all && !window.opera){//ie
			if(window.XMLHttpRequest){//ie7
				wh = html.clientHeight;//落ちる(これは原因ではなかった）
				//alert(document.documentElement.clientHeight);//ウィンドウの高さを返す
				//alert(document.body.clientHeight);//中身の高さを返す
				//wh = document.documentElement.clientHeight;
				//wh = 800;//これも落ちる(これは原因ではなかった）
			}else{//ie 6
				wh = bodyClientHeight;
			}
		}
		//if(_DEBUG_)alert(wh);
		*/
		if(document.all && !window.opera){//ie
			if(window.XMLHttpRequest){//ie7以降
				return document.getElementsByTagName("html").item(0).clientHeight;
				//alert(document.documentElement.clientHeight);//ウィンドウの高さを返す
				//alert(document.body.clientHeight);//中身の高さを返す
			}else{//ie 6
				return document.body.clientHeight || document.documentElement.clientHeight;
			}
		}else{
			return window.innerHeight;
		}
	}else if(cDOM.isBody(obj)){
		//var dh = document.body.clientHeight || document.documentElement.clientHeight;
		//if(window.opera){//opera
		//	dh = html.clientHeight;
		//}
		//if(
		//	(window.innerHeight == bodyClientHeight && !window.opera) || (document.all && !window.opera && !window.XMLHttpRequest)//netscape & ie6
		//	){
			/***** ie6 *****
			if(_DEBUG_)alert("ie6");
			dh = html.scrollHeight;//ウィンドウの高さを返す。
			dh = html.offsetHeight;//ウィンドウの高さを返す。
			dh = document.getElementsByTagName("body")[0].offsetHeight;
			*/
			
			/*----- 最終手段 -----*/
			var scale = document.createElement("span");
			scale.style.display = "block";
			scale.style.visibility = "hidden";
			scale.style.position = "static";
			scale.style.lineHeight = "0";//ie6用
			scale.style.width = "100%";
			scale.style.height = "0";
			scale.style.margin = "0";
			scale.style.padding = "0";
			scale.style.border = "none";
			scale.style.fontSize = "0";//ie6用
			document.body.appendChild(scale);
			var dh = scale.offsetTop;
			document.body.removeChild(scale);
			scale = null;
			//if(_DEBUG_)alert(dh);
			return dh;
		//}
	}else{
		return obj.clientHeight;
	}
});

/**
 *	@return {Number}
 *	
 *	要素のoffsetHeightを返します。
 *	要素が複数ある場合はそれらの最大高さを返します。
 */
cDOM.createPublicMethod("getHeight", function(){
	var maxHeight = 0;
	var height = 0;
	this.each(function(){
		height = cDOM.getHeight(this);
		if(height > maxHeight){
			maxHeight = height;
		}
	});
	return maxHeight;
	//return cDOM.getHeight(this.get(0));
});

/**
 *	@param {String} str
 *	@return {String} str ハイフンで連結された文字列を（CSS用に）camelizeして返します。
 */
cDOM.createProtectedMethod("camelizeCSSPropertyName", function(str){
	if(str.indexOf("-") > -1){
		str = str.split("-");
		for(var i=1, len = str.length; i<len; i++){
			if(str[i].length){
				str[i] = str[i].split("");
				str[i][0] = str[i][0].toUpperCase();
				str[i] = str[i].join("");
			}
		}
		str = str.join("");
	}else if(str==="float"){
		str = "styleFloat";
	}
	return str;
});

/**
 *	@param {String} str
 *	@return {String} 要素に適応されているcssの値を返します。疑似要素は未対応です。
 *	
 *	対象要素が複数の場合はnullを返します。
 */
cDOM.createPublicMethod("getCSS", function(str){
	var css = null;
	var obj = this.get(0);
	try{
		css = document.defaultView.getComputedStyle(obj, null).getPropertyValue(str);
	}catch(e){
		css = obj.currentStyle.getAttribute(this.camelizeCSSPropertyName(str));
	}
	return css;
});

cDOM.createStaticPrivateProperty("isReady", false);
cDOM.createStaticPrivateProperty("handlers", []);

/**
 *	@return {void}
 */
cDOM.createStaticPrivateMethod("callHandlers", function(){
	for(var i=0, len=cDOM.handlers.length; i<len; i++){
		(cDOM.handlers[i])();
		cDOM.handlers[i] = null;
	}
	cDOM.handlers = null;
});
(function(){
	try{
		document.addEventListener("DOMContentLoaded", function(){
			//alert("DOMREADY");
			cDOM.callHandlers();
			cDOM.isReady = true;
		}, false);
	}catch(err){
		document.write('<scr' + 'ipt defer id=BLADES_DOM_READY src=//:><\/script>');
		var script = document.getElementById("BLADES_DOM_READY");
		script.onreadystatechange = function(){
			if(script.readyState === "complete"){
				cDOM.callHandlers();
				cDOM.isReady = true;
				script.parentNode.removeChild(script);
				script = null;
			}
		};
	}
})();

/**
 *	@return {void}
 *
 *	内部参照をすべてnullにします.
 */
cDOM.createPublicMethod("clear", function(){
	this.objs = null;
});

/**
 *	@param {function} handler
 *	@return {void}
 *	
 *	DOM読み込み後に実行する関数を設定します。
 */
cDOM.createStaticPublicMethod("ready", function(handler){
	if(typeof handler === "function"){
		if(cDOM.isReady === true){
			handler();
		}else{
			cDOM.handlers.push(handler);
		}
	}
});

blades.registerClass("DOM", cDOM);

////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 *	@class		blades.FontSizeEvent
 *	@inherits	blades.FontSizeEvent → blades.EventDispatcher → Object
 *	@implements	none
 *	
 *	フォントサイズ変化イベントを扱うシングルトンクラスです。
 *	フォントサイズ変更時にイベントを発火します。
 *	（※名称をFontSizeChangeからFontSizeEventに変更しました＠October 8, 2009）
 */
var cFontSizeEvent = blades.createClass(function(){
	
	var self = this;
	
	//独自イベント作成
	this.createEvent(cFontSizeEvent.CHANGE);
	this.createEvent(cFontSizeEvent.SMALLER);
	this.createEvent(cFontSizeEvent.LARGER);
	
	//初期化（フォントサイズチェック用ダミー要素配置）
	this.init();
	
	var oldSize = this.getCurSize();
	var oldComputedSize = this.getCurComputedSize();
	
	//フォントサイズ監視
	(function(){
		var curSize = self.getCurSize();
		var curComputedSize = self.getCurComputedSize();
		if(oldSize != curSize){
			self.dispatchEvent(cFontSizeEvent.CHANGE);
			if(oldSize > curSize){
				self.dispatchEvent(cFontSizeEvent.SMALLER);
			}else if(oldSize < curSize){
				self.dispatchEvent(cFontSizeEvent.LARGER);
			}
		
		//firefox用
		}else if(oldComputedSize != curComputedSize){
			self.dispatchEvent(cFontSizeEvent.CHANGE);
			if(oldComputedSize > curComputedSize){
				self.dispatchEvent(cFontSizeEvent.SMALLER);
			}else if(oldComputedSize < curComputedSize){
				self.dispatchEvent(cFontSizeEvent.LARGER);
			}
		}
		oldSize = curSize;
		
		//firefox用
		oldComputedSize = curComputedSize;
		
		window.setTimeout(arguments.callee, 100);
	})();	
}).extendsPublic(blades.EventDispatcher).asFinal();

//static
cFontSizeEvent.createStaticPrivateProperty("ID_NAME", "_BLADES_FONTSIZECHANGE_WRAPPER_");
cFontSizeEvent.createStaticPublicProperty("LARGER", "larger");
cFontSizeEvent.createStaticPublicProperty("CHANGE", "change");
cFontSizeEvent.createStaticPublicProperty("SMALLER", "smaller");

/**
 *	@return {void}
 *
 *	フォントサイズ監視用spanを挿入します。
 */
cFontSizeEvent.createPrivateMethod("init", function(){
	var _dummyElement = document.getElementById(cFontSizeEvent.ID_NAME);
	if(_dummyElement){
		this.dummyElement = _dummyElement;
		_dummyElement = null;
	}else{
		this.dummyElement = document.createElement("span");
		this.dummyElement.style.display = "block";
		this.dummyElement.style.visibility = "hidden";
		this.dummyElement.style.position = "absolute";
		this.dummyElement.style.zIndex = "-9999";
		this.dummyElement.style.left = "-9999px";
		this.dummyElement.style.top = "-9999px";
		this.dummyElement.style.margin = "0px";
		this.dummyElement.style.padding = "0px";
		this.dummyElement.style.minWidth = "1px";
		this.dummyElement.style.minHeight = "1px";
		
		//IE6
		if(document.all && !window.opera && !window.XMLHttpRequest){
			this.dummyElement.style.height = "1px";
		}
		
		this.dummyElement.style.lineHeight = "1em";
		this.dummyElement.style.overflow = "visible";
		this.dummyElement.style.fontSize = "1000%";
		this.dummyElement.style.textIndent = "0em";
		
		this.dummyElement.innerHTML = "B";
		this.dummyElement.setAttribute("id", cFontSizeEvent.ID_NAME);
		
		document.body.appendChild(this.dummyElement);
	}
});

/**
 *	@return {String} フォントサイズ監視用spanタグの高さを返します。
 */
cFontSizeEvent.createPrivateMethod("getCurSize", function(){
	return parseInt(this.dummyElement.clientHeight, 10);
});

/**
 *	@return {Number} フォントサイズ監視用spanタグ内のフォントサイズを返します。
 *	
 *	firefoxでbodyのstyleのfont-sizeを動的に変更した際にspanの高さが縮小／拡張されないため、computedStyleのfont-sizeを監視します。
 */
cFontSizeEvent.createPrivateMethod("getCurComputedSize", function(){
	if(document.defaultView){
		//fx,safari,opera,nn,chromeはpxで返す
		return parseInt(document.defaultView.getComputedStyle(this.dummyElement, null).getPropertyValue("font-size"), 10);
	}else{
		return 0;
	}
});

//シングルトンクラスとして登録
blades.registerClass("FontSizeEvent", cFontSizeEvent, true);

////////////////////////////////////////////////////////////////////////////////////////////////////

//ファイル名変更時に対応するためblades.Scriptインスタンス作成時にファイル名は指定しない。(訂正：ieでモジュールロードできないためファイル名を指定）
var js = new blades.Script("blades.js");
var search = js.getSrc().getSearch();
var modules = search.get("load") ? search.get("load").split(",") : null;
if(modules){
	for(var i=0, len=modules.length; i<len; i++){
		js.includeLocal(("blades." + modules[i] + ".js"), "utf-8");
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

})();