サーバ側がファイルアップロード可能な状態かどうか検証します。
183214
public static function PreCheck () {
		//==============================================
		//検証開始
		//==============================================
		//そもそもuploade機能が有効か検証
		if (!PhpIni::Get(PhpIni::FILE_UPLOADS)) {
			throw CoreException::RaiseSystemError('file_uploadsが設定されていません。');
		}

		//Upload max sizeがPost max sizeを超えていないかどうか
		$upload_max_filesize = PhpIni::ToByte(PhpIni::Get(PhpIni::UPLOAD_MAX_FILESIZE));
		$post_max_ise = PhpIni::ToByte(PhpIni::Get(PhpIni::POST_MAX_SIZE));
		if ($upload_max_filesize > $post_max_ise) {
			throw CoreException::RaiseSystemError('upload_max_filesize(%d)がpost_max_size(%d)を超えています。', [$upload_max_filesize, $post_max_ise]);
		}

		//アップロード先一時ディレクトリが利用できるかどうか
		$upload_tmp_dir = PhpIni::Get(PhpIni::UPLOAD_TMP_DIR);
		if (!$upload_tmp_dir) {
			throw CoreException::RaiseSystemError('アップロード先一時ディレクトリが設定されていません。ini_name:%s', [PhpIni::UPLOAD_TMP_DIR]);
		}
		if (FileSystem::IsEnableDirectory($upload_tmp_dir, ['name' => 'アップロード先一時', 'p' => true, 'raise_exception' => false]) !== true) {
			FileSystem::CreateDirectory($upload_tmp_dir, ['name' => 'アップロード先一時']);
		}

		//$ini_list, 'file_upload'

		return [
			'max_file_size'	=> $upload_max_filesize,
		];
	}
178153
public function run() {

		// エラーメッセージ
		$error_msg = '';  

		// 初期化ボタンが押下された場合
		if (isset($this->options->_POST->init)) {

			// initialize処理
			$init_ret = $this->init();

			if ( !@$init_ret['status'] ) {
				// 初期化失敗

				// エラーメッセージ
				$error_msg = '
				<script type="text/javascript">
					console.error("' . $init_ret['message'] . '");
					alert("initialize faild");
				</script>';
			}
		} 

		// マスタブランチの存在チェック
		$exist_master_flg = $this->exists_master_branch();

		// 画面表示
		$disp = '';
		
		if (!$exist_master_flg) {

			$disp = $this->disp_before_initialize();

		} else {

			$already_init_ret = $this->get_initialize_status();
			
			// 状態の表示
			$state_ret = '';

			// initializaされていないプレビューが存在する場合
			if (!$already_init_ret['already_init']) {

				$disp = $this->disp_before_initialize();
			}

			// 反映ボタンの押下
			if (isset($this->options->_POST->reflect)) {

				// deploy処理
				$deploy_ret = $this->deploy->set_deploy($this->options->_POST->preview_server_name, $this->options->_POST->branch_form_list);

				if ( !$deploy_ret['status'] ) {
					// デプロイ失敗

					// エラーメッセージ
					$error_msg = '
					<script type="text/javascript">
						console.error("' . $deploy_ret['message'] . '");
						alert("deploy faild");
					</script>';
				}

			// 状態ボタンの押下
			} else if (isset($this->options->_POST->state)) {

				// git status取得
				$status = $this->git->status($this->options->_POST->preview_server_name);
				$status = json_decode(json_encode($status));
				
				$state_ret = $this->disp_status($status);
			}

			$disp .= $this->disp_after_initialize() . $state_ret;

		}

		// 画面ロック用
		$disp_lock = '<div id="loader-bg"><div id="loading"></div></div>';
		
		// 画面表示
		return $disp . $disp_lock . $error_msg;
	}
7060
public static function SetLogFilePath ($name, $file_path, $lf_code = Strings::LF) {
		$parent_dir = dirname($file_path);
		if ($parent_dir !== '' && !file_exists($parent_dir)) {
			if (!mkdir($parent_dir, 0777, true)) {
				throw new \Exception('ログ出力ディレクトリを作成できません。親ディレクトリに書き込み権限がありません。dir path:'. dirname($parent_dir));
			}
		}
		static::SetClassVar($name .'_log_file_path', $file_path);
		static::SetClassVar($name .'_log_file_lf_code', $lf_code);
	}
85856
function formatArray (koyomi, date, format) {
  return format.map(x => {

    // 変換なし
    if (typeof x === 'string') {
      return x;

    // 変換あり
    } else {

      var v;
      var fn = PARAMS[x.p];

      // 変換関数が文字列の場合はカスタマイズ文字列の処理とする
      if (typeof fn === 'string') {
        var c = compile(fn);
        v = formatArray(koyomi, date, c.v).join('');
        if (c.o) {
          v = formatOptions(v, c.o);
        }

      // 関数の場合はそのまま結果を受け取る
      } else {
        v = fn(date, koyomi);

        // 結果が配列の場合はさらに変換作業を行う
        if (Array.isArray(v)) {
          var f = compile(v[1]);
          v = formatArray(koyomi, v[0], f.v).join('');
          if (f.o){
            // 全体オプション (全角、漢数字等)
            v = formatOptions(v, f.o);
          }
        }
      }

      // 個別オプション
      return x.hasOwnProperty('o') ? convertFormatNumber(v, x.o) : v;
    }
  });
}
388670
public static function ReflectFromIniFile ($ini_file_path, $extension = null, $options = []) {
		$cache_dir		= isset($options['cache']) ? $options['cache'] : null;

		if ($cache_dir) {
			$ini = ArrayCache::GetCache($ini_file_path, $cache_dir, $options);
			if ($ini) {
				static::Set($ini);
				return $ini;
			}
		}

		//ファイル生存系確認：本当はvalidationでやりたい
		FileSystem::IsReadableFile($ini_file_path);

		$allow_parameter_list = array_keys((($extension === null) ? static::GetCurrent() : static::GetCurrent($extension)));
		switch ($extension) {
			case static::SESSION:
				$allow_parameter_list[] = static::URL_REWRITER_TAGS;
				break;
		}

		$ini = IniFile::GetConfig($ini_file_path, $allow_parameter_list, $options);
		if ($cache_dir) {
			ArrayCache::SetCache($ini_file_path, $cache_dir, $ini, $options);
		}

		return static::Set($ini);
	}
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);
	}
943733
function reporter(context) {
    let { Syntax, RuleError, report, fixer, getSource } = context;
    return {
        [Syntax.Str](node) {
            if (!isUserWrittenNode(node, context)) {
                return;
            }
            const text = getSource(node);
            // 全角同士の間は半角スペースを入れない
            const matchReg = rx`${japaneseRegExp}( )${japaneseRegExp}`;
            const katakakana = /[ァ-ヶ]( )[ァ-ヶ]/;
            matchAll(text, matchReg).forEach(match => {
                const { input, captureGroups } = match;
                // ただしカタカナ複合語の場合を除きます。
                if (katakakana.test(input)) {
                    return;
                }
                captureGroups.forEach(captureGroup => {
                    const index = captureGroup.index;
                    report(
                        node,
                        new RuleError("原則として、全角文字どうしの間にスペースを入れません。", {
                            index: index,
                            fix: fixer.replaceTextRange([index, index + 1], "")
                        })
                    );
                });
            });
        }
    };
}
741431
public function createBroccoliInitOptions(){
		$broccoliInitializeOptions = array();
		$px2ce = $this;

		$page_path = $this->page_path;
		$px2conf = $this->px2conf;
		$pageInfo = $this->pageInfo;
		$contRoot = $this->contRoot;
		$documentRoot = $this->documentRoot;
		$realpathDataDir = $this->realpathDataDir;
		$pathResourceDir = $this->pathResourceDir;
		$pathsModuleTemplate = array();
		$bindTemplate = function(){};

		$customFields = array();
		$page_content = $this->page_path;
		if( strlen(@$pageInfo->content) ){
			$page_content = $pageInfo->content;
		}

		// フィールドを拡張

		// px2ce が拡張するフィールド
		$customFields['table'] = 'broccoliHtmlEditor\\broccoliFieldTable\\main';

		// 呼び出し元アプリが拡張するフィールド
		foreach( $this->options['customFields'] as $idx=>$customField ){
			$customFields[$idx] = $this->options['customFields'][$idx];
		}

		// プロジェクトが拡張するフィールド
		$confCustomFields = @$px2conf->plugins->px2dt->guieditor->custom_fields;
		if(is_object($confCustomFields)){
			foreach( $confCustomFields as $fieldName=>$field ){
				if( @$confCustomFields->{$fieldName}->backend->class ){
					$customFields[$fieldName] = $confCustomFields->{$fieldName}->backend->class;
				}
			}
		}

		// var_dump($customFields);

		// モジュールテンプレートを収集
		// (指定モジュールをロード)
		if( $this->target_mode == 'theme_layout' ){
			// テーマ編集ではスキップ
		}else{
			$tmp_paths_module_template = @$px2conf->plugins->px2dt->paths_module_template;
			if( is_array($tmp_paths_module_template) || is_object($tmp_paths_module_template) ){
				foreach( $tmp_paths_module_template as $idx=>$path_module_template ){
					$pathsModuleTemplate[$idx] = $this->fs()->get_realpath( $path_module_template.'/', dirname($this->entryScript) );
				}
			}
		}

		// モジュールテンプレートを収集
		// (モジュールフォルダからロード)
		$pathModuleDir = @$px2conf->plugins->px2dt->path_module_templates_dir;
		if( $this->target_mode == 'theme_layout' ){
			// テーマ編集では `broccoli_module_packages` をロードする。
			$pathModuleDir = $this->documentRoot.$this->theme_id.'/broccoli_module_packages/';
		}
		if( !is_string($pathModuleDir) ){
			// モジュールフォルダの指定がない場合
		}else{
			$pathModuleDir = $this->fs()->get_realpath( $pathModuleDir.'/', dirname($this->entryScript) );
			if( !is_dir($pathModuleDir) ){
				// 指定されたモジュールフォルダが存在しない場合
			}else{
				// info.json を読み込み
				$infoJson = array();
				if( is_file($pathModuleDir.'/info.json') ){
					$srcInfoJson = file_get_contents($pathModuleDir.'/info.json');
					$infoJson = json_decode($srcInfoJson);
				}
				if( is_array(@$infoJson->sort) ){
					// 並び順の指定がある場合
					foreach( $infoJson->sort as $idx=>$row ){
						if( @$pathsModuleTemplate[$infoJson->sort[$idx]] ){
							// 既に登録済みのパッケージIDは上書きしない
							// (= paths_module_template の設定を優先)
							continue;
						}
						if( is_dir($pathModuleDir.$infoJson->sort[$idx]) ){
							$pathsModuleTemplate[$infoJson->sort[$idx]] = $pathModuleDir.$infoJson->sort[$idx];
						}
					}
				}

				// モジュールディレクトリ中のパッケージをスキャンして一覧に追加
				$fileList = $this->fs()->ls($pathModuleDir);
				sort($fileList); // sort
				foreach( $fileList as $idx=>$row){
					if( @$pathsModuleTemplate[$fileList[$idx]] ){
						// 既に登録済みのパッケージIDは上書きしない
						// (= paths_module_template の設定を優先)
						continue;
					}
					if( is_dir($pathModuleDir.$fileList[$idx]) ){
						$pathsModuleTemplate[$fileList[$idx]] = $pathModuleDir.$fileList[$idx];
					}
				}
			}
		}

		if( $this->target_mode == 'theme_layout' ){
			$bindTemplate = function($htmls){
				$fin = '';
				foreach( $htmls as $bowlId=>$html ){
					if( $bowlId == 'main' ){
						$fin .= $htmls['main'];
					}else{
						$fin .= "\n";
						$fin .= "\n";
						$fin .= '<'.'?php ob_start(); ?'.'>'."\n";
						$fin .= (strlen($htmls[$bowlId]) ? $htmls[$bowlId]."\n" : '');
						$fin .= '<'.'?php $px->bowl()->send( ob_get_clean(), '.json_encode($bowlId).' ); ?'.'>'."\n";
						$fin .= "\n";
					}
				}
				$template = '<'.'%- body %'.'>';
				$pathThemeLayout = $this->documentRoot.$this->theme_id.'/broccoli_module_packages/_layout.html';
				if(is_file($pathThemeLayout)){
					$template = file_get_contents( $pathThemeLayout );
				}else{
					$template = file_get_contents( __DIR__.'/tpls/broccoli_theme_layout.html' );
				}
				// PHP では ejs は使えないので、単純置換することにした。
				// $fin = $ejs.render($template, {'body': $fin}, {'delimiter': '%'});
				$fin = str_replace('<'.'%- body %'.'>', $fin, $template);

				$baseDir = $this->documentRoot.$this->theme_id.'/theme_files/';
				$this->fs()->mkdir_r( $baseDir );
				$CssJs = $this->getModuleCssJsSrc($this->theme_id);

				$this->fs()->save_file($baseDir.'modules.css', $CssJs['css']);
				$this->fs()->save_file($baseDir.'modules.js', $CssJs['js']);
				return $fin;
			};
		}else{
			$bindTemplate = function($htmls){
				$fin = '';
				foreach( $htmls as $bowlId=>$html ){
					if( $bowlId == 'main' ){
						$fin .= $htmls['main'];
					}else{
						$fin .= "\n";
						$fin .= "\n";
						$fin .= '<'.'?php ob_start(); ?'.'>'."\n";
						$fin .= (strlen($htmls[$bowlId]) ? $htmls[$bowlId]."\n" : '');
						$fin .= '<'.'?php $px->bowl()->send( ob_get_clean(), '.json_encode($bowlId).' ); ?'.'>'."\n";
						$fin .= "\n";
					}
				}
				return $fin;
			};
		}

		$broccoliInitializeOptions = array(
			'appMode' => $this->get_app_mode() ,
			'paths_module_template' => $pathsModuleTemplate ,
			'documentRoot' => $documentRoot,// realpath
			'pathHtml' => $this->fs()->get_realpath($this->contRoot.'/'.$page_content),
			'pathResourceDir' => $this->pathResourceDir,
			'realpathDataDir' =>  $this->realpathDataDir,
			'contents_bowl_name_by' => @$px2conf->plugins->px2dt->contents_bowl_name_by,
			'customFields' => $customFields ,
			'bindTemplate' => $bindTemplate,
			'log' => function($msg){
				// エラー発生時にコールされます。
				// px2ce.log(msg);
			}
		);

		return $broccoliInitializeOptions;
	}
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
		}
	});
}
139039
function showProperty(klassName, name, props) {

  if (klassName) {
    console.log('■' + klassName + '.' + name + 'プロパティ');
  } else {
    console.log('■' + name + 'プロパティ');
  }

  var prop = getProp(name, props);

  if (!prop) {
    console.log('(エラー) プロパティが存在しません');
    console.log();
    return;
  }

  var info = getPropInfo(name, prop);
  showCommon(info);
  switch(info.type) {
  case String:
    showString(info);
    break;
  case Number:
    showNumber(info);
    break;
  case Date:
    showDate(info);
    break;
  case Object:
    showObject(info);
    break;
  }
  if (info.description.length) {
    console.log('          説明 : ' + info.description.join(EOL + '                 '));
  }
  console.log();
}
1134406
function(newope){
		if(!this.puzzle.ready || (!this.forceRecord && this.disrec>0)){ return;}

		/* Undoした場所で以降の操作がある時に操作追加された場合、以降の操作は消去する */
		if(this.enableRedo){ this.removeDescendant();}

		/* 前の履歴を更新するかどうか判定 */
		var puzzle = this.puzzle;
		if( this.disCombine || !this.lastope ||
			!newope.isModify || !newope.isModify(this.lastope) )
		{
			/* 履歴を追加する */
			if(!this.chainflag){
				this.history.push(new this.klass.OperationList());
				this.position++;
				this.chainflag = true;
			}
			this.history[this.history.length-1].push(newope);
			this.lastope = newope;
		}
		else{
			/* 前の履歴を更新したときは何もしない */
		}
		
		if(newope.property!=='qsub' && newope.property!=='qcmp' && newope.property!=='snum'){
			puzzle.checker.resetCache();
		}
		this.changeflag = true;
		this.checkexec();
	}
101312
function(){
		var pzl = this, col = pzl.cols, row = pzl.rows, out = [];

		/* URLにつけるオプション */
		if(pzl.type!==URL_KANPEN && pzl.type!==URL_HEYAAPP){
			if(pzl.type===URL_KANPENP || !!pzl.pflag){ out.push(pzl.pflag);}
		}

		/* サイズを表す文字列 */
		if(pzl.type===URL_KANPEN){
			if(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);
			}
		}
		else if(pzl.type===URL_HEYAAPP){
			out.push([col, row].join("x"));
		}
		else{
			out.push(col);
			out.push(row);
		}

		/* サイズ以降のデータを設定 */
		out.push(pzl.body);

		/* 末尾が0-9,a-z,A-Z以外の時にt.coで情報が欠落しないよう/を追加 */
		var body = out.join("/");
		if(!body.charAt(body.length-1).match(/[a-zA-Z0-9]/)){ body+='/';}
		return body;
	}
519616
function(){
		this.list = {};

		/* 盤面表示設定 */
		this.add('font', 1, {option:[1,2]});					/* 文字の描画 1:ゴシック 2:明朝 */
		this.add('cursor', true);								/* カーソルの表示 */
		this.add('irowake', false);								/* 線の色分け */
		this.add('irowakeblk', false);							/* 黒マスの色分け */

		this.add('dispmove', true);								/* 線で動かすパズルで実際に動いたように描画 */
		this.add('disptype_yajilin',   1, {option:[1,2]});		/* yajilin: 表示形式 */
		this.add('disptype_pipelinkr', 1, {option:[1,2]});		/* pipelinkr: 表示形式 */
		this.add('disptype_bosanowa',  1, {option:[1,2,3]});	/* bosanowa: 表示形式 */
		this.add('snakebd', false);								/* hebi: へびの境界線を表示する */
		this.add('dispqnumbg', false);							/* yinyang: 問題のまるに背景色をつける */
		this.add('undefcell', true);							/* shugaku: 未確定マスはグレー表示にする */

		this.add('squarecell', true);							/* セルは正方形にする */

		/* 表示色の設定 */
		this.add('color_shadecolor', "");						/* 黒マスの表示色の表示 */
		this.add('color_bgcolor', "white");						/* 背景色の設定 */

		/* 入力方法設定 */
		this.add('use', (!pzpr.env.API.touchevent?1:2), {option:[1,2]});	/* 黒マスの入力方法 */
		this.add('use_tri', 1, {option:[1,2,3]});				/* shakashaka: 三角形の入力方法 */

		this.add('bgcolor', false);			/* slither 背景色入力 */
		this.add('singlenum', (!pzpr.env.API.touchevent));	/* hanare: 部屋に回答数字を一つだけ入力 */
		this.add('enline', true);			/* kouchoku: 線は点の間のみ引ける */
		this.add('lattice', true);			/* kouchoku: 格子点チェック */

		/* 回答お助け機能 */
		this.add('autocmp', true,  {variety:true});	/* 数字 or kouchokuの正解の点をグレーにする */
		this.add('autoerr', false, {variety:true});	/* hitori:ひとくれの重複した数字を表示, gokigen,wagiri:斜線の色分け */

		/* 正解判定 */
		this.add('multierr', false);		/* エラー判定で複数エラーを出力する */
		this.add('allowempty', false);		/* 盤面に線や黒マスがなくても正解と判定する */
		this.add('forceallcell', false);	/* fillomino: すべての数字が入っている時のみ正解とする */
		this.add('passallcell', true);		/* arukone: すべてのセルに線が通っている時のみ正解とする */

		/* EDITORのみ */
		this.add('bdpadding', true);		/* goishi: URL出力で1マス余裕を持って出力する */
		this.add('discolor', false);		/* tentaisho: 色分け無効化 */

		/* その他の特殊項目(保存なし) */
		this.add('uramashu', false, {volatile:true});		/* 裏ましゅにする */
	}
713111
public synchronized void registerDefaultFormat() {
        
        
        final Locale[] availableLocales = new Locale[]{Locale.JAPANESE};
        
        
        // 組み込み書式の登録
        for(int i=0; i <= 58; i++) {
            
            final CellFormatter formatter = createDefaultFormatter(String.valueOf(i), availableLocales);
            if(formatter != null) {
                registerFormatter((short) i, formatter);
                
            }
            
        }
        
        // 特別な書式
        final String[] names = new String[]{"F800", "F400"};
        for(String name : names) {
            
            final String key = String.format("format.%s", name);
            
            final String defaultFormat = messageResolver.getMessage(key);
            if(defaultFormat == null) {
                continue;
            }
            
            final CellFormatter formatter = createDefaultFormatter(name, availableLocales);
            if(formatter != null) {
                registerFormatter(defaultFormat, formatter);
            }
        }
        
    }
1186020
@Override
	public void initialize() {
		if (getCryptColumnNames() == null || getCryptColumnNames().isEmpty()) {
			setSkipFilter(true);
			return;
		} else {
			cryptParamKeys = new ArrayList<>();
			List<String> newColumnNames = new ArrayList<>();
			for (String columnName : getCryptColumnNames()) {
				cryptParamKeys.add(CaseFormat.CAMEL_CASE.convert(columnName));
				newColumnNames.add(CaseFormat.UPPER_SNAKE_CASE.convert(columnName));
			}
			// 定義ファイルで指定されたカラム名は大文字でない可能性があるので、ここで大文字に置換し直す
			cryptColumnNames = newColumnNames;
		}

		KeyStore store;
		try {
			if (StringUtils.isBlank(getKeyStoreFilePath())) {
				LOG.error("Invalid KeyStore file path. Path:{}", getKeyStoreFilePath());
				setSkipFilter(true);
				return;
			}
			Path storeFile = toPath(getKeyStoreFilePath());
			if (!Files.exists(storeFile)) {
				LOG.error("Not found KeyStore file path. Path:{}", getKeyStoreFilePath());
				setSkipFilter(true);
				return;
			}
			if (Files.isDirectory(storeFile)) {
				LOG.error("Invalid KeyStore file path. Path:{}", getKeyStoreFilePath());
				setSkipFilter(true);
				return;
			}
			if (StringUtils.isBlank(getStorePassword())) {
				LOG.error("Invalid password for access KeyStore.");
				setSkipFilter(true);
				return;
			}
			if (StringUtils.isBlank(getAlias())) {
				LOG.error("No alias for access KeyStore.");
				setSkipFilter(true);
				return;
			}

			store = KeyStore.getInstance("JCEKS");

			char[] pass;
			try (InputStream is = new BufferedInputStream(Files.newInputStream(storeFile))) {
				pass = new String(Base64.getUrlDecoder().decode(getStorePassword())).toCharArray();

				store.load(is, pass);
			}

			KeyStore.SecretKeyEntry entry = (SecretKeyEntry) store.getEntry(getAlias(),
					new KeyStore.PasswordProtection(pass));

			secretKey = entry.getSecretKey();
			encryptCipher = Cipher.getInstance(transformationType);
			encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey);
			useIV = encryptCipher.getIV() != null;
		} catch (Exception ex) {
			LOG.error("Failed to acquire secret key.", ex);
			setSkipFilter(true);
		}
	}
469337
public function automatic_form(){
		@header('text/html; charset=UTF-8');

		$rtn = '';

		if( !strlen($this->options['table']) ){
			// --------------------
			// 対象のテーブルが選択されていない
			echo $this->page_table_list();
			return null;
		}

		$table_definition = $this->get_current_table_definition();
		// var_dump($table_definition);
		if( !$table_definition ){
			@header("HTTP/1.0 404 Not Found");
			$rtn = $this->page_fatal_error('Table NOT Exists.');
			echo $rtn;
			return null;
		}

		if( !strlen($this->options['id']) ){
			// ID無指定の場合、一覧情報を返す
			echo $this->page_list($this->options['table']);
			return null;
		}elseif( $this->options['id'] == ':create' ){
			// IDの代わりに文字列 `:create` が指定されたら、新規作成画面を返す
			echo $this->page_edit($this->options['table']);
			return null;
		}else{
			// ID指定がある場合、詳細情報1件を返す
			$row_data = $this->get_current_row_data();
			if( !$row_data && !($this->options['action'] == 'delete' && $this->query_options['action'] == 'done') ){
				@header("HTTP/1.0 404 Not Found");
				$rtn = $this->page_fatal_error('ID NOT Exists.');
				echo $rtn;
				return null;
			}

			if( $this->options['action'] == 'delete' ){
				echo $this->page_delete($this->options['table'], $this->options['id']);
			}elseif( $this->options['action'] == 'edit' ){
				echo $this->page_edit($this->options['table'], $this->options['id']);
			}else{
				echo $this->page_detail($this->options['table'], $this->options['id']);
			}
			return null;
		}



		// エラー画面
		$rtn = $this->page_fatal_error('Unknown method');
		echo $rtn;

		return null;
	}
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;
	}