月と燃素と、ひと匙の砂糖この点を押さえておくと、こんなことまで意識するごく一部の人々と議論する際に役立つこともあるでしょう。Clientは死んだんだいくら呼んでも帰っては来ないんだもうあの時間は終わって、君も人生と向き合う時なんだ弾幕の海にたゆたう、アブストラクトシューティングNoiz2sa。ChromeにNoiz2saを以前移植して公開してあったのですが、こちらでは書きそびれてたので、クリスマスというタイミングに書くことにします。“Noiz2sa”をブラウザで遊べるようにしてみました。Clientという仕組みを使っていて、これを使うと比較的簡単にネイティブのゲームをブラウザ上で動かすことが出来るようになります!GamepadのAPIがうまく動かないので残念ながらゲームパッドでは動く動かないのですが、キーボードでならガリガリ動くのでJoyToKeyでも使ってやってみてください!...だったら普通にWindows版で遊ぶ?そ、そうですよね...。何もしてないけどクロスプラットフォームNativeClientは、何もしなくてもクロスプラットフォームに対応していて、今回の拡張もLinux/Windows/MaxOSXで動きます。ちなみに開発自体はLinuxでやってます。NativeClientのしんどいところNativeClientはセキュリティ上の要請から、色々制限があります。Portsがあるお陰で普通に使う分には困りませんが、ファイルアクセスやネットへの接続などでは独自のライブラリを使わなければなりません。今回ゲームということでネットワークは使っていないのですが、タイトルの「noiz2sa」のロゴ画像(ビットマップ)や弾幕の定義データ(XML)、BGMや効果音のファイルなど、比較的数は少ないもののファイルアクセスがあり、これに対処する必要がありました。ClientにはURLLoaderというクラスがあるので、これを使えば任意のURLの内容を取得できます。これをローカルファイルの代わりに使えば良さそうです...が、今回はゲームなのでローディングを避けたいのと、大した容量でもない(8MBくらい)なので、全部バイナリ内に入れてしまうことにしました。GitHubとして全データを格納します。ledyba/Noiz2saNaClソースコードを改変できるので別に乗っ取る必要はないのですが、NativeClientの元の記事がそういう感じで乗っ取ってたのでそうしときました。ディレクトリ内のファイルを列挙するAPIであるreaddirなどもおんなじ感じで乗っ取っております。この方法はGoogle先生謹製の記事を参考にしていて、ソースも一部拝借してます。DevelopersさてどうしたものかNativeClient、ファイルが絡むと一気にめんどくさくなります。既存の技術(Flashとか)を置き換えるには少し不便ですね。Fujisaki諸事情でWordPressをインストールして別箇所で使っていたのですが、これは素晴らしいですね!!!何が素晴らしいって、もうUIは使いやすいし!アップデートは自動だし!固定ページとかの編集も簡単だし!テンプレートを簡単に変更できるし!プラグインは豊富だし!かわいいテンプレート一杯あるし!かわいいテンプレートがたくさんあるし!かわ(ryもう移行しない理由とかないよねーないよねー、ということでちょっと重い腰を上げて移行!することにしました。言語別にパッケージが分かれてるのは正直ダサいと思いますが、不満はそれぐらいです。はてな記法を捨てたい。はてな記法のプラグインを使ってて依存していたため移行をためらっていたのですが、今回この負の連鎖を断ち切るべく、プラグインの変換エンジン部分を適当に引っ張ってきて、エクスポートしたデータのはてな記法の部分を変換する(!)スクリプトを書きました。export******.txtごめんなさい:追記部分の変換を忘れてました。使用時には注意してくださいね...。今回Perl使ったのは初めてなのですが、空文字列をfalseとして認識する使用で随分ひっかかりました。Fujisakiお久しぶりです、ψ(プサイ)です。今日は今やってるプロジェクトとは一切関係なく、gmtime/localtimeの実装が気になったので、読んで分かったことをまとめておきます。変換してくれるCの標準ライブラリ関数です。unixtimeのままでは人間が到底読めないので、表示する時などに必要な関数です。思えば、このgmtime/localtimeの実装は結構めんどくさそうです。年=(int)1970+(unixtime/(24*365*3600))...みたいな感じで簡単に算出できますが、これでは全然駄目な点がたくさんあります。うるう年は?うるう秒は?(localtimeの時)時差は?どうやるか自体は大体想像できると思いますが、折角なので読んでみました。そんな具体的な話には興味ないという方は飛ばして下さい。newlibのgmtimeを読んでみようnewlibは標準Cライブラリの軽量な実装です。組み込みの分野でよく使われていて、コンパクトなのが特徴だそうです。ためしに、このライブラリでのgmtimeを読んでみます。newlib/libc/time以下のフォルダにあります。*)_REENT_TM(_REENT));}gmtimeはグローバル変数のtm構造体を返すのですが、ユーザの指定したtm構造体に値を格納するgmtime_rという関数もあるので、それに処理を投げているようです。1));}localtimeと処理を共用しているようで、その共通の関数に投げてます。3つ目の引数の「1」は、gmtを使うという意味のようです。*tim_p;この関数は結構長いので、ちょっとずつ読んで行きましょう。ローカル変数の定義です。昔のCの規格でも動くように、ローカル変数は必ず関数(もっというとスコープ)の一番最初で宣言されているみたいです。std/dstという文字列が見えますね...サマータイムと通常時間の事です。私は最初、すっかり存在を忘れてました。オレオレ実装を作っていたらすっかり忘れていた所です。}1970年の元旦からの日数と、残りの秒数を求めているみたいです。if文の分岐先が中々不思議ですね。何も考えなくても機械的に決定できるので、問題ないです。days;少し長いですが、1,970年の元旦からの日数から、年を求めています。isleap関数はうるう年の時は1を、そうでないときは0を返す関数で、year_lengthsは{365,366}の配列です。このふたつを組み合わせるとその年の日数をうるう年を考慮した上で知ることができます。基本的には1年ずつ年数を調べて、最初に計算した1970年からの経過時間であるdaysから引いていって、1年に満たなくなるまでループを回す、っていう、素朴な実装です。最初に分岐がありますが、相変わらず、days<0になるのはいまいちどういうケースなのか想像できないです。最後の-YEAR_BASEですが、tm構造体のtm_yearの値は1900年からの年数を表す事になってるので、これで引いています。1;ここまでで、daysは1年のうちでの日数を表しているので、年でやったのと同じように何月なのかを計算しています。;こんな感じの配列で、うるう年を考慮した月の日数の一覧です。最後の+1ですが、tm_mdayは1から始まるきまりになってるので、その調整です。最後の最後にgmtimeとlocaltimeでの分岐処理が入ります。0;gmtの時はtm_isdts=0に設定してるだけで簡単です。gmtにはサマータイムとかは無く、またunixtimeはGMTの1970年の元旦からの秒数なので時差もありません。localtimeの時の処理はかなり骨がおれます。if文の中身を読んで行きましょう。0;_daylightはグローバル変数で、サマータイムを使う可能性があるときにセットされます。res->tm_isdstの判定なのですが、すいません、よくわかりません。__tznorthがfalseの時、条件が反転するみたいです。サマータイム、嫌すぎる→コメント覧参照ですが、これはどうやら南半球でのサマータイム(10月〜翌年3月ぐらい)の判定と、北半球でのそれとでの差のようです。これも最初まったく考えが至りませんでした。...北半球から出たことないです...。hours;サマータイムを考慮しつつ、時差を取得して、その分を足したり引いたりしている処理です。この時、機械的に足すので、時間が24を超えたり、マイナスになるかもしれません。}}かなり長いですが、これはかなり単純で、例えば分が60を超えていたら調整のためにその上の時間を足して、...という処理を延々年まで行なっていってるだけです。いかがだったでしょうか。一つ一つの処理はそこまで複雑ではないのですが、やはり長いですし、細かい例外もちゃんとフォローしてありましたね。ライブラリは偉大です。閏秒は????????さて、ここまでで気づきませんでしたか。閏秒という概念が登場しなかった、という事実を。実はposix標準ではgmtime/localtimeは閏秒を考慮しないらしいです!えっそれ普通に困るのではが、しかし、glibcのソースを眺めてみると、めんどくさくてあまり読んでないのですが、次の内部関数を見ると、どうやらうるう秒を考慮していそうです。}}むー、なんか複雑になってきました。いうことは:同じ時刻、違うunixtime?閏秒を考慮する場合としない場合で、当然時刻の計算が違ってくるはずです。glibはうるう秒を考慮に入れてるっぽいので、適当に決めたunixtime=1354320000で、差をチェックしてみましょう。0;}まずはnewlibでやってみます。00:00:00あれれ???一緒ですね...さらに泥沼が待っているとはこの時まだ私は知らないのであった...タイムゾーンの設定が、2つあるglibcのところで、うるう秒を考慮にいれているようなソースがありましたね。うるう秒というのはうるう年とは違って、ランダムに挿入されます。どこかに「うるう秒の一覧」を記録しておかないと、正しく計算することができません。Universalこんな感じでたくさん入ってます。この中には時差その他のデータが入っていて、うるう秒のデータも含めることができるそうです。NULLとなってて、2012年の7月にあった最新のうるう秒などのデータが入ってるようには見えません。gmtoff=324002012年7月の表記があるので、ちゃんとうるう秒が反映されているようだ、とわかります。タイムゾーンを正しい方に設定してみるやっと正しい方が分かった所で、この正しい方にタイムゾーンを設定してみましょう。TZ環境変数に正しい方のファイルへのパスを指定すると、どのタイムゾーンのファイルを使うか設定することができます。glibcの方から先にしてみましょう。23:59:35ふぅ。さっきは12/01でしたが、うるう秒を考慮した結果25秒ほど過去に戻って11月になってしまいました。一応、うるう秒を考慮にいれていないはずであるnewlibも試して見ました。00:00:00おおお、やっと差が出ましたね!つ、疲れた...。ちなみに毎度毎度TZ環境変数にいれなくても、システム全体で正しい方を使うようにもできます。まとめgmtime/localtime、簡単そうな処理ですがサマータイムとかうるう秒を考えたらやっぱりライブラリ使いましょうgmtime/localtimeはposix標準ではうるう秒を考慮しません。glibcでは考慮しますが、デフォルトでは無効化されていて、タイムゾーンファイルの指定を変更することで「正しい」時間を表示するように出来ます。する場合としない場合で、2012年現在25秒も違います。なんていうか、...大変ですね(しみじみ)。問題はやっぱりposix標準で「うるう秒を考慮しない」としてる点だと思います。変えられないのが非常に...悔しいですね...。17のChromeでNativeClientが動かなかったので設定することにしました。SELinuxって何じゃらホイSELinuxって名前は聞いたことあって、セキュリティ系の機能らしいというのは知っているのですが、それ以上のことはよく知りませんでした...。いうわけで、調べてみました。セキュアOS機能「SELinux」の基本的な仕組み。古い記事ですが、まあ問題ないでしょう。私の理解したところによると。今までの普通のLinuxには、chmodで設定するような、ユーザーやグループを用いたアクセス制御がありますが、この場合は万が一root権限で動くプロセスを奪取されるとすべてにアクセスし放題になってしまってよろしくありません。いうわけで、SELinuxではそれとは別にプログラム単位で色々な制限を、ファイルへのアクセス制限だけでなく、もっと色々な行動への制限が掛けられるようになっている...ということみたいです。...間違ってたらゴメンネ。httpdにはネットワーク接続の権限が必要だけど、passwdへのアクセスは要らないから、これを制限しよう、という発想だと理解しました。これをTE(Type-Enforcement)と言うそうです。Clientが動かないさて。SDKに入っているexampleを試しに動かしてみましたが...こんな感じで動いてくれません。うまく行くとこうなるはずなんですけどー!で、まずはGoogleで検索してみたのですが、どうやら今回のSELinuxが問題で動かないようになっているようだ、という事が分かりました。■まずは全体を無効にしてみるまずは、SELinux全体を無効にしてみました。Permissiveこうすると全体のSELinuxが無効になります。この状態でさっきのExampleが綺麗に表示されたので、SELinuxが問題だと分かります。あとで有効に戻すには次のコマンドを使って下さい。policycoreutils-guiどうやらChromeにはsandboxとsandbox_naclという2つのドメインが割り当てられているようです(この割り当て自体はFedoraの中の人がやってるようです)。考えても後者が怪しいので、Permissiveボタンを押してnaclの方をPermissiveモード(SELinux無効)にしてみると...やっぱり動作しました。これが問題みたいです。■AuditのログからSELinux用のモジュールを作るSELinuxを一時的に解除して動くようにしましたが、SELinuxはアクセス制御は行なっていませんが、ログを、Auditdというデーモンのログに記録しています。Fedoraの場合は/var/log/audit/audit.logに入っております。このAuditというデーモン、syslogdみたいな感じらしいです。Syslogdよりリッチなシステムらしいです。〜OSレベルの監査ログ徹底活用〜が参考になります。nacl...といったキーワードを調べていくと、chrome_sandbox_nacl_tというのがnacl関連だと思われるので、それでgrepします。/var/log/audit/audit.logさらにこれでログを抽出した上で、audit2allowというプログラムを用いて、SELinuxでの設定ファイル、モジュールを作る事ができます。module名とすると、モジュールのコンパイルもしてくれます。-iを使ってインストールします。chrome_sandbox_nacl.pp以上です。さっきのGUIでnaclだけPermissiveにしていたのを元に戻してEnforcingにしても、ちゃんとnaclが動作するようになるはずです!■モジュールを作らなくても大丈夫な場合もある今回はモジュールを作りましたが、正直言って結構大工事でしたね。それ以外にも、getsebool/setseboolで設定できるフラグや、ファイルのタイプを変更する方法でもSELinuxの制限を何とか出来たりもするようです。■SELinuxは分かりづらい。SELinuxは他のLinuxのデーモンなどと違い、設定ファイルがバイナリにコンパイルされた状態で保存されています。(/etc/selinuc/targetd/以下)。速度が重要な所ですから、多分そのためだとは思うのですが、いまいち分かりづらいです。上記で使ったaudit2allowの代わりに、audit2whyというのを使うと制限された理由を教えてくれたりもするようです。access.Missingって...。Fedoraの中の人のミスじゃないかなあ、これ...。Fujisaki■リリースノートコメントの表示時間に関するバグの修正と、前回言っていた差分による自動アップデータを搭載したバージョンを公開します。自動アップデートを搭載したので、今後のアップデート作業は大分楽になると思います。いえ、最初のバイナリのサイズがまた増えてしまったのですが...。■変更履歴コメントの表示時間がue/shitaと通常コメントで逆になっていた問題を修正しました。自動アップデータを搭載しました(bazaarを利用しています)FFmpegのバイナリを最新のものに更新しましたlibxml2とx264を更新しました。■ダウンロードいつも通りSourceforgeからどうぞなお、zipと7zは内容は同じです。7zのほうがファイルサイズが小さいので7zが解凍できる人はどうぞ。■自動アップデータの使い方Wikiに書いておきましたBazaarの軽量チェックアウトを使っています。従来のSubversionより容量を使わなかったので急遽乗り換えました。前の記事で書いたJavaScriptのファミコンエミュレータ「CycloaJS」を実装する際に使った最適化の手法について紹介します。■関数呼び出し、避けましょうまずはこんな関数から〜。(i&0xfff);}}));}cycloa.probe.measureっていうのは、実行時間を測ってミリ秒単位で返してくれるだけのユーティリティ関数です。最初のベンチマークでは変数に足し算する処理をクラスメソッドに移譲していますが、次のベンチマークでは移譲せずに直接書いてます。こんな例だと馬鹿馬鹿しいですが、規模が大きくなると前者みたいな方式の方が見通しがよくなったりするんですよね...。これを、Chrome21とFirefox14.0.1を用いてログを取ってみました。293関数呼び出しを加えただけでかなり遅くなります。C/C++やJavaのような感覚でgetter/setterなどを作ると一気に遅くなってしまいます。今回エミュレータでは、CPUのエミュレーション部分がメモリの読み書きを行う際のメソッドを、すべてコードジェネレータを用いてインライン展開しています。同様に、その他の通常ならば別のメソッドに分けるような処理も、すべて一つの関数内で行うようにしました。erbを用いて埋め込むなどしてできる限り可読性を下げないようにはしているものの、正直見難くなっているのが実情です...。出しバージョンが極端に遅くなります。思ってプロファイラを有効にすると、なぜか差がでなくなってしまいます...。572として、二度目以降やっぱり関数呼び出しバージョンが遅くなってしまいます。■ローカル変数、使いましょうお次はこのコードです。obj;obj.variable580280this.obj.variable655292ChromeとFirefoxで随分特性が違いますが、できる限りローカル変数を使うのが一番なのは間違いありません。//こちらもローカル変数を参照}};};このように一旦ローカルに保持しています。...これだけでかなり見づらくなるのでおすすめしません...。variable;}のようにして、一旦ローカル変数にコピーして最後に再度戻すといった事もしています。書き戻す前にthis.variableにアクセスすると分かりづらいバグになるので非常に注意です。0;}というようにしてしまっています。すると1番目の関数呼び出しのコストも避けられます...が、まずモジュールごとの名前空間が無くなるため、そこに気を付けなければなりません。今回の例ではVideoとCPUのparameterという変数名が衝突しているため、__cpu__と__video__というように接頭辞を付けて区別してますがあまりにも不毛です。去年書いて駒場祭で作り方に関する本も出した「Cycloa」というファミコンエミュレータを、今回JavaScriptに移植してみました。Egoというアクションパズルゲームを一緒に配布させていただいています(これはオープンライセンスではありません)。エミュレータや、jsnesなどが既にありますが、前者は軽量なもののスプライトの再現で一部端折っているところがあり、また後者は通常のPC用エミュレータと同レベルの正確なエミュレーションを行なっているものの、非常に重くミドルレンジクラスのPCでは60FPSのリアルタイムが出ないという問題がありました。今回のエミュレータでは、通常のPC向けのエミュレーション精度を保ちつつ、どこまで高速化できるのか検証するのを主目的としました。■どれくらい高速化できたのかを確かめてみようというわけで、既存のエミュレータとのベンチマーク取って見ました。ChromeでFPSリミットを外してどれぐらいの速度が出るのかを調べます。AlterEgoの起動画面でのFPSを比較してみました。194fpsjsnesはそもそもこのPCだとリアルタイムで描画できません。Emulatorより遅いですが、このエミュレータよりスプライトの再現性が高いので、まあ良いのかなと...。C++ネイティブの元のエミュレータには全然勝てません。それでも3〜4倍にまで縮まってるのは、流石Chromeと言ったところでしょうか...■ソースコードソースコードはgithubで公開中です。C++版も同様に公開中。■具体的な手法に関してはまた後日ということで...とりあえず、もうJavaScriptはあんまり書きたくないですね...。―より良いコードを書くためのシンプルで実践的なテクニック」。具体例としょーもないイラスト(褒め言葉)を交えながら読みやすくてシンプルなコードを書くための軽い読み物です。■アタリマエのことしか書いてない本当に当たり前のことしか書いてない本です。説明する名前の変数を付ける、tmpとかの抽象的な名前は基本的に避けるべきだけど、スコープが短くて本当にtmpならそれはそれでアリ、一度に一つのことしかしないコードにしないと頭がこんがらがる、短絡評価とかを使った「頭いいコード」は逆に読みづらい、...突拍子のある事は一切書いてなくて、どれも本当に「まあそうだよねぇ」って言いながら読み進められます。...でもその「当たり前」の事が出来ないんですよねぇorz同様の「当たり前の事しか書いてない」っていう理由で「達人プログラマ」は読む必要無いんじゃない?って前書きました。達人プログラマは当時としては先進的(?)な内容を書いていたので今となってはその説明は要らないかな...という感じなのですが、こちらは各々の持ってる「読みやすいソースコードの基準、目安」みたいなものを改めて文章とソースコードを使って説明しなおしているような本で、一種のたたき台として、「あー、前そういうのあったなー」とか「あの前のコード、ここに出てる駄目コードそのものじゃん!」とか、あーでもないこーでもないと昔の所業を懺悔しながら読める本としてお勧めです。■複数人で読んでコードレビューとか楽しそうそんなわけで、会社とかで複数人で一つのソースコードを書いているようなシチュエーションで、コード書いてる人が各々この本を読んで、今までのソースコードをレビューする、みたいな使い方をすると楽しそうです。いう本が無いと何がどう悪いのかを0から説明しなければなりませんけど、レビューする人全員がこの本を読んでれば「ここはさ、あの本の**章に書いてある駄目なコードそのものじゃん?」みたいに簡単に説明できてやりやすそうです。FujisakiupcampというイベントでのLT。Fujisaki■リリースノート公開から2ヶ月以上たったので、バグ修正バージョンのさきゅばす2.0b2を公開しました。バグフィックスのみのバージョンです。その他、NGワードスクリプトのサンプルを増やしたりしたので参考にしてみてください。■変更履歴Pythonを最新版に載せ替え、配布サイズを削減しました。スペルミスなどを修正しました。NGスクリプトのサンプルを追加しました。公式動画をDLできないバグを修正しました。Windowsにおいて、NGスクリプトの改行コードがCRLFだった場合、エラーを発生させないように変更しましたライセンス表示を、配布バイナリ内からWebサイト上に移動しました。■ダウンロードダウンロードはSourceforge内のダウンロードページから行えます。■スクリーンショットようせいさんかわいい...GUIの変更は殆どありません(ぇ■その他registっていう単語は無い(!)そうですが、ねこまたでバッチリ使ってしまっておりました...か、悲しい。ライセンス表示のためにファイルが一個増えてしまって、普通に読まれないReadmeがさらに読まれなくなるのではと思って減らしてみました。一緒に配布してるテキストは見づらいのでできるだけ減らしたいです。