
// menuTypes() の順番と一致している必要あり
var _rotary_ = 0;
var _address_ = 1;
var _calendar_ = 2;
var _group_ = 3;
var _panel_ = 4;
var _date_ = 5;
var _none_ = 6;
var _number_ = 7;
var _yearMonth_ = 8; // 年月のみの入力

function menuTypes(){
	// メニューの形式
	return ["Rotary","Address","Calendar","Group","Panel","Date","None","Number","YearMonth"]
}

var _menu_to_tail_ = 0;
var _menu_to_last_row_ = 1;
var _menu_replace_ = 2;
var _menu_to_head_ = 3;
function menuActions(){
	// メニューを文中に挿入する位置
	return ["文末へ追加","最終行へ追加","置換","文頭へ挿入"];
}
function menuActionForIndex(ix){
    // 番号 ix に対応するメニューアクションを文字列で返す
    var array = menuActions();
    return (array.length > ix) ? array[ix] : null;
}
function indexForMenuAction(st){
    // メニューアクション文字列に対応する番号を返す
    var array = menuActions();
    for (num in array){
        var actionSt = array[num];
        if (actionSt == st) return num;
    }
    return (-1); // ERROR
}

function buttonTypes(){
    // チェインするかどうかを設定
    return ["no chain", "chain"];
}

function fieldTypes(){
    // 一行の文字列、複数行のテキスト
	return ["String","Text"];
}

function MML0026(){
	// 記録者分類および医療資格コード: groupCode
	return { "doctor":"医師","dentist":"歯科医師","nurse":"看護師","assistantNurse":"准看護師","lab":"臨床検査技師","rad":"レントゲン技師","pharmacist":"薬剤師","pt":"理学療法士","ot":"作業療法士","psy":"精神保健福祉士","cps":"臨床心理技術者","nutritionist":"栄養士","dentalHygienist":"歯科衛生士","dentalTechician":"歯科技工士","clinicalEngineer":"臨床工学士","careManager":"介護支援専門員","other":"その他の医療従事者","acupuncturist":"鍼灸師","patient":"患者およびその代理人","clerk":"書記","office worker":"事務" };
}

function MML0028(){
	// 医科診療科コード: sectionCode
	return { "01":"内科","02":"精神科","03":"神経科","04":"神経内科","05":"呼吸器科","06":"消化器科","07":"胃腸科","08":"循環器科","09":"小児科","10":"外科","11":"整形外科","12":"形成外科","13":"美容外科","14":"脳神経外科","15":"呼吸器外科","16":"心臓血管外科","17":"小児外科","18":"皮膚泌尿器科","19":"皮膚科","20":"泌尿器科","21":"性病科","22":"肛門科","23":"産婦人科","24":"産科","25":"婦人科","26":"眼科","27":"耳鼻咽喉科","28":"気管食道科","29":"理学療法科","30":"放射線科","31":"麻酔科","32":"人工透析科","33":"心療内科","34":"アレルギー","35":"リウマチ","36":"リハビリ","A1":"鍼灸","00":"その他" };
}

var _osType;
function osType(){
    // OS のタイプを返す
    if (!_osType){
        var st = window.navigator.userAgent;
        if (st.indexOf("Macintosh") > 0){
            _osType = "mac";
        } else if (st.indexOf("iPad") > 0){
            _osType = "ipad";
        } else if (st.indexOf("iPhone") > 0){
            _osType = "iphone";
        } else {
            _osType = st;
        }
    }
    
    return _osType;
}

function _log(val){
    // コンソールへデバッグ用ログを表示
    console.log(val);
}

function isTouchDevice(){
    // device が iPad, iPhone, iPod かどうかを返す
    var ua = navigator.userAgent;
    if (ua.indexOf('iPad') >= 0) return true;
    if (ua.indexOf('iPhone') >= 0) return true;
    if (ua.indexOf('iPod') >= 0) return true;
    return false;
}

function is_HL7_format(){
	// HL7 形式に設定すると「都道府県番号・点数表番号・医療機関コード」など
	// に対応していないので、それらのコードが印刷されない。
	return false;
}

function medicalEncodeType(buff){
	// buff がどのようなフォーマットで encode されているか調べて返す
	if ((buff.indexOf("MSH|") >= 0) && (buff.indexOf("PID|") >= 0))
		return "HL7";
	else if (buff.indexOf("(") && buff.indexOf(")"))
		return "NOA";
	else {
		alert("=== Undefined encode ===\n" + buff);
		return "";
	}
}

var _leftbrackets2 = "（"; // encodeParentheses 中では '(' を倍角に変換
var _rightbrackets2 = "）"; // encodeParentheses 中では ')' を倍角に変換
function encodeParentheses(value){
    // value 中の '(',')' を decodeObject で展開されないよう encode
    // decodeObject でも解けないものとする：DocMaker などで利用
    value = convertSTRING(value, "(", _leftbrackets2);
    value = convertSTRING(value, ")", _rightbrackets2);
    
    return value;
}
function decodeParentheses(value){
    // value 中の '(',')' を decode
    value = convertSTRING(value, _leftbrackets2, "(");
    value = convertSTRING(value, _rightbrackets2, ")");
    
    return value;
}

var _leftbrackets = "^[^"; // encode 中で使う '('
var _rightbrackets = "^]^"; // encode 中で使う ')'
function encodeValue(value){
    // value 中の '(',')' を decodeObject で展開されないよう encode
    value = convertSTRING(value, "(", _leftbrackets);
    value = convertSTRING(value, ")", _rightbrackets);
    
    return value;
}
function encodeObject(obj){
	// obj を "key(value)" の文字列に encode して返す -- NOA format と呼ぶ
	// encode 方法として JSON 形式その他が考えられるが NOA format が最も軽いので採用
	// ### 現状では配列はサポートしていない
	var buff = "";
	for (key in obj){
		var value = obj[key];
		if (typeof(value) == "object"){
			buff += key + "(" + encodeObject(value) +")";
		} else {
			// "(", ")" は特定文字にしておく（ decode する時に元へ戻す）
			value = convertSTRING(value, "(", _leftbrackets);
			value = convertSTRING(value, ")", _rightbrackets);
			
			buff += key + "(" + value +")";
		}
	}
	return buff;
}
function decodeObject(buff){
	// "key(value)" 形式の文字列を OBJECT に decode して返す
	var obj = new Object();
    if (buff){
        var len = buff.length, begin, end;
        var key, value;
        for (var p=begin=nest=0; p < len; p++){
            var ch = buff.charAt(p);
            if (ch == '('){
                if (nest == 0){
                    key = trim(buff.substring(begin, p)); // key 終端
                    begin = p + 1; // value 開始位置
                }
                nest++;
            } else if (ch == ')'){
                if (--nest == 0){
                    if (nest == 0){
                        value = buff.substring(begin, p); // value 終端:trim しない
                        begin = p + 1; // key 開始位置
                    }
                    
                    if (value.indexOf(")") > 0){ // まだ入れ子になっているなら
                        obj[key] = decodeObject(value);
                    } else {
                        // 特定文字を "(", ")" へ戻す
                        value = convertSTRING(value, _leftbrackets, "(");
                        value = convertSTRING(value, _rightbrackets, ")");
                        
                        obj[key] = value;
                    }
                }
            }
        }
    }
	return obj;
}

function encodeSTRING(value){
	// #, &, +  < > などが URI 送信で化けるため encode して送る
	if (value.length == 0) return value;
	value = convertSTRING(value, "#", "%x0;");
	value = convertSTRING(value, "&", "%x1;");
	value = convertSTRING(value, "+", "%x2;");
	value = convertSTRING(value, "<", "%x3;");
	value = convertSTRING(value, ">", "%x4;");
	value = convertSTRING(value, " ", "%x5;");
	value = convertSTRING(value, "\\n", "%x6;");
	value = convertSTRING(value, "\"", "%x7;");
	value = convertSTRING(value, "$", "%x8;");
	value = convertSTRING(value, "'", "%x9;");
	value = convertSTRING(value, "\\'", "%xa;"); // DocMaker の Image 用
	return value;
}
function decodeSTRING(value){
	// #, &, +  < > などが URI 送信で化けるため encode して送られたものを decode
	value = convertSTRING(value, "%x0;", "#");
	value = convertSTRING(value, "%x1;", "&");
	value = convertSTRING(value, "%x2;", "+");
	value = convertSTRING(value, "%x3;", "<");
	value = convertSTRING(value, "%x4;", ">");
	value = convertSTRING(value, "%x5;", " ");
	value = convertSTRING(value, "%x6;", "\n");
	value = convertSTRING(value, "%x7;", "\"");
	value = convertSTRING(value, "%x8;", "$");
	value = convertSTRING(value, "%x9;", "'");
	value = convertSTRING(value, "%xa;", "\\'"); // DocMaker の Image 用
	//value = convertSTRING(value, "%xb;", ")");
	return value;
}

function nengouArray(){
	return ["西暦","平成","昭和","大正","明治"];
}

function insTable(){
	// HL7 保険種別（IOB_Insurance）を基準に設定
	return [" :","国保:C0^国民健康保険","国保退職:67^国民健康保険退職者","組合:06^組合管掌健康保険","政府:01^政府管掌健康保険","協会:KY^協会","生活保護:12^生活保護法","学校共済:34^学校共済組合","警察共済:33^警察共済組合","国家共済:1^国家公務員共済組合","地方共済:332^地方公務員等共済組合","船員:02^船員保険","後期高齢:KK^後期高齢者","自衛:07^自衛官等","母子:23^母子保健法","老人:27^老人保健法による老人医療","公費:PE^公費","その他:OT^その他"];
}
var _insArray;
function insArray(){
	// (" ","国保","組合"..) のような配列
	if (!_insArray){
		var array = insTable();
		_insArray = new Array();
		for (var i=0,ct=array.length; i < ct; i++){
			var st = array[i];
			var ary = st.split(":");
			_insArray.push(ary[0]);
		}
	}
	return _insArray;
}

function publicInsArray(){
	return [" : ","老人:3","一人親:3","一人親(食):0","一人親(一部 食):1","子:0","障害:3","障害(食):0","障害(一部 食):1","乳幼児:0","介護保険:"];
}
function publicInsItems(){
	// (" ","老人","一人親"..) のような配列
	var array = new publicInsArray();
	var items = new Array();
	for (var i=0,ct=array.length; i < ct; i++){
		var st = array[i];
		var ary = st.split(":");
		items.push(ary[0]);
	}
	return items;
}
function publicInsObjects(){
	// insObj["老人"] = "3" (割)のようなオブジェクト
	var array = new publicInsArray();
	var objects = new Array();
	for (var i=0,ct=array.length; i < ct; i++){
		var st = array[i];
		var ary = st.split(":");
		var item = ary[0];
		objects[item] = (ary.length > 1) ? ary[1] : "3";
	}
	return objects;
}

function makeArray(firstItem, count){
	// firstItem から count 数の配列を作成して返す
	var array = new Array();
	for (var i=0; i < count; i++)
		array[i] = firstItem++;
    
	return array;
}

/*function nodeId(label, suffix){
    // label と suffix で element の id を生成して返す
    // label に '/' などが含まれていても問題なくする
    label = convertSTRING(label, "/", "_");
    return label + suffix;
}*/

/////////////////////////////////////////////////////
/// オブジェクト関連の関数 //////////////////////////////

function allKeys(obj){
    // key:value のオブジェクトから key の配列を返す
    var array = new Array();
    for (key in obj){
        array.push(key);
    }
    return array;
}

/// オブジェクト関連の関数 //////////////////////////////
/////////////////////////////////////////////////////


/////////////////////////////////////////////////////
/// 文字列関連の関数 ///////////////////////////////////

function isDigit(val){
	// val が数値かどうかをチェックして返す
    if (val.length == 0) return false;
    
	val = "" + val;
	for (var i=0,ct=val.length; i < ct; i++){
		var ch = val.charAt(i);
        if ((ch == ".") || (ch == "-")) continue;
		if ((ch < "0") || (ch > "9")) return false;
        
		if ((ch >= "０") && (ch <= "９")) return true;
	}
	return true;
}

function imageFiles(){
	// 画像ファイルの拡張子の入った配列を返す
	return ["jpg","JPG","jpeg","JPEG","tif","TIF","tiff","TIFF","png","PNG","gif","GIF","pdf","PDF"];
}
function isImageFile(filename){
	// 拡張子でイメージかどうかを判定
	var sfx = suffix(filename);
	var array = imageFiles();
    for (i in array){
		if (sfx == array[i])
			return true;
	}
	return false;
}

function movieFiles(){
	// 動画ファイルの拡張子の入った配列を返す
	return ["mp4","MP4","mov","MOV","m4v","M4V"];
}
function isMovieFile(filename){
	// 拡張子で動画かどうかを判定
	var sfx = suffix(filename);
	var array = movieFiles();
    for (i in array){
		if (sfx == array[i])
			return true;
	}
	return false;
}

function suffix(filename){
	// "filename.jpg" などのファイル名から拡張子 "jpg" を返す
    // '/' を含む filename の場合、最終 '/' の右側だけを取り出す
    var array = filename.split("/");
    if (array.length > 1)
        filename = array[array.length - 1];
    
	var array = filename.split(".");
	if (array.length > 1)
		return array[array.length - 1];
	else
		return "";
}

function isSame(st1, st2){
    // 文字列同士を比較
	if (!st1 && !st2) return true;
	if (!st1 || !st2) return false;

	return ((st1.length == st2.length) && (st1.indexOf(st2) == 0)) ? true : false;
}

function trim(value){
	// 文字列両端の 空白相当文字 を削除
    if (!value) return "";
    
	for (var i=0, len =value.length; i < len; i++){
		var ch = value.charAt(i);
		if ((ch == " ") || (ch == "　") || (ch == "\n")
			|| (ch == "\r") || (ch == "\t")) continue;
		break;
	}
	value = value.substring(i);
	for (var i=value.length-1; i >= 0; i--){
		var ch = value.charAt(i);
		if ((ch == " ") || (ch == "　") || (ch == "\n")
			|| (ch == "\r") || (ch == "\t")) continue;
		break;
	}
	return value.substr(0, i+1);
}
function trimCR(value){
	// 文字列両端の 改行 を削除
    if (!value) return "";
    
	for (var i=0, len =value.length; i < len; i++){
		var ch = value.charAt(i);
		if ((ch == "\n") || (ch == "\r") || (ch == "\t")) continue;
		break;
	}
	value = value.substring(i);
	for (var i=value.length-1; i >= 0; i--){
		var ch = value.charAt(i);
		if ((ch == "\n") || (ch == "\r") || (ch == "\t")) continue;
		break;
	}
	return value.substr(0, i+1);
}

function trimQuotation(value){
    // value 両端の " あるいは ' を削除して返す
	if (value.charAt(0) == "\"")
        value = value.substring(1);
	if (value.charAt(value.length-1) == "\"")
		value = value.substring(0, value.length-1);
	if (value.charAt(0) == "\'")
        value = value.substring(1);
	if (value.charAt(value.length-1) == "\'")
		value = value.substring(0, value.length-1);
	
	return value;
}
function trimDoubleQuotation(value){
    // value 両端の " を削除して返す
	alert("Use trimQuotation(), not trimDoubleQuotation()");
	
	return trimQuotation(value);
}

function convertSTRING(buff, from, to){
	// buff 中の from 文字すべてを to 文字に変換する
	if (!buff || (buff.length == 0)) return buff;
	buff = buff + ""; // 文字列にしておく必要あり
	//if (buff.length == 0) return buff;
	
	var array = buff.split(from);
	if (array.length > 1) buff = array.join(to);
	return buff;
}

function replaceAll(st, regexp, newstring){
	// st 中の regexp に相当する文字をすべて newstring に置換して返す
	if (!st || (st.length == 0)) return st;
    
	while (st.indexOf(regexp) >= 0)
		st = st.replace(regexp, newstring);
    
	return st;
}

function transferCR(value){
	// 改行 "\n" を "<br>" に変換
	return convertSTRING(value, "\n", "<br>");
}

function transferToCR(value){
	//  HTML での改行をすべて "\n" に変換
	if (value.length){
        value = convertSTRING(value, "</div>", "");
        
        if (value.indexOf("<br><div>") + 9 == value.length) // 文末なら改行しない
            value = convertSTRING(value, "<br><div>", "");
        else
            value = convertSTRING(value, "<br><div>", "\n");
     
        value = convertSTRING(value, "<div>", "\n");

        value = convertSTRING(value, "<br>", "\n");
        value = convertSTRING(value, "<BR/>", "\n");
        value = convertSTRING(value, "<br/>", "\n");
        value = convertSTRING(value, "<br//>", "\n"); // なぜかゴミが付くことがあるので
	}
	return value;
}

function htmlToPlain(html){
    // html テキストから全ての <タグ> を取除いたテキストを返す
    var plain = "";
    var isTag = false;
    for (pos in html){
        var ch = html.charAt(pos);
        
        if (ch == "<") isTag = true;
        if (!isTag) plain += ch;
        if (ch == ">") isTag = false;
    }
    return plain;
}

function number_format(st){
    // 数値の文字列をカンマで区切って返す
    st = st + ""; // 数値であっても文字列にする
    if (st.length <= 3){
        return st;
    } else if (st.length <= 6){
        if ((st.length == 4) && (st.substr(0,1) == "-")){
            return st;
        } else {
            var num1 = st.substr(0, st.length - 3);
            var num2 = st.substr(st.length - 3);
            return num1 + "," + num2;
        }
    } else if (st.length <= 9){
        if ((st.length == 7) && (st.substr(0,1) == "-")){
            var num1 = st.substr(0, st.length - 3);
            var num2 = st.substr(st.length - 3);
            return num1 + "," + num2;
        } else {
            var num1 = st.substr(0, st.length - 6);
            var num2 = st.substr(st.length - 6, 3);
            var num3 = st.substr(st.length - 3, 3);
            return num1 + "," + num2 + "," + num3;
        }
    } else {
        return st;
    }
}

function splitStringWith(str, separators){
    // st を 配列：separators に含まれるセパレータで区切り配列にして返す
    // セパレータは幾つ連続してもひとつのセパレータと見なされる
    var array = new Array();
    var st = "";
    var isInSeparator = false;
    for (num in str){
        var ch = str[num];
        var hitSeparator = false;
        for (n in separators){
            if (ch == separators[n]){
                hitSeparator = true; // セパレータがあった
                if (!isInSeparator){
                    // 初めてセパレータに当たった
                    array.push(st);
                    isInSeparator = true; // セパレータの中に居る
                }
            }
        }
        if (hitSeparator){
            // 文字がセパレータと同じだった
            continue;
        } else {
            if (isInSeparator){
                // セパレータの中から出る
                isInSeparator = false;
                st = "";
            }
            st += ch;
        }
    }
    array.push(st);
    return array;
}

/// 文字列関連の関数 ///////////////////////////////////
/////////////////////////////////////////////////////


/////////////////////////////////////////////////////
/// HTML 関連の関数 //////////////////////////////////

function decodeHTML(buff){
    // HTML のスペースなどを通常の文字列へデコード
    buff = buff.replace(/&nbsp;/ig, " ");
    buff = buff.replace(/&quot;/ig, "\"");
    buff = buff.replace(/&gt;/ig, ">");
    buff = buff.replace(/&lt;/ig, "<");
    buff = buff.replace(/&amp;/ig, "&");

    return buff;
}

function htmlForValue(val){
	// DB 値 val を HTML で表示する HTML 形式に変換
	// "<IMG:image.jpg>" 形式で記述されている部分を
	// "<A HREF=../Images/image.jpg TARGET=_blank>
	// <IMG SRC=../Images/image.jpg HEGHT=30>
	// </A>" のように拡張して表示
    if (val == null) return val;
    if (val.length == 0) return val;

	var array = val.split("<IMG:");
	if (array.length > 1){
		// image タグを拡張表示
        
		//  image 格納フォルダー位置はサーバ側で任意に変更できるよう
		//  folder path は imageFolder() からダイナミックに得る
		for (num in array){
            if (num == 0) continue;
            
			var ln = array[num];
			var ary = ln.split(">");
			if (ary.length > 1){
				var url = trim(ary[0]);
                
                // "<IMG:/foo/bar.png/>" 型式の場合は "/>" を外す
                // "///>" の形にも対応
                while (url.charAt(url.length - 1) == "/"){
                    url = url.substr(0, url.length - 1);
                }

				var buff = referenceOf(url);
                
				ary[0] = buff;
				ln = ary.join(">");
                
				array[num] = ln;
			}
		}
        
		val = array.join("");
	}
    
	val = transferCR(val);	// "\n" を "<br>" に置換して表示
    
	return val;
	
	function referenceOf(url){
        // thumbNailSize() は preference.js などで設定しておくこと
        var imageHeight = thumbNailSize();
        var sfx = suffix(url);
        
		if (isImageFile(url)){
			var action = "openImage('"+url+"')";
			return "<a onclick=\"" + action + "\">"
			+ "<img src=\"" + url +"\" class=\"imageClass\" height=\"" + imageHeight + "\"></a";
		} else if (isMovieFile(url)){
			var action = "openImage('"+url+"')";
			return "<a onclick=\"" + action + "\">"
			+ "<img src=\"movie.jpg\" height=\"" + imageHeight + "\"></a";
		} else if (sfx == "zip"){
			var action = "openZip('"+url+"')";
			return "<a onclick=\"" + action + "\">"
			+ "<img src=\"folder.jpg\" height=\"" + imageHeight + "\"></a";
		} else if (sfx == "txt"){
			var action = "openImage('"+url+"')";
			return "<a onclick=\"" + action + "\">"
			+ "<img src=\"text.png\" height=\"" + imageHeight + "\"></a";
		} else {
			var action = "openImage('"+url+"')";
			return "<a onclick=\"" + action + "\">"
			+ "<img src=\"file.png\" height=\"" + imageHeight + "\"></a";
		}
	}
    
    function htmlToPlain(value){
        // HTML タグをすべて削除した文字列にして返す
        return value.replace(/<\/?[^>]+>/gi, "");
    }
}

function xmlToObject(html, parentArgs){
    // XML, HTML を object に変換して返すパーサー
    // ### OrcaAgent では使わないが自力で解析する場合の関数 ###
    html = trim(html);
    _debug("=== xmlToObject->"+html); //##
    
    // <?xml ?> タグはスキップ
    var array = html.split("<?xml");
    for (num in array){
        if (num == 0) continue;
        
        var ln = array[num];
        var pos = ln.indexOf("?>");
        if (pos >= 0) array[num] = ln.substr(pos + 2);
    }
    html = array.join("");
    
    //alert("== xmlToObject->"+html); //##
    
    var pos = html.indexOf('<');
    if (pos < 0){ // '<tag>' が存在しない文字列だった
        _debug("VALUE === "+html);//##
        return html;
    } else {
        var obj = new Object();
        var childNumber = 0;
        while ((0 <= pos) && (pos < html.length)){
            var ln = html.substr(pos + 1); // '<' 以後の文字列
            _debug("next block->"+ln);//##
            
            // 文字列を beginTag の分だけ右へ移動
            var p = ln.indexOf('>');
            if (p < 0){
                alert(label + " を閉じる > が存在しない構文エラー");
                return "";
            }
            
            // label を取り出す 
            var ary = ln.substr(0, p).split(' ');
            var label = ary[0]; 
            var beginTag = '<' + label;
            var endTag = '</' + label + '>';
            _debug("LABEL === "+label);//##
            
            // label タグにパラメータがあれば記憶しておく
            var args = new Object(); // label タグのパラメータ
            if (ary.length > 1){
                for (num in ary){
                    if (num == 0) continue; // label
                    var st = ary[num];
                    var ar = st.split('=');
                    args[ar[0]] = (ar.length > 1) ? trimQuotation(ar[1]) : "";
                }
            }
            
            pos += p + 2;
            ln = trim(html.substr(pos)); // '>' 以後の文字列：value 部分
            _debug(label+" 以後の文字列->"+ln);//##
            
            // value を取り出す
            var indent = 0;
            var len = ln.length;
            for (var p=0; p < len; p++){ // 文字列を１文字ずつスキャン
                if (ln.charAt(p) == '<'){
                    var st = ln.substr(p); // p 位置以後の文字列
                    if (st.indexOf(beginTag) == 0){ // 同じ開始タグがあった
                        // <label ...> と <label_another ...> が同じに見なされないよう区別
                        var ary = st.split(' ');
                        if (label == ary[0])
                            indent++;
                    } else if (st.indexOf(endTag) == 0){ // 終了タグがあった
                        indent--;
                    }
                    
                    if (indent < 0){ // beginTag に対応する endTag が見つかった
                        var value = ln.substr(0, p);
                        _debug("VALUE === "+value);//##
                        
                        args.value = xmlToObject(value, args);
                        var key = (parentArgs && (parentArgs.type == "array"))
                        ? label+'.'+childNumber : label;
                        obj[key] = args; // obj に child を追加
                        _debug("<p>== "+label+"("+obj[key]+")</p>");//##
                        
                        pos += endTag.length; // 文字列の残りをスキャン
                        break;
                    }
                } else {
                    pos++;
                }
            }
            var st = html.substr(pos); // endTag 以後の文字列
            while (st && (st.length > 0)){ // 次の < までの空白や改行をスキップ
                if (st.indexOf('<') == 0) break;
                st = html.substr(++pos);
            }
            childNumber++;
        }
        return obj;
    }
}

function inner_text(elm){
    // FireFox では innerText は使えないので textContent を使う
    if (typeof elm.textContent != "undefined") {
        return elm.textContent;
    } else {
        return elm.innerText;
    }
}

/// HTML 関連の関数 //////////////////////////////////
/////////////////////////////////////////////////////


/////////////////////////////////////////////////////
/// 年令関連 /////////////////////////////////////////

function age(birthYear, birthMonth, birthDay, ageMonthDate){
	// 本日の年齢を返す： age("2011-1-1") 形式も OK
    // ## age() へ渡す ageMonthDate　以外のパラメータは *** 文字列 *** として渡すこと
    // ageMonthDate パラメータがあれば、年齡を年・月・日で返す
	var array = birthYear.split("-");
	if (array.length == 3){
		// age("2011-1-1") 形式も OK
		birthYear = array[0];
		birthMonth = array[1];
		birthDay = array[2];
	}
    birthMonth -= 1;
	var now = new Date();
    var nowy = now.getFullYear();
    var nowm = now.getMonth();
    var nowd = now.getDate();
    
    var intervalY = nowy - birthYear;
    var intervalM = nowm - birthMonth;
    var intervalD = nowd - birthDay;
    if (intervalD < 0){
        intervalD = (new Date(nowy, nowm, 0)).getDate() - birthDay + nowd;
        intervalM--;
    }
    if (intervalM < 0){
        intervalM += 12;
        intervalY--;
    }
    
    if (ageMonthDate)
        return [intervalY, intervalM, intervalD];
    else
        return intervalY;
}

function ageAtDate(birthDate, someDate){
	// someDate における年齢を返す
	var array = birthDate.split(" ");
	var date = array[0];
	array = date.split("-");
	var bYear = array[0] * 1;
	var bMonth = array[1] * 1;
	var bDay = array[2] * 1;
	
	array = someDate.split(" ");
	date = array[0];
	array = date.split("-");
	var sYear = array[0] * 1;
	var sMonth = array[1] * 1;
	var sDay = array[2] * 1;
	
	var today = sYear * 10000 + sMonth * 100 + sDay;
	var birthdate = bYear * 10000 + bMonth * 100 + bDay * 1;
	return Math.floor((today - birthdate) / 10000);
}

function birthDateWithPatientId(pid){
	// patientId から生年月日を計算して返す
	// 100才以上の場合はエラー値になる
    alert("birthDateWithPatientId(pid) *** regacy function."); //##
    
	var year = today().substr(0, 4);
	var thisY = year.substr(2, 2); // 今年の西暦年の下２桁
	var y = pid.substr(4, 2) * 1;
	var pidY = pid.substr(4, 2); // patientId から取り出した西暦の下２桁
	var m = pid.substr(0, 2) * 1;
	var d = pid.substr(2, 2) * 1;
	y = (pidY <= thisY) ? 2000 + y : 1900 + y;
	return y + "-" + m + "-" + d;
}
function patientIdWithBirthdate(birthDate){
	// 生年月日から patientId の最初の６桁を生成して返す
	var array = birthDate.split("-");
	var yy = array[0].substr(2, 2);
	var mm = (array.length > 1) ? array[1] * 1 : 1;
	var dd = (array.length > 2) ? array[2] * 1 : 1;
	if (mm < 10) mm = "0" + mm;
	if (dd < 10) dd = "0" + dd;
	return "" + mm + dd + yy;
}

/// 年令関連 /////////////////////////////////////////
/////////////////////////////////////////////////////

/////////////////////////////////////////////////////
/// 日付関連 /////////////////////////////////////////

var _weeks = ["日","月","火","水","木","金","土"];

function wareki(dateString){
	// "2010-6-3" を "平成22年6月3日" へ変換して返す
	var array = dateString.split("-");
	if (array.length == 3){
		var yy = array[0] * 1;
		var mm = array[1] * 1;
		var dd = array[2] * 1;
        
		if (yy < 1868){
			return dateString;
		} else if (yy < 1912){
			return "明治"+(yy-1867)+"年"+mm+"月"+dd+"日";
		} else if (yy == 1912){
			if (mm < 7)
				return "明治"+(yy-1867)+"年"+mm+"月"+dd+"日";
			else if ((mm == 7) && (dd < 30))
				return "明治"+(yy-1867)+"年"+mm+"月"+dd+"日";
			else
				return "大正"+(yy-1911)+"年"+mm+"月"+dd+"日";
		} else if (yy < 1926){
			return "大正"+(yy-1911)+"年"+mm+"月"+dd+"日";
		} else if (yy == 1926){
			if ((mm == 12) && (dd >= 25))
				return "昭和"+(yy-1925)+"年"+mm+"月"+dd+"日";
			else
				return "大正"+(yy-1911)+"年"+mm+"月"+dd+"日";
		} else if (yy < 1989){
			return "昭和"+(yy-1925)+"年"+mm+"月"+dd+"日";
		} else if (yy == 1989){
			if ((mm == 1) && (dd < 7))
				return "昭和"+(yy-1925)+"年"+mm+"月"+dd+"日";
			else
				return "平成"+(yy-1988)+"年"+mm+"月"+dd+"日";
		} else
			return "平成"+(yy-1988)+"年"+mm+"月"+dd+"日";
	} else
		return dateString;
}

function nengou(yy){
	// 西暦に相当する和暦年号を返す
	if (yy < 1868)
		return "西暦";
	else if (yy < 1912)
		return "明治";
	else if (yy < 1926)
		return "大正";
	else if (yy < 1989)
		return "昭和";
	else
		return "平成";
}

function seireki(date){
	// 和暦を西暦に変換して返す
	// date は "昭和17年3月23日" のような形式
	var array = separateYYMMDD(date);
	var label = array[0];
	var yy = array[1]*1;
	var mm = array[2]*1;
	var dd = array[3]*1;
	
	if (isSame(label, "平成"))
		yy += 1988;
	else if (isSame(label, "昭和"))
		yy += 1925;
	else if (isSame(label, "大正"))
		yy += 1911;
	else if (isSame(label, "明治"))
		yy += 1867;
	
	return yy+"-"+mm+"-"+dd;
}

function seirekiYear(nengou, yy){
	// 和暦を西暦にして返す
	if (nengou == "平成")
		return yy * 1 + 1988;
	else if (nengou == "昭和")
		return yy * 1 + 1925;
	else if (nengou == "大正")
		return yy * 1 + 1911;
	else if (nengou == "明治")
		return yy * 1 + 1867;
	else
		return yy * 1;
}
function warekiYear(nengou, year){
	// nengou に相当する和暦年を返す
    if (nengou == "平成")
		return year - 1988;
	else if (nengou == "昭和")
		return year - 1925;
	else if (nengou == "大正")
		return year - 1911;
	else if (nengou == "明治")
		return year - 1867;
	else
		return year;
}

function dayAndTime(time){
	// time(時刻)を "2008-05-04 16:35:00" のような文字列にして返す
	var date = new Date(time);
	var yy = date.getYear();
	var mm = date.getMonth() + 1;
	var dd = date.getDate();
	if (yy < 2000) { yy += 1900; }
	if (mm < 10) { mm = "0" + mm; }
	if (dd < 10) { dd = "0" + dd; }
	hr = date.getHours();
	if (hr < 10) { hr = "0" + hr; }
	mn = date.getMinutes();
	if (mn < 10) { mn = "0" + mn; }
	sc = date.getSeconds();
	if (sc < 10) { sc = "0" + sc; }
	return yy + "-" + mm + "-" + dd + " " + hr + ":" + mn + ":" + sc;
}

function todayAndTimeId(){
	// タイムスタンプ "2009-09-11 09:15:00" から
	// "20090911091500" のような ID を作成して返す
	var date = new Date();
	var yy = date.getYear();
	var mm = date.getMonth() + 1;
	var dd = date.getDate();
	var hr = date.getHours();
	var mn = date.getMinutes();
	var sc = date.getSeconds();
	if (yy < 2000) { yy += 1900; }
	if (mm < 10) { mm = "0" + mm; }
	if (dd < 10) { dd = "0" + dd; }
	if (hr < 10) { hr = "0" + hr; }
	if (mn < 10) { mn = "0" + mn; }
	if (sc < 10) { sc = "0" + sc; }
	
	return "" + yy + mm + dd + hr + mn + sc;
}

function todayAndTime(){
	// 現在の時刻を "2008-05-04 16:35:00" のような文字列にして返す
	return stringWithDate(new Date());
}

function today(){
	// 本日の年月日を "2008-05-04" のような文字列にして返す
	var date = new Date();
	var yy = date.getYear();
	var mm = date.getMonth() + 1;
	var dd = date.getDate();
	if (yy < 2000) { yy += 1900; }
	if (mm < 10) { mm = "0" + mm; }
	if (dd < 10) { dd = "0" + dd; }
	
	return yy + "-" + mm + "-" + dd;
}

function weekOfDate(date, inString){
	// date:"2008-06-08 11:10:00" の曜日の番号を返す
	var array1 = date.split(" ");
	var array2 = array1[0].split("-");
	if (array2.length > 2){
		var yy = array2[0] * 1;
		var mm = array2[1] * 1 - 1;
		var dd = array2[2] * 1;
		var aDate = new Date(yy,mm,dd);
		var week = aDate.getDay();
        
        // inString なら曜日を文字列で、そうでなければ曜日番号で返す
		return (inString) ? _weeks[week] : week;
	}
	return "";
}

function lastDateTime(date){
	// date が "2008-06-18 08:01:00" であっても "2008-06-18" であっても
	// その日の最終時刻 "2008-06-18 23:59:59" を返す
	var array = date.split(" ");
	return array[0] + " 23:59:59";
}

function yyyymmdd(date){
	// date が "2008-06-18 08:01:00" であっても "2008-06-18" であっても
	// その日付部分 "2008-06-18" を返す
	var array = date.split(" ");
	return array[0];
}

function isDate(date){
	// date が "2008-06-18 08:01:00" なら 2 を返す
    // date が "2008-06-18"  型式なら 1 を返す
    // それ以外なら 0 を返す：日付フォーマットではない
	if (date.length < 10) return 0; // 日付が短かすぎる
	
	var array = date.split(" ");
	var ymd = array[0];
	var hms = array[1];
  
    // 年月日を検証
	var array1 = ymd.split("-");
	if (array1.length < 3) return 0; // "yyyy-mm-dd" 形式でない
    for (num in array1){
        if (!isDigit(array1[num])) return 0; // 数値ではない
    }
    
    // 時間があるなら時間を検証
    if (array.length > 1){
        var array1 = hms.split(":");
        if (array1.length < 3) return 0; // "hh:mm:ss" 形式でない
        for (num in array1){
            if (!isDigit(array1[num])) return 0; // 数値ではない
        }
    }
    
    return (array.length == 1) ? 1 : 2;
}

function shortDate(date, hasTime){
	// date が "2008-06-18 08:01:00" なら
	// その日付部分の短縮形 "080618" を返す
    // hasTime なら時刻を加え "080618 0801" を返す
	if (date.length < 10) return date; // 日付が短すぎる
	
	var array = date.split(" ");
	var ymd = array[0];
	var hms = array[1];
	var array1 = ymd.split("-");
	if (array1.length < 3) return date; // "yyyy-mm-dd" 形式でない
    
	var yy = array1[0].substr(2,2);
	var mm = array1[1];
	var dd = array1[2];
    if (hasTime){
        var ary = hms.split(':');
        var hour = ary[0];
        var min = ary[1];
        var sec = ary[2];
        
        return yy + mm + dd + " " + hour + min;
    } else {
        return yy + mm + dd;
    }
}
function longDate(date){
	// date が "090830" なら "2009-08-30" にして返す
	if (date.length < 6){
		return date;
	} else if (date.length < 10){
		// date が "090830" の場合
		var yy = "20" + date.substr(0,2);
		var mm = date.substr(2,2);
		var dd = date.substr(4,2);
	} else {
		// date が "20090830" の場合
		var yy = date.substr(0,4);
		var mm = date.substr(4,2);
		var dd = date.substr(6,2);
	}
	return yy + "-" + mm + "-" + dd;
}

function arrayWithDateTime(dateTime){
	// dateTime は "2008-05-04 16:35:00" のような文字列
    // これを[年, 月, 日, 時, 分, 秒] の配列に入れて返す
    if (trim(dateTime).length == 0)
        return ["00","00","00","00","00","00"];

    var dateArray = new Array();
	var array = dateTime.split(" ");
    
	var array1 = array[0].split("-");
    if (dateTime.length > 0) // 年
        dateArray.push(array1[0]);
    else
        dateArray.push("");
    if (array1.length > 0) // 月
        dateArray.push(array1[1]);
    else
        dateArray.push("");
    if (array1.length > 1) // 日
        dateArray.push(array1[2]); 
    else
        dateArray.push("");
    
    // 時分秒を追加
    if (array.length > 1){
        var array2 = array[1].split(":");
        dateArray.push((array2[0].length > 0) ? array2[0] : "00"); // 時
        dateArray.push((array2[1].length > 0) ? array2[1] : "00"); // 分
        dateArray.push((array2[2].length > 0) ? array2[2] : "00"); // 病
    } else {
        dateArray.push("00"); // 時
        dateArray.push("00"); // 分
        dateArray.push("00"); // 秒
    }
	return dateArray;
}
function dateTimeWithArray(array){
    // array は[年, 月, 日, 時, 分, 秒] の配列
	// これを "2008-05-04 16:35:00" のような文字列に入れて返す
    var dateTime = array[0];
    for (num in array){
        if (num == 0) continue; // 0番目は上記で処理済み
        
        var st = array[num];
        if (st.length == 1) st = "0" + st;
        
        if (num < 3){
            dateTime += "-" + st;
        } else if (num == 3){
            dateTime += " " + st;
        } else {
            dateTime += ":" + st;
        }
    }
    return dateTime;
}

function dateWithString(date){
	// date は "2008-05-04 16:35:00" のような文字列
	var array = date.split(" ");
	var array1 = array[0].split("-");
	var array2 = array[1].split(":");
	var yy = array1[0];
	var mm = array1[1] - 1;
	var dd = array1[2];
	var hou = array2[0];
	var min = array2[1];
	var sec = array2[2];
	return new Date(yy, mm, dd, hou, min, sec);
}
function stringWithDate(date){
	// Date() を "2008-05-04 16:35:00" のような文字列にして返す
	var yy = date.getYear();
	var mm = date.getMonth() + 1;
	var dd = date.getDate();
	if (yy < 2000) { yy += 1900; }
	if (mm < 10) { mm = "0" + mm; }
	if (dd < 10) { dd = "0" + dd; }
	hr = date.getHours();
	if (hr < 10) { hr = "0" + hr; }
	mn = date.getMinutes();
	if (mn < 10) { mn = "0" + mn; }
	sc = date.getSeconds();
	if (sc < 10) { sc = "0" + sc; }
	return yy + "-" + mm + "-" + dd + " " + hr + ":" + mn + ":" + sc;
}

function getLastDate(Y,M){
	// Y 年 M 月の日数を返す
	// その年月の１日の「１秒前」の日付を出させている
	var d1 = new Date(Y, M, 1);
	var t1 = d1.getTime();
	d1.setTime(t1-1000)
	
	return d1.getDate();
}

function isSameDate(st1, st2){
	// 年月日部分だけの比較をして同じかどうかを返す
	if (!st1 && !st2) return true;
	if (!st1 || !st2) return false;
	
	st1 = st1.toString();
	st2 = st2.toString();
	if (st1.length < 10) return false;
	if (st2.length < 10) return false;
	
	var dt1 = st1.substr(0, 10);
	var dt2 = st2.substr(0, 10);
    
	return (dt1 == dt2) ? true : false;
}

function isSameMonth(st1, st2){
	// 年月部分だけの比較をして同じかどうかを返す
	if (!st1 || !st2) return 0;
	
	st1 = st1.toString();
	st2 = st2.toString();
	if (st1.length < 10) return 0;
	if (st2.length < 10) return 0;
	
	var dt1 = st1.substr(0, 7);
	var dt2 = st2.substr(0, 7);

	return (dt1 == dt2) ? 1 : 0;
}

function separateYYMMDD(date){
	// 年月日を何らかのセパレータで分離し array に入れて返す
	// 1942-3-23, 1942年3月23日 昭和17年3月23日 などの形式に対応
	// array("昭和",17,3,23,0) のような形式で返す
	var num, i, len = date.length;
	var isWareki = 0, hasNum = 0;
	var array = new Array();
	for (i=num=0; i < len; i++){
		var ch = date.charAt(i);
		if ((ch != ' ') && (0 <= ch) && (ch <=9)){	// 数値
			if (i == 0)
				array.push("");		// 西暦
			else if (isWareki > 0){
				label = date.substring(0, i);
				array.push(label);	// 和暦
				isWareki = 0;
			}
			num = num * 10 + ch * 1;
			hasNum = 1;
		} else {					// 数値以外
			if (i == 0)
				isWareki = 1;
			else if (hasNum > 0)
				array.push(num);
			num = 0;
			hasNum = 0;
		}
	}
	array.push(num);
	
	// date がフォーマット通りでない場合は default 値を返す
	if (array.length < 4) array = ["", "1988", "1", "1"];
	
	return array;
}

function dateTimeArray(dateTime){
    // "2013-01-29 13:43:00" を配列にして返す
    // "2013-01-29" の場合は時刻 "00:00:00" 相当になる
    var results = new Array();
    var array = dateTime.split(" ");
    var date = array[0];
    var ary = date.split("-");
    results.push(ary[0]); // yyyy
    results.push(ary[1]); // mm
    results.push(ary[2]); // dd
    
    if (array.length > 1){
        var time = array[1];
        var ary = time.split(":");
        results.push(ary[0]); // hour
        results.push(ary[1]); // min
        results.push(ary[2]); // sec
    } else {
        results.push("00"); // hour
        results.push("00"); // min
        results.push("00"); // sec
    }
    return results;
}

function secondsBetween(date1, date2){
	// date1 から date2 までの経過秒数を返す
	// date は "2008-05-04 16:35:00" のような文字列
	var d1 = dateWithString(date1);
	var sec1 = d1.getTime();
	var d2 = dateWithString(date2);
	var sec2 = d2.getTime();
	return (sec2 - sec1) / 1000;
}

function daysBetween(datetime1, datetime2){
    // datetime1, datetime2 間の日数を返す
    // 両日の０時０分０秒同士で計算するので、多少誤差が出る可能性あり
    var date1 = datetime1.substr(0, 10) + " 00:00:00";
    var date2 = datetime2.substr(0, 10) + " 00:00:00";
    var seconds = secondsBetween(date1, date2);
    
    return (seconds) ? seconds / (60 * 60 * 24) : 0;
}

function dateWthDiff(dateTime, diff){
    // dateTime から diff 分後の日時を返す
	var date = dateWithString(dateTime); // 文字列日時を Date() へ変換
	var sec = date.getTime();
    date.setTime(sec + diff * 60 * 1000);
    
    return stringWithDate(date);
}

/// 日付関連 /////////////////////////////////////////
/////////////////////////////////////////////////////


/////////////////////////////////////////////////////
/// 配列関連の関数 /////////////////////////////////////

function indexOfArray(array, item){
	// array の中の item の存在する位置を返す
	// なければ (-1) を返す
    for (num in array){
		if (array[num] == item) return num;
	}
	return (-1);
}

function arrayHasItem(array, item){
	// array 中に item が含まれているかをチェックして返す
    for (i in array){
		if (isSame(array[i], item)) return true;
	}
	return false;
}

function hasMember(array, item){
	// array 中に item があれば 1 なければ 0 を返す
    for (i in array){
		if (array[i] == item) return 1;
	}
	return 0;
}

/// 配列関連の関数 /////////////////////////////////////
/////////////////////////////////////////////////////


/////////////////////////////////////////////////////
/// オブジェクト関連の関数 //////////////////////////////

function allKeys(obj){
    // key:value のオブジェクトから key の配列を返す
    var array = new Array();
    for (key in obj){
        array.push(key);
    }
    return array;
}

function keyForValueIn(obj, value){
    // obj 中の value に対する key を返す
    for (key in obj){
        if (value == obj[key])
            return key;
    }
    return null;
}

function objectCount(obj){
    // object の中の子供の数を返す
    if (!obj)
        return 0;
    
    var count = 0;
    for (key in obj)
        count++;
    return count;
}

function object2json(obj){
	// オブジェクトを JSON 形式の文字列にして返す
    // ## JSON.stringify(obj) を使うと NOAManager の MenuTable アーカイブ保存でコケル
    return JSON.stringify(obj);
    /*
	var buff = "{";
	for (key in obj){
		var val = obj[key];
		if (val == null){
			buff += '"' + key + '":"",';
		} else if (typeof(val) == "object"){
			buff += '"' + key + '":' + object2json(val) + ',';
		} else {
			// ### UniversalSection.documentName のアーカイブでの問題
			// val 中の '"' を '\"' に置換
			val = convertSTRING(val, '"', '^');
			// val 中の改行を '<br>' に置換
			val = convertSTRING(val, '\r\n', '<br>');
			
			buff += '"' + key + '":"' + val + '",';
		}
	}
    buff = (buff.length > 1) ? buff.substr(0, buff.length-1) + "}" : '""';
	return buff;
     */
}

/// オブジェクト関連の関数 //////////////////////////////
/////////////////////////////////////////////////////


