﻿/**
 * DDP名前空間定義
 */
if (typeof(DDP) == 'undefined') DDP = {};

if (typeof(console) == 'undefined' || console == null){ console = { 'log' : function(){} } };
// デバッグモード設定
if (typeof(DDP.DEBUG_MODE) == 'undefined' || DDP.DEBUG_MODE == null) {
	DDP.DEBUG_MODE = false;
}
if (!DDP.DEBUG_MODE) console.log = function() {};
console.log('load DDP_Framework.js ...');

//////////////////////// 共通系ユーティリティ関数 START ////////////////////////
(function(){
// local scope
var _undef,
	_win = window,
	_doc = document,
	_body = _doc.body,
	_ua = navigator.userAgent,
	_docEle = _doc.documentElement;

/* DOMContentLoaded */
var _ieContentLoded = function(win, fn) {
	var d = win.document, done = false,
	init = function () {
		if (done) { return; }
		done = true;
		fn();
	};
	(function () {
		try {
			d.documentElement.doScroll('left');
		} catch (e) {
			setTimeout(arguments.callee, 0);
			return;
		}
		init();
	})();
	d.onreadystatechange = function() {
		if (d.readyState == 'complete') {
			d.onreadystatechange = null;
			init();
		}
	};
};
/* DomReady */
(function(){
var _domReady = {};
var isReady = false,
	bound = false,
	fnList = [];
_domReady.fire = function() {
	if(isReady) return;
	isReady = true;
	if (fnList) {
		for(var i = 0, l = fnList.length; i < l; i++) {
			fnList[i].call(_win, []);
		}
		fnList = [];
	}
};
_domReady.bindReady = function() {
	if (bound) return;
	bound = true;
	if (_doc.readyState === 'complete' ) {
		setTimeout(_domReady.ready, 1);
		return;
	}
	if (_doc.addEventListener) {
		_doc.addEventListener('DOMContentLoaded', _domReady.fire, false);
	} else if (_doc.attachEvent) {
		(function(){
			if (isReady) return;
			try {
				_doc.documentElement.doScroll('left');
			} catch(error) {
				setTimeout(arguments.callee, 0);
				return;
			}
			_domReady.fire();
		})();
	} else {
		var baseLoad = _win.onload;
		_win.onload = function() {
			if (baseLoad) {
				baseLoad();
			}
			_domReady.fire();
		};
	}
};
_domReady.ready = function(fn) {
	_domReady.bindReady();
	if (isReady) {
		fn.call(_win, []);
	} else {
		fnList.push(function() { return fn.call(_win, []); });
	}
};
//_domReady.bindReady();
DDP.ready = _domReady.ready;
})();

/**
 * 指定したID 属性を検索してそのノードを返す。
 * @param id ID
 */
DDP.getNode = function(id) {
	return DDP.DOM.isNode(id) ? id : _doc.getElementById(id);
};
/**
 * イベントを登録する際に使用する関数。
 * ブラウザ間の違いを吸収します。
 * @param elem イベントを登録するエレメント
 * @param type イベント名
 * @param func 登録する関数
 * @return イベント登録できた場合true,それ以外はfalse
 * @type boolean
 */
DDP.addEvent = function(elem, type, func) {
	if (!elem) { return false; }
	var isWinLoad = elem.nodeType + '' == 'undefined' && type == 'load' && elem == _win;
	if (isWinLoad) {
		DDP.ready(func);
		return;
	}
	if (elem.addEventListener) {
		// Safari, Firefox, Opera
		elem.addEventListener(type, func, false);
	} else if (elem.attachEvent) {
		// IE
		elem.attachEvent('on'+type, func);
	} else {
		// MacIE、Opera6、Netfront3.0、Netscape3
		return false;
	}
	return true;
};
/**
 * イベントを登録する際に使用する関数。
 * ブラウザ間の違いを吸収します。
 * @param elems イベントを登録するエレメント配列
 * @param type イベント名
 * @param func 登録する関数
 * @return 全イベント登録できた場合true,それ以外はfalse
 * @type boolean
 */
DDP.addEvents = function(elms, type, func) {
	var arr = DDP.toArray(elms), ret = true;
	for(var i = 0, eLen = arr.length; i < eLen; i++) {
		ret |= DDP.addEvent(arr[i], type, func);
	}
	return ret;
};
/**
 * イベントを除去する際に使用する関数。
 * ブラウザ間の違いを吸収します。
 * @param elem イベントを除去するエレメント
 * @param type イベント名
 * @param func 除去する関数
 * @return イベント除去できた場合true,それ以外はfalse
 * @type boolean
 */
DDP.removeEvent = function(elem, type, func) {
	if (!elem) { return false; }
	if (elem.removeEventListener) {
		// Safari, Firefox, Opera
		elem.removeEventListener(type, func, false);
	} else if (elem.detachEvent) {
		// IE
		elem.detachEvent('on'+type, func);
	} else {
		// MacIE、Opera6、Netfront3.0、Netscape3
		return false;
	}
	return true;
};
/**
 * 文字列全置換関数。
 * @param text 文字列全体
 * @param sText 置換前文字列
 * @param rText 置換後文字列
 * @return 置換後の文字列
 * @type String
 */
DDP.allReplace = function(text, sText, rText) {
	var str = '' + text;
	str = str.split(sText);
	str = str.join(rText);
	return '' + str;
};
/**
 * 連想配列オブジェクトをマージします
 * される側とする側に同じデータがある場合、される側のデータは上書かれます。
 * @param map1 mergeされるマップ情報
 * @param map2 mergeするマップ情報
 */
DDP.merge = function(map1, map2) {
	for(var key in map2) {
		map1[key] = map2[key];
	}
};
/**
 * 書式に合わせてメッセージを組み立てます
 * <pre>
 * 例：
 * var message = 'hello,{0}!';
 * var result = DDP.formatMessage(message, 'world');
 * alert(result); // 出力:hello,world!
 * </pre>
 */
DDP.formatMessage = function() {
	if (arguments == null) { return null; }
	var result = arguments[0];
	for(var i = 1,aLen = arguments.length; i < aLen; i++) {
		result = DDP.allReplace(result, '{' + (i - 1) + '}', arguments[i]);
	}
	return result;
};
/**
 * 数値を金額表記の文字列に変換します。
 * @param amount 数値
 * @return 文字列に変換した金額(999,999形式)
 * @type String
 */
DDP.convertToAmountString = function(amount) {
	// 文字列に変換
	amount = '' + amount;
	var prev = '';
	while(prev != amount) {
		// 前回の結果を記録
		prev = amount;
		// 置換処理
		amount = amount.replace(/^(-?\d+)(\d{3})/, '$1,$2');
	}
	return amount;
};
/**
 * 対象値がArrayでない場合は長さ1の配列として返す。
 * @param value 対象値
 */
DDP.toArray = function(value) {
	var arr = [];
	if (value instanceof Array) {
		arr = value;
	} else {
		arr[0] = value;
	}
	return arr;
}
/**
 * 対象Nodeの表示状態を設定します。
 * @param node 対象node
 * @param display 表示:true,非表示:false
 */
DDP.setVisible = function(node, display) {
	if (!node) return
	node.style.display = display ? '' : 'none';
}
/**
 * disabled属性を設定します。
 * @param id 対象Nodeまたはそのid
 */
DDP.setDisabled = function(id, disabled) {
	if (!id) return;
	var arr = DDP.toArray(id);
	for(var i = 0, l = arr.length; i < l; i++) {
		var node = DDP.getNode(arr[i]);
		if (!node) continue;
		node.disabled = disabled;
	}
};
/**
 * 対象NodeのStyleClass指定に、新しいStyleClassを追加します
 * @param node 対象node
 * @param additionalClasses 追加するクラス
 */
DDP.addClass = function(node, additionalClasses) {
	var classes = additionalClasses.split(' ');
	for(var i = 0, cLen = classes.length; i < cLen; i++) {
		var targetClass = classes[i];
		if (targetClass == '') continue;
		var reg = new RegExp('\\b' + targetClass + '\\b');
		if (!node.className.match(reg)) {
			node.className += ' ' + targetClass;
		}
	}
};
/**
 * 対象NodeのStyleClass指定から、指定したStyleClassを取り除きます
 * @param node 対象node
 * @param removedClasses 取り除くクラス
 */
DDP.removeClass = function(node, removedClasses) {
	var classes = removedClasses.split(' ');
	for(var i = 0, cLen = classes.length; i < cLen; i++) {
		var targetClass = classes[i];
		if (targetClass == '') continue;
		var reg = new RegExp('\\s?\\b' + targetClass + '\\b');
		node.className = node.className.replace(reg, '');
	}
};
/**
 * 対象NodeのStyleClass指定に、指定したStyleClassがあるかどうか判定します
 * @param node 対象node
 * @param targetClasses 対象クラス
 * @return 全てのClassが存在する場合:true
 * @type boolean
 */
DDP.existClass = function(node, targetClasses) {
	var classes = targetClasses.split(' ');
	for(var i = 0, cLen = classes.length; i < cLen; i++) {
		var targetClass = classes[i];
		if (targetClass == '') continue;
		var reg = new RegExp('\\b' + targetClass + '\\b');
		if (!node.className.match(reg)) {
			return false;
		}
	}
	return true;
};
/**
 * 対象NodeのStyleClass指定に、指定したStyleClassを追加または除去します。
 * @param node 対象node
 * @param targetClasses 対象クラス
 * @param isAdd 追加の場合は true 、それ以外は false 。
 * @return 全てのClassが存在する場合:true
 * @type boolean
 */
DDP.setClass = function(node, targetClasses, isAdd) {
	return isAdd ? DDP.addClass(node, targetClasses) : DDP.removeClass(node, targetClasses);
};
/**
 * idのNodeのHref属性に「javascript:;」を設定します。
 * @param id 対象Nodeまたはそのid
 */
DDP.addHrefJs = function(id) {
	if (!id) return;
	var arr = DDP.toArray(id);
	for(var i = 0, l = arr.length; i < l; i++) {
		var item = arr[i];
		var node = DDP.getNode(item);
		if (!node) continue;
		node.setAttribute('href', 'javascript:;');
	}
}
/**
 * 選択ボックスの選択されている項目のvalue値を取得します
 * @param select 選択ボックスエレメント
 * @return 選択されている項目のvalue値
 */
DDP.getSelectedValue = function(select) {
	if (select.selectedIndex == -1) return;
	return select.options[select.selectedIndex].value;
};
/**
 * 選択ボックスの選択されている項目のStyleClassを選択ボックスのStyleClassに設定します
 * @param select 選択ボックスエレメント
 */
DDP.changePullDownStyleClass = function(select) {
	if (select.selectedIndex == -1) return;
	select.className = select.options[select.selectedIndex].className;
};
/**
 * プルダウンの選択値の同期を行います。
 * @param source 設定元プルダウンエレメントまたはID
 * @param destination 設定先プルダウンエレメントまたはID
 */
DDP.syncPullDownSelectedValue = function(source,destination) {
	DDP.getNode(destination).value = DDP.getNode(source).value;
};
/**
 * 指定したselect要素にoptionを追加します。
 * @param select 対象要素
 * @param text optionのテキスト
 * @param value optionのvalue
 * @param classNme optionのcssクラス名(指定時のみ設定)
 * @param color optionのstyle.color(指定時のみ設定)
 */
DDP.addOption = function(select, text, value, classNme, color) {
	if (!select) return select;
	if (DDP.Env.ie > 8) {
		var o = _doc.createElement('option');
		o.text = text;
		o.value = value;
		if (classNme) o.className = classNme;
		if (color) o.style.color = color;
		select.options.add(o);
		//try {
		// IE
		//var id = select.id, m = select.outerHTML.match(/([\s\S]+)(\r?\n?<\/select>)/i);
		//if (!(m && m.length == 3)) return select;
		//var arr = [''], idx = 1;
		//arr[idx++] = m[1];
		//arr[idx++] = DDP.formatMessage('<option value="{0}">{1}</option>', value, text);
		//arr[idx++] = m[2];
		//select.outerHTML = arr.join('');
		//select = DDP.getNode(id);
		//select.selectedIndex = 0;
		//if (!(classNme || color)) return select;
		//var o = select.options[select.options.length - 1];
		//if (classNme) o.className = classNme;
		//if (color) o.style.color = color;
		//} catch(e) { alert(select.options.length); }
	} else {
		// IE以外
		var o = new Option(text, value);
		if (classNme) o.className = classNme;
		if (color) o.style.color = color;
		select.options[select.options.length++] = o;
	}
	return select;
};
/**
 * 指定したselect要素のoptionを削除します(未指定のものを除く)。
 * @param select 対象要素
 * @param excludeSelected 選択された値を除くかどうか
 */
DDP.clearOption = function(select, excludeSelected) {
	if (!select || select.options.length < 1) return select;
	var o, nso = select.options[0].value == '' ? select.options[0] : null;
	if (DDP.Env.ie > 7) {
		// IE
		var id = select.id, m = select.outerHTML.match(/(<select((?!<)[\s\S])+>)([\s\S]*)(<\/select>)/i)
		if (!(m && m.length == 5)) return;
		var arr = [''], idx = 1;
		o = excludeSelected && select.selectedIndex > 0 ? select.options[select.selectedIndex] : null;
		arr[idx++] = m[1];
		arr[idx++] = nso ? nso.outerHTML : '';
		arr[idx++] = o ? o.outerHTML : '';
		arr[idx++] = m[5];
		select.outerHTML = arr.join('');
	} else {
		// IE以外
		var l = -1;
		o = excludeSelected  && select.selectedIndex > 0 ? select.options[select.selectedIndex] : null;
		select.options.length = 0;
		if (nso) select.options[++l] = nso;
		if (o) select.options[++l] = o;
	}
};
/**
 * 指定したselect要素のoptionを削除します(未指定のものを除く)。
 * @param select 対象select要素
 * @param index 
 */
DDP.removeOption = function(select, index) {
	if (!select || !select.options || select.options.length == 0 || index < 0) return;
	if (select.options.length <= index) return;
	select.removeChild(select.options[index]);
};
DDP.photoRoll = function(id, src, alt) {
	DDP.getNode(id).src = src;
	DDP.getNode(id).alt = alt;
};
///////////////////////// 共通系ユーティリティ関数 END /////////////////////////

/**
 * テキストボックス内にフォーカスがある場合にEnterをクリックした際、Postbackを防止する処理。
 * @param e イベント情報
 */
DDP.cancelEnterSubmit = function(e){
	var key = 0;
	if (typeof(e.keyCode) != 'undefined'){
		key = e.keyCode;
	}else if (typeof(e.which) != 'undefined'){
		key = e.which;
	}
	if (key == 13) {
		var uName = navigator.userAgent;
		if (uName.indexOf('MSIE') > -1) {
			if (_win.event.srcElement.type!='submit' && _win.event.srcElement.type!='textarea') {
				return false;
			}
		} else {
			if (e.target.type!='submit' && e.target.type!='textarea') {
				return false;
			}
		}
	}
};
/**
 * 画面をポップアップ表示させる（横幅：700px）。
 * 既にポップアップしている場合は、ポップアップ画面が切り替わる。
 * @param targetUrl ポップアップ表示させる画面のURL
 */
DDP.openPopupWindow = function(targetUrl){
	_win.open(targetUrl,'popup','width=700, menubar=no, toolbar=no, scrollbars=yes, resizable=yes');
};
/**
 * 複数画面をポップアップ表示させる（横幅：700px）。
 * 既にポップアップしている場合でも、さらにポップアップ画面が切起動する。
 * @param targetUrl ポップアップ表示させる画面のURL
 */
DDP.openPopupWindows = function(targetUrl){
	_win.open(targetUrl,'','width=700, menubar=no, toolbar=no, scrollbars=yes, resizable=yes');
};
/**
 * 画面をポップアップ表示させる（横幅：1000px）。
 * 既にポップアップしている場合は、ポップアップ画面が切り替わる。
 * @param targetUrl ポップアップ表示させる画面のURL
 */
DDP.openBigPopupWindow = function(targetUrl){
	_win.open(targetUrl,'popup','width=1000, menubar=no, toolbar=no, scrollbars=yes, resizable=yes');
};
/**
 * 複数画面をポップアップ表示させる（横幅：1000px）。
 * 既にポップアップしている場合でも、さらにポップアップ画面が切起動する。
 * @param targetUrl ポップアップ表示させる画面のURL
 */
DDP.openBigPopupWindows = function (targetUrl){
	_win.open(targetUrl,'','width=1000, menubar=no, toolbar=no, scrollbars=yes, resizable=yes');
};
/**
 * 印刷用ダイアログをポップアップ表示する
 */
DDP.dispPrintDialog =function (){
	if (_win.print) {
		_win.print();
	} else {
		var browser = '<OBJECT ID="browserObj" WIDTH=0 HEIGHT=0 CLASSID="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2"></OBJECT>';
		_body.insertAdjacentHTML('beforeEnd', browser);
		browserObj.ExecWB(6, 2);
	}
};
/**
 * 合計金額エリアと航空検索結果表を非表示にして、処理中アニメーションGIFを表示する
 */
DDP.ShowOnProcImg = function(){
	var waitAnimation = _doc.getElementById('wait_animation');
	if (waitAnimation != null){
		waitAnimation.style.display = 'block';
	}
	var airArea = _doc.getElementById('air_area');
	if (airArea != null) {
		airArea.style.display = 'none';
	}
	var amountFareArea = _doc.getElementById('amount_fare_area');
	if (amountFareArea != null) {
		amountFareArea.style.display = 'none';
	}
	var bottomConfirmPanel = _doc.getElementById('bottom_confirm_panel');
	if (bottomConfirmPanel != null) {
		bottomConfirmPanel.style.display = 'none';
	}
};
/**
 * 合計金額エリアと航空検索結果表を表示して、処理中アニメーションGIFを非表示にする
 */
DDP.HideOnProcImg = function(){
	var waitAnimation = _doc.getElementById('wait_animation');
	if (waitAnimation != null) {
		waitAnimation.style.display = 'none';
	}
	var airArea = _doc.getElementById('air_area');
	if (airArea != null) {
		airArea.style.display = 'block';
	}
	var amountFareArea = _doc.getElementById('amount_fare_area');
	if (amountFareArea != null) {
		amountFareArea.style.display = 'block';
	}
	var bottomConfirmPanel = _doc.getElementById('bottom_confirm_panel');
	if (bottomConfirmPanel != null) {
		bottomConfirmPanel.style.display = 'block';
	}
};
/**
 * 指定した文字数になるまで、対象文字列の右側または左側に、指定した文字を埋め込みます。
 * @param value 対象文字列
 * @param totalWidth 文字数。未指定の場合はvalue.length + 1。
 * @param paddingChar 埋め込み文字。未指定の場合は value が数値の場合 '0'、それ以外は ' '。
 * @param isLeft 左寄せの場合は true 、それ以外は false。
 * @return 演算後の文字列。
 */
DDP.pad = function(value, totalWidth, paddingChar, isLeft) {
	var ret = '' + value;
	if (!totalWidth) {
		totalWidth = ret.length + 1;
	}
	if (!paddingChar) {
		paddingChar = (typeof value === 'number') ? '0' : ' ';
	}
	while(ret.length < totalWidth) {
		ret = !!isLeft ? paddingChar + ret : ret + paddingChar;
	}
	return ret;
};
/**
 * 指定した文字数になるまで、対象文字列の右側に、指定した文字を埋め込みます。
 * @param value 対象文字列
 * @param totalWidth 文字数。未指定の場合はvalue.length + 1。
 * @param paddingChar 埋め込み文字。未指定の場合は value が数値の場合 '0'、それ以外は ' '。
 * @return 演算後の文字列。
 */
DDP.padLeft = function(value, totalWidth, paddingChar) {
	return DDP.pad(value, totalWidth, paddingChar, true);
};
/**
 * 指定した文字数になるまで、対象文字列の左側に、指定した文字を埋め込みます。
 * @param value 対象文字列
 * @param totalWidth 文字数。未指定の場合はvalue.length + 1。
 * @param paddingChar 埋め込み文字。未指定の場合は value が数値の場合 '0'、それ以外は ' '。
 * @return 演算後の文字列。
 */
DDP.padRight = function(value, totalWidth, paddingChar) {
	return DDP.pad(value, totalWidth, paddingChar, false);
};
/**
 * 指定したID 属性を検索してそのエレメントを返す。
 * @param id ID
 * @return {Element}
 */
DDP.getElement = function(id) {
	return DDP.getNode(id);
};
/**
 * 指定した要素のインラインスタイルのdisplayプロパティに 'none' を設定します。
 * @param {} element
 */
DDP.hideElement = function(element) {
	DDP.setVisible(element, false);
};
/**
 * 指定した要素のインラインスタイルのdisplayプロパティに '' を設定します。
 * @param {} element
 */
DDP.showElement = function(element) {
	DDP.setVisible(element, true);
};
/**
 * 指定した要素のインラインスタイルのdisplayプロパティが
 * 'none' なら false、
 * それ以外は true を返します。
 * @param {} element
 */
DDP.getVisible = function(element) {
	//return element.style.display == 'none' ? false : true;
	if (!element) return undefined;
	return element.style.display == 'none' ? false : true;
};
/**
 * 画面のサイズ情報を取得します。
 */
DDP.getPageSize = function() {
	var scrollX, scrollY;
	if (_win.innerHeight && _win.scrollMaxY) {
		scrollX = _body.scrollWidth;
		scrollY = _win.innerHeight + _win.scrollMaxY;
	} else if (_body.scrollHeight > _body.offsetHeight){
		scrollX = _body.scrollWidth;
		scrollY = _body.scrollHeight;
	} else {
		scrollX = _body.offsetWidth;
		scrollY = _body.offsetHeight;
	}

	var winWidth, winHeight;
	if (self.innerHeight) {
		winWidth = self.innerWidth;
		winHeight = self.innerHeight;
	} else if (_docEle && _docEle.clientHeight) {
		winWidth = _docEle.clientWidth;
		winHeight = _docEle.clientHeight;
	} else if (_body) {
		winWidth = _body.clientWidth;
		winHeight = _body.clientHeight;
	}

	var pageWidth = scrollX < winWidth ? winWidth : scrollX;
	var pageHeight = scrollY < winHeight ? winHeight : scrollY;
	return {
		'pageWidth': pageWidth,
		'pageHeight': pageHeight,
		'winWidth': winWidth,
		'winHeight': winHeight,
		'scrollX': scrollX,
		'scrollY': scrollY
	};
};
/**
 * スクロール情報を取得します。
 */
DDP.getScrollPos = function() {
	return { 'left': (_body.scrollLeft || _docEle.scrollLeft), 'top': (_body.scrollTop || _docEle.scrollTop) };
};
/**
 * 要素の位置情報を取得します。
 * @param elm 要素
 */
DDP.getElementScreenPosition = function(elm) {
	var html = elm.ownerDocument.documentElement;
	var rect = null;
	if (elm.getBoundingClientRect) {
		rect = elm.getBoundingClientRect();
	} else if (_doc.getBoxObjectFor) {
		pos = _doc.getBoxObjectFor(elm);
		rect = { left: pos.x, top: pos.y };
	} else {
		return null;
	}
	var left = rect.left - (html.clientLeft ? html.clientLeft : 0);
	var top = rect.top - (html.clientTop ? html.clientTop : 0);
	return { 'left': left, 'top': top };
};
/**
 * 要素の位置情報を取得します。
 * @param elm 要素
 */
DDP.getPosition = function(elm){
	//var height = elm.offsetHeight;
	// スクロール幅を取得
	var scrollPos = DDP.getScrollPos();
	// 画面内座標を取得
	var pos = DDP.getNodeScreenPosition(elm);
	if (!pos) return false;
	// スクロール幅を加算
	return { 'left': pos.left + scrollPos.left, 'top': pos.top + scrollPos.top };
};
/**
 * 指定ミリ秒で遅延実行します。
 * @param fn 実行する関数
 * @param delay 遅延させるミリ秒
 */
DDP.delayExec = function(fn, delay) {
	var handler = setInterval(function() {
		clearInterval(handler);
		fn();
	}, delay);
};
/**
 * IFrameを遅延読込します。
 * <pre>
 * [[HTML]]
 *   <div id="outer"><!-- <iframe src="***"></iframe> --></div>
 * [[Code]]
 *   DDP.delayIframeLoad({outerId: 'outer', delay: 500 });
 * </pre>
 * @param
 */
DDP.delayIframeLoad = function(conf) {
	if (!conf) return;
	var outer = DDP.getNode(conf.outerId);
	if (!outer) return;
	var delay = conf.delay ? conf.delay : 500;
	DDP.delayExec(function() {
		outer.innerHTML = outer.innerHTML.replace(/<!--|-->/g, "");
	}, delay);
};

///////////////////////// DDP.Env START /////////////////////////
/** 環境情報を定義 */
DDP.Env = (function(){
	var _ie = (function(){ //http://ajaxian.com/archives/attack-of-the-ie-conditional-comment
			var v = 3, div = _doc.createElement('div');
			while (
				div.innerHTML = '<!--[if gt IE '+(++v)+']><i></i><![endif]-->',
				div.getElementsByTagName('i')[0]
			);
			return v > 4 ? v : _undef;
		}()),
		_ff = (function(){
			var v = (/(?:Firefox\/)(\d+\.\d)/.exec(_ua) || [,-1])[1];
			return v == -1 ? _undef : parseFloat(v);
		}());
	return {
		ie: _ie,
		ff: _ff
	};
}());
///////////////////////// DDP.Env END /////////////////////////

///////////////////////// DDP.DOM START /////////////////////////
DDP.DOM = {};
DDP.DOM.isNode = function(obj) {
	if (DDP.Env.ie < 9) {
		if (!!obj && !(obj instanceof Object) && typeof(obj.nodeType) == 'number') {
			try {
				obj.nodeType = obj.nodeType;
			} catch(e) {
				return true;
			}
		}
		return false;
	} else {
		return !!obj && obj instanceof Node;
	}
};
///////////////////////// DDP.DOM END /////////////////////////

///////////////////////// DDP.DateTime START /////////////////////////
/**
 * DDP.DateTime
 * new DDP.DateTime(); = DDP.DateTime.now
 * new DDP.DateTime(totalMillisec);
 * new DDP.DateTime(year,month,day);
 * new DDP.DateTime(year,month,day,hour,minute,second);
 */
DDP.DateTime = function() {
	this.initialize.apply(this, arguments);
};
DDP.DateTime.cultures = {
	jajp: {
		diffUTC: 9,
		apNames :{
			full:  { AM: '午前', PM: '午後'},
			short: { AM: 'AM', PM: 'PM'}
		},
		dayNames: {
			//monday,tuesday,wednesday,thursday,friday,saturday,sunday
			full: new Array('日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日'),
			short:new Array('日'    ,'月'    ,'火'    ,'水'    ,'木'    ,'金'    ,'土')
		},
		monthNames: {
			// januray,february,march,april,may,june,july,august,september,october,november,december
			full: new Array('1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'),
			short:new Array('1'  ,'2'  ,'3'  ,'4'  ,'5'  ,'6'  ,'7'  ,'8'  ,'9'  ,'10'  ,'11'  ,'12')
		}
	}
};
DDP.DateTime.cultures = {
	def: DDP.DateTime.cultures.jajp,
	jajp: DDP.DateTime.cultures.jajp
};
DDP.DateTime.regExpFormat = /dddd|ddd|dd|d|fff|ff|f|hh|h|HH|H|mm|m|MMMM|MMM|MM|M|ss|s|tt|t|yyyy|yyy|yy|y/g;
DDP.DateTime.daysMonth = new Array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365);
DDP.DateTime.daysMonthLeapYear = new Array(0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366);
DDP.DateTime.isLeapYear = function(year) {
	return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
};
DDP.DateTime.daysInMonth = function(year, month) {
	if (DDP.DateTime.isLeapYear(year)) {
		return DDP.DateTime.daysMonthLeapYear[month] - DDP.DateTime.daysMonthLeapYear[month - 1];
	} else {
		return DDP.DateTime.daysMonth[month] - DDP.DateTime.daysMonth[month - 1];
	}
};
DDP.DateTime.now = function() {
	var d = new Date();
	return new DDP.DateTime(d.getFullYear(), d.getMonth() + 1, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
};
DDP.DateTime.today = function() {
	var d = new Date();
	return new DDP.DateTime(d.getFullYear(), d.getMonth() + 1, d.getDate());
};
DDP.DateTime.utcNow = function() {
	var d = new Date();
	return new DDP.DateTime(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
};
DDP.DateTime.prototype = {
	/* Constractor */
	initialize: function() {
		this.culture = DDP.DateTime.cultures.def;
		var days = 0, year = 0, month = 0, day = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0;
		var toNum = function(val) {
			var type = typeof val;
			if (type === 'number') return val;
			if (type === 'string' && !!val) return parseInt(val.replace(/^0+/, ''));
			throw('invalid argument.');
		};
		switch (arguments.length) {
			case 0:
				var d = new Date();
				year = d.getFullYear();
				month = d.getMonth() + 1;
				day = d.getDate();
				hours = d.getHours();
				minutes = d.getMinutes();
				seconds = d.getSeconds();
				milliseconds = d.getMilliseconds();
				break;
			case 1:
				milliseconds = toNum(arguments[0]);
				break;
			case 3:
				year = toNum(arguments[0]);
				month = toNum(arguments[1]);
				day = toNum(arguments[2]);
				break;
			case 7:
				year = toNum(arguments[0]);
				month = toNum(arguments[1]);
				day = toNum(arguments[2]);
				hours = toNum(arguments[3]);
				minutes = toNum(arguments[4]);
				seconds = toNum(arguments[5]);
				milliseconds = toNum(arguments[6]);
				break;
			default:
				throw('invalid arguments.length.');
		}

		days = (!year && !month && !day) ? 0 : this._ymd2days(year, month, day);
		this.timespan = new DDP.TimeSpan(days, hours, minutes, seconds, milliseconds);
	},
	/* Methods */
	add: function(timespan) {
		return new DDP.DateTime(this.totalMilliseconds() + timespan.totalMilliseconds());
	},
	addDays: function(days) {
		return this.add(new DDP.TimeSpan(days, 0, 0, 0));
	},
	addHours: function(hours) {
		return this.add(new DDP.TimeSpan(hours, 0, 0));
	},
	addMilliseconds: function(milliseconds) {
		return this.add(new DDP.TimeSpan(0, 0, 0, 0, milliseconds));
	},
	addMinutes: function(minutes) {
		return this.add(new DDP.TimeSpan(0, minutes, 0));
	},
	addMonths: function(months) {
		var day = this.day(), month = this.month() + (months % 12), year = this.year() + Math.round(months / 12);
		if (12 < month) {
			month -= 12;
			year++;
		} else if (month < 1) {
			month += 12;
		}
		var days = DDP.DateTime.daysInMonth(year, month);
		// 2010/3/29 -1month => 2010/02/28
		day = (days < day) ? days : day;
		return new DDP.DateTime(year, month, day).add(this.timeOfDay());
	},
	addSeconds: function(seconds) {
		return this.add(new DDP.TimeSpan(0, 0, seconds));
	},
	addYears: function(years) {
		return this.addMonths(years * 12);
	},
	compareTo : function(datetime){
		return this.timespan.compareTo(datetime.timespan);
	},
	equals: function(datetime) {
		return this.timespan.equals(datetime.timespan);
	},
	toString : function(format) {
		return this._format(!format ? 'yyyy/MM/dd HH:mm:ss.fff' : format);
	},
	_format: function(format, culture) {
		var useCulture = (culture) ? culture : this.culture;
		var ret = '', data = this._createFormatData(useCulture);
		var regexp = DDP.DateTime.regExpFormat;
		while(true) {
			var l = regexp.lastIndex, arr = regexp.exec(format);
			ret += format.slice(l, arr ? arr.index : format.length);
			if (!arr) break;
			var s = arr[0];
			ret += data[s] !== undefined ? data[s] : s;
		}
		return ret;
	},
	_createFormatData: function(culture) {
		var data = new Array();
		var year = this.year(), month = this.month(), day = this.day(), dayOfWeek = this.dayOfWeek(),
			hour = this.hour(), minute = this.minute(), second = this.second(), millisecond = this.millisecond();
		var strYear = '' + year;
		var padLeft0 = function(value) { return DDP.padLeft(value, 2, 0); };
		data['dddd'] = culture.dayNames.full[dayOfWeek];
		data['ddd']  = culture.dayNames.short[dayOfWeek];
		data['dd'] = padLeft0(day);
		data['d'] = day;
		data['fff'] = DDP.padLeft(millisecond, 3, '0');
		data['ff'] = DDP.padLeft(Math.floor(millisecond / 10), 2, '0');
		data['f'] = Math.floor(millisecond / 100);
		data['hh'] = padLeft0(hour > 12 ? hour - 12 : hour);
		data['h'] = hour > 12 ? hour - 12 : hour;
		data['HH'] = padLeft0(hour);
		data['H'] = hour;
		data['mm'] = padLeft0(minute);
		data['m'] = minute;
		data['MMMM'] = culture.monthNames.full[month - 1];
		data['MMM'] = culture.monthNames.short[month - 1];
		data['MM'] = padLeft0(month);
		data['M'] = month;
		data['ss'] = padLeft0(second);
		data['s'] = second;
		data['tt'] = (hour > 12 ? culture.apNames.full.PM : culture.apNames.full.AM);
		data['t'] = (hour > 12 ? culture.apNames.short.PM : culture.apNames.short.AM);
		data['yyyy'] = year;
		data['yyy'] = year;
		data['yy'] = strYear.length > 1 ? strYear.slice(-2) : strYear;
		data['y'] = data['yy'];
		return data;
	},
	_ymd2days: function(year, month, day) {
		var div = function(x,y){ return Math.floor(x/y); };
		var lastYear = year - 1;
		var arr = DDP.DateTime.isLeapYear(year) ? DDP.DateTime.daysMonthLeapYear : DDP.DateTime.daysMonth;
		var a = div(lastYear, 400),
			b = div(lastYear % 400, 100),
			c = div(lastYear % 100, 4),
			d = lastYear % 4,
			e = arr[month - 1] + day - 1;
		return (146097 * a) + (36524 * b) + (1461 * c) + (365 * d) + e;
	},
	// [part] 0:year, 1:dayOfYear, 2:month, 3:da
	_span2ymd: function(part) {
		// 1/01/01=1days,1/12/31=365day
		//   4years=365*4+1  =  1,461days
		// 100years=1461*25-1= 36,524days
		// 400years=36524*4-1=146,097days
		// totalDays = (146,097 * a) + (36,524 * b) + (1,461 * c) + (365 * d) + e
		// e = daysMonth + daysThisMont
		var div = function(x,y){ return Math.floor(x/y); };
		var days = Math.floor(this.timespan.totalDays());
		var a = div(days, 146097);
		days -= a * 146097;
		var b = div(days, 36524);
		// 36524*4=146,096 < 146,09
		if (b == 4) {
			b = 3;
		}
		days -= b * 36524;
		var c = div(days, 1461);
		// 1461*25=36525 > 3652
		days -= c * 1461;
		var d = div(days, 365);
		// 365*4=1460 < 146
		if (d == 4) {
			d = 3;
		}
		// year
		var year = (((((a * 400) + (b * 100)) + (c * 4)) + d) + 1);
		if (part == 0) {
			return year;
		}
		// dayOfYea
		days -= d * 365;
		if (part == 1) {
			return (days + 1);
		}
		// month
		var idx = 0, arr = DDP.DateTime.isLeapYear(year) ? DDP.DateTime.daysMonthLeapYear : DDP.DateTime.daysMonth;
		while (days >= arr[idx]) {
			idx++;
		}
		if (part == 2) {
			return idx;
		}
		// day
		return (days - arr[idx - 1] + 1);
	},
	/* Properties */
	date: function() {
		return new DDP.DateTime(this.timespan.totalMillisec());
	},
	day: function() {
		return this._span2ymd(3);
	},
	// 0:sun,1:mon,2:tue,3:wed,4:
	dayOfWeek: function() {
		return (this.timespan.days() + 1) % 7;
	},
	dayOfYear: function() {
		return this._span2ymd(1);
	},
	hour: function() {
		return this.timespan.hours();
	},
	millisecond: function() {
		return this.timespan.milliseconds();
	},
	minute: function() {
		return this.timespan.minutes();
	},
	month: function() {
		return this._span2ymd(2);
	},
	second: function() {
		return this.timespan.seconds();
	},
	timeOfDay: function() {
		return new DDP.TimeSpan(this.timespan.totalMillisec % (1000 * 60 * 60 * 24));
	},
	totalMilliseconds: function() {
		return this.timespan.totalMilliseconds();
	},
	year: function() {
		return this._span2ymd(0);
	}
};
///////////////////////// DDP.DateTime END /////////////////////////

///////////////////////// DDP.TimeSpan START /////////////////////////
/**
 * DDP.TimeSpan
 * new DDP.TimeSpan(totalMillisec);
 * new DDP.TimeSpan(hours,minutes,seconds);
 * new DDP.TimeSpan(days,hours,minutes,seconds);
 * new DDP.TimeSpan(days,hours,minutes,seconds,milliseconds);
 */
DDP.TimeSpan = function() {
	var days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0;
	switch(arguments.length) {
		case 1:
			milliseconds = arguments[0];
			break;
		case 3:
			hours = arguments[0];
			minutes = arguments[1];
			seconds = arguments[2];
			break;
		case 4:
			days = arguments[0];
			hours = arguments[1];
			minutes = arguments[2];
			seconds = arguments[3];
			break;
		case 5:
			days = arguments[0];
			hours = arguments[1];
			minutes = arguments[2];
			seconds = arguments[3];
			milliseconds = arguments[4];
			break;
		default:
			throw('invalid arguments.');
	}

	this.totalMillisec = (days * 1000 * 60 * 60 * 24) + (hours * 1000 * 60 * 60) + (minutes * 1000 * 60) + (seconds * 1000) + milliseconds;
};
DDP.TimeSpan.prototype = {
	/* Methods */
	toString: function() {
		return (Math.abs(this.days()) ? DDP.padLeft(Math.abs(this.days())) + '.': '') + DDP.padLeft(Math.abs(this.hours())) + ':' + DDP.padLeft(Math.abs(this.minutes())) + ':' + DDP.padLeft(Math.abs(this.seconds())) + '.' + Math.abs(this.milliseconds());
	},
	compareTo : function(timespan){
		if (this.totalMillisec == timespan.totalMillisec) return 0;
		return (this.totalMillisec > timespan.totalMillisec) ? 1 : -1;
	},
	equals: function(timespan) {
		return this.compareTo(timespan) == 0;
	},
	/* Properties */
	days: function() {
		return this.round(this.totalMillisec / (1000 * 60 * 60 * 24));
	},
	hours: function() {
		return this.round((this.totalMillisec % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
	},
	minutes: function() {
		return this.round((this.totalMillisec % (1000 * 60 * 60)) / (1000 * 60));
	},
	seconds: function() {
		return this.round((this.totalMillisec % (1000 * 60)) / (1000));
	},
	milliseconds: function() {
		return this.round(this.totalMillisec % 1000);
	},
	totalDays: function() {
		return this.totalMillisec / (1000 * 60 * 60 * 24);
	},
	totalHours: function() {
		return this.totalMillisec / (1000 * 60 * 60);
	},
	totalMinutes: function() {
		return this.totalMillisec / (1000 * 60);
	},
	totalSeconds: function() {
		return this.totalMillisec / (1000);
	},
	totalMilliseconds: function() {
		return this.totalMillisec;
	},
	round: function(value) {
		return Math.floor(value);
	}
};
///////////////////////// DDP.TimeSpan END /////////////////////////

///////////////////////// DDP.SmoothScroller START /////////////////////////
/**
 * @class ページ内アンカー遷移スクロール ユーティリティ
 */
DDP.SmoothScroller = {
	/**
	 * ページ内同ページへのアンカータグにイベント登録を行います。
	 */
	fixAllLinks: function() {
		var allLinks = _doc.getElementsByTagName('a');
		for(var i=0,aLen=allLinks.length;i<aLen;i++) {
			var lnk = allLinks[i];
			if ((lnk.href && lnk.href.indexOf('#') != -1) &&
				((lnk.pathname == location.pathname) ||
				('/'+lnk.pathname == location.pathname)) &&
				(lnk.search == location.search)) {
				DDP.addEvent(lnk,'click',DDP.SmoothScroller.smoothScroll);
			}
		}
	},
	/**
	 * ページ内同ページへのアンカータグのクリックイベント
	 * Targetのアンカーへのスクロールを行います。
	 * @param e クリックイベントオブジェクト
	 */
	smoothScroll: function(e) {
		var target;
		if (_win.event) {
			target = _win.event.srcElement;
		} else if (e) {
			target = e.target;
		} else return;
		if (target.nodeName.toLowerCase() != 'a') {
			target = target.parentNode;
		}
		if (target.nodeName.toLowerCase() != 'a') return;
		var anchor = target.hash.substr(1);
		var destinationLink = DDP.getNode(anchor);
		if (!destinationLink) {
			var allLinks = _doc.getElementsByTagName('a');
			for(var i=0;i<allLinks.length;i++) {
				var lnk = allLinks[i];
				if (lnk.name && (lnk.name == anchor) ||
					lnk.id && (lnk.id == anchor)) {
				destinationLink = lnk;
				break;
				}
			}
		}
		
		DDP.SmoothScroller.smoothScrollTo(destinationLink, anchor);
		
		if (e && e.preventDefault && e.stopPropagation) {
			e.preventDefault();
			e.stopPropagation();
		}
	},
	smoothScrollTo: function(destinationLink, anchor, endFunc) {
		if (!destinationLink) return true;
		var destx = destinationLink.offsetLeft;
		var desty = destinationLink.offsetTop;
		var thisNode = destinationLink;
		while (thisNode.offsetParent &&
			(thisNode.offsetParent != _body)) {
			thisNode = thisNode.offsetParent;
			destx += thisNode.offsetLeft;
			desty += thisNode.offsetTop;
		}
		clearInterval(DDP.SmoothScroller.INTERVAL);
		var currentPosition = DDP.SmoothScroller.getCurrentYPos();
		var stepsize = parseInt((desty - currentPosition)/DDP.SmoothScroller.STEPS);
		DDP.SmoothScroller.INTERVAL = setInterval(function() {
			DDP.SmoothScroller.scrollWindow(stepsize, desty, anchor, endFunc);
		}, 10);
		if (_win.event) {
			_win.event.cancelBubble = true;
			_win.event.returnValue = false;
		}
	},
	/**
	 * 目的のアンカーへ指定した距離分スクロール値を操作します。
	 * @param scramount 移動距離
	 * @param dest 目的値
	 * @param anchor 目的アンカー名
	 */
	scrollWindow: function(scramount,dest,anchor,endFunc) {
		var wascypos = DDP.SmoothScroller.getCurrentYPos();
		var isAbove = (wascypos < dest);
		_win.scrollTo(0, wascypos + scramount);
		var iscypos = DDP.SmoothScroller.getCurrentYPos();
		var isAboveNow = (iscypos < dest);
		if ((isAbove != isAboveNow) || (wascypos == iscypos)) {
			_win.scrollTo(0,dest);
			clearInterval(DDP.SmoothScroller.INTERVAL);
			if (anchor) {
				_win.location.hash = anchor;
			}
			if (endFunc) {
				endFunc();
			}
		}
	},
	/**
	 * 現在のスクロール位置を取得します。
	 */
	getCurrentYPos: function() {
		if (_body && _body.scrollTop)
			return _body.scrollTop;
		if (_docEle && _docEle.scrollTop)
			return _docEle.scrollTop;
		if (_win.pageYOffset)
			return _win.pageYOffset;
		return 0;
	}
};
/**
 * 何回のインターバルで、目的のアンカーに移動するか
 */
DDP.SmoothScroller.STEPS = 15;
///////////////////////// DDP.SmoothScroller END /////////////////////////

///////////////////////// DDP.DebugBox START /////////////////////////
/**
 * @fileoverview デバッグ用ボックス
 * @class デバッグ用ボックス
 */
DDP.DebugBox = function () { this.initialize.apply(this, arguments); };
DDP.DebugBox.prototype = {
	/**
	 * コンストラクタ
	 * @constructor
	 * @param debugInfo デバッグ情報(C#では Url.EscapeUriStringメソッドで文字列をエスケープされている。)
	 */
	initialize: function (debugInfo) {
		this.id = 'debugBox';
		this.debugInfo = debugInfo;
		this.load();
	},
	/**
	 * 画面へのロードを行う。
	 */
	load: function() {
		var self = this;
		var box = _doc.createElement('div');
		box.id = self.id;
		var bs = box.style;
		bs.width = '90%';
		bs.height = '250px';
		bs.border = '1px solid #CCC';
		bs.backgroundColor = '#FFF';
		bs.overflow = 'auto';
		_body.insertBefore(box, _body.firstChild);
		var debugInfoTextArea = _doc.createElement('textarea');
		debugInfoTextArea.id = self.id + '_' + 'debugInfoTextArea';
		debugInfoTextArea.cols = 200;
		debugInfoTextArea.rows = 15;
		debugInfoTextArea.value = decodeURIComponent(self.debugInfo);
		box.appendChild(debugInfoTextArea);
		var closeButton = _doc.createElement('input');
		closeButton.id = self.id + '_' + 'closeButton';
		closeButton.type = 'button';
		closeButton.value = 'close';
		DDP.addEvent(closeButton, 'click', function (e) {
			_body.removeChild(_body.firstChild);
		});
		box.appendChild(closeButton);
	}
};
///////////////////////// DDP.DebugBox END /////////////////////////

///////////////////////// DDP.TemplateProcessor START /////////////////////////
/**
 * @fileoverview テンプレート処理を行うクラスです。
 * @class テンプレート処理を行うクラスです。
 *
 * 仕様
 *
 * [% code %]         ：コードの実行
 * [%= context.**** ] ：変数代入
 * <% %>
 * <%= %>
 *
 * [% と %] を文字列として扱う場合は\でエスケープする。
 * ex) [\% と \%]
 */
DDP.TemplateProcessor = function() { this.initialize.apply(this, arguments); };
DDP.TemplateProcessor.prototype = {
	/**
	 * コンストラクタ
	 * @constructor
	 * @param template テンプレート
	 */
	initialize: function(template) {
		this.template = template;
		this.javascriptSource = "var applied = function(context) {" + "\r\n"
			+ this.analyze() + "\r\n"
			+ "return __code.join('');" + "\r\n"
			+ "}(context);";
	},
	/**
	 * テンプレートにcontext(JSON形式のデータ)を適用します。
	 * @param context テンプレートに挿入するJSON形式のデータ。
	 * @return テンプレートにcontext(JSON形式のデータ)を適用された文字列。
	 */
	apply: function(context) {
		if (!context) context = {};
		try {
			eval(this.javascriptSource);
		} catch(ex) {
			// alert("Parse Error\r\nType: " + ex.Type + "\r\nMessage: " + ex.Message);
		}
		//evalの結果を返す。
		return applied;
	},
	/**
	 * テンプレートの解析を行い、eval可能な文字列を返します。
	 * @return テンプレートを解析した結果のeval可能な文字列。
	 */
	analyze: function() {
		/*
		try {
		var __code = [];
		var __cCnt = 0;
		// テンプレートから作成したコード
		} catch(ex) {
		alert('Analyze Error\r\nType: ' + ex.Name + '\r\nMessage: ' + ex.Message);
		}
		*/
		// evalで評価されるコード
		var codeline = [""];
		var lCnt = 1;
		codeline[lCnt++] = "var __code = []; var __cCnt = 0;";
		codeline[lCnt++] = "__code[__cCnt++] = unescape('";
		var template = this.template;
		var isCode = false;
		var isVariable = false;
		// 代入式
		var strVariable = "";
		// テンプレート文字以外 __code[__cCnt++] = unescape('エンコードされた文字列'); として出力
		// テンプレート文字     __code[__cCnt++] = this.;
		var maxLength = template.length;
		for(var i = 0; i < maxLength; i++) {
			// 1文字目
			var s1 = template.charAt(i);
			// 2文字目
			var s2 = (i + 1 < maxLength) ? s1 + template.charAt(i + 1) : "";
			// 3文字目
			var s3 = (i + 2 < maxLength) ? s2 + template.charAt(i + 2) : "";
			// エスケープの場合
			if (s3 == "[\\%" || s3 == "\\%]") {
				var s = "";
				// 現在のモードがコード・代入のどちらかの場合は、\\を空文字に置換
				if (isCode || isVariable) {
					s = s3.replace("\\", "");
				}
				// 現在のモードがコード・代入のどちらでもない場合は、\\を空文字に置換してエスケープ
				else {
					s = escape(s3.replace("\\", ""));
				}
				// 現在のモードが代入の場合はストック
				if (isVariable) {
					strVariable += s;
				}
				// 現在のモードが代入以外の場合
				else {
					codeline[lCnt++] = s;
				}
				i += 2;
			}
			// コード開始タグ
			else if (s2 == "[%" && s3 != "[%=") {
				isCode = true;
				codeline[lCnt++] = "');\r\n";
				i += 1;
			}
			// 代入開始タグ
			else if (s3 == "[%=") {
				isVariable = true;
				codeline[lCnt++] = "');\r\n" + "__code[__cCnt++] = ";
				i += 2;
			}
			// 終了タグ
			else if (s2 == "%]") {
				if (isVariable) {
					codeline[lCnt++] = DDP.TemplateProcessor.format(strVariable) + ";";
					strVariable = "";
					isVariable = false;
				}
				isCode = false;
				codeline[lCnt++] = "\r\n" + "__code[__cCnt++] = unescape('";
				i += 1;
			}
			// 開始・終了タグ以外
			else {
				var s = "";
				if (isCode || isVariable) {
					// 現在のモードがコード・代入のどちらかの場合
					s = s1;
				} else {
					// 現在のモードがコード・代入のどちらでもない場合は、エスケープ
					s = escape(s1);
				}
				if (isVariable) {
					// 現在のモードが代入の場合
					strVariable += s;
				} else {
					codeline[lCnt++] = s;
				}
			}
		}
		return "try {" + "\r\n"
			 + codeline.join("") + "');" + "\r\n"
			 + "} catch(ex) {"
			 //+ "alert('Analyze Error\\r\\nType: ' + ex.Name + '\\r\\nMessage: ' + ex.Message);"
			 + "}";
	}
};
/**
 * フォーマット指定によりeval可能な結果を返す。
 * 現在は未実装。
 * @param format フォーマット指定されたテンプレートに適用する文字列。
 * @return フォーマット指定によりeval可能な文字列。
 */
DDP.TemplateProcessor.format = function(format) {
	return format;
};
///////////////////////// DDP.TemplateProcessor END /////////////////////////

///////////////////////// DDP.TableMenu START /////////////////////////
/**
 * @fileoverview IEのためのプルダウン幅調整用コントロール（テーブルメニュー）を
 * 提供するクラスです。
 * @class
 * @param txtName 選択項目表示用テキストボックスのID
 * @param selectName 同期対象プルダウンのID
 * @param frameId 表示フレームID
 * @param buttonId テーブルメニュー表示ボタンのID
 */
DDP.TableMenu = function (txtName, selectName, frameId, buttonId) {
	this.initialize.apply(this, arguments);
};
DDP.TableMenu.prototype = {
	/** option要素にColor値 */
	optionColor: 'black',
	/** 未選択option要素にColor値 */
	noselectOptionColor: '#cc6600',
	/** 選択領域に適用するCSSクラス名 */
	cssClassMenu: 'tblMenuTable',
	/** 選択できない要素に適用するCSSクラス名 */
	cssClassMenuDisabled: 'tblMenuDisabled',
	/** 選択された要素に適用するCSSクラス名 */
	cssClassMenuSelected: 'tblMenuSelected',
	/** 選択可能な要素に適用するCSSクラス名 */
	cssClassMenuNormal: 'tblMenuNormal',
	/**
	 * コンストラクタ。
	 * テーブルメニューを初期化します。
	 * @constructor
	 * @param txtName 選択項目表示用テキストボックスのID
	 * @param selectName 同期対象プルダウンのID
	 * @param frameId 表示フレームID
	 * @param buttonId テーブルメニュー表示ボタンのID
	 */
	initialize: function(txtName, selectName, frameId, buttonId) {
		var ie = 0;
		/*@cc_on
		ie = @_jscript_version;
		@*/
		/** IE判定用変数 */
		this.isIE = !!(window.attachEvent && !window.opera && ie < 9 );
		/** テーブルメニューDOMインスタンス */
		this.tblMenuTbl = null;
		/** 選択表示用テキストボックスDOMインスタンス */
		this.tblMenuText = null;
		/** 同期対象プルダウンDOMインスタンス */
		this.tblMenuSelect = null;
		/** マウスオーバー中のDOMインスタンス */
		this.tblMenuCurrent = null;
		/** テーブルメニュー表示ボタンDOMインスタンス */
		this.tblMenuButton = null;
		/** 親ドキュメント用IFrameDOMインスタンス */
		this.tblFrame = null;
		/** 表示フレームID */
		this.tblFrameId = null;
		/** 初期化済み判定フラグ */
		this.tblIsInitialized = false;
		/** 表示用IFrameドキュメント */
		this.tblIFrameDocument = null;
		this.tblFrameId = frameId;
		this.tblMenuSelect = DDP.getNode(selectName);
		this.tblFrame = DDP.getNode(frameId);
		if (this.tblMenuSelect && this.tblFrame) {
			// 初期化完了
			this.tblIsInitialized = true;
		}else {
			// 初期化失敗
			this.tblIsInitialized = false;
			return;
		}
		// イベント登録
		var __this = this;
		DDP.addEvent(this.tblMenuSelect, 'mousedown', function() { __this.show(); });
		DDP.addEvent(this.tblFrame, 'blur', function() { __this.hide(); });
		// 初期化が完了したら更新を行い、プルダウンと内容を同期する。
		this.update();
		// 同期が完了したら、非表示にする。
		this.hide();
		// プルダウンがdisableの場合、当コントロールもdisableに設定する
		if (this.tblMenuSelect && this.tblMenuSelect.disabled) {
			this.disable();
		}
	},
	/**
	 * テーブルメニューを表示します。
	 */
	show: function() {
		if (!this.tblIsInitialized) return;
		// IEでない場合、初期化が正常に完了していない場合、disableの場合は処理しない。
		if (!this.isIE || !this.tblIsInitialized || this.tblMenuSelect.disabled){ return; }
		this.tblMenuSelect.disabled = true;
		// 表示処理を行う
		var fs = this.tblFrame.style;
		fs.display = '';
		fs.visibility = 'visible';
		fs.zIndex = 1;
		this.update();
		this.tblFrame.focus();
	},
	/**
	 * テーブルメニューを非表示にします。
	 */
	hide: function() {
		if (!this.tblIsInitialized) return;
		this.tblMenuSelect.disabled = false;
		if (this.tblFrame != null) {
			var fs = this.tblFrame.style;
			fs.display = 'none';
			fs.visibility = 'hidden';
			fs.zIndex = 0;
		}
	},
	/**
	 * 行に選択済みスタイルを適用します。
	 * 項目に対し、マウスオーバーした際に使用する。
	 * @param event マウスオーバーイベントのイベントオブジェクトまたはそれと同等のもの
	 */
	enterRow: function(event) {
		if (!this.tblIsInitialized) return;
		var row = event.target ? event.target : event.srcElement;
		if (row != this.tblMenuCurrent) {
			this.tblMenuCurrent.className=this.cssClassMenuNormal;
		}
		row.className=this.cssClassMenuSelected;
		this.tblMenuCurrent = row;
	},
	/**
	 * 行を選択します。
	 * 項目に対し、クリックした際に使用する。
	 * @param event クリックイベント（マウスダウン）のイベントオブジェクトまたはそれと同等のもの
	 */
	selectRow: function(event) {
		if (!this.tblIsInitialized) return;
		// 項目選択の内部処理する
		this.selectRowInner(event);
		if (this.tblMenuSelect.handler) {
			// 同期しているプルダウンのChangeEventを発生させる
			this.tblMenuSelect.handler.onChangeEvent();
		}
		// クリックされたので、非表示に設定する
		this.hide();
	},
	/**
	 * 行を選択します。項目に対し、クリックした際に使用する。
	 * 内部処理を実装しています。
	 * @param event クリックイベント（マウスダウン）のイベントオブジェクトまたはそれと同等のもの
	 */
	selectRowInner: function(event) {
		if (!this.tblIsInitialized) return;
		// 選択したCellを取得
		var cell = event.target ? event.target : event.srcElement;
		// 選択したCellの値によって、プルダウンを更新する
		this.tblMenuSelect.value = cell.getAttribute('value');
		if (this.tblMenuSelect.selectedIndex == -1) {
			// -1が設定されいた場合（選択処理が不正の場合）、0を設定
			this.tblMenuSelect.selectedIndex = 0;
		}
	},
	/**
	 * テーブルメニューのHTMLを生成します。
	 */
	generateHtml: function() {
		if (!this.tblIsInitialized) return;
		this.tblFrame.style.position='absolute';
		if (this.tblIFrameDocument==null) {
			// IFrame内ドキュメントのHTMLを生成する
			var html = '<html><head><title>title</title>'
			+ '<link href="./plus/css/plus_table_menu.css" media="all" rel="stylesheet" type="text/css" />'
			+ '</head><body style="margin:0px">'
			+ '</body></html>';
			// 生成したHTMLを書き出す
			this.tblIFrameDocument = this.tblFrame.contentDocument ? this.tblFrame.contentDocument : document.frames[this.tblFrameId].document;
			this.tblIFrameDocument.open();
			this.tblIFrameDocument.write(html);
			this.tblIFrameDocument.close();
		}
		// 同期対象のプルダウンの内容に合わせてBody内のHTMLを生成する
		var bodyArray = [''], bIdx = 1;
		bodyArray[bIdx++]='<div class="' + this.cssClassMenu +'">\n';
		for(var i=0,l=this.tblMenuSelect.options.length; i<l; i++) {
			var opt=this.tblMenuSelect.options[i];
			var cellText =opt.innerHTML;
			var cellValue=opt.value;
			var rhtml = '<div value="' + cellValue + '" class="';
			// セルの状態に合わせて、スタイルを設定する
			if (cellText.match(/[(]0件[)]/)) {
				rhtml+=this.cssClassMenuDisabled;
			} else if (cellValue == this.tblMenuSelect.value) {
				rhtml+=this.cssClassMenuSelected;
			} else {
				rhtml+=this.cssClassMenuNormal;
			}
			// 色も設定する
			if (opt.style.color==this.noselectOptionColor) {
				rhtml+='" style="color:' + this.noselectOptionColor;
			}
			bodyArray[bIdx++]= rhtml + '">' + cellText + '</div>';
		}
		bodyArray[bIdx++]='</div>';
		// 文字の大きさ測り、テーブルメニューの調整を行うためのrulerを生成しておく
		bodyArray[bIdx++]='<span id="ruler" style="visibility:hidden;position:absolute;"></span>\n';
		var body=bodyArray.join('');
		// IFrame内ドキュメントのbodyの内容を更新する
		this.tblIFrameDocument.body.innerHTML = body;
		// 作成したDOMオブジェクトのインスタンスを取得する
		this.tblMenuTbl = this.tblIFrameDocument.body.childNodes.item(0);
	},
	/**
	 * 全ての項目に対し、イベントの登録を行います
	 */
	addEventAll: function() {
		if (!this.tblIsInitialized) return;
		var __this = this;
		var rows = this.tblMenuTbl.childNodes;
		var rlen = (rows.length);
		for(var i=0; i<rlen; i++) {
			var row = rows.item(i);
			if (row.className != this.cssClassMenuDisabled){
				DDP.addEvent(row, 'mousedown', function(e){ __this.selectRow(e); });
				DDP.addEvent(row, 'mouseover', function(e){ __this.enterRow(e); });
				if (row.className == this.cssClassMenuSelected) {
					this.tblMenuCurrent = row;
				}
			}
		}
	},
	/**
	 * テーブルメニューのIFrameの表示位置を、テキストボックスの位置に同期させます。
	 */
	setPosition: function(){
		if (!this.tblIsInitialized) return;
		// テキストボックスに位置を揃える
		var control = this.tblMenuSelect;
		var x = control.offsetLeft;
		var y = control.offsetHeight + control.offsetTop + 1;
		// 親を再帰的に参照し、オフセット値を算出する
		while (control.offsetParent != document.body
			 &&control.offsetParent != document
			 &&control.nodeName !='HTML') {
			x += control.offsetParent.offsetLeft;
			y += control.offsetParent.offsetTop;
			control = control.offsetParent;
		}
		var fs = this.tblFrame.style;
		fs.left = x+'px';
		fs.top = y+'px';
	},
	/**
	 * テーブルメニューの大きさを内容に合わせ調整します。
	 */
	resize: function() {
		if (!this.tblIsInitialized) return;
		// tblFrameのサイズを大きくする
		this.tblFrame.width = '1000px';
		this.tblFrame.height = '1000px';
		var rows = this.tblMenuTbl.childNodes;
		var rlen = (rows.length);
		var control = this.tblMenuSelect;
		// 再計算させるために一度参照する
		var wTemp = control.offsetWidth + 0;
		// 定規として使用するNodeを取得
		var rulerNode = this.tblIFrameDocument.getElementById('ruler');
		// 最低幅として、selectの幅を使用する
		var maxWidth = control.offsetWidth;
		// 項目一つ一つの長さを調べて、最大の長さに合わせて幅を調整する
		for(var i=0; i<rlen; i++) {
			var row = rows.item(i);
			// 指定した文字列で使用する文字列幅を取得する
			var width = this.getStringWidth(rulerNode, row.innerHTML);
			if (maxWidth < width) { maxWidth = width };
		}
		// 再計算させるために一度参照する
		var temp = this.tblMenuTbl.offsetHeight + 0;
		this.tblIFrameDocument.body.style.overflow='hidden';
		// 取得した内容によって、IFrameの大きさを調整する
		this.tblFrame.height = (this.tblMenuTbl.offsetHeight + 2) + 'px';
		this.tblFrame.width = (maxWidth + 2) + 'px';
	},
	/**
	 * 選択されている内容に合わせて、プルダウンの色を更新します。
	 */
	updateColor: function() {
		if (!this.tblMenuSelect) return;
		var ss = this.tblMenuSelect.style;
		if (this.tblMenuSelect.selectedIndex==0) {
			ss.color=this.noselectOptionColor;
			for(var i=1,l=this.tblMenuSelect.options.length;i<l;i++) {
				this.tblMenuSelect.options[i].style.color=this.optionColor;
			}
		} else {
			ss.color=this.optionColor;
			this.tblMenuSelect.options[0].style.color=this.noselectOptionColor;
		}
	},
	/**
	 * テーブルメニューの内容を同期対象のプルダウンに合わせて更新します。
	 */
	update: function() {
		var __this = this;
		// 初期化が正常に主る用している場合のみ処理
		if (!this.isIE || !this.tblIsInitialized){
			if (this.tblMenuSelect) {
				// 他のブラウザでもでも、色は更新する
				DDP.addEvent(this.tblMenuSelect,'change', function(e) { __this.updateColor(e); });
				this.updateColor();
			}
			return;
		}
		// ここからはIEの場合のみ処理
		// == 項目内容の同期 ==
		// HTMLを生成し、反映する
		this.generateHtml();
		// 作成されてたDOMに対し、イベントを登録する
		this.addEventAll();
		// 作成されたFrameの位置を調整する
		// 親要素にposition:relative;, iframeにposition:absolute;top:(selectの高さ);で対応
		//this.setPosition();
		// 作成されたFrameの大きさを調整する
		this.resize();
		// == 選択項目の同期 ==
		// 選択状態が不正な場合は処理しない
		if (this.tblMenuSelect.selectedIndex == -1) {
			return;
		}
		// 選択項目の値を取得
		var selectedValue = this.tblMenuSelect.options[this.tblMenuSelect.selectedIndex].value;
		var rows = this.tblMenuTbl.childNodes;
		var rlen = (rows.length);
		for(var i = 0; i < rlen; i++) {
			var row = rows.item(i);
			if (selectedValue == row.getAttribute('value')) {
				// 同期対象プルダウンの選択項目同じ項目に対し選択処理を実行
				this.selectRowInner({target:row});
				break;
			}
		}
	},
	/**
	 * 指定したNodeに文字列を配置した際の文字列の幅を取得します。
	 * @param rulerNode 文字列の幅を計るために配置するNode
	 *   このNodeに配置した際の大きさを取得することが出来る。
	 * @param str 幅を取得する対象文字列
	 * @type Number
	 * @return 取得した幅数値
	 */
	getStringWidth: function(rulerNode, str) {
		if (!this.tblIsInitialized) return 0;
		// フレームの大きさが小さいと正しく計測できないため変更する
		var prevWidth = this.tblFrame.width;
		this.tblFrame.width = 2000;
		// Nodeの全ての子要素を削除
		var c;
		while (c = rulerNode.lastChild) rulerNode.removeChild(c);
		// 文字列を含む新しいテキストノードを作成し、追加する
		var text = rulerNode.appendChild(rulerNode.ownerDocument.createTextNode(str));
		// 大きさ取得のために、一度参照する（一度目は正しい値が取得できない）
		var temp = rulerNode.offsetWidth + 0;
		// 大きさを取得する
		var width = rulerNode.offsetWidth;
		// 追加したNodeを削除する
		rulerNode.removeChild(text);
		// 変更した幅を元に戻す
		this.tblFrame.width = prevWidth;
		return width;
	},
	/**
	 * テーブルメニューを無効にします。
	 */
	disable: function() {
		if (!this.isIE || !this.tblIsInitialized){ return; }
		this.tblMenuSelect.style.color='';
	},
	/**
	 * テーブルメニューを有効にします。
	 */
	enable: function() {
		if (!this.isIE || !this.tblIsInitialized){ return; }
	}
};
///////////////////////// DDP.TableMenu END /////////////////////////

///////////////////////// DDP.Element START /////////////////////////
/**
 * 要素を表すクラスです。
 * @class
 */
DDP.Element = function(id) {
	/**
	 * 内部で保持するElement。
	 * @type {Element}
	 */
	this.element = null;
	this.initialize.apply(this, arguments);
};
DDP.Element.next = function(elm) {
	if (elm.nextElementSibling) return elm.nextElementSibling;
	do {
		elm = elm.nextSibling;
	} while(elm && elm.nodeType != 1)
	return elm;
};
DDP.Element.prototype = {
	/**
	 * 要素のIDで初期化します。
	 * @param {String} id 要素のID。
	 * @constructor
	 */
	initialize: function(id) {
		this.element = DDP.getNode(id);
	},
	/**
	 * 指定した要素が存在するかどうかを示す値を取得します。
	 * @return {Boolean} 指定した要素が存在するかどうかを示す値。
	 */
	exists : function() {
		return this.element != null;
	},
	/**
	 * 要素が表示されているかどうかを示す値を取得します。
	 * @return {Boolean} 表示されているかどうかを示す値。
	 */
	visible: function() {
		return DDP.getVisible(this.element);
	},
	/**
	 * 要素を非表示にします。
	 */
	hide : function() {
		DDP.hideElement(this.element);
	},
	/**
	 * 要素を表示します。
	 */
	show : function() {
		DDP.showElement(this.element);
	},
	/**
	 * 指定したクラスを追加します。
	 * @param {String[]} classNames クラス名の配列
	 */
	addClass : function(classNames) {
		DDP.addClass(this.element, classNames.join(','));
	},
	/**
	 * 指定したクラスを削除します。
	 * @param {String[]} classNames クラス名の配列
	 */
	removeClass : function(classNames) {
		DDP.removeClass(this.element, classNames.join(','));
	},
	/**
	 * 次のエレメントを取得します。
	 * @return {Element} 次のエレメント
	 */
	nextElement : function() {
		return DDP.Element.next(this.element);
	}
};
///////////////////////// DDP.Element END /////////////////////////

///////////////////////// DDP.Button START /////////////////////////
/**
 * Buttonを表すクラスです。
 * @param {String} id 要素のID
 */
DDP.Button = function(id) {
	this.initialize.apply(this, arguments);
};
/**
 * prototypeを上書き。
 */
DDP.Button.prototype = new DDP.Element();
/**
 * 初期化します。
 * @constructor
 * @param {String} id 要素のID
 */
DDP.Button.prototype.initialize = function(id) {
	var __this = this;
	DDP.Element.prototype.initialize.apply(this, [id]);
	// clickイベント登録
	DDP.addEvent(this.element, 'click', function() { __this.onClickEvent(); });
};
/**
 * clickイベントが発生した場合の処理を記述
 * 継承したクラスによってオーバーライドされることを想定しています
 */
DDP.Button.prototype.onClickEvent = function() {
};
/**
 * clickイベントを発生させます。
 */
DDP.Button.prototype.raiseClickEvent = function() {
	this.element.click();
};
/**
 * コントロールを使用可能に設定します。
 */
DDP.Button.prototype.enable = function() {
	this.element.disabled = false;
};
/**
 * コントロールを使用不可能に設定します。
 */
DDP.Button.prototype.disable = function() {
	this.element.disabled = true;
};
///////////////////////// DDP.Button START /////////////////////////
})();
