http://www.drk7.jp/MT/archives/001587.html
426134
function _num2ja(num, opt) {
    var sign = {
        "+": "",
        "-": "−"
    };
    var zero = "零";
    var point = "点";
    var zero2nine = ["〇", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
    var ten2thou = ["", "十", "百", "千"];
    var suffices = [
        "",
        "万",
        "億",
        "兆",
        "京",
        "垓",
        "禾予",
        "穣",
        "溝",
        "澗",
        "正",
        "載,",
        "極",
        "恒河沙",
        "阿僧祇",
        "那由他",
        "不可思議",
        "無量大数"
    ];

    num = num.replace(/,/g, "");
    num.match(/([+-])?(\d+)(?:\.(\d+))?/i);
    var sig = RegExp.$1;
    var int = RegExp.$2;
    var fract = RegExp.$3;
    var seisuu = "";
    var shins = [];

    for (let i = int.length; i > 0; i -= 4) {
        shins.push(int.substring(i, i - 4));
    }
    if (shins.length >= 18) {
        return suffices[17];
    }

    var suffix = 0;
    for (let i = 0; i < shins.length; i++) {
        var shin = shins[i];
        if (shin == "0000") {
            suffix++;
            continue;
        }
        var sens = "";
        var keta = 0;
        var digits = shin.split("").reverse();
        for (var j = 0; j < digits.length; j++) {
            var digit = digits[j];

            if (opt["fixed4"] || opt["with_arabic"]) {
                if (opt["with_arabic"]) {
                    var flg = 0;
                    // 余分な 0 を削除する
                    if (digit == "0") {
                        for (var k = j + 1; k < digits.length; k++) {
                            flg += digits[k] == "0" ? 0 : 1;
                        }
                        if (flg == 0) {
                            digit = "";
                        }
                    }
                    sens = digit + sens;
                } else {
                    sens = zero2nine[digit] + sens;
                }
            } else {
                var suuji = digit == 1 && !opt["p_one"] && keta > 0 ? "" : zero2nine[digit];
                if (digit != 0) {
                    sens = suuji + ten2thou[keta] + sens;
                }
            }
            keta++;
        }
        seisuu = sens + suffices[suffix++] + seisuu;
    }
    var result = (sign[sig] || "") + seisuu;
    result = result || zero;
    if (fract) {
        result = result + point + fract;
    }
    return result;
}
127269
function getISOWeekNumber (date) {
  var wn = getWeekNumber(date, 1, 1);
  var d1_1 = new Date(date.getFullYear(), 0, 1);
  var w1_1 = d1_1.getDay();
  // 初週の日数が少ない場合は週番号がひとつ前にずれる
  if (!w1_1 || 4 < w1_1) {
    wn--;
  }
  if (wn === 0) {
    return 53;
  } else if (wn === 53) {
    // 最終週の場合も多いほうの年の週番号とする
    var d12_31 = new Date(date.getFullYear(), 11, 31);
    var w12_31 = d12_31.getDay();
    return w12_31 && w12_31 < 4 ? 1 : wn;
  } else {
    return wn;
  }
}
777325
function sequantial (target, listName) {

  /**
   * 各行に対して関数を呼び出します
   * @method forEach
   * @param  {Function} callback
   */
  target.forEach = function forEach (callback) {
    var list = [].slice.call(this[listName]);
    var len = list.length;
    for(var i = 0; i < len; i++) {
      callback(list[i], i, list);
    }
  };

  /**
   * すべての行に対して、真であるかを調査する
   * @method every
   * @param  {Function} callback
   * @return {Boolean}
   */
  target.every = function every (callback) {
    var list = [].slice.call(this[listName]);
    var len = list.length;
    for(var i = 0; i < len; i++) {
      if (!callback(list[i], i, list)) {
        return false;
      }
    }
    return true;
  };

  /**
   * いずれかの行に対して、真であるかを調査する
   * @method some
   * @param  {Function} callback
   * @return {Boolean}
   */
  target.some = function some (callback) {
    var list = [].slice.call(this[listName]);
    var len = list.length;
    for(var i = 0; i < len; i++) {
      if (callback(list[i], i, list)) {
        return true;
      }
    }
    return false;
  };

  /**
   * callbackを満たす行を配列で返す
   * @method filter
   * @param  {Function} callback
   * @return {Array}
   */
  target.filter = function filter (callback) {
    var list = [].slice.call(this[listName]);
    var len = list.length;
    var result = [];
    for(var i = 0; i < len; i++) {
      if (callback(list[i], i, list)) {
        result.push(list[i]);
      }
    }
    return result;
  };

  /**
   * 各行から新しい配列を作成します
   * @method map
   * @param  {Function} callback
   */
  target.map = function map (callback) {
    var list = [].slice.call(this[listName]);
    var len = list.length;
    var result = [];
    for(var i = 0; i < len; i++) {
      result.push(callback(list[i], i, list));
    }
    return result;
  };

  /**
   * 各行から値を計算します
   * @method reduce
   * @param  {Function} callback
   * @param  {Mixed}    initial
   * @return {Mixed}    result
   */
  target.reduce = function reduce (callback, initial) {
    var list = [].slice.call(this[listName]);
    var len = list.length;
    var value = initial;
    for(var i = 0; i < len; i++) {
      value = callback(value, list[i], i, list);
    }
    return value;
  };

  /**
   * 各行をインデックスの降順で値を計算します
   * @method reduceRight
   * @param  {Function} callback
   * @param  {Mixed}    initial
   * @return {Mixed}    result
   */
  target.reduceRight = function reduceRight (callback, initial) {
    var list = [].slice.call(this[listName]);
    var len = list.length;
    var value = initial;
    for(var i = len - 1; -1 < i; i--) {
      value = callback(value, list[i], i, list);
    }
    return value;
  };

}
1265758
public static function FilesDetectiveSessionFixation () {
		//==============================================
		//変数初期化
		//==============================================
		$save_path = static::SavePath();

		//==============================================
		//ディレクトリ
		//==============================================
		//ディレクトリ存在確認
		if (!file_exists($save_path)) {
			if (!mkdir($save_path, 0700, true)) {
				throw CoreException::RaiseSystemError('セッションセーブディレクトリがありません。dir:%s', [$save_path]);
			}
		}

		//対象確認
		if (!is_dir($save_path)) {
			throw CoreException::RaiseSystemError('セッションセーブディレクトリがファイルです。dir:%s', [$save_path]);
		}

		//書き込み権確認
		if (!is_writable($save_path)) {
			throw CoreException::RaiseSystemError('セッションセーブディレクトリに書き込めません。dir:%s', [$save_path]);
		}

		//読み込み権確認
		if (!is_readable($save_path)) {
			throw CoreException::RaiseSystemError('セッションセーブディレクトリから読み込みできません。dir:%s', [$save_path]);
		}

		//==============================================
		//ファイル：セッションフィクセーション対策
		//==============================================
		//セッション取得元検証
		$session_name = session_name();
		if (isset($_POST[$session_name]) || isset($_GET[$session_name])) {
			throw CoreException::RaiseSystemError('クッキー以外の経路でセッションを指定されました。session_id:%s', [$session_id]);
		}

		//セッションIDがあった場合の検証
		$session_id = (isset($_COOKIE[$session_name])) ? $_COOKIE[$session_name] : session_id();
		if ($session_id !== '') {
			//不正な文字列がないか検証
			if (strpos($session_id, '.') !== false || strpos($session_id, '/') !== false || strpos($session_id, "\\") !== false) {
				throw CoreException::RaiseSystemError('セッションIDに不正な文字列が存在します。session_id:%s', [$session_id]);
			}

			//セッションファイルパスの作成
			$session_file_path = sprintf('%s/%s%s', str_replace("\\", '/', $save_path), static::SESSION_FILE_NAME_PREFIX, $session_id);

			//ファイル存在確認
			if (!file_exists($session_file_path)) {
				static::DeleteSessionCookie();
				throw CoreException::RaiseSystemError('セッションファイルがありません。セッションフィクセーションの疑いがあります。file:%s', [$session_file_path]);
			}

			//対象確認
			if (!is_file($session_file_path)) {
				throw CoreException::RaiseSystemError('セッションファイルがファイルではありません。file:%s', [$session_file_path]);
			}

			//書き込み権確認
			if (!is_writable($session_file_path)) {
				throw CoreException::RaiseSystemError('セッションファイルに書き込めません。file:%s', [$session_file_path]);
			}

			//読み込み権確認
			if (!is_readable($session_file_path)) {
				throw CoreException::RaiseSystemError('セッションファイルから読み込みできません。file:%s', [$session_file_path]);
			}
		}

		//==============================================
		//処理の終了
		//==============================================
		return true;
	}
261766
function setupDeveloperMenu(param) {
	var gdr = engineFiles.gameDriver;
	var defaultTotalTimeLimit = 85; // 85秒をデフォルトの制限時間としてあつかう。

	// loocalStorageにメニューの位置、サイズを保存している
	var config = {};
	if ("localStorage" in window) {
		var saved = JSON.parse(localStorage.getItem("akashic-sandbox-config"));
		if (saved) {
			config = saved;
		}
	}
	if (config.size == null) {
		config.size = {
			right: {width: "400px", height: "100%"},
			bottom: {width: "100%", height: "300px"}
		};
	}
	if (config.isPositionRight == null) {
		config.isPositionRight = true;
	}
	if (config.showGrid == null) {
		config.showGrid = false;
	}
	if (config.omitInterpolatedTick == null) {
		config.omitInterpolatedTick = false;
	}
	if (isNaN(parseInt(config.totalTimeLimit, 10))) {
		config.totalTimeLimit = defaultTotalTimeLimit;
	}
	if (config.warningEs6 == null) {
		config.warningEs6 = true;
	}
	if (config.sendsSessionParameter == null) {
		config.sendsSessionParameter = false;
	}
	if (config.mode == null) {
		config.mode = "single";
	}
	// ES6以降でサポートされるオブジェクトが使われている場合警告を出す。
	if (config.warningEs6) {
		warningEs6OnConsole();
	}

	var sandboxConfig = window.sandboxDeveloperProps.sandboxConfig;

	config.autoSendEvents = config.autoSendEvents || !!sandboxConfig.autoSendEventName;
	config.eventsToSend = !!sandboxConfig.autoSendEventName ? JSON.stringify(sandboxConfig.events[sandboxConfig.autoSendEventName]) : config.eventsToSend;

	var events = {};
	if (sandboxConfig.events) {
		Object.keys(sandboxConfig.events).forEach(function (name) {
			events[name] = JSON.stringify(sandboxConfig.events[name]);
		});
	}

	var props = window.sandboxDeveloperProps;
	var amflow = props.amflow;

	// 各viewの情報
	var views = {
		'general-view': {title: "General", show: true},
		'events-view': {title: "Events", show: false},
		'camera-view': {title: "Cameras", show: false},
		'e-view': {title: "E", show: false},
		'niconico-view': {title: "Niconico", show: false},
		'playlog-view': {title: "Replay", show: false},
		'snapshot-view': {title: "Snapshot", show: false}
	};

	// vue.jsにバインドするデータ
	var data = {
		showMenu: sandboxConfig.showMenu ? sandboxConfig.showMenu : false,
		players: [],
		selfId: props.sandboxPlayer.id,
		selfName: props.sandboxPlayer.name,
		path: props.path,
		gameId: props.gameId,
		events: events,
		cameras: [],
		focusingCameraIndex: undefined,
		inputPlayerName: null,
		inputPlayerId: null,
		config: config,
		entities: [], // {className: string, id: number, children: Array}
		entityRect: {
			enable: false,
			show: false,
			withChildren: false,
			rectStyle: {top: "0px", left: "0px", width: "0px", height: "0px"}
		},
		targetEntity: null,
		snapshots: null,
		snapshotPreview: null,
		profiler: {
			show: (window.location.search.indexOf("profiler=1") >= 0), // todo: リファクタリング時にクエリオプションのパースを統一する
			expand: false
		},
		isPaused: false,
		isReplay: param.isReplay,
		currentTime: 0,
		replayDuration: param.replayDuration,
		replayDone: false,
		playlog: {
			list: [] // {name: string, url: string}
		},
		views: views,
		isIchibaContent: function() {
			var environment = props.game._configuration.environment;
			if (!environment || !environment.niconico || !environment.niconico.supportedModes) {
				return false;
			}
			return environment.niconico.supportedModes.length > 0;
		}(),
		rankingGameState: {
			score: "N/A",
			playThreshold: "N/A",
			clearThreshold: "N/A"
		},
		remainingTime: "N/A",
		isStopGame: false,
		modeList: [
			{text: "ひとりで遊ぶ(single)", value: "single"},
			{text: "ランキング(ranking)", value: "ranking"}
		]
	};

	if (config.autoJoin && !param.isReplay) {
		// NOTE: この時点でgame._loadedにgame._start()がハンドルされている必要がある
		// スナップショットから復元時はloadedが発火しないのでJOINは行われない
		props.game._loaded.addOnce(function() {
			var p = props.sandboxPlayer;
			data.players.push({player: {id: p.id, name: p.name}, self: true});
			amflow.sendEvent([0 /* Join */,  3, p.id, p.name, null ]);
		});
	}

	if (config.autoSendEvents && !param.isReplay) {
		props.game._loaded.addOnce(function () {
			sendEvents();
		});
	}

	if (config.sendsSessionParameter && data.isIchibaContent && !param.isReplay) {
		var totalTimeLimit = parseInt(config.totalTimeLimit, 10);

		if (isNaN(totalTimeLimit)) {
			totalTimeLimit = defaultTotalTimeLimit;
		}
		// ランキング用イベントを送信する。
		var sessionParameters = {
			"mode": config.mode
		};
		if (config.mode === "ranking") {
			sessionParameters["totalTimeLimit"] = totalTimeLimit;
			// 前の仕様ではtotalTimeLimitより25秒程度短いgameTimeLimitが送られていたので、互換性のためにtotalTimeLimitと一緒に送っておく。
			sessionParameters["gameTimeLimit"] = totalTimeLimit - 25;
		}
		props.game._loaded.addOnce(function () {
			amflow.sendEvent([0x20, 0, "dummy", {
				"type": "start",
				"parameters": sessionParameters
			}]);
		});
		if (config.mode === "ranking") {
			var gameStartTime = Date.now();
			var intervalId = setInterval(function () {
				var currentRemainingTime = totalTimeLimit - (Date.now() - gameStartTime) / 1000;
				data.remainingTime = currentRemainingTime > 0 ? Math.ceil(currentRemainingTime) : 0;
			}, 1000 / props.game.fps);
			setTimeout(function () {
				data.remainingTime = 0;
				clearInterval(intervalId);
				if (config.stopsGameOnTimeout) {
					if (props.game && props.game.audio) {
						// 音を明示的に止める。
						Object.keys(props.game.audio).forEach(function (key) {
							props.game.audio[key].stopAll();
						});
					}
					props.driver.stopGame();
					// akashic-sandboxがゲームを止めたことをユーザーに明示するために、強制的にメニューを開いてメッセージを表示する。
					data.isStopGame = true;
					data.showMenu = true;
					var elements = document.getElementsByClassName("dev-menu-view");
					for (var i = 0; i < elements.length; i++) {
						var element = elements[i];
						data.views[element.id].show = element.id === "niconico-view";
						element.style.display = data.views[element.id].show ? "block" : "none";
					}
				}
			}, totalTimeLimit * 1000);
		}
	}

	// 歯車ボタン
	var devBtn = document.querySelector("#dev-btn");
	devBtn.addEventListener("click", function() {
		data.showMenu = !data.showMenu;
	});


	// 設定をlocalStorageに保存する関数
	function saveConfig() {
		if ("localStorage" in window) {
			localStorage.setItem("akashic-sandbox-config", JSON.stringify(config));
		}
	}

	// プレイヤーのStorageValueStoreを生成する
	function createStorageValueStore(playerId, keys) {
		var convertedKeys = [];
		keys.forEach(function(key) {
			var ck = {};
			for (var k in key) {
				ck[k] = key[k];
			}
			ck.userId = playerId;
			convertedKeys.push(ck);
		});
		var values = props.gameStorage.load(convertedKeys);
		return new g.StorageValueStore(convertedKeys, values);
	}

	// プレイヤーをジョインさせる関数
	function joinGame() {
		var playerId = data.inputPlayerId;
		var playerName = data.inputPlayerName;
		if (!playerId) {
			alert("Player IDを入力してください");
			return;
		}
		for (var i = 0; i < data.players.length; ++i) {
			if (data.players[i].player.id === playerId) {
				alert("Player ID: \"" + playerId + "\"は既に参加しています。");
				return;
			}
		}
		if (playerId === data.selfId && inputPlayerName !== data.selfName) {
			alert("Player ID: \"" + playerId + "\"のPlayer Nameは\"" + data.selfName + "\"になります。");
			playerName = data.selfName;
		}
		data.players.push({
			player: { id: playerId, name: playerName },
			self: (playerId === props.game.selfId)
		});
		data.inputPlayerId = data.inputPlayerName = null;
		amflow.sendEvent([0 /* Join */,  3, playerId, playerName, null ]);
	}

	// プロファイラーの各種設定
	// この値は次回の redrawProfilerCanvas() 呼び出し時に適用される
	var profilerSettings = {
		expand: data.profiler.expand,
		width: 170,
		margin: 5,
		padding: 5,
		align: "vertical", // 縦並び
		// align: "horizontal", // 横並び
		bgColor: "white",
		fontColor: "black",
		fontSize: 17,
		fontMaxColor: "deeppink",
		fontMinColor: "dodgerblue",
		fontMinMaxColor: "gray",
		graphColor: "lavender",
		graphWidth: 3,
		graphWidthMargin: 1,
		graphPadding: 5
	};

	// note: プロファイラー表示処理の範囲をわかりやすくするため {} で囲んでいる
	{
		var s = {};
		var updateProfilerConfig = function() {
			s = Object.create(profilerSettings);
		};

		var profilerData = {
			fps: {
				name: "fps",
				data: [],
				max: 0,
				min: Number.MAX_VALUE
			},
			skipped: {
				name: "skipped",
				data: [],
				max: 0,
				min: Number.MAX_VALUE
			},
			interval: {
				name: "interval",
				data: [],
				max: 0,
				min: Number.MAX_VALUE
			},
			frame: {
				name: "frame",
				data: [],
				max: 0,
				min: Number.MAX_VALUE
			},
			rendering: {
				name: "rendering",
				data: [],
				max: 0,
				min: Number.MAX_VALUE
			}
		};

		var profilerCanvas = document.getElementById("profilerCanvas");
		profilerCanvas.addEventListener("click", function() {
			toggleProfilerCanvasSize();
		});
		profilerCanvas.style.display = data.profiler.show ? "block" : "none";

		var profilerCanvasContext = profilerCanvas.getContext("2d");

		// todo: SimpleProfilerのコンストラクタパラメータにgetValueTriggerを与えるように修正
		props.driver._gameLoop._clock._profiler._calculateProfilerValueTrigger.add(function(value) {
			var deltaX;
			var deltaY;
			if (s.align === "vertical") {
				deltaX = 0;
				deltaY = s.height + s.margin;
			} else {
				deltaX = s.width + s.margin;
				deltaY = 0;
			}
			updateProfilerData(profilerData.fps,       value.framePerSecond,    deltaX * 0, deltaY * 0, 2);
			updateProfilerData(profilerData.skipped,   value.skippedFrameCount, deltaX * 1, deltaY * 1, 1);
			updateProfilerData(profilerData.interval,  value.rawFrameInterval,  deltaX * 2, deltaY * 2, 1);
			updateProfilerData(profilerData.frame,     value.frameTime,         deltaX * 3, deltaY * 3, 1);
			updateProfilerData(profilerData.rendering, value.renderingTime,     deltaX * 4, deltaY * 4, 1);
		});

		var updateProfilerData = function(profilerData, profileValue, x, y, fixed) {
			profilerData.data.unshift(profileValue.ave);
			drawGraph(profilerData, profileValue, x, y, fixed);
		};
		var drawText = function(text, x, y, color, maxWidth) {
			profilerCanvasContext.fillStyle = color;
			profilerCanvasContext.fillText(text, x, y, maxWidth);
		};
		var drawGraph = function(profilerData, profilerValue, x, y, fixed) {
			profilerCanvasContext.fillStyle = s.bgColor;
			profilerCanvasContext.fillRect(x, y, s.width, s.height);
			profilerCanvasContext.fillStyle = s.graphColor;
			var min = Number.MAX_VALUE;
			var max = 0;
			for (var i = 0; i < profilerData.data.length; ++i) {
				var offsetX = s.width - i * (s.graphWidth + s.graphWidthMargin) - s.graphWidth - s.graphPadding;
				var data = profilerData.data[i];
				if (data < min) {
					min = data;
				}
				if (data > max) {
					max = data;
				}
				if (offsetX < s.graphWidth + s.graphPadding / 2) {
					profilerData.data.pop();
					break;
				}
			}
			if (min < profilerData.min) profilerData.min = min;
			if (profilerData.max < max) profilerData.max = max;

			var areaHeight = s.height - s.graphPadding * 2;
			var rate = max > areaHeight ? areaHeight / max : 1;
			for (var i = 0; i < profilerData.data.length; ++i) {
				var offsetX = s.width - i * (s.graphWidth + s.graphWidthMargin) - s.graphWidth - s.graphPadding;
				var height = profilerData.data[i] * rate;
				profilerCanvasContext.fillRect(
					x + offsetX,
					y + s.height - height - s.graphPadding,
					s.graphWidth,
					height
				);
			}
			var valueOffsetX = s.width * 0.6;
			var maxWidth = valueOffsetX - s.padding;
			var maxValueWidth = (s.width - valueOffsetX) - s.padding;
			drawText(profilerData.name + ":", x + s.padding, y + s.padding + s.fontSize, s.fontColor, maxWidth);
			drawText(profilerValue.ave.toFixed(fixed), x + valueOffsetX, y + s.padding + s.fontSize, s.fontColor, maxValueWidth);
			drawText(max.toFixed(fixed), x + valueOffsetX, y + s.padding + s.fontSize * 2, s.fontMaxColor, maxValueWidth);
			drawText(min.toFixed(fixed), x + valueOffsetX, y + s.padding + s.fontSize * 3, s.fontMinColor, maxValueWidth);
			var min_max = " " + profilerData.min.toFixed(0) + "-" + profilerData.max.toFixed(0);
			drawText(min_max, x + s.padding, y + s.padding + s.fontSize * 2.5, s.fontMinMaxColor, maxWidth);
		};

		// profilerSettings の設定にもとづいたプロファイラーを描画する
		function redrawProfilerCanvas() {
			updateProfilerConfig();
			var width;
			var height;
			s.height = s.fontSize * 3 + s.padding * 2;
			if (s.align === "vertical") {
				width = s.width;
				height = (s.height + s.margin) * Object.keys(profilerData).length - s.margin;
			} else {
				width = (s.width + s.margin) * Object.keys(profilerData).length - s.margin;
				height = s.height;
			}
			profilerCanvas.width = width;
			profilerCanvas.height = height;
			if (s.expand) {
				profilerCanvas.style.width = width * 1.5 + "px";
				profilerCanvas.style.height = height * 1.5 + "px";
			} else {
				profilerCanvas.style.width = width + "px";
				profilerCanvas.style.height = height + "px";
			}
			profilerCanvasContext.font = s.fontSize + "px sans-serif";
		}

		var profilerCheckBox = document.getElementById("show-profiler");
		// プロファイラー情報の表示をトグル表示する関数
		function toggleProfiler() {
			if (!data.profiler.show) {
				profilerCanvas.style.display = "block";
				profilerCheckBox.checked = true;
			} else {
				profilerCanvas.style.display = "none";
				profilerCheckBox.checked = false;
			}
			data.profiler.show = !data.profiler.show;
		}

		// プロファイラー情報の拡縮をトグルする関数
		function toggleProfilerCanvasSize() {
			profilerSettings.expand = !s.expand;
			redrawProfilerCanvas();
		}

		profilerCheckBox.checked = data.profiler.show;
		redrawProfilerCanvas();
	}

	// g.Game.tickを上書きする。
	var originalTickFunc = props.game.tick;
	props.game.tick = function (advanceAge, omittedTickCount) {
		if (data.isIchibaContent && props.game.vars && props.game.vars.gameState) {
			// ユーザーに値の型も意識させるため、JSON.stringifyを使用する。
			data.rankingGameState.score = getJsonStringifiedValue(props.game.vars.gameState.score);
			data.rankingGameState.playThreshold = getJsonStringifiedValue(props.game.vars.gameState.playThreshold);
			data.rankingGameState.clearThreshold = getJsonStringifiedValue(props.game.vars.gameState.clearThreshold);
		}
		return originalTickFunc.apply(props.game, arguments);
	};

	// g.Camera2Dを上書き
	/**
	 * Akashicゲームコンテンツ内で生成されたg.Camera2Dの一覧を取得する手段が無いため、
	 * g.Camera2Dのコンストラクタを無理やり上書きしている。
	 */
	var camera2D = g.Camera2D;
	var cameras = [];
	function registerCamera(cam) {
		data.cameras.push({id: cam.id, name: cam.name, local: cam.local});
		cameras.push(cam);
	}
	g.Camera2D = function () {
		camera2D.apply(this, arguments);
		registerCamera(this);
	};
	// staticメンバを再現
	Object.keys(camera2D).forEach(function (key) {
		g.Camera2D[key] = camera2D[key];
	});
	// staticメンバを再現してもデシリアライズは正常に動作しない
	// (オリジナルのコンストラクタを使ってしまう)のでさらに無理やり上書きする。
	g.Camera2D.deserialize = function (ser, game) {
		var ret = camera2D.deserialize(ser, game);
		registerCamera(ret);
		return ret;
	};
	g.Camera2D.prototype = camera2D.prototype;

	// g.Game#focusingCameraをsetter/getter化することで、コンテンツ側からのfocusingCameraの変更を感知
	Object.defineProperty(props.game, "focusingCamera", {
		set: function(c) {
			data.focusingCameraIndex = cameras.indexOf(c);
		},
		get: function() {
			return cameras[data.focusingCameraIndex];
		}
	});

	// viewを表示する関数
	// v-showで上手くやるべきかもしれない
	function renderView(vm) {
		var viewElms = vm.$el.querySelectorAll(".dev-menu-view");
		for (var i = 0; i < viewElms.length; i++) {
			var el = viewElms[i];
			el.style.display = data.views[el.id].show ? "block" : "none";
		}
	}

	// g.Eから {className: string, id: number, children: Array} を作る
	function createEntityObject(e) {
		var obj = {id: e.id, className: e.constructor.name, children: []};
		if (e.children && e.children.length > 0) {
			e.children.forEach(function(c) {
				obj.children.push(createEntityObject(c));
			});
		}
		return obj;
	}

	// 親エンティティを辿り、掛けあわせたマトリックスを返す
	function parentsMatrix(e, focusingCamera) {
		if (e.parent && e.parent.getMatrix) {
			var m1 = e.parent.getMatrix();
			var m2 = parentsMatrix(e.parent, focusingCamera);
			if (m2) {
				return m1.multiplyNew(m2);
			}
			return m1;
		} else {
			if (focusingCamera) {
				return focusingCamera.getMatrix();
			}
			return undefined;
		}
	}

	// g.E#_calculateBoundingRectを改造したもので、hidden状態のエンティティの包含矩形の計算、子孫エンティティを計算対象に含めるかどうかの指定ができる
	// NOTE: g.E#_calculateBoundingRectが実装クラスによりオーバーライドされる可能性があるためakashic-engineにデバッグ用の包含矩形計算機能を入れる方が良い
	function calculateEntityBoundingRect(entity, parentsMatrix, withChildren) {
		var matrix = entity.getMatrix();
		if (parentsMatrix) {
			matrix = parentsMatrix.multiplyNew(matrix);
		}

		var thisBoundingRect = {left: 0, right: entity.width, top: 0, bottom: entity.height};

		var targetCoordinates = [
			{x: thisBoundingRect.left, y: thisBoundingRect.top},
			{x: thisBoundingRect.left, y: thisBoundingRect.bottom},
			{x: thisBoundingRect.right, y: thisBoundingRect.top},
			{x: thisBoundingRect.right, y: thisBoundingRect.bottom}
		];
		var convertedPoint = matrix.multiplyPoint(targetCoordinates[0]);
		var result = {left: convertedPoint.x, right: convertedPoint.x, top: convertedPoint.y, bottom: convertedPoint.y};
		for (var i = 1; i < targetCoordinates.length; ++i) {
			convertedPoint = matrix.multiplyPoint(targetCoordinates[i]);
			if (result.left > convertedPoint.x)
				result.left = convertedPoint.x;
			if (result.right < convertedPoint.x)
				result.right = convertedPoint.x;
			if (result.top > convertedPoint.y)
				result.top = convertedPoint.y;
			if (result.bottom < convertedPoint.y)
				result.bottom = convertedPoint.y;
		};
		if (withChildren && entity.children !== undefined) {
			for (var i = 0; i < entity.children.length; ++i) {
				var nowResult = calculateEntityBoundingRect(entity.children[i], matrix, true);
				if (nowResult) {
					if (result.left > nowResult.left)
						result.left = nowResult.left;
					if (result.right < nowResult.right)
						result.right = nowResult.right;
					if (result.top > nowResult.top)
						result.top = nowResult.top;
					if (result.bottom < nowResult.bottom)
						result.bottom = nowResult.bottom;
				}
			};
		}
		return result;
	}

	function updateEntityList() {
		var entities = props.game.scene().children;
		data.entities = [];
		entities.forEach(function(e) {
			data.entities.push(createEntityObject(e));
		});
	}

	function insertEventString (str) {
		data.config.eventsToSend = str;
	}

	function sendEventsWithValue(str) {
		var es = [];
		try {
			es = JSON.parse(str);
		} catch (e) {
			alert(e);
			console.log(e);
		}
		es.forEach(function (e) { amflow.sendEvent(e); });
	}

	function sendEvents() {
		if (!config.eventsToSend) {
			console.log("No events to send.");
			return;
		}
		sendEventsWithValue(config.eventsToSend);
	}

	function focusBoundingRect(id) {
		if (!data.entityRect.enable) {
			return;
		}
		var e = null;
		if (id < 0) {
			e = props.game._localDb[id];
		} else {
			e = props.game.db[id];
		}
		if (!e) {
			return;
		}
		// NOTE: fitToWindowすると破綻する
		var container = document.getElementById("container");
		var offsetTop = container ? container.offsetTop : 0;
		var rect = calculateEntityBoundingRect(e, parentsMatrix(e, props.game.focusingCamera), data.entityRect.withChildren);
		var s = data.entityRect.rectStyle;
		if (rect) {
			// 2 はフォーカス用divのボーダーサイズ
			s.top = offsetTop + (rect.top - 2) + "px";
			s.left = (rect.left - 2) + "px";
			s.width = (rect.right - rect.left) + "px";
			s.height = (rect.bottom - rect.top) + "px";
		}
		data.entityRect.show = true;
	}

	function unfocusBoundingRect() {
		data.entityRect.show = false;
		var s = data.entityRect.rectStyle;
		s.top = s.left = s.width = s.height = "0px";
	}

	function updateTargetEntity(id) {
		var e = null;
		if (id < 0) {
			e = props.game._localDb[id];
		} else {
			e = props.game.db[id];
		}
		if (e) {
			data.targetEntity = {
				className: e.constructor.name,
				id: id,
				local: e.local,
				touchable: e.touchable,
				visible: e.visible(),
				x: e.x,
				y: e.y,
				width: e.width,
				height: e.height,
				angle: e.angle,
				opacity: e.opacity,
				destroyed: e.destroyed()
			};
		} else {
			data.targetEntity = null;
		}
	}

	var SNAPSHOT_PREFIX = "akss:" + props.gameId + "/";
	var snapshots = {};
	var snapshotsList = [];

	// ゲームコンテンツからのスナップショット保存要求をハンドル
	var saveSnapshotOriginal = props.game.saveSnapshot;
	props.game.saveSnapshot = function(gameSnapshot) {
		// browser-engineのGame#saveSnapshot()を実行
		saveSnapshotOriginal.apply(props.game, arguments);

		if (!gameSnapshot) return;

		var time = new Date();
		var y = time.getFullYear();
		var m = time.getMonth();
		m = m < 10 ? "0" + m : m;
		var d = time.getDate();
		d = d < 10 ? "0" + d : d;
		var h = time.getHours();
		h = h < 10 ? "0" + h : h;
		var min = time.getMinutes();
		min = min < 10 ? "0" + min : min;
		var s = time.getSeconds();
		s = s < 10 ? "0" + s : s;

		var name = y + "-" + m + "-" + d + "-" + h + "-" + min + "-" + s;
		var snapshot = {
			age: props.game.age,
			randGenSer: props.game.random[0].serialize(),
			gameSnapshot: gameSnapshot,
			players: data.players
		};
		addSnapshotsList(name, snapshot);

		// LocalStorageに保存
		localStorage.setItem(SNAPSHOT_PREFIX + name, JSON.stringify(snapshot));
	};

	// LocalStorageに保存されているスナップショットの一覧
	for (i in localStorage) {
		if (i.indexOf(SNAPSHOT_PREFIX) !== -1) {
			addSnapshotsList(i.split("/")[1], JSON.parse(localStorage.getItem(i)));
		}
	}
	data.snapshots = snapshotsList;

	// スナップショットリストの追加 (Vue.js)
	function addSnapshotsList(name, data) {
		snapshots[name] = data;
		snapshotsList.push({
			name: name,
			data: JSON.stringify(data, null, "  ")
		});
	}

	// スナップショットの削除 (Vue.js + LocalStorage)
	function removeSnapshot(name) {
		localStorage.removeItem(SNAPSHOT_PREFIX + name);
		snapshotsList = snapshotsList.filter(function(e) {
			return e.name !== name;
		});
		delete snapshots[name];
		data.snapshots = snapshotsList;
	}

	// Grid表示
	var gridCheckBox = document.getElementById("show-grid");
	var gridCanvas = document.getElementById("gridCanvas");
	setupGrid();
	resizeGrid();
	drawGrid();
	function setupGrid() {
		if (config.showGrid === true) {
			gridCheckBox.checked = true;
			gridCanvas.style.display = "block";
		}
		gridCanvas.width = props.game.width;
		gridCanvas.height = props.game.height;
		gridCanvas.style.width = props.game.width + "px";
		gridCanvas.style.height = props.game.height + "px";
	}
	function resizeGrid() {
		var container = document.getElementById("container");
		var node = container.lastChild.firstChild;
		gridCanvas.style.transformOrigin = node.style.transformOrigin;
		gridCanvas.style.transform = node.style.transform;
	}
	function drawGrid() {
		var context = gridCanvas.getContext("2d");
		context.save();
		context.strokeStyle = "#CCC";
		context.setLineDash([3, 3]);
		drawGridLine(20, 20);
		context.strokeStyle = "#AAA";
		context.setLineDash([]);
		drawGridLine(100, 100);
		context.restore();

		function drawGridLine(gridWidth, gridHeight) {
			var x, y;
			context.beginPath();
			for (x = 0.5; x <= props.game.width; x += gridWidth) {
				context.moveTo(x, 0);
				context.lineTo(x, props.game.height);
			}
			for (y = 0.5; y <= props.game.height; y += gridHeight) {
				context.moveTo(0, y);
				context.lineTo(props.game.width, y);
			}
			context.stroke();
		}
	}
	function toggleGrid() {
		if (gridCheckBox.checked) {
			gridCanvas.style.display = "block";
			config.showGrid = true;
		} else {
			gridCanvas.style.display = "none";
			config.showGrid = false;
		}
		saveConfig();
	}

	var omitInterpolatedTickCheckBox = document.getElementById("omit-interpolated-tick");
	setupOmitInterpolatedTick();
	function setupOmitInterpolatedTick() {
		if (config.omitInterpolatedTick) {
			omitInterpolatedTickCheckBox.checked = true;
			changeDriverState({ loopConfiguration: { omitInterpolatedTickOnReplay: true } });
		}
	}
	function toggleOmitInterpolatedTick() {
		if (omitInterpolatedTickCheckBox.checked) {
			changeDriverState({ loopConfiguration: { omitInterpolatedTickOnReplay: true } });
			config.omitInterpolatedTick = true;
		} else {
			changeDriverState({ loopConfiguration: { omitInterpolatedTickOnReplay: false } });
			config.omitInterpolatedTick = false;
		}
		saveConfig();
	}

	// time 更新
	function updateCurrentTime() {
		data.currentTime = param.timeKeeper.now();
	}
	props.game._sceneChanged.add(function (scene) {
		if (!scene.update.contains(updateCurrentTime)) {
			scene.update.add(updateCurrentTime);
		}
	});

	var PLAYLOG_PREFIX = "akpl:" + props.gameId + "/";
	var playlogList = [];
	if (param.isReplay) {
		// プレイログ再生時はディベロッパーメニューを強制表示
		// note: views["general-view"].showがtrueかつ他のviewsのメンバのshowがfalseである、という前提条件で無理やり対応
		views["general-view"].show = false;
		views["playlog-view"].show = true;
		data.showMenu = true;
	}
	function savePlaylog() {
		var name = +new Date();
		var dump = amflow.dump();
		var jsonData = JSON.stringify({
			tickList: dump.tickList,
			startPoints: dump.startPoints,
			fps: props.game.fps
		});
		if (localStorage.getItem(PLAYLOG_PREFIX + name)) {
			if (!window.confirm("同名のリプレイ情報がすでに存在します。上書きしてもよろしいでしょうか？")) {
				return;
			}
			_removePlaylog(name);
		}
		localStorage.setItem(PLAYLOG_PREFIX + name, jsonData);
		var url = dumpPlaylog(name);
		data.playlog.list.push({name: name, url: url});
	}
	function reloadPlaylog(name) {
		var currentUrl = location.protocol + "//" + location.host + location.pathname;
		if (name) {
			window.location.href = currentUrl + "?playlog=" + name;
		} else {
			window.location.href = currentUrl;
		}
	}
	function changeDriverState(arg, callback) {
		props.driver.changeState(arg, function (err) {
			if (err) {
				console.log(err);
			}
			if (callback) {
				callback(err);
			}
		});
	}
	function rewindReplay() {
		param.timeKeeper.setTime(0);
		updateCurrentTime();
	}
	function playPauseReplay() {
		if (data.isPaused) {
			param.timeKeeper.start();
			data.isPaused = false;
		} else {
			param.timeKeeper.pause();
			data.isPaused = true;
		}
	}
	function onClickTimeProgress(ev) {
		var progress = document.getElementById("dev-menu-time-progress");
		var targetTime = Math.floor(ev.offsetX * progress.max / progress.offsetWidth);
		param.timeKeeper.setTime(targetTime);
	}
	function accelerateReplay() {
		param.timeKeeper.setRate(param.timeKeeper.getRate() * 2);
	}
	function decelerateReplay() {
		param.timeKeeper.setRate(param.timeKeeper.getRate() / 2);
	}
	function playFromHere() {
		if (props.amflow.dropAfter) {
			props.amflow.dropAfter(props.game.age);
		}
		props.driver.stopGame();
		props.driver.changeState({
			driverConfiguration: {
				executionMode: gdr.ExecutionMode.Active,
				playToken: gdr.MemoryAmflowClient.TOKEN_ACTIVE
			},
			loopConfiguration: {
				playbackRate: 1,  // 実行速度もリセットしておく
				loopMode: gdr.LoopMode.Realtime,
				delayIgnoreThreshold: 6,  // Ugh! GameLoopがデフォルト値にリセットする方法を提供するべき
				jumpTryThreshold: 90000
			}
		}, function (err) {
			if (err) {
				console.log(err);
				return;
			}
			data.isReplay = false;
			props.driver.setNextAge(props.game.age);
			props.driver.startGame();
		});
	}
	function removePlaylog(name) {
		if (!window.confirm("リプレイ情報を削除しますか？"))
			return;
		_removePlaylog(name);
	}
	function _removePlaylog(name) {
		localStorage.removeItem(PLAYLOG_PREFIX + name);
		playlogList = playlogList.filter(function(e) {
			if (e.name === name)
				window.URL.revokeObjectURL(e.url);
			return e.name !== name;
		});
		data.playlog.list = playlogList;
	}
	function dumpPlaylog(name) {
		var playlog = localStorage.getItem(PLAYLOG_PREFIX + name);
		if (!playlog) return;
		var blob = new Blob([ playlog ], { type : "application/x-download" });
		return URL.createObjectURL(blob);
	}
	var loader = document.getElementById("load-playlog-handler");
	loader.addEventListener("change", function (e) {
		var file = e.target.files[0];
		var reader = new FileReader();
		reader.readAsText(file);
		reader.onload = function (ev) {
			if (localStorage.getItem(PLAYLOG_PREFIX + file.name)) {
				if (!window.confirm("同名のリプレイ情報がすでに存在します。上書きしてもよろしいでしょうか？")) {
					return;
				}
				_removePlaylog(file.name);
			}
			localStorage.setItem(PLAYLOG_PREFIX + file.name, ev.target.result);
			var url = dumpPlaylog(file.name);
			data.playlog.list.push({name: file.name, url: url});
		};
	}, false);

	// LocalStorageに保存されているプレイログの一覧
	for (i in localStorage) {
		if (i.indexOf(PLAYLOG_PREFIX) !== -1) {
			var name = i.split("/")[1];
			var url = dumpPlaylog(name);
			playlogList.push({
				name: name,
				url: url
			});
		}
	}
	data.playlog.list = playlogList;

	function getJsonStringifiedValue(value) {
		try {
			var stringifiedValue = JSON.stringify(value);
			return stringifiedValue === undefined ? "undefined" : stringifiedValue;
		} catch (e) {
			return "N/A (circular reference)";
		}
	}

	Vue.component("entity-list-item", {
		template: "#entity-list-item-template",
		props: {
			model: Object,
			index: Number
		},
		data: function () {
			return {
				open: false
			};
		},
		computed: {
			hasChildren: function () {
				if (this.model.children && this.model.children.length > 0) {
					return true;
				}
				return false;
			}
		},
		methods: {
			toggle: function () {
				this.open = !this.open;
			},
			selectEntity: function() {
				updateTargetEntity(this.model.id);
			},
			focusEntity: function() {
				focusBoundingRect(this.model.id);
			},
			unfocusEntity: function() {
				unfocusBoundingRect();
			}
		}
	});

	var vm = new Vue({
		el: "#dev-menu",
		data: data,
		ready: function(v) {
			// v-show/v-ifだと一瞬メニューが見えてしまうため、".dev-menu-hide"を初期状態で付けている
			// それを外して表示制御をv-showに任せる
			var e = this.$el;
			e.className = e.className.replace(/dev-menu-hide/g, "");
			// interact.js によるリサイズ処理
			interact("#dev-menu")
				.resizable({
					preserveAspectRatio: true,
					edges: { left: true, top: true }
				})
				.on("resizemove", function (event) {
					if (data.config.isPositionRight) {
						data.config.size.right.width  = event.rect.width + "px";
					} else {
						data.config.size.bottom.height = event.rect.height + "px";
					}
					saveConfig();
				});
			renderView(this);
		},
		methods: {
			leaveGame: function(index) {
				var p = {id: data.players[index].player.id, name: data.players[index].player.name};
				data.players.$remove(data.players[index]);
				amflow.sendEvent([1 /* Leave */,  3, p.id ]);
			},
			toggleMenu: function() {
				data.showMenu = !data.showMenu;
			},
			closeMenu: function() {
				data.showMenu = false;
			},
			togglePosition: function() {
				data.config.isPositionRight = !data.config.isPositionRight;
				saveConfig();
			},
			changeView: function(target) {
				for (id in data.views) {
					data.views[id].show = false;
				}
				target.show = true;
				renderView(this);
			},
			toggleBackground: function() {
				var bg = document.body.style.backgroundColor;
				document.body.style.backgroundColor = bg ? "" : "black";
			},
			togglePreventDefault: function() {
				saveConfig();
			},
			toggleWarningEs6: function() {
				saveConfig();
			},
			toggleProfiler: toggleProfiler,
			fitToWindow: function() {
				// setOffsetしないとメニューにゲーム画面が被って、メニューサイズを変更しようとするとバグるのでとりあえず true
				window.sandboxDeveloperProps.utils.fitToWindow(true);
				resizeGrid();
			},
			revertSize: function(){
				window.sandboxDeveloperProps.utils.revertViewSize();
				resizeGrid();
			},
			captureScreen: 	function(e) {
				var cvs = document.getElementsByTagName("canvas");
				e.srcElement.setAttribute("href", cvs.item(1).toDataURL());
			},
			joinGame: joinGame,
			saveSnapshot: function() {
				// スナップショット要求の発火
				if (props.game.snapshotRequest) {
					props.game.snapshotRequest.fire();
				}
			},
			removeSnapshot: removeSnapshot,
			loadSnapshot: function(name) {
				console.log("snapshot loaded: " + name);
				var snapshot = snapshots[name];

				// developerメニューの把握するカメラを全リセット
				data.cameras = [];
				cameras = [];
				// プレイヤー情報を再現 (この復元はゲームコンテンツのプレイヤー情報の復元とは関係がない)
				data.players = snapshot.players;

				props.game._reset({
					age: snapshot.age,
					randGen: g.XorshiftRandomGenerator.deserialize(snapshot.randGenSer)
				});
				props.game._loadAndStart({ snapshot: snapshot.gameSnapshot });
			},
			previewSnapshot: function(index, name) {
				data.snapshotPreview = {
					name: name,
					data: snapshotsList[index].data
				};
			},
			savePlaylog: savePlaylog,
			reloadPlaylog: reloadPlaylog,
			rewindReplay: rewindReplay,
			playPauseReplay: playPauseReplay,
			onClickTimeProgress: onClickTimeProgress,
			accelerateReplay: accelerateReplay,
			decelerateReplay: decelerateReplay,
			playFromHere: playFromHere,
			removePlaylog: removePlaylog,
			setFocusingCamera: function(index) {
				var c = cameras[index];
				if (props.game.focusingCamera !== c) {
					props.game.focusingCamera = c;
				} else {
					props.game.focusingCamera = undefined;
				}
				// TODO: GAMEDEV-2414, GAMEDEV-2415
				props.game.modified = true;
			},
			updateEntityList: updateEntityList,
			consoleDump: function() {
				var e = data.targetEntity;
				if (e.local) {
					console.log(props.game._localDb[e.id]);
				} else {
					console.log(props.game.db[e.id]);
				}
			},
			onEventsToSendChanged: function() {
				saveConfig();
			},
			onAutoSendEventsChanged: function() {
				saveConfig();
			},
			insertEventString: insertEventString,
			sendEvents: sendEvents,
			sendEventsWithValue: sendEventsWithValue,
			onAutoJoinChanged: function() {
				saveConfig();
			},
			onSendsSessionParameterChanged: function() {
				saveConfig();
			},
			onModeChanged: function() {
				saveConfig();
			},
			onTotalTimeLimitChanged: function() {
				saveConfig();
			},
			onStopGameChanged: function() {
				saveConfig();
			},
			toggleGrid: toggleGrid,
			toggleOmitInterpolatedTick: toggleOmitInterpolatedTick
		}
	});
}
87231
function(){
		var partslist = this.modifyNodes;
		var newcomponents = [];
		for(var i=0,len=partslist.length;i<len;i++){
			partslist[i].component = null;
		}
		for(var i=0,len=partslist.length;i<len;i++){
			if(partslist[i].component!==null){ continue;}	// 既にidがついていたらスルー
			var component = this.createComponent();
			this.searchSingle(partslist[i], component);
			this.setComponentInfo(component);
			newcomponents.push(component);
		}
		this.modifyNodes = [];
		return newcomponents;
	}
978750
def h2z(text, ignore='', kana=True, ascii=False, digit=False):
    
    def _conv_dakuten(text):
        """
        半角濁点カナを全角に変換
        """
        text = text.replace(u"ｶﾞ", u"ガ").replace(u"ｷﾞ", u"ギ")
        text = text.replace(u"ｸﾞ", u"グ").replace(u"ｹﾞ", u"ゲ")
        text = text.replace(u"ｺﾞ", u"ゴ").replace(u"ｻﾞ", u"ザ")
        text = text.replace(u"ｼﾞ", u"ジ").replace(u"ｽﾞ", u"ズ")
        text = text.replace(u"ｾﾞ", u"ゼ").replace(u"ｿﾞ", u"ゾ")
        text = text.replace(u"ﾀﾞ", u"ダ").replace(u"ﾁﾞ", u"ヂ")
        text = text.replace(u"ﾂﾞ", u"ヅ").replace(u"ﾃﾞ", u"デ")
        text = text.replace(u"ﾄﾞ", u"ド").replace(u"ﾊﾞ", u"バ")
        text = text.replace(u"ﾋﾞ", u"ビ").replace(u"ﾌﾞ", u"ブ")
        text = text.replace(u"ﾍﾞ", u"ベ").replace(u"ﾎﾞ", u"ボ")
        text = text.replace(u"ﾊﾟ", u"パ").replace(u"ﾋﾟ", u"ピ")
        text = text.replace(u"ﾌﾟ", u"プ").replace(u"ﾍﾟ", u"ペ")
        return text.replace(u"ﾎﾟ", u"ポ").replace(u"ｳﾞ", u"ヴ")

    if ascii:
        if digit:
            if kana:
                h2z_map = H2Z_ALL
            else:
                h2z_map = H2Z_AD
        elif kana:
            h2z_map = H2Z_AK
        else:
            h2z_map = H2Z_A
    elif digit:
        if kana:
            h2z_map = H2Z_DK
        else:
            h2z_map = H2Z_D
    else:
        h2z_map = H2Z_K
    if kana:
        text = _conv_dakuten(text)
    if ignore:
        h2z_map = _exclude_ignorechar(ignore, h2z_map.copy())
    return _convert(text, h2z_map)
1120757
function teachingRec(index){
    teachingIsPlay=false;
    teachingIsRec=!teachingIsRec;
    clearInterval(teachingCountIntervalId);
    if(!teachingIsRec){
        KMB.cmdStopTeachingMotion();
        KMB.cmdEnable();
    }else{
        KMB.cmdEraseMotion(index);//消してないとエラー無しで録画出来ない
        //info::cmdEraseMotionの実行完了までのインターバルが必要。500ms (新ファームでEraseMotion->StartTeachingMotionを統合したコマンド新設予定)
        setTimeout(()=>{
            KMB.cmdStartTeachingMotion(index,teachingRecTime);
            teachingCountIntervalTime=teachingRecTime+1000;
            teachingCountFnc();
            teachingCountIntervalId=setInterval(teachingCountFnc,1000);
        },500);
    }
    $(".teachingPlayB").prop("disabled",teachingIsRec);
}
91080
function(lastope){
		// 前回と同じ場所なら前回の更新のみ
		var property = this.property;
		if( lastope.group    === this.group &&
			lastope.property === this.property  &&
			lastope.num      === this.old   &&
			lastope.bx       === this.bx    &&
			lastope.by       === this.by    &&
			(property === 'qnum'  || 
			 property === 'qnum2' ||
			 property === 'qchar' ||
			 property === 'anum'  ||
			(property === 'snum' && lastope.pos === this.pos))
		)
		{
			lastope.num = this.num;
			return true;
		}
		return false;
	}
1361730
private boolean executeCommand(final LineReader reader) throws Exception {
		String prompt = new AttributedStringBuilder()
				.style(AttributedStyle.BOLD.foreground(AttributedStyle.GREEN))
				.ansiAppend("uroborosql")
				.style(AttributedStyle.DEFAULT)
				.append(" > ")
				.toAnsi();
		String line = reader.readLine(prompt);
		if (line == null || line.isEmpty()) {
			// 空なら何もせずにループ
			return true;
		}

		String[] parts = line.split("\\s+");
		Optional<ReplCommand> command = commands.stream().filter(c -> c.is(parts[0])).findFirst();
		if (command.isPresent()) {
			return command.get().execute(reader, parts, sqlConfig, props);
		} else {
			showHelp(reader.getTerminal());
			return true;
		}
	}
646009
public static function DefaultRule () {
		return [
			//状態
			static::RULE_REQUIRE			=> [function ($value, $options, $meta = []) {return $value !== null;}, '必須入力項目 {:title}が入力されていません。'],
			static::RULE_NOT_EMPTY			=> [function ($value, $options, $meta = []) {return (is_array($value)) ? !empty($value) : preg_match("/[^\s]+/um", $value) === 1;}, '{:title}を入力してください。'],
			static::RULE_NOT_STRING_EMPTY	=> [function ($value, $options, $meta = []) {return (is_array($value)) ? !empty($value) : trim($value, "\r\n") !== '';}, '{:title}を入力してください。'],

			//逆状態
			static::RULE_NOT_REQUIRE		=> [function ($value, $options, $meta = []) {return $value === null;}, '必須除外項目 {:title}が入力されました。'],

			//スカラー値
			'bool'			=> [function ($value, $options, $meta = []) {return filter_var($value, \FILTER_VALIDATE_BOOLEAN);}, '{:title}には1, true, on, yesのいずれかを入力してください。'],
			'int'			=> [function ($value, $options, $meta = []) {return is_int(filter_var($value, \FILTER_VALIDATE_INT)) && 0 === preg_match("/\A[^0-9\-\+eEx]\z/", $value);}, '{:title}には整数を入力してください。'],
			'positive_int'	=> [function ($value, $options, $meta = []) {return filter_var($value, \FILTER_VALIDATE_INT) > -1;}, '{:title}には正の整数を入力してください。'],
			'negative_int'	=> [function ($value, $options, $meta = []) {return filter_var($value, \FILTER_VALIDATE_INT) < 1;}, '{:title}には負の整数を入力してください。'],
			'int_length'	=> [function ($value, $options, $meta = []) {return static::Length($value, ['length' => $options[0] ?? $options['length'] ?? null], $options);}, '{:title}は{:length:0}桁入力してください。'],
			'int_range'		=> [function ($value, $options, $meta = []) {return is_int(filter_var($value, \FILTER_VALIDATE_INT, $options));}, '{:title}には{:min_range:0}から{:max_range:1}までの間の半角数値を入力してください。'],
			'int_min_range'	=> [function ($value, $options, $meta = []) {return is_int(filter_var($value, \FILTER_VALIDATE_INT, ['min_range' => $options['min_range']]));}, '{:title}には{:min_range:0}以上の半角数値を入力してください。'],
			'int_max_range'	=> [function ($value, $options, $meta = []) {return is_int(filter_var($value, \FILTER_VALIDATE_INT, ['max_range' => $options['max_range']]));}, '{:title}には{:max_range:0}以下の半角数値を入力してください。'],

			'float'			=> [function ($value, $options, $meta = []) {return is_float(filter_var($value, \FILTER_VALIDATE_FLOAT)) && 0 === preg_match("/\A[^0-9\-\+eEx\.]\z/", $value);}, '{:title}には実数を入力してください。'],

			//bit演算
			'bit_any'		=> [function  ($value, $options, $meta = []) {$value = (int) $value;return $value !== 0 && $value === ($value & $options[0] ?? $options['bit'] ?? 0);}, '{:title}には有効なbit値を入力してください。'],
			'bit_or'		=> [function  ($value, $options, $meta = []) {$value = (int) $value;return $value !== 0 && $value === ($value & $options[0] ?? $options['bit'] ?? 0);}, '{:title}には有効なbit値を入力してください。'],

			//型
			'is_array'		=> [function ($value, $options, $meta = []) {return is_array($value);}, '{:title}には配列を設定してください。'],
			'is_bool'		=> [function ($value, $options, $meta = []) {return is_bool($value);}, '{:title}には真偽値を設定してください。'],
			'is_callable'	=> [function ($value, $options, $meta = []) {return is_callable($value);}, '{:title}にはコーラブルな値を設定してください。'],
			'is_double'		=> [function ($value, $options, $meta = []) {return is_double($value);}, '{:title}には浮動小数点を設定してください。'],
			'is_float'		=> [function ($value, $options, $meta = []) {return is_float($value);}, '{:title}には浮動小数点を設定してください。'],
			'is_int'		=> [function ($value, $options, $meta = []) {return is_int($value);}, '{:title}には整数を設定してください。'],
			'is_integer'	=> [function ($value, $options, $meta = []) {return is_integer($value);}, '{:title}には整数を設定してください。'],
			'is_iterable'	=> [function ($value, $options, $meta = []) {return is_iterable($value);}, '{:title}にはイテレータブルな値を設定してください。'],
			'is_long'		=> [function ($value, $options, $meta = []) {return is_long($value);}, '{:title}には整数を設定してください。'],
			'is_null'		=> [function ($value, $options, $meta = []) {return is_null($value);}, '{:title}にはNULLを設定してください。'],
			'is_numeric'	=> [function ($value, $options, $meta = []) {return is_numeric($value);}, '{:title}には数字または数値形式の文字列を設定してください。'],
			'is_object'		=> [function ($value, $options, $meta = []) {return is_object($value);}, '{:title}にはオブジェクトを設定してください。'],
			'is_real'		=> [function ($value, $options, $meta = []) {return is_real($value);}, '{:title}には浮動小数点を設定してください。'],
			'is_resource'	=> [function ($value, $options, $meta = []) {return is_resource($value);}, '{:title}にはリソース型の値を設定してください。'],
			'is_scalar'		=> [function ($value, $options, $meta = []) {return is_scalar($value);}, '{:title}にはスカラーな値を設定してください。'],
			'is_string'		=> [function ($value, $options, $meta = []) {return is_string($value);}, '{:title}には文字列を設定してください。'],

			//意味
			'num'			=> [function ($value, $options, $meta = []) {return ctype_digit($value);}, '{:title}には数値のみ入力してください。'],
			'numeric'		=> [function ($value, $options, $meta = []) {return ctype_digit($value);}, '{:title}には数値のみ入力してください。'],
			'digit'			=> [function ($value, $options, $meta = []) {return ctype_digit($value);}, '{:title}には数値のみ入力してください。'],
			'alpha'			=> [function ($value, $options, $meta = []) {return ctype_alpha($value);}, '{:title}にはアルファベットのみ入力してください。'],
			'alpha_num'		=> [function ($value, $options, $meta = []) {return ctype_alnum($value);}, '{:title}にはアルファベットと数字のみ入力してください。'],
			'blank'			=> ["/^\s/", '{:title}には空白以外を入力しないでください。'],
			'phone'			=> ["/^\d{2,4}\-\d{4}\-\d{4}\$/", '{:title}には電話番号を入力してください。例：000-0000-0000'],

			//PHP session id
			'session_id'	=> ["/\A[,0-9a-zA-Z\-]{1,128}\z/", '{:title}にはsession idとして有効な値を入力してください。'],

			//UUID
			'uuid_v4'		=> ["/\A[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-4[0-9a-fA-F]{3}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}\z/", '{:title}にはUUID v4を入力してください。'],

			//e-mail
			'email'			=> [function ($value, $options, $meta = []) {return is_string(filter_var($value, \FILTER_VALIDATE_EMAIL));}, '{:title}にはemailアドレスを入力してください。例：user@example.com'],
			'email_char'	=> [function ($value, $options, $meta = []) {return filter_var($value, \FILTER_SANITIZE_EMAIL) === $value;}, '{:title}にはemailアドレスで使用できる文字を入力してください。'],
			'email_strict'	=> [function ($value, $options, $meta = []) {$separated_value = explode('@', $value);return isset($separated_value[1]) && filter_var($value, \FILTER_SANITIZE_EMAIL) === $value && checkdnsrr($separated_value[1], 'MX') && count(dns_get_record($separated_value[1], DNS_MX)) !== 0;}, '{:title}には有効なemailアドレスを入力してください。'],
			'email_include_localhost'	=> [function ($value, $options, $meta = []) {if (is_string(filter_var($value, \FILTER_VALIDATE_EMAIL))) {return true;};$separated_value = explode('@', $value);if (count($separated_value) !== 2 || $separated_value[1] !== 'localhost') {return false;};return is_string(filter_var($separated_value[0].'@example.com', \FILTER_VALIDATE_EMAIL));}, '{:title}には有効なemailアドレスを入力してください。'],
			'email_jp_limited'	=> [function ($value, $options, $meta = []) {return static::EmailJpLimited($value, $options, $meta);}, '{:title}にはemailアドレスを入力してください。例：user@example.com'],

			//IP addr
			'ip_addr'				=> [function ($value, $options, $meta = []) {return filter_var($value, \FILTER_VALIDATE_IP) === $value;}, '{:title}にはIPアドレスを入力してください。'],
			'ip_v4_addr'			=> [function ($value, $options, $meta = []) {return filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4) === $value;}, '{:title}にはIP V4アドレスを入力してください。'],
			'ip_v6_addr'			=> [function ($value, $options, $meta = []) {return filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6) === $value;}, '{:title}にはIP V6アドレスを入力してください。'],
			'no_private_ip_addr'	=> [function ($value, $options, $meta = []) {return filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_NO_PRIV_RANGE) === $value;}, '{:title}にはプライベートIPアドレス以外のIPアドレスを入力してください。'],
			'no_res_ip_addr'		=> [function ($value, $options, $meta = []) {return filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_NO_RES_RANGE) === $value;}, '{:title}には予約済みIPアドレス以外のIPアドレスを入力してください。'],

			//ホスト
			'hostname'				=> [function ($value, $options, $meta = []) {return static::Hostname($value, $options, $meta);}, '{:title}には有効なホスト名を入力してください。'],
			'host'					=> [function ($value, $options, $meta = []) {return static::Hostname($value, $options, $meta) || filter_var($value, \FILTER_VALIDATE_IP) === $value;}, '{:title}には有効なホスト名を入力してください。'],

			//ポート
			'port'							=> [function ($value, $options, $meta = []) {$length = strlen($value);return $length === strspn($value, '1234567890') && -0 < $value && $value < 65536;}, '{:title}には有効なポートを入力してください。'],
			'well_known_port'				=> [function ($value, $options, $meta = []) {$length = strlen($value);return $length === strspn($value, '1234567890') && -0 < $value && $value < 1024;}, '{:title}には有効なポートを入力してください。'],
			'registered_port'				=> [function ($value, $options, $meta = []) {$length = strlen($value);return $length === strspn($value, '1234567890') && 1023 < $value && $value < 49152;}, '{:title}には有効なポートを入力してください。'],
			'dynamic_and_or_private_ports'	=> [function ($value, $options, $meta = []) {$length = strlen($value);return $length === strspn($value, '1234567890') && 49151 < $value && $value < 65536;}, '{:title}には有効なポートを入力してください。'],

			//DNS
			'exists_host'		=> [function ($value, $options, $meta = []) {return checkdnsrr($value, $options['type']);}, '{:title}には存在するホスト名を入力してください。'],
			'exists_host_mx'	=> [function ($value, $options, $meta = []) {return checkdnsrr($value, 'MX');}, '{:title}には存在するホスト名を入力してください。'],
			'exists_host_ns'	=> [function ($value, $options, $meta = []) {return checkdnsrr($value, 'NS');}, '{:title}には存在するホスト名を入力してください。'],
			'exists_host_soa'	=> [function ($value, $options, $meta = []) {return checkdnsrr($value, 'SOA');}, '{:title}には存在するホスト名を入力してください。'],
			'exists_host_ptr'	=> [function ($value, $options, $meta = []) {return checkdnsrr($value, 'PTR');}, '{:title}には存在するホスト名を入力してください。'],
			'exists_host_cname'	=> [function ($value, $options, $meta = []) {return checkdnsrr($value, 'CNAME');}, '{:title}には存在するホスト名を入力してください。'],
			'exists_host_aaaa'	=> [function ($value, $options, $meta = []) {return checkdnsrr($value, 'AAAA');}, '{:title}には存在するホスト名を入力してください。'],
			'exists_host_a6'	=> [function ($value, $options, $meta = []) {return checkdnsrr($value, 'A6');}, '{:title}には存在するホスト名を入力してください。'],
			'exists_host_srv'	=> [function ($value, $options, $meta = []) {return checkdnsrr($value, 'SRV');}, '{:title}には存在するホスト名を入力してください。'],
			'exists_host_naptr'	=> [function ($value, $options, $meta = []) {return checkdnsrr($value, 'NAPTR');}, '{:title}には存在するホスト名を入力してください。'],
			'exists_host_naptr'	=> [function ($value, $options, $meta = []) {return checkdnsrr($value, 'NAPTR');}, '{:title}には存在するホスト名を入力してください。'],
			'exists_host_any'	=> [function ($value, $options, $meta = []) {return checkdnsrr($value, 'ANY');}, '{:title}には存在するホスト名を入力してください。'],

			'exists_dns_record_mx'	=> [function ($value, $options, $meta = []) {return count(dns_get_record($value, DNS_MX)) !== 0;}, '{:title}には存在するホスト名を入力してください。'],

			//範囲
			'range'			=> [function ($value, $options, $meta = []) {return static::Range($value, $options, $options['format'] ?? null, $options);}, '{:title}には{:min_range:0}から{:max_range:1}までの間の値を入力してください。'],
			'min_range'		=> [function ($value, $options, $meta = []) {return static::Range($value, ['min_range' => $options[0] ?? $options['min_range'] ?? null], $options['format'] ?? null, $options);}, '{:title}には{:min_range:0}以上の値を入力してください。'],
			'max_range'		=> [function ($value, $options, $meta = []) {return static::Range($value, ['max_range' => $options[1] ?? $options['max_range'] ?? $options[0] ?? null], $options['format'] ?? null, $options);}, '{:title}には{:max_range:0}以下の値を入力してください。'],

			//日付
			'date'			=> [function ($value, $options, $meta = []) {return static::DateTime($value, $options['format'] ?? static::YMD);}, '{:title}には{:format:0}形式の日付を入力してください。'],
			'time'			=> [function ($value, $options, $meta = []) {return static::DateTime($value, $options['format'] ?? static::HIS);}, '{:title}には{:format:0}形式の時間を入力してください。'],
			'datetime'		=> [function ($value, $options, $meta = []) {return static::DateTime($value, $options['format'] ?? static::YMD_HIS);}, '{:title}には{:format:0}形式の日付と時間を入力してください。'],

			//文字列長さ
			'length'			=> [function ($value, $options, $meta = []) {return static::Length($value, ['length' => $options[0] ?? $options['length'] ?? null], $options);}, '{:title}は{:length:0}文字入力してください。'],
			'between_length'	=> [function ($value, $options, $meta = []) {return static::Length($value, $options, $options);}, '{:title}は{:min_length:0}文字以上{:max_length:1}文字以内で入力してください。'],
			'max_length'		=> [function ($value, $options, $meta = []) {return static::Length($value, ['max_length' => $options[0] ?? $options['max_length']], $options);}, '{:title}は{:max_length:0}文字以内で入力してください。'],
			'min_length'		=> [function ($value, $options, $meta = []) {return static::Length($value, ['min_length' => $options[0] ?? $options['min_length']], $options);}, '{:title}は{:min_length:0}文字以上入力してください。'],

			//カラーコード
			'color_code'	=> [function ($value, $options, $meta = []) {return \ickx\fw2\constants\web\ColorCode::IsHexColorCode($value);}, '{:title}には16進数のカラーコードを入力してください。'],

			//配列
			'in'					=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_IN,					$options[0] ?? $options['operand'] ?? null, $options);}, '{:title}に未定義の値が入力されています。'],
			'not_in'				=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_NOT_IN,				$options[0] ?? $options['operand'] ?? null, $options);}, '{:title}の値は利用できません。'],
			'not_overlap'			=> [function ($value, $options, $meta = []) {$tmp = [];foreach ($value as $element) {if (in_array($element, $tmp, true)) {return false;}$tmp[] = $element;}return true;}, '{:title}に重複した値があります。'],
			'key'					=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_KEY,					$options[0] ?? $options['key_set'] ?? null, $options);}, '{:title}に未定義の値が入力されています。'],
			'key_exists'			=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_KEY_EXISTS,			$options[0] ?? $options['key_set'] ?? null, $options);}, '{:title}に未定義の値が入力されています。'],
			'any'					=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_ANY,					$options[0] ?? $options['operand'] ?? null, $options);}, '{:title}に必須項目が含まれていません。'],
			'any_key_exists'		=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_ANY_KEY_EXISTS	,	$options[0] ?? $options['key_set'] ?? null, $options);}, '{:title}には{:key_set:0}のいずれかを入力してください。'],
			'not_any_key_exists'	=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_NOT_ANY_KEY_EXISTS,	$options[0] ?? $options['key_set'] ?? null, $options);}, '{:title}には{:key_set:0}のいずれかを入力してください。'],
			//'min'
			//'max'

			//比較
			'<'				=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_LT,		$options[0] ?? $options['operand'] ?? null, $options);}, '{:title}には{:operand:0}未満の値を入力してください。'],
			'<='			=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_LT_EQ,	$options[0] ?? $options['operand'] ?? null, $options);}, '{:title}には{:operand:0}以下の値を入力してください。'],
			'>'				=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_GT,		$options[0] ?? $options['operand'] ?? null, $options);}, '{:title}には{:operand:0}より上の値を入力してください。'],
			'>='			=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_GT_EQ,	$options[0] ?? $options['operand'] ?? null, $options);}, '{:title}には{:operand:0}以上の値を入力してください。'],
			'=='			=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_EQ,		$options[0] ?? $options['operand'] ?? null, $options);}, '{:title}が{:operand:0}と異なります。'],
			'!='			=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_NOT_EQ,	$options[0] ?? $options['operand'] ?? null, $options);}, '{:title}が{:operand:0}と同じです。'],
			'==='			=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_S_EQ,		$options[0] ?? $options['operand'] ?? null, $options);}, '{:title}が{:operand:0}と異なります。'],
			'!=='			=> [function ($value, $options, $meta = []) {return static::Comparison($value, static::OP_S_NOT_EQ,	$options[0] ?? $options['operand'] ?? null, $options);}, '{:title}が{:operand:0}と同じです。'],

			//ファイルシステム
			'file_exists'	=> [function ($value, $options, $meta = []) {clearstatcache(true, $value);return file_exists($value);}, 'パス：{:value}は存在しません。'],
			'is_dir'		=> [function ($value, $options, $meta = []) {clearstatcache(true, $value);return is_dir($value);}, 'パス：{:value}はディレクトリではありません。'],
			'is_file'		=> [function ($value, $options, $meta = []) {clearstatcache(true, $value);return is_file($value);}, 'パス：{:value}はファイルではありません。'],
			'readable'		=> [function ($value, $options, $meta = []) {clearstatcache(true, $value);return is_readable($value);}, 'パス：{:value}は読み込めません。'],
			'writable'		=> [function ($value, $options, $meta = []) {clearstatcache(true, $value);return is_writable($value);}, 'パス：{:value}は書き込めません。'],
			'executable'	=> [function ($value, $options, $meta = []) {clearstatcache(true, $value);return is_executable($value);}, 'パス：{:value}は実行できません。'],
//			'file_size'		=> [function ($value, $options, $meta = []) {clearstatcache(true, $value);return filesize($value);}, 'パス：{:value}は存在しません。'],

			'parent_is_dir'		=> [function ($value, $options, $meta = []) {$value = dirname($value);clearstatcache(true, $value);return is_dir($value);}, 'パス：{:value}の親はディレクトリではありません。'],
			'parent_exists'		=> [function ($value, $options, $meta = []) {$value = dirname($value);clearstatcache(true, $value);return file_exists($value);}, 'パス：{:value}の親ディレクトリがありません。'],
			'parent_executable'	=> [function ($value, $options, $meta = []) {$value = dirname($value);clearstatcache(true, $value);return strtolower(substr(\PHP_OS, 0, 3)) === 'win' ? is_readable($value) : is_executable($value);}, 'パス：{:value}の親ディレクトリを開けません。'],
			'parent_readable'	=> [function ($value, $options, $meta = []) {$value = dirname($value);clearstatcache(true, $value);return is_readable($value);}, 'パス：{:value}の親ディレクトリを読み込めません。'],
			'parent_writable'	=> [function ($value, $options, $meta = []) {$value = dirname($value);clearstatcache(true, $value);return is_writable($value);}, 'パス：{:value}の親ディレクトリに書き込めません。'],

			//ファイルアップロード
			'upload_check_status'	=> [function ($value, $options, $meta = []) {return static::CheckUploadStatus($value, $options, $meta);}, '{:title}{:adjust}でエラーが発生しました。error code:{:error_code} {:validator_message}'],
			'upload_range_filesize'	=> [function ($value, $options, $meta = []) {return static::Range($value['size'], $options, $options['format'] ?? null, $options);}, '{:title}はファイルサイズを{:min_range:0}バイトから{:max_range:1}バイトまでの間にしてください。'],
			'upload_min_filesize'	=> [function ($value, $options, $meta = []) {return static::Range($value['size'], ['min_range' => $options[0] ?? $options['min_range'] ?? null], $options['format'] ?? null, $options);}, '{:title}はファイルサイズが{:min_range:0}バイト以上必要です。'],
			'upload_max_filesize'	=> [function ($value, $options, $meta = []) {return static::Range($value['size'], ['max_range' => $options[1] ?? $options['max_range'] ?? $options[0] ?? null], $options['format'] ?? null, $options);}, '{:title}はファイルサイズが{:max_range:0}バイト以下である必要があります。'],
			'upload_mimetype'		=> [function ($value, $options, $meta = []) {return $value['type'] > $options[0] ?? $options['max'] ?? null;} ,'{:title}は{:max:0}バイト以上にしてください。'],
			'upload_ext'			=> [function ($value, $options, $meta = []) {return $value['type'] > $options[0] ?? $options['max'] ?? null;} ,'{:title}は{:max:0}バイト以上にしてください。'],
			'upload_name'			=> [function ($value, $options, $meta = []) {return $value['type'] > $options[0] ?? $options['max'] ?? null;} ,'{:title}は{:max:0}バイト以上にしてください。'],

			//文字セット
			'charset_email'			=> [function ($value, $options, $meta = []) {$filterd_length = strlen(filter_var($value, \FILTER_SANITIZE_EMAIL));return $filterd_length !== 0 && $filterd_length === strlen($value);}, '{:title}にはemailに利用できる文字を入力してください。'],
			'charset_full_kana'		=> [function ($value, $options, $meta = []) {return 1 === preg_match(sprintf("/^[ァ-ヶぁ-ん%s]+$/u", (isset($options['append_pattern']) ? $options['append_pattern'] : '')), $value);}, '{:title}に利用できない文字「{:reject_character:0}」が含まれています。', ['reject_character' => function ($value, $options, $meta = []) {preg_match_all(sprintf("/([^ァ-ヶぁ-ん%s])/u", (isset($options['append_pattern']) ? $options['append_pattern'] : '')), $value, $reject_character);return implode(', ', array_unique($reject_character[1]));}],],
			'charset_full_katakana'	=> [function ($value, $options, $meta = []) {return 1 === preg_match(sprintf("/^[ァ-ヶ%s]+$/u", (isset($options['append_pattern']) ? $options['append_pattern'] : '')), $value);}, '{:title}に利用できない文字「{:reject_character:0}」が含まれています。', ['reject_character' => function ($value, $options, $meta = []) {preg_match_all(sprintf("/([^ァ-ヶ%s])/u", (isset($options['append_pattern']) ? $options['append_pattern'] : '')), $value, $reject_character);return implode(', ', array_unique($reject_character[1]));}],],
			'charset_full_hiragana'	=> [function ($value, $options, $meta = []) {return 1 === preg_match(sprintf("/^[ぁ-ん%s]+$/u", (isset($options['append_pattern']) ? $options['append_pattern'] : '')), $value);}, '{:title}に利用できない文字「{:reject_character:0}」が含まれています。', ['reject_character' => function ($value, $options, $meta = []) {preg_match_all(sprintf("/([^ぁ-ん%s])/u", (isset($options['append_pattern']) ? $options['append_pattern'] : '')), $value, $reject_character);return implode(', ', array_unique($reject_character[1]));}],],
			'charset_full_alpha'	=> [function ($value, $options, $meta = []) {return 1 === preg_match(sprintf("/^[ａ-ｚＡ-Ｚ%s]+$/u", (isset($options['append_pattern']) ? $options['append_pattern'] : '')), $value);}, '{:title}に利用できない文字「{:reject_character:0}」が含まれています。', ['reject_character' => function ($value, $options, $meta = []) {preg_match_all(sprintf("/([^ａ-ｚＡ-Ｚ%s])/u", (isset($options['append_pattern']) ? $options['append_pattern'] : '')), $value, $reject_character);return implode(', ', array_unique($reject_character[1]));}],],
			'charset_full_num'		=> [function ($value, $options, $meta = []) {return 1 === preg_match(sprintf("/^[０-９%s]+$/u", (isset($options['append_pattern']) ? $options['append_pattern'] : '')), $value);}, '{:title}に利用できない文字「{:reject_character:0}」が含まれています。', ['reject_character' => function ($value, $options, $meta = []) {preg_match_all(sprintf("/([^０-９%s])/u", (isset($options['append_pattern']) ? $options['append_pattern'] : '')), $value, $reject_character);return implode(', ', array_unique($reject_character[1]));}],],

			//エンコーディング
			'utf8'			=> [function ($value, $options, $meta = []) {return static::Encoding($value, ['encoding' => 'UTF-8'] + $options);}, '{:title}がUTF-8ではなく{:encoding}になっています。'],
			'sjis-win'		=> [function ($value, $options, $meta = []) {return static::Encoding($value, ['encoding' => 'SJIS-win'] + $options);}, '{:title}がSJIS-winではなく{:encoding}になっています。'],
			'eucjp-win'		=> [function ($value, $options, $meta = []) {return static::Encoding($value, ['encoding' => 'eucJP-win'] + $options);}, '{:title}がeucJP-winではなく{:encoding}になっています。'],

			//PREG 互換正規表現
			'preg_regex'	=> [function ($value, $options, $meta = []) {return filter_var($value, \FILTER_VALIDATE_REGEXP) === $value;}, '{:title}にはPREG互換の正規表現を入力してください。'],

			//正規表現
			'regex'			=> [function ($value, $options, $meta = []) {return preg_match($options[0] ?? $options['regex'] ?? null, $value) === 1;}, '{:title}がパターンに一致しません。'],

			//クレジットカード
			'luhn'			=> [function ($value, $options, $meta = []) {for ($i = 0, $digits = strrev($digits), $alt = true, $total = 0; ($str = substr($digits, $i, 1)) !== false;$total += $alt ? $str : ($str < 5 ? $str * 2 : 1 + ($str - 5) * 2), $alt = !$alt, $i++); return $total % 10 === 0;}, '{:title}のチェックディジットが正しくありません。'],
			'credit_card'	=> [function ($value, $options, $meta = []) {return static::CreditCard($value, $options, $meta);}, '{:title}のクレジットカード番号が正しくありません。'],

			//パディング
			'padding'		=> [function ($value, $options, $meta = []) {return $value === str_pad($value, $options['length'], $options['char'], $options['vector']);}, '{:title}の値が正しくありません。'],
			'zero_padding'	=> [function ($value, $options, $meta = []) {return $value === str_pad($value, $options['length'], '0', \STR_PAD_LEFT);}, '{:title}の値が正しくありません。'],

			//HTML
			'html'				=> [function ($value, $options, $meta = []) {return static::Html($value, $options[0] ?? $options['value'] ?? null, $options);}, '{:title}に利用できない{:validator_message}が含まれています。'],
			'html_element'		=> [function ($value, $options, $meta = []) {return static::HtmlElement($value, $options[0] ?? $options['value'] ?? null, $options);}, '{:title}に利用できないHTML要素 {:validator_message}が含まれています。'],
			'html_tag'			=> [function ($value, $options, $meta = []) {return static::HtmlElement($value, $options[0] ?? $options['value'] ?? null, $options);}, '{:title}に利用できないHTMLタグ {:validator_message}が含まれています。'],
			'html_attribute'	=> [function ($value, $options, $meta = []) {return static::HtmlAttribute($value, $options[0] ?? $options['value'] ?? null, $options);}, '{:title}に利用できないHTML属性 {:validator_message}が含まれています。'],
			'html_attr'			=> [function ($value, $options, $meta = []) {return static::HtmlAttribute($value, $options[0] ?? $options['value'] ?? null, $options);}, '{:title}に利用できないHTML属性 {:validator_message}が含まれています。'],

			//コールバック
			'callback'		=> [function ($value, $options, $meta = []) {return static::Callback($value, $options, $meta);}, ''],
		];
	}
848469
function(){
		/* URLの種類からURLを取得する */
		var domain = (!pzpr.env.node ? document.domain : ''), url = "", pid = this.pid;
		if(!!domain){ domain += location.pathname;}
		else{ domain = "pzv.jp/p.html";}
		switch(this.type){
			case URL_PZPRV3:  url="http://"+domain+"?%PID%/"; break;
			case URL_KANPEN:  url="http://www.kanpen.net/%KID%.html?problem="; break;
			case URL_KANPENP: url="http://www.kanpen.net/%KID%.html?pzpr="; break;
			case URL_HEYAAPP: url="http://www.geocities.co.jp/heyawake/?problem="; break;
		}

		return url.replace("%PID%", pzpr.variety(pid).urlid)
				  .replace("%KID%", pzpr.variety(pid).kanpenid);
	}
553452
function(){
		/* "ものを動かしたように描画する"でなければinputLineと同じ */
		if(this.puzzle.execConfig('dispmove')){
			this.inputMoveLine();
			return;
		}
		
		var pos, border;
		if(!this.board.borderAsLine){
			pos = this.getpos(0);
			if(this.prevPos.equals(pos)){ return;}
			border = this.prevPos.getnb(pos);
		}
		else{
			pos = this.getpos(0.35);
			if(this.prevPos.equals(pos)){ return;}
			border = this.prevPos.getborderobj(pos);
		}
		
		if(!border.isnull){
			if(this.inputData===null){ this.inputData=(border.isLine()?0:1);}
			if     (this.inputData===1){ border.setLine();}
			else if(this.inputData===0){ border.removeLine();}
			border.draw();
		}
		this.prevPos = pos;
	}
529867
function(){
		var pzl = this, col = pzl.cols, row = pzl.rows, out = [];
		var puzzlenode = (this.type===FILE_PBOX_XML ? this.body.querySelector('puzzle') : null);

		/* サイズを表す文字列 */
		if(pzl.type===FILE_PBOX_XML){
			var sizenode = puzzlenode.querySelector('size');
			if(sizenode){ puzzlenode.removeChild(sizenode);}
			if(pzl.pid==="slither"||pzl.pid==='kakuro'){ row++; col++;}
			puzzlenode.appendChild(this.createXMLNode('size', {row:row, col:col}));
		}
		else if(pzl.type===FILE_PBOX && pzl.pid==="kakuro"){
			out.push(row + 1);
			out.push(col + 1);
		}
		else if(pzl.pid==="sudoku"){
			out.push(col);
		}
		else{
			out.push(row);
			out.push(col);
		}

		/* サイズ以降のデータを設定 */
		if(pzl.type!==FILE_PBOX_XML){
			out.push(pzl.body);
		}

		/* 履歴・メタデータ出力がある形式ならば出力する */
		if((pzl.type===FILE_PZPR) && !!JSON){
			if(!pzl.metadata.empty()){
				var info = {metadata:pzl.metadata.getvaliddata()};
				if(pzl.history){ info.history = pzl.history;}
				out.push("info:" + JSON.stringify(info,null,1));
			}
			else if(pzl.history){
				out.push("history:" + JSON.stringify(pzl.history,null,1));
			}
		}
		else if(pzl.type===FILE_PBOX_XML){
			var propnode = puzzlenode.querySelector('property');
			if(propnode){ puzzlenode.removeChild(propnode);}
			propnode = this.createXMLNode('property');
			var meta = pzl.metadata;
			propnode.appendChild(this.createXMLNode('author',     {value:meta.author}));
			propnode.appendChild(this.createXMLNode('source',     {value:meta.source}));
			propnode.appendChild(this.createXMLNode('difficulty', {value:meta.hard}));
			if(!!meta.comment){
				var commentnode = this.createXMLNode('comment');
				commentnode.appendChild(this.body.createTextNode(meta.comment));
				propnode.appendChild(commentnode);
			}
			puzzlenode.appendChild(propnode);
			
			// 順番を入れ替え
			puzzlenode.appendChild(puzzlenode.querySelector('board'));
			puzzlenode.appendChild(puzzlenode.querySelector('answer'));
		}

		var outputdata;
		if(pzl.type!==FILE_PBOX_XML){
			outputdata = out.join("\n");
		}
		else{
			outputdata = new XMLSerializer().serializeToString(this.body);
			if(!outputdata.match(/^\<\?xml/)){ // jshint ignore:line
				outputdata = '<?xml version="1.0" encoding="UTF-8"?>\n' + outputdata;
			}
		}
		return outputdata;
	}
920779
private function init() {

		$current_dir = realpath('.');

		$output = "";
		$result = array('status' => true,
						'message' => '');

		$server_list = $this->options->preview_server;
		array_push($server_list, json_decode(json_encode(array(
			'name'=>'master',
			'path'=>$this->options->git->repository,
		))));

		set_time_limit(0);

		foreach ( $server_list as $preview_server ) {
			chdir($current_dir);

			try {

				if ( strlen($preview_server->path) ) {

					// デプロイ先のディレクトリが無い場合は作成
					if ( !file_exists( $preview_server->path) ) {
						// 存在しない場合

						// ディレクトリ作成
						if ( !mkdir( $preview_server->path, 0777) ) {
							// ディレクトリが作成できない場合

							// エラー処理
							throw new \Exception('Creation of preview server directory failed.');
						}
					}

					// 「.git」フォルダが存在すれば初期化済みと判定
					if ( !file_exists( $preview_server->path . "/.git") ) {
						// 存在しない場合

						// ディレクトリ移動
						if ( chdir( $preview_server->path ) ) {

							// git セットアップ
							exec('git init', $output);

							// git urlのセット
							$url = $this->options->git->protocol . "://";
							if( strlen(@$this->options->git->username) ){
								// ID/PW が設定されていない場合は、認証情報なしでアクセスする。
								$url .= urlencode($this->options->git->username) . ":" . urlencode($this->options->git->password) . "@";
							}
							$url .= $this->options->git->url;
							exec('git remote add origin ' . escapeshellarg($url), $output);

							// git fetch
							exec( 'git fetch origin', $output);

							// git pull
							exec( 'git pull origin master', $output);

							chdir($current_dir);
						} else {
							// プレビューサーバのディレクトリが存在しない場合

							// エラー処理
							throw new \Exception('Preview server directory not found.');
						}
					}
				}

			} catch (\Exception $e) {
				set_time_limit(30);

				$result['status'] = false;
				$result['message'] = $e->getMessage();

				chdir($current_dir);
				return $result;
			}

		}
		set_time_limit(30);

		$result['status'] = true;

		return $result;
	}
425502
function(){
		if(this.mouseend && this.notInputted() && !!this.clickTateyoko){
			this.clickTateyoko();
			return;
		}

		var cell = this.getcell();
		if(cell.isnull){ return;}

		// 黒マス上なら何もしない
		if     (this.pid!=="amibo" && cell.ques===1){ }
		else if(this.pid==="amibo" && cell.isNum()){ }
		// 初回 or 入力し続けていて別のマスに移動した場合
		else if(this.mouseCell!==cell){
			this.firstPoint.set(this.inputPoint);
		}
		// まだ入力していないセルの場合
		else if(this.firstPoint.bx!==null){
			var val=null,
				dx = this.inputPoint.bx-this.firstPoint.bx,
				dy = this.inputPoint.by-this.firstPoint.by;
			if     (dy<=-0.50 || 0.50<=dy){ val=1;}
			else if(dx<=-0.50 || 0.50<=dx){ val=2;}
			
			if(val!==null){
				var plus = (this.pid==="amibo"||this.pid==="tatamibari");
				
				var shape = 0;
				if(this.puzzle.playmode){ shape = {0:0,11:3,12:1,13:2}[cell.qans];}
				else                    { shape = {'-1':0,1:3,2:1,3:2}[cell.qnum];}
				if((this.inputData===null) ? (shape & val) : this.inputData<=0){
					val = (!plus ? 0 : -val);
				}
				
				// 描画・後処理
				if(!plus)     { shape  = val;}
				else if(val>0){ shape |= val;}
				else          { shape &= ~(-val);}
				
				if(this.puzzle.playmode){ cell.setQans([0,12,13,11][shape]);}
				else                    { cell.setQnum([-1,2,3,1][shape]);}
				cell.draw();
				
				this.inputData = +(val>0);
				this.firstPoint.reset();
				
				if(this.pid==="tatamibari"){ this.mousereset();}
			}
		}

		this.mouseCell = cell;
	}
228319
function makeFiles(list, dest, savedir, callback) {
  let shell = path.join(__dirname, '../sh/copy.sh');

  return exec('chmod +x ' + shell, (err) => {
    if (err !== null) throw ('[Error: makeFiles: chmod:] ' + err);
    let tmp = []; // 保存先のパスを格納する配列
    let fin = countup(list.length);

    list.forEach((file, index) => {
      let source = file; // コピー元
      let target = path.join(savedir, dest, file); // 保存先
      tmp[index] = target;

      // ファイルをコピーする
      let copied = execFile(shell, [source, target, index], (error, stdout, stderr) => {
        if (error !== null) throw ('[Error: makeFiles: copy.sh:] ' + error);
        fin.step(+stdout, (closed, progress) => {
          return (closed && callback) && callback(tmp, path.join(savedir, dest));
        });
      });
    });
  });
}