XREAで動かしていたPython製CGIを復活させただけ

昔立てたPythonCGIが知らん間にInternal Server Errorになって動かなくなっていたので、色々やって復活させた。

Internal Server Error

1年くらい前にXREAマイグレーションがあったらしく、これに巻き込まれたか…。
www.xrea.com



本当は「Internal Server Error」が出力される際のエラーそのもののエラーログが見たいのだが、それは見れないみたい。
考えられる原因を順番につぶしていくしかない。

中身をいじるのがN年ぶりくらいなので色々うろ覚えのところからスタートだが、概ね以下のような順番でアタックして無事解消。

.htaccessの書き方おかしい説

おかしいということは無かったが、後続の手順でテスト用に仕込んだスクリプトが動かなかったりしたのは.htaccessの設定のせいだった。

知らん間にpythonのパスが変わっていた説

www.xrea.com
よく見ると、以前使っていた「/usr/local/bin/python3」ではなくなっており、現在は「/usr/bin/python3.6」
cgiの行頭のshebangを「#!/usr/bin/python3.6」のように修正する必要がありそう。
しかし、あとの検証で前のパスでも特に問題なく動くことが分かったので、根本原因ではなかった。

知らん間にパーミッションがおかしくなっている説

実行属性が設定されていない場合はInternal Server Errorになる。残念ながら、今回の場合は根本原因ではなかった。

とりあえずpythonが動くかを試す

「Content-type: text/html\n\n」を出力しておかないとInternal Server Errorになる。以下のQ9でもあるとおり、ありがちなミスらしい。
www.xrea.com
逆に、以下が動かないなら他が怪しい。

#!/usr/local/bin/python3
print("Content-type: text/html\n\n")

今回はこれで動いたので、とりあえずpython製のcgiを動かすという関門は突破できている。

エラーが発生するcgiのコードを少しずつ移植してエラー発生個所を特定する

今回の場合はcgi本体に記載されたimport文でエラーが発生していることがわかった。
import文をtry-exceptで囲んでも普通に機能することを今更ながら知った。

print("Content-type: text/html\n\n")
try:
    import [module名]
except Exception as e:
    print(e)
No module named 'mysql'

仮想環境にライブラリをインストールする

マイグレーション前はあったモジュールがマイグレーションによって失われたものと思われる。
そのためライブラリを自分でインストールして解決しようとしたが…

まず以下の手順でssh接続を行う。
help.xrea.com

$ python -m pip install --user mysql-connector-python
Exception:
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/pip/basecommand.py", line 215, in main
    status = self.run(options, args)
  File "/usr/lib/python3.6/site-packages/pip/commands/install.py", line 294, in run
    with self._build_session(options) as session:
  File "/usr/lib/python3.6/site-packages/pip/basecommand.py", line 72, in _build_session
    insecure_hosts=options.trusted_hosts,
  File "/usr/lib/python3.6/site-packages/pip/download.py", line 330, in __init__
    self.headers["User-Agent"] = user_agent()
  File "/usr/lib/python3.6/site-packages/pip/download.py", line 94, in user_agent
    from pip._vendor import distro
  File "/usr/lib/python3.6/site-packages/pip/_vendor/distro.py", line 1050, in <module>
    _distro = LinuxDistribution()
  File "/usr/lib/python3.6/site-packages/pip/_vendor/distro.py", line 595, in __init__
    self._distro_release_info = self._get_distro_release_info()
  File "/usr/lib/python3.6/site-packages/pip/_vendor/distro.py", line 984, in _get_distro_release_info
    basenames = os.listdir(_UNIXCONFDIR)
PermissionError: [Errno 13] Permission denied: '/etc'


このように、残念ながらXREAではpipコマンドでのライブラリインストールはできないらしい。
--user オプションを付与してもダメだった。

仕方ないので、仮想環境を構築してそちらにライブラリをインストールする。
手順は以下に述べられているとおり。
nakagawach.tokyo
zenn.dev


以下、「bottle」は今回付けた仮想環境の名前で、実際はどんな名前でもよい。

$ cd ~
$ python3 -m venv --without-pip bottle
$ source ./bottle/bin/activate

pipを使えるようにした後で、欲しいライブラリをインストールする。
以下を実行する前に、get-pip.pyを適当に引っ張ってきてftpで置いておく。
https://bootstrap.pypa.io/pip/3.6/get-pip.py

(bottle) $ python get-pip.py
(bottle) $ pip install mysql-connector-python==8.0.25
(bottle) $ deactivate

なお、上記でライブラリのバージョンを指定したのはpythonのバージョンが若干古く、
現時点で最新バージョンのライブラリをそのままインストールすると実行できなかったため。

これで確かに「No module named 'mysql'」が解消されることを確認する。
shebangを以下のようにすれば、ここで構築した仮想環境で実行することができる。

#!/virtual/[username]/bottle/bin/python3

これで無事解決。

Splatoon3 ヒーローモード BGM メモ

Youtubeの動画は筆者がアップロードしたものではありません

 

・「混沌」をテーマとした今作では、音楽でもさまざまな角度で「混沌」が表現されている。
・ヒーローモードのBGMでは生音と電子音の融合、新旧の音使いの融合や対比が随所で見られる。
・通常のバトルBGMとの対比から、基本はテクノサウンド中心ではあるものの、従来のヒーローモードと比較して生音もかなり取り入れられており、曲のジャンルがかなり多様化している。
・すり身連合のかかわるBGMは上記にとどまらず、キャラの出自にあわせた民族的な音楽を多く取り入れている。古今東西をそのままの形で一緒にしたような、まさにカオスな音楽になっている。

 

www.youtube.com

・1,2のヒーローモードを強く意識した、愉快なテクノ。
・プロローグのクレーターのステージでのみ使用される。
・冒頭のタコのモチーフや規則的に刻まれるリズムムパート、8分音符を基本とする統制のとれたメロディーラインはOCTOTOOLの作風が強く現れている。特に、"Eight Legged Advance"との共通点が多い。
オルタナのBGMを効果的に魅せるため、あえて従来路線を強く表現した曲。
・しかし、中盤の声ネタを刻んだかのようなメロディラインや終盤のディレイラマなどはタコっぽいひょうきんな雰囲気を継承しつつも従来にない表現で新機軸を思わせる。

 

www.youtube.com

・ハイテンポで近未来感のあるテクノ。
・主にヒーロー系ステージ、中でもアスレチックタイプのステージで使用される。
・テンションコードが多く用いられ、テンポも速いことから疾走感がある。
・電子音を基本とした曲調、OCTOTOOLらしいベースライン、サウンドエフェクトが多く鳴らされることから前作までのBGM、特に"Tentacular circus"を意識したものと思われる。
・しかし、変拍子であることや付点リズムを積極的に用いるなど、あまり規則的でないところがある。リズム隊は通常のテクノミュージックよりもドラムンベースに近い。ヒーローモードだけど、何か違う。そんなオルタナの雰囲気をうまく表現した曲といえる。

 

www.youtube.com

・ファンキーなドラムとベースがリードする、ちょっと古めかしいテクノ。
・主にヒーロー系ステージで使用される。
・ビヨビヨしたシンセベースにゲートリバーブの効いたスネアドラムなどは一昔前の音使いを思わせる。
エレキギターやオーケストラヒットなど、電子音的でないところにも独特のクールさがある。
・最初の穏やかなシンセリードから終盤のサイバーなボイスまで、曲想はなかなかに豊かだが、リズムパートが基本的に一定であることとGF♯Eのモチーフが繰り返し用いられることから全体の統一感がある。

 

www.youtube.com

・シャッフルされたリズムで刻む重厚なテクノ。
・主にヒーロー系ステージ、中でもじっくり進むタイプのステージで使用される。
・2種の音が重ねられた重厚なワブルベースにガツガツしたリズム隊。そこだけ聞けば、一見ダブステップ的なハードな曲調に思える。
・しかし、3連符のリズムとビブラートの効いた軽快なリード音。ワブルベースのヤイヤイとした愉快な響きを強調させ、メロディーラインを歌わせる後半部。そして少し間の抜けたメロディ。ハードさは微塵も感じさせず、オルタナの雰囲気に違和感なく溶け込んでいる。

 

www.youtube.com

・ファンキーで落ち着いたローテンポな曲。
・じっくり課題を解くようなステージで用いられる。
・音数が少なく、数十年前のダンスミュージックのような音使い。
・しかし声ネタ的なものは一切使われず、木琴のようなプラック音もあいまって終始落ち着いた雰囲気が漂う。

 

www.youtube.com

4つ打ちの疾走感のある曲。
・主にライドレール的当て系のステージで使用される。
・クラブミュージック的な音使いが随所に見られる。ローパスフィルターが徐々にあけられていくイントロに加え、サイドチェインされたパッド音などは確かにそれらしい感じ。
・軽快なクラビネットが一緒にサイドチェインされながら重なり、合いの手では小気味良いボンゴやブラスパートが挟まってくる。ニョロニョロしたボーカルパートがファンキーさを際立たせる。
・ドリアン旋法のもとでの9thコードなど、テンションコードを駆使した瞑想的なコード進行も特徴的。

 

www.youtube.com

・「ベイベイ」という男性のスキャット音のような声ネタが印象に残る、ローテンポな4つ打ちの曲。
・主に要塞の中をじっくり進むようなステージで使用される。
・後半部はコード進行こそ静的だが、ボコーダーのようなボーカルパートが表情豊かに歌い、飽きさせない。
・前半部の図太いリード音や後半部のプラック音など、かなり電子音に寄っている。しかし裏で支えるストリングスとスネアドラムは生音系であり、特に後者はフィルインでかなり目立つ。

 

www.youtube.com

・テレビのクイズ番組で使われていそうな曲。
・耐久、制限系のステージで使用される。
・絶え間なくなるシンセ音に生音系のリズムパートがリムショットで刻々と時を刻む中、全音階をなぞるベースパートが怪しげな雰囲気を醸成している。

 

www.youtube.com

・重厚さとクールさを兼ね備えた、不思議な4つ打ちの曲。
・使われるステージに法則性はあまりないが、オクト系の特殊なステージが多い。
・前半は重厚なワブルベースに、何かを逆再生したような甲高いパッド音が重なる。アコーディオンのような妙な音色のメロディラインが怪しげに光り、ダークで冷たい雰囲気。
・後半は低音の効いたベースギターと麗しい高音のストリングスが参戦し、ジャジーなメロディーラインでクールに曲を盛り上げる。
・全体を通して他の何にも類似しない独特の空気感があり、作曲者の特別なセンスが感じられる逸品。

 

www.youtube.com

・ヒーローモードのBGMという枠組みの中で最大限カオスを発揮した曲。
・使われるステージに法則性はあまりないが、オクト系の特殊なステージが多い。
・生音の打楽器をサンプリングした忙しないリズムパートを背景にパートがどんどん増えていき、ボルテージが徐々に上がっていく。これらは全音階を基本としながらもお互い全く干渉せずに自由に暴れ、かなり現代音楽的な様相を呈する。
・しかし終盤は一転して軽快で可憐なピアノ?パートが場を独占。それも、音質を敢えて下げることで古めかしい雰囲気をまとわせている。これで曲をしっかり纏め上げあげつつ徐々にテンションを下げながら曲がループする。
・今作のテーマである「混沌」をこの上なく表現しつつ、なぜか纏まりのある怪作。

 

www.youtube.com

・オーケストラ楽器で奏でる、ハイテンポ・ハイテンションな曲。
・無敵感のある曲想にマッチして、スペシャルを駆使するステージで使用される。
・軽快なドラムパートにタンバリンやコンガ、合いの手のハンドクラップが乗っかり、 終始ハイテンションなまま曲が展開する。
・裏拍で盛り上げる掛け声やオペラのような男声パートが愉快な雰囲気をかもし出しつつ徐々に曲を盛り上げ、オーケストラパートが聖者の行進に良く似たモチーフを奏でて最高潮に達する。
・ヒーローモードによくあるオーケストラをサンプリングした音を基調としているものの、トランペット、ティンパニ、鉄琴などはサンプリング感がなく、ヒーローモードでは珍しくかなり生音に寄った曲。
 

(HSP)local変数のポインタを渡してはいけない(戒め)

タイトルですべてが終わっている話だが、自分のスクリプトで原因不明の謎な挙動が発生した経験から戒めとして残しておく。

HSP(Hot Soup Processor)という言語は基本的にすべての変数がグローバル変数になるという特徴があり、大規模なプログラムを作るときにはさまざまな工夫が必要になる。

そういった中で唯一ローカル変数として扱えるものが、モジュール機能のlocal宣言変数と呼ばれるもの。命令実行と同時に作成され、命令終了とともに破棄される。実行単位で新たに作成されることから、再起的に呼び出す場合などに多用される。(普通の変数だと再帰的に呼び出しても同じ変数を参照してしまう)
www.onionsoft.net


 
今般あるプログラムを開発中に、命令の終了とともに破棄されるこのlocal変数のポインタをWIN32 APIに突っ込んだ結果、さまざまな怪現象を引き起こしてしまった。原理がわかっていればさもありなんという感じだが、開発中は勿論特段エラーメッセージなどは表示されなかったため、原因究明に手間取ってしまった。

せっかくなので、そんな怪現象を引き起こしてしまったスクリプトを共有してみる(実行してへんなことが起こっても責任は取りませんのであしからず)。

このスクリプト自体は、ある周波数のサイン波の音をWIN32 APIを直接叩いて鳴らし続けるだけ。
そのうち Enter や Space キーを押下すると、怪現象のトリガーとなりうる命令が実行される。
冒頭の bugmode という変数で、「まともな」?コードと「バグった」コードを切り替えられるようにしており、0だと何も起きないはずだが、1だといろんな怪現象が起きる、はず。

#include "winmm.as"

bugmode = 0 //1だとバグったコードが実行される
goto *main

#deffunc testfnc str _txt
	return

#deffunc waveOut var _wave, int _nBufferLength, int _nUser, local whdrl, local lpData, local dwBufferLength, local dwUser
	// WAVEHDR 構造体
	lpData          = varptr(_wave)
	dwBufferLength  = _nBufferLength
	dwBytesRecorded = 0
	dwUser          = _nUser
	dwFlags         = 12 // WHDR_BEGINLOOP | WHDR_ENDLOOP
	dwLoops         = 1  // ループ回数
	lpNext          = 0
	reserved        = 0

	if bugmode = 1{
		whdrl = lpData, dwBufferLength, dwBytesRecorded, dwUser, dwFlags, dwLoops, lpNext, reserved
		// 再生
		waveOutPrepareHeader hWaveOut, varptr(whdrl), 32 // sizeof(WAVEHDR)
		waveOutWrite hWaveOut, varptr(whdrl), 32 // sizeof(WAVEHDR)
	}else{
		whdrl_global(0, _nUser) = lpData, dwBufferLength, dwBytesRecorded, dwUser, dwFlags, dwLoops, lpNext, reserved
		// 再生
		waveOutPrepareHeader hWaveOut, varptr(whdrl_global(0, _nUser)), 32 // sizeof(WAVEHDR)
		waveOutWrite hWaveOut, varptr(whdrl_global(0, _nUser)), 32 // sizeof(WAVEHDR)
	}
	return

*main
	oncmd gosub *womessage,$3BD //MM_WOM_DONE
	dim whdrl_global,8,2

	f = 300.0 //周波数
	srate = 44100
	buffersize = 20000
	blocksize = 4

	
	// WAVEFORMATEX 構造体
	wBytesPerSample = 2      // 量子化バイト数
	
	wFormatTag      = 0x0001 // WAVE_FORMAT_PCM
	nChannels       = 2      // ステレオ
	nSamplesPerSec  = srate  // サンプルレート
	wBitsPerSample  = wBytesPerSample * 8
	nBlockAlign     = nChannels * wBytesPerSample
	nAvgBytesPerSec = nSamplesPerSec * nBlockAlign
	cbSize          = 0
	
	wfex = wFormatTag | (nChannels << 16), nSamplesPerSec, nAvgBytesPerSec, nBlockAlign | (wBitsPerSample << 16), cbSize

	hWaveOut = 0
	waveOutOpen varptr(hWaveOut), -1, varptr(wfex), hwnd, 0, 0x00010000 // WAVE_MAPPER, CALLBACK_WINDOW

	sdim wave, buffersize*blocksize, 2

	buffernum = 0
	bufreadyflg = 0,0 //1だとバッファ格納済み

	
	repeat
		//波形の作成
		repeat buffersize
			wpoke wave(buffernum), cnt * 4    , int(sin(2.0 * M_PI * f * yyyyy / srate) * 0x7FFF ) & 0xFFFF
			wpoke wave(buffernum), cnt * 4 + 2, int(sin(2.0 * M_PI * f * yyyyy / srate) * 0x7FFF ) & 0xFFFF
			yyyyy++
		loop

		//波形の再生が終わるまで待つ
		buffernum = -1
		repeat
			foreach bufreadyflg
				if bufreadyflg(cnt) = 0 : buffernum = cnt: break
			loop
			if buffernum >= 0 : break
			await 0
		loop
		bufreadyflg(buffernum) = 1

		//波形を流す
		waveOut wave(buffernum), buffersize*blocksize, buffernum
	
		buffernum = (buffernum+1)\2
	
		stick sticks
		if sticks & 16{//space
			title "ユーザー定義命令に長い文字列を流す"
			testfnc "tttttttttttttttttttttttttttt"
		}
		if sticks & 32{//enter
			title "splitで文字列を複数個に分割する"
			tmp="a/a"
			split tmp, "/", tmp2
		}
	loop

*womessage
	dupptr whdr,lParam,8*4
	if whdr(3) >= 0{
		if length(bufreadyflg@) <= whdr(3) {
			title "eee"
			bufreadyflg@(0) = 0
			bufreadyflg@(1) = 0
		}else{
			title ""+whdr(3)
			bufreadyflg@(whdr(3)) = 0
		}
	}
	return 0

(参考)
www13.plala.or.jp
archive.kerupani129.net


以下でこのスクリプトの解説を少ししておく。

音の再生のためには、波形データをメモリ上に展開しておく必要がある。ここでWIN32 APIが提供している機能は、メモリ上に展開した波形を登録・再生する機能(waveOutWrite)と、再生が終わったことをウィンドウメッセージ(MM_WOM_DONE)で知らせる機能である。

動的に波形を生成する場合には、波形を生成→WIN32 APIに登録→波形を生成… という処理を繰り返す必要がある。前の波形の再生が終わってすぐに波形を生成・登録したとしてもわずかな時間のギャップが生まれてしまう。つまり音が途切れ途切れになってしまうので、前の波形の再生が終わる前に新しい波形を生成・登録しておく必要がある。
ここで再生中の波形データを上書きして登録するというのはいまいちなため、メモリ上の別の場所に展開してこちらを登録しておく。そして前の波形データの再生が終わったら、次はそちらの場所を再利用する。
このように、2箇所のメモリバッファを交互に使って再生することを、ダブルバッファリングという。

上記スクリプト中では、WAVEHDR 構造体(whdrl)に波形データを指すポインタなどを登録して再生、再生が終わったらサブルーチン「*womessage」でMM_WOM_DONEを受け取る、という処理を2個のバッファに対して交互に繰り返し実行することで波形データを再生している。

このうち今回のスクリプト怪現象を発生させている変数が、ユーザー定義命令waveOut中にあるlocal宣言変数whdrlである。
bugmode = 1とした場合、こいつをwaveOutWriteに投げたあとでwaveOut命令の実行が終了、変数が破棄されてしまうためにその後の動作が色々不正となってしまう。

自分の環境では以下のような現象が発生した。

  • (Enterキー押下により)split命令を行うと、2つあるバッファのうち1つからMM_WOM_DONEが帰ってこなくなり、ダブルバッファリングが無効化されて音が途切れ途切れになってしまう。
  • (spaceキー押下により)ユーザー定義命令に長い文字列を渡すと、MM_WOM_DONEは帰ってくるものの、最初に渡した WAVEHDR 構造体を指しているはずのlParamが謎のメモリアドレスを指している。さらに以降でも(HSP側の)変数の参照がおかしくなったためか、bufreadyflgへの代入でスクリプトが止まってしまう

どういう原理でこうなっているのかはわからないものの、HSP側の変数の管理に異常を来たしていることは明らかなようである。

ちなみに、バグらないほう(bugmode = 0とした場合)は、whdrlをグローバル変数で(バッファを2個用意している都合上)2個確保するよう対処している。
変数whdrl自体は命令の実行のたびに新しく生成されるほうがうれしいのだが、上記現象の都合上そうすることはできない。

WindowsでAndroidエミュレータが起動しなかったときの対処法メモ

概要

以上、でもいいかもしれないけれども、もう少し詳しく書いておく。

症状

Android Studioからエミュレータを起動しようとすると、なにやら起動しようとしているらしいゲージは出てくるが……

f:id:vidamrot:20190715204208p:plain

これが消えてからは何も出てこず。各種コンソールやIDEのログを見ても特にエラーメッセージは見当たらず。

解決法

コマンドから自前でエミュレータを起動してみる。そもそもエミュレータがどこにあるかは、Project StructureからSDKのパスを調べればすぐにわかる。

f:id:vidamrot:20190715204350p:plain

f:id:vidamrot:20190715204424p:plain

エミュレータsdkフォルダ内のemulatorフォルダ内にあるので、これで実際に起動してみる。

f:id:vidamrot:20190715204437p:plain

なんだ、ちゃんとエラーメッセージが出るじゃないか。どうやらHAX(エミュレータ高速化のためのハードウェア支援)の起動に失敗しているらしい。SDKマネージャからIntel x86 Emulation Acceleratorを更新したら起動するようになった。めでたしめでたし。

iksm_sessionをadbを介して取得するだけのpythonスクリプト

概要

以下のWebサイトに記載されている手順をある程度自動化したもの。
tryfreesoft.at.webry.info

このスクリプトがやること

  • adb(Android Debug Bridge)でroot権限でandroid端末に接続する
  • 接続に失敗したら、Nox.exe(NoxPlayer; Androidエミュレーターの一種)を自前で起動してみる
  • 接続に成功したら、Android端末中のNintendo Switch OnlineのWebViewが保持しているクッキーをadbで取り出す
  • 取り出したクッキーの有効期限を確認し、期限切れの場合は再ログインを促す
  • 申し訳程度のGUI付き

f:id:vidamrot:20190707145924p:plain
iksm_session getter

スクリプトを実行する前の前準備

筆者はWindows 7Androidエミュレーターの一種であるNoxPlayerをインストールして使用している。NoxPlayerを用いる場合の特有の注意点は次のとおり。

  • Root化された端末ではNintendo Switch Onlineが起動できないため、ウィンドウの右上の歯車ボタン→通常設定 からRoot起動をオフにしておく。
  • マルチインスタンスマネージャーにより複数の仮想端末を管理している場合、接続したい端末のポート番号やエイリアス名を事前に調べておく必要がある。以下のサイトが非常に参考になる。

news.mynavi.jp

スクリプト本体

import subprocess
import time
import datetime
import threading
import sqlite3
import tkinter
from contextlib import closing

# android のローカルIPアドレス、ポート番号
ADDR_ANDROID = "127.0.0.1:62001"
# androidエミュレーターを起動するためのコマンド
CMD_ANDROID = "C:\\Program Files (x86)\\Nox\\bin\\Nox.exe -clone:Nox_0"

textBox = None
labelText = None



def guiStart():
    global textBox
    global labelText

    root = tkinter.Tk()
    root.title("iksm_session getter")
    root.geometry("400x120")

    mainFrame = tkinter.Frame(root, bg="white")
    mainFrame.pack(fill = tkinter.BOTH, expand = True)

    textFrame = tkinter.Frame(mainFrame, width=400, height=40, bg="white")
    textFrame.pack()

    labelFrame = tkinter.Frame(mainFrame, bg="lightgray",  relief = 'sunken', borderwidth = 2)
    labelFrame.pack(fill = tkinter.BOTH, expand = True)

    textBox = tkinter.Text(textFrame, height=1, width=48, bg="white")
    textBox.pack()

    button = tkinter.Button(textFrame, text=u'iksm_session取得', height=1)
    button.bind("<Button>",buttonClick)
    button.pack()
    
    # ラベルの文字列を変更したい場合はStringVarを割り当てる。
    labelText = tkinter.StringVar()
    label = tkinter.Label(labelFrame, textvariable = labelText, height=2, anchor='n')
    label.pack(fill = tkinter.BOTH, expand = True)

    root.mainloop()

def buttonClick(e):
    print(e)
    # バックグラウンドの処理は別スレッドで行わないと GUI が固まる。
    threading.Thread(target=backStart).start()

def backStart():
    global textBox
    global labelText

    # android端末とroot権限で接続する。
    # 接続に失敗したら端末を自前で起動しようとする。
    while True:
        subprocess.call('adb connect ' + ADDR_ANDROID)

        # android端末が起動されていない場合、adb root で 1 が返ってくる。
        returncode = subprocess.call('adb root')
        print("return code = ", returncode)
        if returncode == 1:
            labelText.set("Android端末に接続できません。\nNoxを起動します。")
            returncode = subprocess.Popen(CMD_ANDROID)
            print("return code = ", returncode)
        else:
            labelText.set("Android端末に接続完了。")
            break
        time.sleep(30)
    
    #Nintendo Switch Online の WebView のクッキーを5秒に一度取り出す。
    while True:
        subprocess.call('adb pull /data/data/com.nintendo.znca/app_webview/Cookies Cookies.db')
        labelText.set("クッキー取得完了。")

        with closing(sqlite3.connect('Cookies.db')) as conn:
            c = conn.cursor()
            r = c.execute('select expires_utc, value from cookies where name = "iksm_session"').fetchall()[0]
            print(r)
            
            # chrome のクッキーは 1601/01/01 を起点としたUTC時刻で保存されている。
            JST = datetime.timezone(datetime.timedelta(hours=+9), 'JST')
            now_utc = datetime.datetime.now(JST)
            d = datetime.datetime(1970, 1, 1, 0, 0, 0, 0) - datetime.datetime(1601, 1, 1, 0, 0, 0, 0)
            expires_utc = datetime.datetime.fromtimestamp(r[0]/1000000  - d.total_seconds(), JST)
            
        if expires_utc > now_utc:
            # 取り出したクッキーが現時点で有効だったらテキストエリアにiksm_sessionを格納しておしまい。
            textBox.delete('1.0', tkinter.END)
            textBox.insert(tkinter.END, r[1])
            labelText.set("iksm_session取得完了。")
            break
        else:
            labelText.set("クッキーの有効期限が切れています。\nNSO にログインし直してください。")

        time.sleep(5)

if __name__ == '__main__':
    guiStart()

Visual Studioで作ったPythonのBottle Web ProjectをXREAサーバーで動かしてみた話

勉強がてらpythonでwebサイトを構築してみたくなったのでやってみた。
以前個人的に使っていた統合環境がVisual Studio 2017@Windowsだったので、とりあえずこの環境にあるテンプレをサーバー上で動かすのを第一目標とした。
もう少し詳しい人は↓のほうがはるかに参考になる。
errormaker.blog.fc2.com

Visual Studio で Bottle Web Project を作る

とりあえずテンプレートからプロジェクトを作成。
f:id:vidamrot:20181216152726p:plainf:id:vidamrot:20181216152744p:plainf:id:vidamrot:20181216152754p:plain
テンプレート作成後、まずVisual Studioを介したデバッグで動くかを確認。
f:id:vidamrot:20181216152835p:plainf:id:vidamrot:20181216152900p:plain
見れた。

XREAサーバーで動かすための編集

次に、テンプレートそのままではサーバーにアップロードしてもちゃんと動かないので、いくつか編集を加える。

http://ドメイン名/ というURLでアクセスされたときにスタートアップファイルであるapp.pyが起動するように、ファイル名をindex.cgiにリネーム。f:id:vidamrot:20181216154242p:plain

index.cgipythonスクリプトとして実行されるよう、次のようなshebangを1行目に追加(これはXREAサーバー側で指定されているもの)。

#!/usr/local/bin/python3

index.cgiの末尾のBottleを起動する箇所で、サーバーアダプターがwsgirefでは動かないので、cgiに変更する。

#bottle.run(server='wsgiref', host=HOST, port=PORT)
bottle.run(server='cgi', host=HOST, port=PORT)

※逆にcgiにしてしまうとVisual Studioからのデバッグ起動では動かなくなるようなので、PROJECT_ROOTでの分岐を入れたりする必要がありそうだが、ここでは割愛。

XREAサーバーへ転送

とりあえずこれだけの編集を施してサーバーへ転送。gitやFTPを介したファイル転送機能くらい統合環境なんだから付いていそうな気がするが、ぱっとは見つけられなかったのでFFFTPで普通に転送した。
f:id:vidamrot:20181216155507p:plain
index.cgiパーミッションを705にする。
f:id:vidamrot:20181216155730p:plainf:id:vidamrot:20181216155733p:plain

bottle.pyをサーバーに置く。Visual Studioを介して入手したものを使う。
f:id:vidamrot:20181216155816p:plainf:id:vidamrot:20181216155821p:plain
※ただし、1行目にshebangとしてローカルパスが書き込まれてしまっているので、サーバー上では閲覧できないパーミッションにしたり、shebangを変えたりしたほうがいいと思う。

XREAサーバーで動作テスト

サーバー上で問題なく動くかテスト。
f:id:vidamrot:20181216160046p:plain
トップページは見れるが……。
f:id:vidamrot:20181216160050p:plain
それ以外のページは見れない。

.htaccessの設定

これは、"http://ドメイン名/home" ではなく "http://ドメイン名/index.cgi/home" というURLでアクセスしないと見れないようになっているのが原因なので、.htaccessにURLを書き換える処理を追加することで対処する。

.htaccess
DirectoryIndex index.cgi
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /index.cgi/$1  [L]

<Files ~ ".(cgi|xcg)$>
<Limit GET POST>
order allow,deny
allow from all
</Limit>
</Files>

# https://errormaker.blog.fc2.com/blog-entry-54.html
# /*** を /index.cgi/*** に書き換える処理と、
# 外国からのアクセスが集中したときの403エラーを回避する処理が書いてある

これでテンプレートがサーバー上で動くようになった。あとはテンプレートの内容から適当に編集していけばいろいろ出来そう。

Splatoon2 オクトエキスパンション一言メモ

未整頓のメモ置き場

・曲番号の整理

・全ステージの一言攻略メモ、体感難易度

 

#0 shell 開始前の音楽 頻繁にパンニング・フィルターがかかったパッド音、小さな泡のようなシンセ音
#1 progress 浮遊感のあるドラムンベース ゲート加工されたクワイア、モニョモニョしたベース
#2 ripped 太鼓のサンプリング音と怪しげなギターリフ、珍妙で耳に残る声ネタ ヒップホップのようなリズム感
#4 dunno ピコピコした鉄琴のようなシンセを怪しげなパッド音と小気味の良い木琴が飾る、不可思議な曲
#5 thirsty 開始直後のステージの曲 コードのみで構成されたシンセ・パッド、ドラムンベース 工事現場のような環境音
#6 frisk ハネた矩形波シンセ、浮揚感のあるパッド 4つ打ちでノリのいいドラムパート
#8 regret お洒落で落ち着いたエレピ+ローファイなストリングス かなり静かな印象のドラム、ベース
#9 party キレのあるナイロンギターと耳に残るエレピ+ブレイクビーツ お茶目なオケヒ
#11 above 一定のリズムを刻み続けるドラムマシン 爽快感のあるギターリフと重厚なピアノの低音
#12 awake メジャーセブンスコードの分散和音をひたすら奏でるピアノ、穏やかなベースと控えめなリズムパート
#13 shade 単純な波形ながら重厚なワブルベース、怪しげなシンセ音 妙にリズミカルで耳に残るラップ音
#14 crush トランペットやギター、カスタネット?などの生音を交えたお洒落な雰囲気、独特でアップリフティングな声ネタ
#16 salty 力強いシンセ音、攻撃的で不安をあおるベースライン 不規則なリズム
#19 bless 4つのアレの曲 鼓舞するような小太鼓にオーケストラのサンプリングと少々の声ネタを乗せた、神妙な凱旋曲

 

A02|いくらでも食らわせちゃって メツ・シー郡駅|ガチホコを 運べ! ★1
ホッケふ頭でガチホコをゴールまで運ぶ
・ガチ系ステージは塗り負け、1対多、相手はスペシャル持ちと基本的にガン不利対面を強いられる
 ただ、このステージに限ってはごり押しでゴールまで運ぶことも出来なくない

A04|あなたと着たい イカスフィア ペアルツ区駅|時間内にイカスフィアでゴールせよ! ★1
イカス…タコスフィアで、短い制限時間をチェックポイントで回復しながら駆け抜けるコース
・ヌリヌリ棒を越えるのは難しいので、普通に避けたほうがいい

A05|アブナイ女子の聖地 ルーガ森|森を抜けて ゴールせよ! ★1
タコゾネスを倒しながら進んでいくコース
・ヒーローモードのタコゾネスとは強さが違うことがわかる

A06|飛んで、国外脱出 リティ・セレ部駅|飛び跳ねながらゴールせよ! ★1
ジャンプ床中心に構成されたコース
・難所は無いが、なぜか制限時間がある

A07|そこのけコワモテ、ここにあり 千代岩・ルオヤ路駅|時間以内にジェットパックでゴールせよ! ★1
ジェットパックで進んでいくコース
・ジェットパック入門編

A03/B01|更新なき工事現場 仮設・トノ・ツメオル駅|エイトボールを 運べ! ★2
坂やシーソーをわたりながらエイトボールをゴールまで運ぶ
・ゆるい坂でイクラに沿って運ぶところが失敗を許さないつくりになっていて難しい
 イクラに重ねた状態でイクラの向きに全力で弾を撃てばうまくいく

B03|回してでんでん、すべって落ちたら チョベ・リバー駅|回しながら ゴールせよ! ★2
デンデンスイッチが多用されたコース
・回転床のところがちょっと難しい

B04|女子に攻められ マイッチン郡駅|ガチヤグラを 運べ! ★2
エンガワ河川敷でヤグラをゴールまで進める
・死んでも復活が可能、リスポン目の前のジャンプポイントでヤグラにジャンプできる(これはひどいチート)
・タコゾネスのカサって発射レート早い上に傘でのブロックが的確で強くない?

B06|それはタコッペリン号の タイフーン ミル・リバー駅|カーリングボムだけで ゴールせよ! ★1
カーリングボムだけで進めるコース
・最後のミサイルはジャンプで避ける

B07|踏んで! 華麗なステップ ノリノー・リディス湖駅|時間内に バンパー 全部こわせ! ★1
ボールランチャーをスイッチで操作しながらエイトボールをバンパーに当てて、1分30秒以内にすべて壊す
・スイッチは踏んでいる間だけ動作
・全ステージで一番スプラトゥーンの要素のないステージ

B11|ワナの満漢全席 ホンカ・クチュー川駅|エイトボールを 運べ! ★1
敵の攻撃を避けながら、エイトボールをゴールまで運ぶ
・ブキがわかばと扱いやすいのもあり、特に難所は無い

B12|食らって!タコのカルパッチョ イタメ市駅|時間内に コロガリウムで 敵 全員たおせ!
★1
コロガリウムを飛ばして敵をすべて倒す
・最後にタコスナイパーがボスっぽく現れる

B13|逃げ出せぬ戦い バックレフ渓流駅|敵 全員たおせ! ★2
敵を全滅させることで先に進めるコース
・パブロの場合、タコスナイパー・タココマンダー・バイソクボムタコプターが居る2番目のエリアが鬼門
 スナイパー・コマンダーを倒したらバイソクボムタコプターをハイプレで倒す

B14|自分で危険を広げる スツトコ・ドツ恋駅|敵 全員たおせ! ★1
イカの形をした木箱の床の上で敵をすべて倒す
・白いビニール箱が硬いので、その上に乗って攻撃する

B16|寝転がってるヒマは無い カウチポテ島駅|にげる風船 全部こわせ! ★2
狭いステージに次々と現れる逃げる風船を逃さず50個すべて壊す
・1つ1つはそこまで難しくないが、個数が多いだけでなく、猶予が短め

C02|節約こそが美しい ショーエネルツ区駅|限られたインクで ゴールせよ! ★2
限られたインクだけで進む短めのコース
・インクリーナーはおとりのインクを吸わせてから登る

A08/C03|一心同体、エイトボール アベツ区駅|エイトボールを 運べ! ★3
ピョンピョン床やスポンジが大量に配置されたコースでエイトボールをゴールまで運ぶ
・全体的に壁が少なく、すぐにボールが落ちてしまう
 ブキよりも体で押したほうが良いかも

C04|踊り続けて オール内藤駅|一定時間 よけろ! ★4
30秒間敵の攻撃に一度もあたらないように避け続ける
・タコトルーパーが乗っている台の動きとシンクロさせて避けると
 もっとも外側の攻撃が下に落ちるようになるため、少し楽になる
・タコスナイパーの攻撃は大ジャンプで避ける

C06|回転率の高いカフェで チャシバ区駅|時間内に マト 全部こわせ! ★2
一定時間ごとに90度ずつ回転する床に配置された的20個を2分以内にすべて壊す
・スタート地点から赤道部分を回り続ける(回転軸に垂直方向に進む)だけでも大多数の的が破壊できる

C07|エイトボール達の不協和音 チャク・シンサンワ温泉駅|エイトボールを運びながら ゴールせよ! ★1
エイトボールを運んでゴール前のバンパーの山を壊し、3分以内にゴールする
・3個運ぶのは少し大変だが、意外にもたもたしていても時間が余るのであせらずに

C08|高いトコに住んでるヤツら ヒルズゾ区駅|時間内に 敵 全員たおせ! ★3
浮遊する床に座する20体の敵をデンデンスイッチで回転させ、2分以内にすべて倒す
・回転させながら網の上に居ることでマルミサ、ハイプレがキャッチできる
 特にラピエリだと回転中の敵に当てるのは至難の業、しかも直撃させても倒しきれないため、
 惜しみなくスペシャルを使う

C09|エイトボール、撃って走ってスイッチON ナルハ屋駅|エイトボールを 運べ! ★2
エイトボールをレールに乗せ、落ちる前にスイッチを入れていきながらゴールまで運ぶ
・シールド付きタコトルーパーは横から爆風を通せば倒せる

C10|ジェットパック、よける姿は ゲキマ部駅|ジェットパックで 一定時間 よけろ! ★3
ジェットパックで30秒間タコストライク等を避け続ける
・タコストライクはジェットパックの弾を当てれば崩すことが出来る
・タコスナイパーもジェットパックで普通に倒せる

C11|道を切り開け!ファスナーは閉じろ! シャキィ・ノマド・アイ停留駅|道を探しながら ゴールせよ! ★1
透明床のコース
・必ずヒントがある

B15/D01|ニクめないアイツと遠距離恋愛 コア・クマ池駅|ミサイルよけながら ゴールせよ! ★1
ミサイルタコプターの攻撃を避けながら進むコース
・これといった難所は無い

D02|一発でクリアできたら バツチー郡駅|一発で 木箱 全部こわせ! ★2
インク風船を誘爆させ、1回のショットで木箱60個すべてを破壊する
・風船3つを真ん中で爆発させることになる
・下の風船を真ん中で爆発させると、ちょうど残り二つも真ん中で爆発するようになっている

D04|確実に 撃ってプロペラ 意思疎通 ポケ・ベルウ地駅|プロペラリフトに乗って ゴールせよ! ★1
回転床リフトをプロペラで動かしながら進むコース
・プロペラを打つことと落ちないようにすることに気をつけるだけ
 敵や風船はガン無視でよい

D05|エイトボールの新しい遊び方が トレン出井駅|ボールスイッチを 7つ ONにしろ! ★3
限られたインクでエイトボールを撃ち、ボールスイッチ7個をすべて通過させる
・半チャでインクを節約することを意識する

C01/D06|人生のレールにあらがえ! ツッパ里駅|時間内に マト 全部こわせ! ★3
ライドレールに乗りながら、1分以内にライドレール上を動く的20個をすべて壊す
・隣のレールの的を壊し終わってから隣のレールに移ることを意識

D07|今日は朝から床掃除 カジテ津台駅|時間内に マト 全部こわせ! ★3
ローラー・フデでコースを駆け回りながら、時間内に的30個をすべて壊す
・最初の道は、カーボンでも縦振りを使うより塗り進みのほうが速い

D09|スッパイ思い出の教習所 クロズダ・イエッ島駅|ジェットパックで ゴールせよ! ★2
ジェットパックで、インクレールや金網を伝いながら進んでいくコース
・中盤にある金網ゾーン最後のジャンプは、
 金網からのジャンプとジェットパックの空中ジャンプで2段ジャンプする

D10|朝も夜も働いてます データバン区駅|暗がりを進んで ゴールせよ! ★1
暗がりの中ハイカラスクエアを進むコース
・ゴールポイント前が少し厄介な程度

E03|タコミサイル、飛びすぎムズすぎ ゲロゲ路駅|回しながら ゴールせよ! ★2
デンデンスイッチで床を適切な量だけまわして進んでいくコース
・中盤のミサイルは最終盤でも再利用するため、リフトに乗っているときに回したりしないように

E04|まちがって、ピロピロ撃って ソン・ナバ菜々駅|エイトボールを 運べ! ★3
ピロピロを中心としたコースでエイトボールをゴールまで運ぶ
・チャージが短く、複数の仕掛けをしっかり裁きやすい竹のほうが簡単かも
 (スピナーへたくそ・・・)

E05|返されないで ビッグメン湖駅|スイッチをONにしつつ ゴールせよ! ★2
敵の色で塗り返されるとオフになるスイッチが登場するコース
・最後のスタンプ裏のスイッチ、見逃しやすいよなあ

E06|エイトボール 穴に落として オトシダマ アケオーメ・コト要路駅|エイトボールを 一列そろえろ! ★2
エイトボール4個を大砲で撃ち、3x3の穴に落としてビンゴを作る
運ゲー
・一度入ったエイトボールに大砲を撃ち込むとボールを穿り出せる
 ただし、まれにものすごく飛んで台の外に落ちてしまうことがあり、
 「エイトボールを落としたのでチャレンジ失敗でス」

E08|カワイイあのコと ボム投げよう イコチャン川駅|スプラッシュボムだけで ゴールせよ! ★2
スプラッシュボムのみで進めるコース
・ボムコロの練習にどうぞ

E09|運賃は経費で落とせ タクシチケ島駅|業務用インククリーナーを乗りこなし ゴールせよ! ★3
業務用インクリーナーを乗り継いでいくコース
・クイボ縛りでスナイパー2匹を倒すところが少し難しい
 隣のデンデン太鼓のある床の上から攻撃すればやりやすいか
・一番最後のダッシュ床では、ボムでひきつけたらすぐに乗るのがコツ?

E10|メイクブラシで書き殴れ ガング路駅|時間内に 木箱 全部こわせ! ★2
30秒以内に山積みの木箱80個すべてを壊す
・インク回復を忘れない
・赤い木箱2個にはチャクチが入っているので有効活用する
スプチャ ★4
・硬い木箱は貫通しない
・インク回復のタイミングでチャクチを使うように工夫する

E11|男のかくれ家、ここにあり バスエーノ・スナッ区駅|ログポイントを 8コ 集めろ! ★2
定期的に90度ずつ回転する大きな物体に配置された8個のログポイントを集める
・特に最初の1週はなるべく落ちないことを優先的に床を塗って行く

E12/F01|ハイエナどもの夢の跡地 ハジケー・ルバブール駅|ヤツをたおせ! ★4
バブルランチャーを撃ってくるタコツボックス
・連続スタンプが初見殺し
・スタンプや射撃で泡が連鎖的に壊れるとほぼ即死なので、泡には近づかない

F02|動きを止めたら 亜東和・ヨロピ区駅|ジブンのタイミングで ゴールせよ!
スイッチで振り子等の仕掛けをいいタイミングで止めながら進んでいくコース
スクイックリン ★2
クイボのみ ★3
・単純に狙ったタイミングで止めるのも難しいし、インク回復のタイミングも悩ましい

F03|マトを見逃し バイ奈良駅|リフトに乗って 風船 全部こわせ! ★2
ゆっくり回転しながら動くリフトの上から的30個を漏らさずすべて壊す
・ところどころにあるブラシがものすごく邪魔
 近くに来たときは回避に専念すること
・柱の後ろなど微妙に見落としやすい箇所にもある
 視界の外に的があると矢印が出てくるので、見つからない場合
 カメラをグワングワンすると大体の場所がわかる

C05/F04|ヤツから逃げて! エンガ町駅|登りつつ ゴールせよ! ★1
オオバンタコスタンプをボム等で倒しながら、側面を登って進んでいくコース
・難所は特に無いが、最後は一気に

F05|走れ!アイツのように エリマ木駅|にげる風船 全部こわせ!
逃げる風船を順番に50個漏らさず壊す
ジェット ★2
ホット ★3
スシ ★3
・40個目を越えたあたりから露骨にシビアになってくるので、
 簡単な武器種でルートを覚えてからのほうがいい

F06|郊外での アツき戦い トーユス東部駅|敵 倒しながら ゴールせよ!
敵を倒しながら進んでいくコース
ラピブラ ★2
・タコポッドは難なく対処できるが、バイソク系の敵が少し厄介
スクイックリン ★2
・タコボッドはボムで始末したほうが良いことが多い
ハイドラ ★3
・中盤が難所、全滅させる必要は無いのでさっさとジャンプポイントへ

C12/F07|1つでも壊し間違うとアウトです ハンパ・ネッ州駅|同じ形にせよ! ★2
木箱の塊を見本(猫?)と同じ形に削る
・スプチャはフルチャージの貫通効果が厄介

F08|ボヨーン、バシュッで ブツ鳶駅|ジャンプ撃ちしながら ゴールせよ!
高所にある引き寄せポイントをラピブラでジャンプ撃ちしながら登っていくコース
・一度失敗したらほぼ最初からやり直しなのが辛いところ
ラピッド ★3
・ジャンプ+爆風の先のほうでないと届かない場面があり、ややシビア
ラピエリ ★2
・大部分が飛び降りなくても届くようになり、少し簡単

F09|校区外は悪の巣窟 ナタデ高校駅|ガチホコを 運べ! ★3
マンタマリア号で5分以内にガチホコをゴールまで運ぶ
・ゴール上のシールドとスプリンクラーを壊してからゴール

F10|ぐるぐる回せ! カクロク・ベーゴ間駅|ログポイントを 8つ 手に入れろ! ★3
スイッチでステージをぐるぐる回しながらログポースを8個集める
・スイッチの回る方向にステージが回る

G02|お腹イッパイ タコイッパイ ザーギン・デーシ州駅|時間内に 敵 全員たおせ! ★2
スペースインベーダーを模したステージで、3分以内に敵をすべて(32体)倒す
・最後のシールドで守られたタココマンダー+タコスナイパーが厄介
 左の赤い箱に入っているプレッサーを上手く使いたい

G03|上から見下ろす気分はどうだい? ペントハウ州駅|敵 全員たおせ! ★1
周囲の壁に構えるタコスナイパー10体をリッター4Kで倒す
・斜線出しっぱななしのでかいクソエイムチャージャーを撃つだけなので非常に簡単

B10/G04|ピロピロ街道を ぶっち切れ! キレタミ山河駅|宙をまいつつ ゴールせよ! ★3
ピロピロがたくさんあるコース
・最後のタコスナイパーに狙われながらピロピロを乗り継いでいくゾーンが難しい
 チェックポイントから数えて3個目のピロピロからほぼ真下にあるピロピロに乗り移るとショートカットができる
・ローラーの場合、縦振りのほうがピロピロが良く伸びる

G05|調子に乗りすぎ要注意 イケ池駅|ダメ風船撃たずに マト 20コこわせ! ★2
1分以内に赤い風船を壊さずに的を20個壊す(全部を壊す必要は無い)
・制限時間があることを忘れがち

A01/G06|ライドレール、いっぱいすぎて ワケワ亀駅|レールを乗り継いでゴールせよ! ★3
デュアルでライドレールを乗り継いでいくコース
的は無い
・なるべくスティックを倒さないようにするのがコツ

G08|七色のチャージャー使い カーラヒヨ湖駅|テクニックを見せつけ ゴールせよ! ★2
短射程チャージャーで空中引き寄せポイントなどを撃っていくアクション要素の高いコース
・実はノーチャでフル射程の竹のほうが簡単なのでは

B05/G09|エイトボール見つけて引き返せ! オートス・リバー駅|エイトボールを 運べ! ★2
コースの奥にあるエイトボールをスタート地点の近くのゴールまで運ぶ
・最後の回転する床を超えてエイトボールを運ぶ所が少し難しい

E07/G10|ジェットパックで連れてって アツ・シー 郡駅|ジェットパックで ゴールせよ! ★1
ジェットパックで段差や穴を越えながら進んでいくコース
・序盤にある、空中の壁が横に動いている箇所は、壁を越えるのではなく普通に横切るだけでよい
 (ジェットパック初心者だとなんとなく越えられそうな気がするんだ……)

D03/H01|ピロピロのおかげです サンキ・ウベリマ町駅|メインサブ使いこなし ゴールせよ! ★1
スプラチャージャーとスプラッシュボムを使いこなしながらピロピロを乗り越えていくコース
・序盤にあるイイダのヒントのとおりボムの時間差を利用する仕掛けでは、
 ボムは右側の網の上に載せるだけでよい
 (左の加速パネルで上昇→投げ込むでやろうとして苦労した人、ほかに居ない?)

H02|無敵で追いかけ爆発ドーン トリー・マメン号駅|時間内に イカスフィアで ゴールせよ! ★1
イカス…タコスフィアで、短い制限時間をチェックポイントで回復しながら駆け抜けるコース
・敵をちゃんと無視できているなら制限時間は問題にならない

H03|かっこよく乗りこなして キツクボウ堂駅|ガチヤグラを 運べ! ★2
ガンガゼでヤグラをゴールまで進める
・死んでも復活が可能、リスポン目の前のジャンプポイントでヤグラにジャンプできる(これはひどいチート)
・プレッサーやめろってまじで

H04|今夜、視線を独り占め ジュリセンオ太刀台駅|時間内に マト 全部こわせ!
徐々に小さくなる隙間を縫って、すばやく横に動く的を1分以内にすべて壊す
ラピブラ ★1
・スプチャとの難易度の落差……
スプチャ ★2
・実はチャージャーも偏差撃ちが必要なんですよ
スプスコ ★4
・心でタイミングを感じ取らないといけない
 イヤホンとかでサウンドプレイするとちょっとはマシになるか?

H05|塗りたくって ゴングーロ・ヤマン場駅|塗り返しつつ ゴールせよ! ★1
ハイドラで長大な射程を生かしながら進んでいくコース
・難所は特に無いが、最後のタコドーザー誘導でちょっとてこずるかも

G01/I01|外はカリカリ、中もカリカリ メガモリス・イー津駅|ヤツを たおせ! ★3
改造版タコツボベーカリー
・2回目に頂上登ったときにハイプレを取っておくとよい
 3回目はあらかじめハイプレで削っておけば幾分楽になる

I02|ギリインク クリアできたら じまんげに イキーリ・ドヤ川駅|限られたインクで ゴールせよ!
限られたインクでゴールを目指すコース
・右ルート、左ルートそれぞれに鍵があり、鍵を使用するとインクタンクアイテムが1個ずつ手に入る
・ただし、完全にインクタンクが空になるとその場で失敗
・正面ルートにはいくつかのギミックの後、ゴールがある
・開幕は左ルートがお勧め
・実は手前左側のブロックの山の赤い箱にもインクタンクが入っており、
 これを利用すると難易度が大幅に下がる(無くてもクリアは出来る)
・インクタンクの補充は各ルートで限界まで使い切ったタイミングで
・正面ルート序盤にある段差上の木箱は、プロペラを使うことで乗り越えられる
・タコゾネスはカサをパージさせてから倒せばよい
・最後のスイッチはオンにするとひっくり返る インク風船があるスイッチをオンにしよう
96 ★2
ノヴァ ★3
・ノヴァのほうがインク管理がシビア、特に開幕で右ルートを選択すると
 バイソク3体すべてに弾を直撃させないと帰れないため、ほぼ詰み


E01/I03|ちゃ…ちゃんと守りなさいよ! ツンデ嶺駅|エイトカプセルを 守りきれ! ★1
ミサイル・タコッペリン号から1分間エイトカプセルを大砲で守りきる
・ミサイルを全部打ち落とすのは少し難しいが、多少漏らしてもエイトカプセルが意外にタフなのでなんとかなる

I04|敵インク、踏んでびっくり オーモーレ津駅|敵インクにふれずに ゴールせよ! ★4
敵インクに一切触れずにゴールする
・終盤のタコススナイパーは、なるべく横に突っ切るようにする
 ここだけはローラーが一番簡単かも

B08/I05|無理は禁物 リンゴダ・イエッ島駅|レールに乗って マト 全部こわせ!
ライドレールに乗りながら的30個を漏らさず壊す
竹 ★4
・縦に並んだ的が壊しづらく、特に終盤はまったく猶予が無い
 前半の簡単な部分でノーチャで的を壊す練習をしておくとよい
スシ ★2
・射程が短く、撃ち漏らしが出来ない
 ジェットで練習してからのほうがよい
ジェット ★1
・ぬるげー

I06|甘くはないゾ ヨーグル・トキノ湖駅|敵 全員たおせ! ★2
引き寄せポイントで小さな床を飛び移りながら、長射程武器で敵(21体)をすべて倒す
・まず真ん中の島に近い箇所まで近づき、タコスナイパーを殲滅してやればあとは簡単

G07/I07|ボクらのタフギア クロ・カンヨン区駅|車を乗り継いで ゴールせよ! ★3
空飛ぶ車を飛び移りながらゴールを目指すコース
ホクサイ
・クイボの足場塗りが強い味方
・最後はインクがギリギリなので、点線に惑わされずギリギリのタイミングで上がり始めるように
ロンブラ
・ホクサイよりも射程は長いが、ボムが取り上げられており足元の塗りが辛いセット
 特に中盤のぐるぐる回るゾーンでそれが顕著
 バイタコトルーパーは確実に仕留めたいが、直撃1撃+爆風が必要になる

I08|環状線内での アツき戦い セキタンス東部駅|敵 全員たおせ! ★2
敵を全滅させると先に進めるコース
・最後の坂のエリアは頂上にハイプレとマルミサがあるため、登ってしまえばウィニングラン
 ボムタコプター側から登ったほうが楽?(上からでもあんまり楽にならないし…)

B02/I09|あっ、マト外しちゃった♪ テヘペー路駅|レールに乗って 風船 全部こわせ!
長射程武器で、ライドレールに乗りながら的30個を漏らさず壊す
スプチャ ★4
・インク回復と金網すり抜けのため、タコ状態で進むのが基本
・風船はノーチャでも壊れるため、貫通が前提の配置以外は半チャで壊していく
 そうしないとインクが足りない…
・全体的に撃ち漏らしを許さないシビアなつくりになっているのに、
 自分が高速で動いていてエイムが狂いやすいため、意外に難しい
竹 ★2
・スプチャと違い貫通が無いが、半チャの射程やインク効率の関係でかなり簡単になる
ジェット ★1
・チャージャーと違いフルオートなのに、相変わらず1発当てれば壊れる
 外しまくっても大丈夫な親切設計のため、ライドレールアクションの練習にでも

H07/J01|温泉旅館でリフレッシュ アン・チエイジン郡駅|ヤツを たおせ! ★4
ジェットパックで改造タコツボビバノンを倒す
・ハイパープレッサーのよけ方はイイダのアドバイスを参考に
・闇雲に上に向かって撃つよりは近くの高台に上って高さをあわせたほうが当てやすいと思われる

J02|ねらってないのに壊れて、いや~ん エチスケチ・ワンタッ地駅|同じ形にせよ!
見本と同じ形になるように木箱を壊す
(普通の木箱を残し、赤い木箱だけを壊す)
・壊すべき木箱が非常に多く、集中力との戦いになる
・隠された鍵で開く扉の中にチェックポイントがある
 これを使うと、失敗しても通過した瞬間の形でやり直せる
・最後は1方向だけ塗れる箱があることに注意(中から出るときも同じ)
ラピエリ ★5
・赤い木箱は普通の木箱の半分程度の耐久力
・普通の爆風では普通の木箱すら1撃であり、大変リスキーなため、直撃メインで進める
 直撃時の小爆風で普通の木箱は2発、赤い木箱は1発で壊れる
 そのため、直撃させる場所もかなり重要になる
・普通の木箱に囲まれた赤い木箱は、周囲の木箱を傷つけずに壊すことが出来ない
・出来る限りたくさん壊してからチェックポイントを使用し、
 わざと自殺して木箱のダメージを回復させるのが有効
スプチャ ★4
・赤い木箱も普通の木箱もノーチャ2発、半チャだと75%以上の溜めで1発
 そのため、射程が短いが誤射の少ないノーチャで削っていく
ボトル ★3

D08/J03|ワタシ達が お相手ヨ! ジョシリョ区駅|エイトカプセルを 守りきれ! ★5
タコゾネス(計15体)からエイトカプセルを1分半守り抜く
・スシなど殲滅力のあるブキなら、ひたすら倒しまくるだけでもなんとかならないこともない
スプチャ
普通にやれば無理ゲーだが、この武器ならではの攻略法がある
・開幕の7体(スシ以外)は斜線を向けると飛び出してくるが、
 ちゃんと斜線隠しをすればジャンプ前に倒せる
・第2群は、前と横の床から3体現れる
 目前の木箱がやわらかく危険度の高いバケツ(向かって左)を着地狩り、
 次にエイトカプセルへの火力が高いスシ→倒しやすいブラスターの順で倒す
・第3群は、斜めの床から2体現れる
 火力が右前の高いスシを着地狩り→カサをパージしていて倒しやすいカサの順で倒す
・第4群は、第2群と同じく前と横の床から3体現れる
 スピードが速く倒しにくい左のホクサイを着地狩りする
 右に現れるブラスターは近づくとハイプレをぶっ放すアホなので、後回しでよい
・第2~4群で、着地狩りが追いつかないレベルでグダると大体失敗する

J04|自分で穴を開けまくっちゃって~ ジョーダン・ハヨシ湖駅|時間内に 敵 全員たおせ!
ゲッソーの形をした木箱の床の上で敵を10体倒す
ノヴァ★2
・敵の足元の箱を壊せばよい
・バイタコトルーパーを先に倒すべき
パブロ★4
・塗り進みはビニールの無い普通の木箱(赤い木箱含む)を一撃で壊すので、避けて進む
・最初の1群はカーリングボムで数を減らす

C14/J05|せまりまくる!ヌリヌリ棒に ビック・ラコイ田駅|よけながら ゴールせよ! ★2
デンデン太鼓でヌリヌリ棒をまわしながらライドレールを進んでいくコース
・3番目のセクションは、1発当てたときは60度、
 2,3発当てたときは90度、4発当てたときは120度回転する
・各セクションでイカフライをすべて取るとボーナスイクラが貰えるが、
 難易度が高いのでクリアを目指すだけなら無視したほうがよい
 以下コンプリートする場合のポイント
 ・2番目のセクションは1箇所だけデンデン太鼓を使わないところがある
 ・3番目のセクションではイカフライ1個をとってから
  すぐに引き寄せポイントで戻るといい感じに全部取れる

D11/J06|あいつとタイマン アウ東部ガン中学校駅|限られたインクで マト 全部こわせ!
限られたインクでマトをすべて壊す
・2列目の2個マトが迫ってくるステージは1撃で壊しきりたい
ラピブラ★2
・3発余裕がある
バケツ★4
・こちらも3発ほど余裕があるが、爆風がない分ラピブラよりも条件が悪い
ローラー★4
・最後はたて振りでまとめて壊す

J07|セレブなタコの生息地 シロガネー瀬駅|気合で ゴールせよ! ★2
敵が多いコース
・落ち着いてやれば難しくない
 プレッサーは最後の盾持ちにでも使おう

F11/J08|ごっつぁんです! モツナ・ベチャン湖駅|ヤツを たおせ! ★4
イカス…タコスフィアで強化タコツボザムライを倒す
・全体的にノックバックが強いため、無敵だからといってごり押しは利かない
・3ターン目の衝撃波は避けるのが難しいので、金網で守ってもらうのが正攻法か
 金網際だと跳ねて落ちてしまうことがあるため、フィールド真ん中で金網と敵の間に
 位置するようにしっかり調節しないといけない