そんな声が返ってくる。まあ無理もない。こんな問いかけにタイムロス無しに具体的な金額を回答する人間のほうが少数派だろう。だからこの反応に私はあくまで寛容だ。
ちなみに、これは私のお気に入り小説の一つ、『三日間の幸福』の冒頭で登場する問いかけだ。図書館にも配架されているので、ぜひ手にとって見て欲しい。
私は今、専攻科に通っている。高専という特殊な環境での生活が始まったのが15歳。今はというとそれから5年と少し経って満20歳。その期間中に選挙権が発生したり、飲酒可能になったりした、などというと大層なことに聞こえるが、実際は5年と少しの年月を過ごして順調に老いているだけのことだ。専攻科1年生というのは大学でいうところの学部3年生にあたる。だから高校1年生相当であるところの本科の1年生にはさぞ「おじさん」に見えているだろう。いや、気を遣わずとも良い。何を隠そう、1年生当時の私の目に映った専攻科生というのは、紛れもなくそうだったのだ。
この6年間は本当に驚くほどあっという間だった。ふと気づけば中学時代からの友人が受験だ大学だと言っていたし、気づけば自分自身が本科を卒業していたし、今だって気づけば2年間しかない専攻科の1年目がその半分を終えて、2017年もあとがきの様相を呈してきている。
何もしていなかったわけではない。
そう、例えば1年生の頃にICT委員会に参加した。入学前、すなわち中学生当時から「技術を学んで立派なプログラマになりたい」という夢があったわけではない。当時、早くに仲良くなった同級生が言った。
「パソコンをカタカタする学校で、パソコンをカタカタする部活が有るらしい、面白そうだ」
「そいつは良い。早速説明会に行こう」
こんな具合である。決して褒められた意思決定ではなかった。それでも「参加」という結果には至った。何かを始める切っ掛けはどんなものでも良いと思っている。それが良かったか悪かったかという議論は、始めてからすれば良い。
話が逸れてしまった。
当時入って何をしていたか思い出すため記憶を遡る。サイコロを数えた。お馴染みのM教材はうさぎと亀のレースを見守るカタツムリ、くらいのペースで進めていたような気がする。そして2年生の時、幽霊部員になった。おや…?回想の雲行きが怪しい。この話はやめよう。
冗談混じりの話ははさておき、私は1年生の頃どちらかと言うとプログラミングよりもWebサイトの作成という娯楽にハマった。敢えて「娯楽」なんて言い方をしたけれど、当時の私にとっては時間を忘れて――実際夜が朝になっていたこともあった――キーボードを叩き続ける、人生で初めての経験だった。訳の分からない呪文を、黒い画面に、慣れない手つきでひたすら打ち込んでブラウザで開く。するとそこに「世界でたった一つだけ」のWebサイトが姿を見せる。たまらなく新鮮で爽快で、素晴らしい体験だった。
幽霊部員になってから3年生くらいまで、Webサイト作りに没頭した。一人複数役のチャットや、誰得ニュースサイトもどき。そういうガラクタを積み上げて、ある日、テスト対策を主名目としたサイトを立ち上げてPDFやノートの写真をホスティングした。それなりにウケが良かった。と言ってもサイトの使い勝手とかデザインとか、そういうところではないだろうが。そんなことは問題ではない。
「自己満足に浸るだけ状態」だった私は「人に見られる・使ってもらうこと」を知った。
2年生になってからは学生会の広報局という局に所属していたこともあって、校内行事の特設サイトを作ったりもした。それは4年生まで続いた。その他にも、Twitterのbotだったり、アンケート集計のアプリだったりメールクライアントだったり色々と「誰かに使ってもらいたいガラクタ」を生成し続けた。
それを見たり、使ったりしてくれた人から意見をもらえることがあった。「面白い」「すごい、楽しい」といった言葉に舞い上がり、「重い」「見にくい、使いづらい」といった言葉で反省する。このような浮き沈みは、プログラムを公開しないことには体験できない。何かプログラムがあった時、それが神プログラムになるのも、はたまたクソプログラムになるのも、全て公開された後の話だ。あらゆるものは評価されて初めて認識される。
勘違いしないで欲しい。私は何も「公開せずに一人で作り一人で使うことが悪だ」と言っているわけではない。あくまで、「公開することによって、そうしないことと比べてこう違うのではないか」と持論を述べているに過ぎない。一人で作って満足していた時代の成果というのも見えない形で、つまり自分のスキルアップという形で確実に活きている。
「それで、君は結局何の話がしたかったんだい?」
そう思われても仕方ないな、と一旦思考を落ち着ける。
言語化に失敗し、脳内に取り残されてしまった電気信号が、話が長くなるに連れて蓄積されている。良くない癖だ。
「でも君がそう感じられるのも、私が記事を公開して、それを君が読んだからなんだよ」
「無茶苦茶だなぁ」
認識されるためには評価が必要だと言った。
人生もそうなんじゃないか、と思う。誰かが自分を評価することで、認識され続ける。「自分を覚えている人がいなくなった時、人は本当に死ぬ」というのはよく聞く主張だ。それが良い評価か悪い評価かということは、さしたる問題ではない。認識されている間、自分を認識する誰かの中で生き続ける。
インターネットで世界中と繋がる現代、認識されるハードルは昔に比べて遥かに低くなった。今や小学生でさえもスマートフォンを自在に操り、世界にその足跡を残すことができる。
『自分の人生には、何円くらいの価値があると思いますか?』
冒頭で小出しにした小説『三日間の幸福』の中では、その原題『寿命を買い取ってもらった。一年につき、一万円で。』にもある通り、主人公は「一年につき一万円」という寿命の査定を受けるシーンがある。
自分はどうだろう?自分の人生がいくらであるか、自分一人では分からない。だが、全ての人は評価(小説内いう査定)を受ける権利を等しく持っている。
私はこれからの人生においてもきっと、その権利を副次的に行使する。作りたいと思った時にガラクタを作り、それを公開する。
そうすることで私は今日も、そして明日からも生を実感していく。
こんばんは、wassan128です。
この記事はICT Advent Calendar 2017 24日目の記事になります。
今ハッカソンからの帰りの機内でこの文章を書いているのですが、悪天候のせいか、離着陸前後にめちゃくちゃ揺れていて怖いです。あと酔う。
実はAdvent Calendarという文化に参加すること自体が初めてで、「何々Advent Calendar N日目の記事です」という文言をブログに書くだけでも緊張で手が震えてしまいます。それなのにこんな駄文を書いてしまったのはきっと夜だから。そう夜が悪いのです。僕はそんな夜が好きです。
明日はこのカレンダーの火蓋を切ったその人、委員長の記事です。一日目の記事は「世の中ままならないですよね、ママだけに」などと言いながら読んでしまい、申し訳ありませんでした。次の記事はきっと真面目に読みます。
以上です、駄文にお付き合い下さりありがとうございました。
昨日今日(10月21日, 22日)の2日間、KOSENセキュリティコンテスト2017が木更津高専主管で開催されていました。実は去年もKOSENセキュリティコンテストに参加していましたが、今回は前回大会と競技形式が変わり、Jeopardy(クイズ)形式とKoH(King of Hill)形式というラインナップでした(KoHなどの解説はこちらなどを参照ください)。
私はチームEAnbai(いつもの)のメンバーとして参加し、JeopardyのWeb問題などを解いたり、KoHを触ってみたりしていました。一日目を12位で折り返したチームの最終成績は35チーム中5位で、惜しくも表彰には届きませんでしたが、記憶に新しい内に解いた問題のwriteupや反省をしたいと思います。
問題のURLが渡されるのでアクセスをすると、ログインフォームが出てきます。すると「adminでログインしてね」(記憶違いかもしれない)と言われるので、ユーザー名に「admin' or 1=1 ---
」を入力したらフラグが出ました。
先程の問題と同じようなログインフォームが出てきて、その下の方にそのロジック部分風のソースコードが貼ってありました。adminのパスがフラグ、となっておりさっきよりは複雑なSQLi問なのかな?と思いながらソースを眺めていたらデータベースを読み込んでいる部分が目に入り、おもむろにURLに「/data.db」をつけたらデータベースが降ってきました()
それをsqlite3
で開き、.ta
するとユーザーのテーブルが見えるのでselect * from users
するとフラグが見えました。灯台下暗し…。
難読化されたJavaScriptのファイルが見えるページで「deobfuscate js and find the key」と言われるのでどのツールで難読化されたのか知ろうと思い「”___=window;”」みたいなキーワードで検索すると、jsrollerというのが出てきて「これかなぁ」と思って見たものの、「これ難読化解除機能ない説ある…?」となりました。仕方がないので難読化されたままのコードをBeautifyして夕食後に見直したらなんとなくやってることの雰囲気がわかったので、キーを計算していそうな所にconsole.log
を挟み、DOMがloadするまで待つみたいな処理を消すなどの調整をいくつかして開発者コンソールで実行したらフラグが見えました(調整後のコードは以下)。
|
|
他のフラグはleetっぽい雰囲気ある中でそうではなかった上、「フラグの文字列ハードコードされてるんかい!」という気持ちになり、submitするまで合っているか不安な問題ではありました。
JavaScriptの穴埋め問題みたいな感じになっていて、10個あるピースを全て正しく配置してalert(1)
されたときのコードの(?)ハッシュ値がフラグ、という問題でした。
「eval」「call」「(0o000101)」などがピースになっていて、「alert」という文字列を2進・8進・16進文字で表したやつを連結して小文字にして…という意図がわかってからは開発者コンソールでぽちぽちと試しながらやりました。
|
|
Weak RSA1はチームメイトに任せてこっちをやっていました。公開鍵(N, e1)、(N, e2)とそれらを使って暗号化されたc1, c2が渡されました。また問題文中に「Same modulo, diffrent key.」とあったのでCommon Modulus Attack(こちらが参考になります)か~ということでpythonでdecryptして出てきた値をbinascii.a2b_hex(n[2:])
したらフラグが出ました。
この他にもいくつか分業的にJeopardyの問題を触ったりしましたが、KoHについてはほぼ手が出ず、辛かったです。
チームのバランス的には結構良く、比較的きれいに分業できていたのでその点は良かったと思いますが、KoHや難易度の高い問題に取り組んでいる時の自分含めた各位の進捗具合の把握などはまだまだ課題かなと感じました。
また個人的に、暗号も面白いな~と感じることが多くなってきたのでちゃんとできるようになるためにも数学を勉強し直そう…と思いました。
簡単ではありますが、以上です。
チームメイトの皆さん、担当教員の先生2日間ありがとうございました。
去る10月8日~10月9日に開催された「プログラミングコンテスト(通称: プロコン)」の自由部門本戦に参加しました。結果は敢闘賞でした。数カ月に渡ってチームで企画・開発を進めてきましたが、この経験を忘れないように簡単な参加記を残したいと思います。ところどころ内輪でしか通じない部分もあるかと思いますがその点はご了承いただき、温かい目で見ていただければ幸いです。
さて、本戦終了から1週間ほど経ってはしまいましたが、時系列順に回想を初めていきます。
年が明けてすぐ(つまり、まだ高専本科5年の時)、某M教授からプロコン参加のお誘いをいただきました。正直な話、最初話を聞いたときは卒研やセキュリティの勉強の方に気持ちが行っていたのであまり乗り気ではなく、かなり迷いました。ただ本科自体に参加した経験がなかったり、専攻科でどのような人生を送ろうか考えている時期でもあったので「まあやってみるか」くらいの気持ちで参加意志を表明した記憶があります。
この頃既にチームメンバーの構成などを大まかに聞き、コミュ障の僕は餅を食べながら震えていました(1月なので)。
「さて実際に何を作ろうか」ということを考えるこの期間ですが、アイデアの欠片が出てはダメ出しを食らい、という日々でした。個人で趣味の開発をするときはあまり深いことは考えず、「とりあえずこんなの作ってみるか~」くらいのノリで進めるのでやはりこの段階では結構苦戦しました。
アイデア出しにおいて良かったことはSlackを活用して、とりあえずアイデアの卵をたくさん出してみる、ことが出来ていた点です。ちょうどアイデア出し開始より少し前にSlackにスレッド機能が実装されていたので、1日1レス目標を立ててアイデアの卵を皆で生み出していました。良くなかったのは、このアイデアの卵を育てきれなかった点です。たくさん出たアイデアの卵の中から自分の一番好きなものを挙げて、それを1日1個ずつブラッシュアップ方式を取っていましたが、1日と言っても放課後の時間は限られており、アイデアを育てるのには十分な時間が取れていなかったなと感じています。
とは言ってもアイデアの卵たちもそのまま時の狭間へ――というわけではなく、趣味での開発には面白そうなものもいくつかあったので時間を作って掘り出してみるのも良いかなと思います。
結論から言うとアイデア欠乏によりチームが他チームに吸収合併されることになりました。この時にチームを離れていくメンバーもいて、正直僕にとっても迷い2という感じの心境でした。この後さらに様々な話し合い、感情のゆらめきを経て僕が新チーム(?)のリーダーを務めることになりました。チーム「サーモン焼いたらシャケ」が爆誕します(このチーム名が発案されるのはこれより少しあとのことだったとは思いますが)。
チーム開発、リーダー業…。正直不安しかありませんでした。しかしこの時既に予選資料提出が近づいていてそれどころではなかったので、アイデアの整理をチーム内でしながら予選資料作成までなんとか持っていけました。提出ギリギリまでSlackでああでもないこうでもないと言いながら作業したのは結構楽しかったです。
予選を通過しました。
ここまで触れていませんでしたが、サーモンでは「2機のドローンとヘッドマウントディスプレイを用いた立体視」をテーマに開発を進めていくことになります。
予選結果発表までは空白だったわけではなく、システム構成の見直しをしたりしていました。今思えばこの時期にお買い物フェーズ完了、個々のテストくらいまで出来ていると良かったのですが、この辺は予選結果によっては考えものなのでジレンマだな~みたいな気持ちです(ドローンなどの購入は予算を大幅にドロンする可能性があったので)。
「アイデア出しは辛いが、開発さえ始まればどうにかなるだろう」と思っていた時期が僕にもありますた。
まずお買い物フェーズで失敗を重ねてしまいました。ドローンが発注から配達完了まで1ヶ月近くかかる事実の発覚や、小道具的機器の発注ミスなど痛手が多かったです。発注したと思い込んでいたものが実際にはしていなかったり、購入物品の仕様の確認が足りず届いたものが思っていたのと違うといったことまであり、かなり辛かったです。結果、元々委員会で保有していたヘッドマウントディスプレイやRaspberry Pi関連以外の開発が大きく遅れることになりました。
そのようにどったんばったん大騒ぎをしつつ、僕はヘッドマウントディスプレイへの映像描画を主に担当していました。ヘッドマウントディスプレイにはOculus Riftを使っていて、SDKやAPIも提供されていたのですんなり行くかと思いきや学内ネットワークでのランタイムや開発環境セットアップ、そもそもリソース大食漢であるところのOculus Riftを満足させられるだけのPCの用意など罠が多く仕掛けられていました。この実にVIPな立ち振舞には頭を抱えましたが、某あっちー先生にかなり支援をいただいてどうにかスタートラインに立つことができ、圧倒的感謝の気持ちで不可視の涙を滝のように流しながら開発をはじめました(本当にありがとうございました)。
さて、初めはVisual Studioを使ってC/C++で開発を進めようと思っていたわけですが、これが謎のエラーや環境的な問題で進行できなくなり途中で方針転換をしました。たられば話になりますが、この方針転換はもっと早く実施するべきでした。Python用に作られたAPIのラッパーライブラリを発見してから数日で進捗が出ました。ここから「映像の取り込みにはOpenCV」「描画にはOpenGL」の構成で本格的に開発に取り掛かりました。この時既に9月。焦りとバグしかありませんでしたが、どうにか映像を描画することが出来たときはかなりホッとしたのを覚えています。映像をテクスチャとして貼り付ける方式でしたが、ひとまず映像が描画できるようになって暫くの間左側のレンズだけ貼り付けがうまく行かず「鈴カステラ鈴カステラ」と言っていたは今となっては良い思い出です(これはライブラリがハードウェアから取得してくる初期パラメータが破損していたのが原因だった)。
こうして思い返してみても本当にヘッドマウントディスプレイに時間がかかりすぎて無限に辛いです(僕の中では夏休み突入前に終わっていたかった)。僕が鈴カステラと格闘している間、他のメンバーには分業でドローンをやってもらったり、その電源系をどうにかしてもらったり、シンクロ飛行のための超音波・画像処理をやってもらったり、また夏休み期間中にパンフレット原稿の提出も控えていたので、そちらをやってもらったりしていました。進捗が順調なタスクもあればそうでないタスクもあり、特にドローンは知見があるメンバーがほぼ皆無だったのでなかなか思うように行きませんでした。この辺のタスク振り分け的なところもにわかリーダーであるところの僕の甘さが出てしまって、負担が大きすぎるメンバーが出たり、逆に何をしたら良いかわからない、というメンバーを出してしまい、チーム開発の難しさを痛感しました。ただ、基本的に開発期間中は和気藹々と作業できていた(ちょっと騒ぎ過ぎなぐらいw)のでその点は良かったと思います。デスマデスマと世紀末のような感情で作業するよりもよっぽど良く、これはチーム開発のある意味醍醐味(なんか語感良いなこれ)なのかなと思ったりしました(一人のときは静かに開発するので)(これには多少嘘が含まれています)。「うるせぇ!」と思っていた皆さん、いたらごめんなさい。でもこれもあったから楽しく開発を続けられたと思うんです。
気づけば夏休みも明け、9月末があっという間に過ぎ、10月に突入しました。プロコン本戦に向けて展示用のポスターを作ったり、マニュアルを書いたり、配布用パンフレットを作ったり…という時期です。このあたりはチームメンバーに助けてもらいつつ開発もギリギリまで並行してやっていました。サーモンは全体的に提出物も含めてギリギリになることが多く、添削をしていただいた教授にも負担をかけてしまったなと反省しています。
今回開発を進めていたシステムは一部を事前に海上である山口県へ輸送する必要がありました。この時点でヘッドマウントディスプレイの調整は半強制的にできなくなり、UI部分のプログラムは開発半ばで送られていきました。
このあたりから流石にプレゼンのことを考え始めました(またしてもギリギリ)。僕は原稿を作って読むのが苦手(実はこれの根っこは中学時代の意見文発表会にあるのかもしれないと思った)なので、ひとまずスライドをバーっと作って「よしよし」とか言って眺めていた記憶があったりなかったりします。
(記事的な意味で)やっと本戦です。実際には木曜の夜にやっている衝撃映像を流したりする番組タイトルみたいな心境で飛行機に乗り、寝不足の頭を低速回転扠せながらプレゼン資料を見たり、半ばで送られてしまったUIプログラムの合体用調整をしていました。
山口県は思ったより暑かったです。翌日のプレゼンでのスーツ着用にいささか以上の不安を感じながら、Day0の夜はプログラムの調整とプレゼン資料を読んだりしていました。
プレゼン当日は午前中ホテル残留組となり、会場先発メンバーから「システムが動かない」という電話を受けて青くなりながらプレゼン練習に使いました。スライド自体はある程度出来ていても時間調整がうまく出来ていなくて不安がありました。不安しか感じてないなこいつ。そんなこんなで午後になり、一足先に社会人勢となった激強同級生から貰ったウィダーインゼリーを飲んでいました。そうこうしている内に発表時間となり、自分の前2人のプレゼンを予想以上に暑い会場で聞いた後、どうにか8分を乗り切りました。質疑応答も含めて終了後に教授に言われた「あのごまかし力はすごい」という言葉は良い意味でも悪い意味でも忘れられません。プレゼン後は一般公開の方の手伝いをしたり、他チームのプレゼンを聞いたりして会場でのDay0は終了しました。
夜は翌日のデモ・マニュアル審査に向けて、ストーリーを皆で考えたり、WIP状態で搬送したUIプログラムの調整をしていました。ちなみに魔剤完飲デビューを果たしました。
朝一でデモ審査が一つ入っており、システムのセットアップをしていました。しかしここでヘッドマウントディスプレイの接続が認識しなくなる、という問題が発生しました。ディスプレイ表示用にもう一つポートがあったので、1つ目のデモ審査はディスプレイに画面を表示してEnterキー押下でプログラムを実行できるようにし、ヘッドマウントディスプレイを接続してプログラムを起動する方式で行いました。が、デモ用に用意していた動画が短かったこともあり、思うように出来ないまま終わってしまいました。それからも原因究明に取り組み、その間にもデモ審査が入り、グラフィックボードが認識しなくなり(接触不良?)、デモ審査が入り、結局描画が正常に出来ないままマニュアル審査まで終わってしまいました。ドローンは会場で飛ばすことが出来ないので、デモ・マニュアル審査の肝はヘッドマウントディスプレイによる立体視であり、これが動かなかったのはとても大きな痛手でした。審査員に「今見れない状態です」という説明をしなければならなかったことが、本当に悔しかったです。この件において良くなかったのは、ヘッドマウントディスプレイが接続できる代替PCを用意していなかったことです。ハードウェアのリソース要件が厳しいことは予めわかっていたので調達が難しいのは飲み込んで、どうにかしてでももう1台は用意しておくべきでした。あとは、変換を噛ませすぎていたことも良くなかったことの一つで、後からわかったことなのですがDisplayポートとHDMIの変換コネクタが故障していたのが描画出来なかった直接の原因でした。この他にもミニディスプレイにミニHDMIとHDMIの変換を使ったりしていたので、今から思い返してみればどうしてこんな綱渡り構成にしてしまったのか、と悔やまれます。
接続がうまくいなくなってからの作業中、ディスプレイ自体を貸してくださった企業の方、ディスプレイの変換コネクタを貸そうとしてくださった他高専の方、電源関係のテストをさせてくださった隣ブースの高専の方、本当にありがとうございました。
午後の一般公開、閉会式を経てプロコンは終了したのでした。
失礼しました、乱文が出てしまいました。
最後まで読んでいただいた方にはおわかりの通り、とても反省点の多い、しかしそれだけに良い経験となった、そして何より楽しいプロコンでした。基本的に「何が起こるかわからない」のが世の常で、「時間」にしても「物品」にしても余裕を持ってやっていくことの必要性というのを再確認しました。閉会式の時の「ここはプログラミングコンテスト。物をしっかりと作れないと」という言葉が胸に刺さりました。自分たちで開発をやっている間というのは、どうしても盲目になってしまいます。そこでどうにか視界を広げて(それこそ立体視でもして)、何が求められているのか、本当にこのやり方で良いのか、そのあたりの見つめ直しというのを心がけていきたいものです。
サーモンチームのメンバーには感謝してもしきれないです。このようなへっぽこリーダーについてきてくれて、ありがとう。「大変だったことほど、後から思い返すと楽しかった記憶として回顧される」と言ったものですが、企画書を書いたり、プログラムを書いている時間というのはそういう意味でもそういう意味を抜きにしても純粋に楽しかったです。
プロコンに誘ってくださったM教授、ありがとうございました。チーム合併のときに「なぜ僕はプロコンに参加しているのか、わからなくなってきた」と言った時に、プロコンにお誘いをいただいた真意(?)をお話いただいた時の会話は僕がプロコン続投の心境に立ち直るにあたって大きな要素でした。他にも機器やアドバイスなど多大な支援をいただいたあっちー先生、ドローンに関する知見を多く頂いたsryn先生、ドローン研の皆さん、そして幼稚園状態のサーモンを温かい目で見守ってくれ、見事特別賞を勝ち取った回らない寿司屋の皆さん、関係各位の皆さん本当にありがとうございました。
長くなってしまいましたが、この拙文回顧が僕にとっての戒めとなり、時々読み返しては懐かしさを感じる娯楽となり、そして少々の高望みが許されるのであれば、今後のプロコンメンバーにとっての参考やモチベーションとして少しでも貢献できれば光栄です。
以上です。
]]>去る23日、沖縄コンベンションセンターで10回目(記念回!)の「Hardening 1010 Cash Flow」が開催されており、そこに参加しました。チーム「術中Hack」のメンバーとして参加し、グランプリをいただきました。記念回に初参加で参戦できただけでなく、10時間という今までにない競技時間を体験できたり、ラスト(?)沖縄回に参加できたり、グランプリをいただけたりと、本当に参加できて良かったと思えました。運営の皆様、MPの皆様、術中Hackの皆様、その他すべての関係者の皆様に感謝しております。
本記事ではチームのことや僕が競技中にやったことのメモを残したいと思います。
文字通り「堅牢化」を行う競技です。では何を堅牢化するのか?というと「ECサイト」やそれに関連する「サーバー」です。予め脆弱性の仕込まれた環境・ECサイトを安全な状態にし、攻撃者の手に落ちないよう守り、そして売り続ける――概要はこんな感じです。詳しい説明は公式サイトをご覧ください。
6人で構成された今回のチームは、内4人が沖縄高専からの参加ということで社会人が多く参加されるこの大会においては平均年齢が若いチームでした。とはいえ社会人の方がチームのリーダーやまとめ役を引き受けてくださり、とても安心感のある、居心地の良いチームでした。
高専勢は比較的集まりやすかったこともあり、話し合いをしたり情報共有をしたりしました。チーム全員での集まりはHardening Day前日の22日に行われ、そこで翌日の競技に向けて懇親を兼ねて戦略を話し合いました。この時点でのチームの方針は「初手借金、投資重視」でした。
それ以前はチームリーダーが爆速で作ってくださったSlackで情報共有をやったり、trelloでタスクの整理をしていました。
僕は競技中主に「Webコンテンツの管理、脆弱性修正」を担当していました。開幕後各サーバーに接続できてからはユーザー(root含めて7個くらい?)のパスワードをデフォルトから変更したり、ECサイトはどんな感じなのか実際に見てみたり、WordPressの管理者パスワードを変更したりしました。
またWordPressには今回出るかなーと思い予習していたWordPress4.7.1の権限昇格の脆弱性で話題になったバージョン4.7.1が使われていたので、WordPressのソースコードを改変して対応しました。多分、ちゃんとこの段階で作業をしたECサイトについては攻撃を先回りで回避できたと思います(真相は不明)。
ここまでは比較的平和でしたが、お昼を食べ終わってしばらくしてからバックドアが置かれていたり、修正漏れのあったサイトが改ざんされたりしました。不要なディレクトリの移動などはこの辺りで行ったと思います。
この後個人情報漏洩()があったりしましたが、MPの方が教えてくれた「OSコマンドインジェクション脆弱性を含むサイト」のソースコードを修正したり、ところどころCSSがおかしくて見にくくなっているサイトの修正を行ったりしました。
競技終了の数十分前からはMP製品画面、実際の画面、端末などとにらめっこするまさに死活監視を行っていました。
10時間の競技が終了した瞬間はかなりほっとしたような感覚になっていました。
脆弱性を予習していて良かったです。サイトが改ざんされたりシステムが壊されたときにどうしてそれが起こってしまったのか、あたりがつくかつけられないかでかなり気持ち的なところに差があったと思います。予習では実際に自分で環境を作り、脆弱性を検証し、ソースコードを修正して攻撃が通用しないことを確認、というところまでの一連の流れをやっていたので本番でも流れがなんとなくつかみやすく、それなりにスムーズに作業できたと思います。
また、お昼のバーガーが美味しかった点が挙げられます。
サーバーのパス変更や脆弱性修正が漏れていた所がありました。中盤~になってその穴を突かれたりしてしまったので、競技環境資料をよく見ながら最初の段階で注意深く確認を行うべきだったと思います。また、脆弱性だけでなくサービス自体の使用を通してノウハウを増やしておけばよかったなと思いました。WordPressなど普段使わないサービスをもう少し触っておけば、管理者パスワードの変更やユーザー登録ボタンの削除などの作業がより円滑になったと思います。この他にも設定ファイルで失敗したり、コマンド慣れが足りなかったりとまだまだ技術的な部分やそうでない部分で自分は未熟だなぁと感じる点が多くありました。
また、お昼のバーガーを急いで食べてしまった点が挙げられます。
チームメンバーに恵まれ、MP(製品と担当者の方々)に恵まれ、運にも愛され、グランプリという結果をいただきました。10時間という競技時間は今思えば長かったようで短かったですが、その中で得た学びはとても多かったし、何より楽しかったです。「売上を意識すべき競技」や、セキュリティベンダーの製品を実践的なシチュエーション下で使わせて頂ける、こんな体験はなかなか学生という身分ではできないなと思いました。
貴重な体験をさせてくださり、本当にありがとうございました。
どうも、EAnbai『Web』担当(自称)です。もうしばらく前の話になってしまいましたが、picoctf2017にいつも通りEAnbaiで参加していました。Web問題メインで取り組んだので、解くことができたWeb問をメモしておきます。
問題のサイトを見ると、良い感じのサイトが出てきます。ソースコードを見ると下の方にコメントで
|
|
と書かれているので、他のファイル(cssやjs)も探索すると同じようにパーツが出てきてそれらをつなげるとフラグになります。
ログインフォームが出てくるのでインジェクションするとフラグがもらえます。
Oh, sweet, they made a spinoff game to Toaster Wars! That last room has a lot of flags in it though. I wonder which is the right one...? Check it out here.
こんな感じの問題文で、リンクを叩くとゲームが始まりました(図1)。クライアント側からは特に有用な情報を見つけられず、問題に付されているヒントを見ると
I think this game is running on a Node.js server. If it's configured poorly, you may be able to access the server's source.
とあり、なるほどpackage.jsonとかが見えるのか、というあたりを付けることができました。実際に「/package.json」としてみるとサーバー側のソースコードがserverディレクトリで管理されており、起動時はserv.jsが実行されていることがわかりました。
|
|
ここからはサーバー側のソースコードを読む作業で、serv.jsから辿っていくと複数のソースコードが見えました。
ところでこのゲームは1F~4Fのフロア構成になっており、4Fに行くと沢山の旗がキャラクターが取得・使用可能なアイテムとして置いてあります。問題文でも「正しいフラグはどれ?」と聞いているので、それがわかりそうな情報を探すという方針で間違いなさそうです。
さて、ソースコードを少し読むと、このゲームの実装にはsocket.ioが使われており、いくつかあるメッセージの中に「revealFlag」と言うものを見つけることができました。そしてどうやら何らかのアクションを起こせばこのイベントが発生して、PICO_CTF_FLAGという名前の環境変数に書き込まれているフラグを読めるようだ、ということがわかりました。
|
|
さらにソースコードを見ていくとステージ情報が定義されたファイルが含まれており、その中でも特に例の4Fの旗アイテムを使用すると全アイテムロストもしくはrevealFlag effectが発生する、つまり正しいフラグを取得・使用すれば正解を見ることができ、間違えればその機会が潰えるということがわかりました。使用されたフラグアイテムが正しいフラグであるかはrevealFlagメッセージを処理するコード部
|
|
で確認していることがわかるので、あとは普通にゲームを進めて正しいフラグを取得し、使用するとフラグを見ることができます。
開くと「Access Denied」と言われるのでソースコードを見るとコメントでcookies.sqliteというファイルにクッキーを隠してるから安全だぜと言った趣旨の文章が書かれていて、/private/cookies.sqliteにアクセスするとダウンロードすることができます。この中身をsqliteを使って見てみるとそれっぽい文字列が入っているのが見えるのでこれを問題サイトのIDというクッキーを書き換えて設定、再アクセスするとフラグがもらえます。
開くとLogin/Registerボタンが出てきて、流石にlevel1の問題のようには行きません。とりあえずhogeみたいな適当なアカウントをRegisterしてLoginすると何かポストできるページが出てきます(図2)。
問題文からSQLのunionを使ったSQLiであることが推察でき、色々試しているうちにユーザー登録時にSQL命令を混入させることでログイン後のページに情報を表示させることができそう、ということがわかりました。ということでまとめると
という手順で解けます。
しかしまだどのtableにユーザー情報が格納されているかわからないので、unionを使って情報収集します。ここで問題文のI like lite sql:)
という部分からデータベースにsqliteが採用されていることが窺えるので、sqlite_masterテーブルから情報を抜き出します(図3)。これでusersテーブルと言うものが存在することがわかりました(ユーザー登録時のSQLによってエラー情報を表示(サーバー側でエラーを吐くようになっている)させ、ポスト部分のtable名「posts」をリークし、そこからusersテーブルの存在をエスパーする方法もある)。あとは前述の手順に従ってusersテーブルから情報を抜き出すSQLを混入したユーザーでログインすればフラグが貰えそうです。
詰まったところとしてはユーザー名部分でSQLを組み立てる時にシングルクォーテーションを意識しなければならない点、カラム数を合わせる必要がある点でした。前者はコメントでは回避できなかったので、pass取得のための命令の後に
|
|
を付け加えて回避しました。後者は最終的にnullをselectのリストに加えることで回避しました。この手順を踏むと無事フラグを取得することができました(図3)。unionベースSQLiの内容把握にあたり、このあたりなどを参考にしました。
気合いを入れて解いたのはTW_GR_E1_ARTとHappy Unionで、それ以外の問題は割りとサクっといきました(というかTWはゲームを進めてフロア4まで行くのが普通に楽しかったので遊んでしまった)。特にHappy Unionが解けた時はEAnbai『Web』担当を自称しておきながら今まであまりちゃんとWeb問を解けなかったので、嬉しかったです。ただLevel3の残り2問と4のWeb問などまだまだ解けていないものがあるので、精進します。
あとpwnもそろそろちゃんとできるようになりたいので、チーム内でpwnable.krの問題を解いたりしていますがpicoctfの問題も難易度が良い感じなのでwriteupを適宜見ながらやっていきたいです。
以上です。
]]>2017/02/03 19:00~2017/02/06 17:00(日本時間)、AlexCTFがアレクサンドリア大学主催で開催されていました。例によってチームEAnbaiの一員として参加し、チームとしては1190ptで215位(/1029?)で終了しました。以下、解いた/取り組んだ問題について簡単に書きます。
Stringsコマンドで文字列を見るだけで終わり。
Flag: ALEXCTF{Y0u_h4v3_45t0n15h1ng_futur3_1n_r3v3r5ing}
USB通信のキャプチャが渡されるのでWiresharkで確認する。どうやらUSB_BULK outというのが怪しく、データが入ってるっぽい。いくつかあるが、その中にそれらしきものを見つけた。
|
|
先頭2byteを見るとどうやらpngっぽいのでファイルにして中身を見る。
|
|
Flag: ALEXCTF{SN1FF_TH3_FL4G_OV3R_USB}
Flag: Heartbleed
AlexCTFのページにロゴにフラグが隠されているので探してね、という問題。
フラグをテキストで保存し、vimで以下の置換を適用。
|
|
Flag: ALEXCTF{OUR_LOGO_ROCKS}
pycが渡されてフラグを探す問題。pycdcを用いてPythonソースコードを復元した。
|
|
|
|
フラグを5文字ずつに区切ってMD5ハッシュにしたものをソースコード内に保持しているので、ソースコード内のmd5ハッシュを復元すれば終わり。onlineのデコードサイトでdecryptしたものをつなげて投げたものの通らず、何でだろう…と思っていたら7つ目のハッシュが1文字足りていなかった。チームSlackに投げたところ先輩が解いてくれたので結果オーライ(とは言え悔しいので精進します(´・ω・`))。頭に0をつけるだけの発想がどうして出てこなかったんだろう…。
僕「CA issueって言ってるし何か問題あるんじゃね!?」
sio「issuedだと『発行する』の意になるってよ」
僕「魔剤!?(カチカチ…)letsencrypt」
> フラグだった <
問題文適当に読みすぎた。英語勉強し直したほうが良い。
これはCTFに限らず、自分で箱を作ってその中で考えるのではなく、試せるだけの可能性を試すことが大事だと感じました(特にfore3)。
また、暗号系の問題を先輩に任せっきりなので、どうにか来年は暗号系もある程度解けるように真面目に数学勉強し直そうと思いました。
以上です。
2016/12/10 15:00~の24時間、SECCON 2016 online CTF(オンライン予選)が開催されました。私はチームEanbai(先輩、同級生、私の三人)として初参加を果たし、チーム得点は500点、順位は1834チーム中159位で終えました。
ちなみに12月10日はやんばるツーデーマーチというウォーキングイベントも開催されていて、例年通り私は40kmコースに友人たちと4:00~15:30まで参加してからのSECCONログインだったので身体も頭もくたくたになりましたが、どちらも楽しかったです。
では早速、解けた問題のWriteupをば。
|
|
シンプルな問題文にbinというファイルが添えられていました。fileコマンドで何のファイルなのか確認すると
|
|
とのことだったので、ひとまず拡張子をexeに変えて実行します。すると、「Input password >」と表示されて入力待ち状態になります。適当に「hogehoge」とか打つと「password is wrong.」と怒られてしまうので、ひとまず次の手順に従ってパスワードを入手しました。
1はIDAで確認しました。この時ついでにIDAが吐いてくれるアセンブリのグラフビューを眺めてbinがどのようなプログラムになっているのか、大きなプログラムでもなかったので大まかに把握しました。2、3までやったところで、パスワードが「I have a pen.」であることがわかりました。流行を抑えていくスタイルなんですね。正しいパスワードがわかったのでもう一度プログラムを(デバッガ無しで)普通に起動して打ち込んでやると今度は「Your password is correct.」と言われてプログラムは終了します。やったぜ!…ところでフラグは?デバッガでどうなっているのかもう一度見ていきます。
そして、ここから問題名にもある通りAnti-debugとの戦いになります。ollydbgで掴んだ状態でもう一度I have a pen.を唱えると今度は「But detected debugger!」とも言われるようになりました。該当部分のコードを確認すると、どうやらIsDebuggerPresent関数を使って自分自身がデバッガに掴まれていることを検知してフラグを守っている健気な姿が見られました。
これを突破するためにOlly AdvancedというAnti-Anti-debugを実装したプラグインがあったので、それを使おうと思ったのですが、IsDebuggerPresentの次のNtGlobalFlag隠しを有効にしても突破できず、その後は結局手動でバイナリを書き換えていきました。ちゃんと読まないでプログラムのバイナリを書き換えるのはあまりよろしくないですが、Anti-debugに関しては少しの命令を実行して、その結果レジスタにロードされる値などを元に検出を行っているものが大半なので、cmp命令の部分をnopで埋めればプログラムの大元の動作を破壊することなく突破できてしまいます。
例えば、先程のNtGlobalFlagもcmp命令をなかったことでJNZ命令に引っかからなくなり、スキップできます。少なくとも今回のバイナリに関しては手元で試した全ての検出手法がこのcmp2nop(勝手にそう呼んでる)でスキップできました。
ただ最後の最後、(暗号化された)フラグっぽい文字列がollydbgでも見えるようになってきたところで0と1を比較して違ったらフラグ見せない、みたいな処理があったのでそこは比較結果が一致になるように改変して突破しました。
全ての検出機構を無事突破し、フラグの復号処理を抜けたら終わりです。ちなみに出てきたフラグを見てもわかりますが、Ascii85というエンコード方式なんだそう。へー。また一つ知見を得ました。
以上、pafish.exeが頭に浮かんだ状態で終始取り組んだ問題でした。
Flag: SECCON{check_Ascii85}
メモリダンプのファイルが渡されて、中身を解析してフラグをくれるWebサイトにアクセスしてね!という問題。ヒントが2つ与えられていて、とりあえず1つ目のヒントに従ってVolatility(公式サイトリンク)というフォレンジックツールを導入しました。CUIツールで、引数に色々とオプションを付けるとよしなにやってくれる良い奴です。下記の例では、imageinfoオプションを付けて推奨Profileを調べています(このダンプファイルはWinXPSP2x86でやっていけば良さそう。後でも使います)。
|
|
さて、2つ目のヒントにhostsを見ろと書いてあったので、とりあえずファイルのダンプの仕方を調べてやってみます。
|
|
これでカレントディレクトリにfile.None.0x819a3008.hosts.datみたいなファイルが生成されて、この中身を見ると
hostsですね。注目すべきは最後の行のcrattack.tistory.comというやつ。果たして本当にそうでしょうか?と33分探偵ばり(ネタが古い)にnslookupすると
|
|
ほらね。やっぱり何かありそうです。問題文でも偽のアクセスがどうのこうのと言ってるので、方針は良さそうです。ここからはコマンドリファレンスとにらめっこして情報を幾つか見ましたが、最終的に答えにたどり着けたのは「iehistory」というオプションでした。
|
|
このサイト自体はアクセスしても特にフラグらしいものは得られませんでしたが、iehistoryで出てきた/Data-Science-import-pandas-as-pdというやつにアクセスするとファイルが落ちてきて、それをテキストエディタとかで読むとフラグが書いてある、というオチでした。
これらの作業をするにあたって、Volatility CheatSheet_v2.4.pdfとCommand Reference(at github)を大いに活用しました。
Flag: SECCON{_h3110_w3_h4ve_funw4rg4m3}
pcapファイルが渡されて、中にVoIP電話の音声パケットデータが入っているので、それを聞き取る問題。これはEnglishをlistenする問題で英語パーフェクトマスター!wの私は「余裕やんけ」と言いながら聞き取った「SECCON{9001IBR}」をポストするも無残に散りました。正しいフラグは「SECCON{9001IVR}」。チームメンバーの先輩が無事得点してくれました。良かったです。
愉快な動きをするSECCON TOWER(YouTubeへのリンク)の動きからアルファベットを読み出して、その結果をどうにかデコードしてPNGファイルを出力する問題。最初の趣旨説明部分で21文字(ただし.(ピリオド)含む)がわかるように説明してくれていて、それを表にまとめるとその他のわかっていない6文字もなんとなく推察できるようになっていました。ただ、とにかく動画が長くて、色々しんどい問題だ…ってなったところで解くのをやめてしまいました。面白かったので時間があったらやってみようかなという感じです。
上に挙げた以外の問題もいくつか触ったりしましたが、pwnの問題もflag.txtという文字がスタック上に見えるのに手が届かない、そういう感じで悔しかったです。あとWeb問も解けなかったので、この辺できるようになりたいなと思いました。
来週はセキュリティミニキャンプ in 沖縄ですね。
以上です。
]]>ちょうど一週間前の11月27日(日)に「KOSENセキュリティ・コンテスト2016」というコンテストが開催され、私は4人からなる最南端の高専生チームEAnbaiの一員として参加した。コンテスト概要はサイバーな雰囲気漂うデザインの公式サイトを参照されたい。運営・参加者共に初めての試みだった本コンテスト。記憶に新しいうちに、参加記とは言えないだろう参加記をここに書き残したい。ちなみに私達のチームは31チーム参加中7位タイで競技を終えた。タイというのも、コンテストのランキング表は最終得点日時に基づく時系列が考慮されていたのだ。時系列も考慮した場合の私達の最終順位は11位であることも、ランキング警察訪問に備えて付しておこう。
(追記)しばらくして大会に使用された環境が異なっていたことが運営の方の調査によって明らかになり、その違いによってランキング時に2つの部門に分けられました。その結果とあるファイルがあった部門において3位となり、表彰状をいただきました。
この頃から運営からのメールでの連絡が増え始め、一歩一歩確実に戻ることなく近づいてくる競技の足音とプロ参加者の自己紹介に震えながら、更新されていく情報に耳を傾けていた。競技数日前、SSHでの競技サーバー接続テスト用の情報が公開された。各々好みのターミナルを起ち上げ、指定されたサーバーアドレスを打ち込み、研究室の回線を介して正常にサーバーへ接続できることを確認した。北は北海道、南は我らが沖縄県からの参加がある本コンテストだが、このようにインターネット経由で参加できるオンライン形式のコンテストなので参加は容易い。勉強会や現地会場でのみ執り行われる大会には地理的ハードルが高い私達でも、オンラインの大会ならば亜光速で現地入りできるのだから、通信技術には頭が上がらない。
この数日後、予告されていた事前課題が解放された。初めての亜光速現地入りの時の入口から少し時間を進めたところから入れば、それにたどり着けるようだ。既に学生寮の自室へ戻っていた私は、研究室から亜光速現地入りして現場検証を行うチームメンバーからの報告を見ていた。翌日、チームメンバーの報告どおり「iotcar.py」、「iotcar」の存在をそれぞれ自分の目で確かめた。どうやらiotcarの方はpython iotcar.py
とした時と同じ挙動をするものらしい。運営からSlackを通じて提供されている事前課題の情報と照らし合わせつつ、それを実行し、コマンドをUDPで送信し挙動を見ることを行った――こう書くと何だか大層なことをやってのけているように思えるが、実際は運営から渡されたサンプル通信プログラムをサーバー上に新たなファイルとして作成して実行したにすぎない。
少なくともここまでの作業は全国の参加チームで行われたことだろう。私達のチームではこのリモートブラックボックスiotcar.pyが本番、どのように作用してくるのかを考えていた。パラメータを指定してコマンドを送信すること、コマンドの仕様がそれぞれわかっていたが、事前課題として示されていたプログラムに基づいたコマンドの送信方法では、本番数多のコマンドを送信することを予想するとあまりにも効率が悪いと判断した。そこで以下のようなプログラムを作成した。
|
|
コマンド送信を簡略化するためのこのプログラム利用者は天才であることを前提に作成したので、使い勝手はあまり考慮されていないが本番でどの程度このプログラムが力を発揮できるのかわからない中だったので、まあひとまずといったところだ。ここがEAnbaiによるiotcarピークだった。
結論から言うと、EAnbaiはiotcarを得点につなげることができなかった(問題の内訳が公開されていない今、本当に獲得できていないのかは定かではないが恐らくそうだろう)。コンテストの加点は5分に一度運営側で脆弱性の修正が行われたことが確認された段階で行われる仕組みになっており、自分たちのどの作業が自分たちの得点になったのかは即時に判断できない場合がある。ひとまずサーバーにアクセスして一体どんな脆弱性やおかしな設定が与えられているのか、確認するところから始めるしかない。本番環境のサーバーにアクセスしてまずはじめに、事前課題の洞窟と同じ風景が広がっているのが一目見えた。しかし今回は事前環境とは違う点がある。iotcar.pyを編集できるのだ。その変化に満足しながらひとまずpython iotcar.py
とする。しかし期待に反してプログラムはSyntax Errorを話すのだった。ここからもう一人のチームメンバーと共同でのiotcar.pyデバッグが始まる。これに没頭しすぎたのは今考えると良くなかった。もう少し編集可能になった宝について、その使いみちを検討すべきだったが、満足に実行できるようにすることを優先して時間をかけすぎた感が否めない。しかしもちろん無駄な作業だったわけではない。構文エラー、変数名の誤り等いくつかのエラーを乗り越えてiotcar.pyは正常に動作した。
この作業と並行して他のチームメンバー2人によるサーバー内探索が進んでいた。不審なユーザーがJoeアカウントで登録されていたのを修正したり、設定不備なファイルの修正を行ったりと、いくつかの得点を重ねていた。root権限に飢えながら行われたこれらの幾つかの作業が最終得点700点の全てだと思われる。一方、前日に用意したコマンド送信用のプログラムも正常に動作し、iotcar.pyにコマンドが送られ、ファイルに書き込まれ、Webページの表示からWarningが消えていくのを見て私はある程度の満足感を覚えていた。しかし、くどいようだがこれらの作業は得点には繋がらなかった。アプローチの仕方が間違っていて、本質的な解決に至っていなかったからだ。ここからは苦しい時間が続いた。/var/www内のPHPファイルの内容が明らかに怪しいのはわかっていて、ソースコードを読むことでどのような脆弱性があって、Webインターフェースでの実際の作用まである程度想定できていた。足りなかったのはroot権限だった。編集権限までは与えられていなかったこれらの問題児に手を付けたくてもつけられない、どうにかして糸口を見つけ出したい、そんな状況が続いた――直ぐ側にある宝に気づけないまま。
「灯台下暗し」とは、まさにあのことだったのだろう。この件に関しては後日運営から追加情報が出次第、追記することにするがいやはや、今になってみれば何故あの大きな大きな宝に気づくことができなかったのだろうか、と悔やまれるばかりだ。宝があったとかなかったとか言う議論とは別の次元に、私達がその宝に気づけなかったという事実はある。この悔しさをバネに、次の機会では大きい魚を逃さぬように目を凝らさねばならないと誓ったのだった。
悔しさが残る競技となった一方、楽しかったという感情も大きかったです。きっと、セキュリティミニキャンプに参加して、セキュリティを勉強し始めた約1年前の自分では知識不足で何からどう手を付けていいのかすらわからなかったと思います(当時はLinuxすらまともに触ったことがなかった)。朝10時から始まり15時半まで5時間半続いた競技時間、数字だけ見ると長いように思えますが実際にはあっという間でした。12時頃に寮食を食べに食堂まで行く時間も惜しくて、普段の数倍のスピードでご飯を食べながら/etc/shadowをどう開くかGoogle検索片手に考えていたので何を食べていたのかもよく思い出せないですが、これも良い思い出です。
今回のコンテストはCTFというよりはHardening色が強い競技形態だったと思います。といっても僕はHardeningへの参加経験がなく、今回をきっかけに参加してみたい気持ちが今まで以上に強くなりました。CTFなどのコンテスト自体の参加経験も浅いので、今後も研鑽を積みつつ顔を出していきたいです。
最後になりますが、運営の皆様方、一緒に参加したチームメンバー、当日学校に来てくださった担当の先生、本当にありがとうございました。雑多な記事になってしまいましたが、今回は以上です。
Windows Media Player(以下、WMP)はスキンを何らかの手段で入手して、自分の好きな見た目に変更することができます。もちろん自分で作ることもでき、xml/javascriptを用いて比較的簡単にできるので、やっていきます。僕はn年前にiphon…1ph0n3の4sをモデルにしたものを作ったことがあり、今回はそれをip..1ph0n3の5sモデルで作りなおそうと思います。なぜ6系ではないかというと僕の携帯が5sだからです(どうでもいい)。ちなみに作ったものはできればここでダウンロードできるようにしたいのですが、現在著作権利用(林檎社公式音楽再生アプリのスクショを使用しており、著作権利用ガイドラインを読んだ感じ大丈夫ではあると思うが念のため)に関する確認の途中なので、ダウンロードファイルの設置はそこら辺が明確になり次第ということにします。では、やっていきます。
世の中の大半のスキン内部はおおよそ以下のようなファイル構成になって(いると思)います。
wmsファイルの中身はxmlで、この中で見た目を記述していきます。実際にスキンをリリースする際はこれらのファイルをまとめてzipに圧縮し、拡張子をwmzに変更すれば良いだけです。スキンを適用するときはwmzファイルをダブルクリックすると、ダウンロード・適用画面が出てくるのでポチポチやるとすぐ適用できます。
開発中はいちいちwmzにすると面倒なので、wmsファイルをダブルクリック、表示し、更新はWeb開発時のようにF5キーで行います。
1ph0n3(しつこい)の画像は適当にフリーのモックアップイメージを拾ってきます(もちろん自前でも可)。今回はこちらを使わせていただくことにします。次に再生ボタンや次へボタンなどの各パーツをなんとかして調達します。今回は「前へ、次へ、再生、一時停止、プレイリスト表示、WMPライブラリへ戻る、シャッフル、リピート、シャッフル押下時、リピート押下時」を用意しました。ボタンだけでなく、シークバー、ボリュームバー用の画像なども個別に用意しないといけないので結構気合が入ります。
画像は背景を透過して描画させることができます。透過したい部分を何か単色で塗りつぶし、それを後で記述するxmlでclipping colorとして指定すれば良いので、とりあえず今回は#FFFF00(黄色)で透過したい部分を塗っておきます。
HTMLやCSSを書いたことのある人なら、なんとなくイメージが湧きやすいと思いますが、ここはただただ書くだけです。予め意味を持たされているタグを利用しつつ、今回は以下の様な記述を行いました。
テーマ全般に関するタグです。スキンのタイトル(スキンセレクターで表示される名前)、著作者表示、製作者に加えてJavaScriptのファイルを指定します。複数ある場合は;(セミコロン)で区切るようです。
htmlでいうbodyタグといったところでしょうか。背景画像やその他表示に関する属性を記述できます。clipping colorで指定した色が透過されて描画されます。
htmlでいうdiv(ここでhtml5信者に刺される)的なタグということにしておきましょう。
プレイヤーのイベントハンドラをここで登録しました。各イベントの発生毎にmeta_upload関数が呼び出され、メタ情報が更新・再描画されます。
WMPのライブラリ(何を言っているかわからないかもしれないが、恐らくほとんどの人が一度は見たことがあるはず)を表示するボタンを指定しています。
ボタンです。今回はプレイリストを表示するようにonclickで意味付けをしたものが書いてあります。
テキストです。idを指定して、javascriptで書き換えているものがいくつかあります。
三角の再生開始ボタンです。
一時停止ボタンです。
曲を早戻ししそうな見た目をしていますが、プレイリストのひとつ前の曲へ移動するボタンです。
prevbuttonの逆をするボタンです。
プレイリスト内の曲をリピート再生するか指定するボタンです。
プレイリスト内の曲を順番通りでなくランダムに再生するか指定するボタンです。
スキン表示を最小化でタスクバーに隠すボタンです。
閉じるボタンです。
再生中の曲名を表示します。
実際に動かす球(?)とボリューム出てます色バーと出てません色バーを画像で指定すると良い感じにボリュームバーが出来上がります。
ボリュームバーのように3つ画像を用意・指定するとシークバーが描画されます。
プレイリストに入っている曲を描画する領域です。
その他のタグや各タグに指定できる属性はスキンプログラミングリファレンスで確認できます。凝りたい方はこちらを一読されると良いと思います。
JavaScriptでは再生中の曲が変わった時などに、メタ情報(アルバムアートワーク、作曲者、曲名…)の更新を行います。今回のコードは以下の様な感じです。
meta_update関数はメタ情報を更新して、上のwmsファイルで指定したidの要素を書き換える処理をしています。getIdx関数はプレイリストの何番目の曲を再生しているのかというのを表示するために、今何番目が流れているのかを調べる関数です(リファレンスをぱっと見た感じそういうメンバをcurrentPlaylistオブジェクトに見つけられなかったので適当に書いたけど、本当にないのかよくわからず…)。これをwms内でイベントハンドラに登録する形で記述してあるのがわかると思います。重要なのは<player>に登録してある、currentItemChangeイベント等でしょう。これは曲が変わるときなどに発生するイベント(説明が雑)なので、ここでメタ情報を更新しておけば、良い感じなります。
windows media playerのスキン久々に作った pic.twitter.com/c7zoSuJuh3
— わっさん (@wassan128) 2016年8月26日
昔作った時も思いましたが、結構情報が少ない印象です(リファレンス見ればだいたい解決しますが)。n年前に制作した時はどうやって情報を集めたかあんまり覚えていませんが、個人的には実際にあるスキンを解凍してソースを見てみるというのが一番手っ取り早いと思います(もちろん、作者がそれを許諾しているスキンで)。あとはcss書いたことがあるとfontSizeなどの属性が雰囲気でわかるので、書きやすいと思います。JavaScript部分もあんまり最初リファレンス読まずに書いていたので手探り状態で、CurrentItemChangeにたどり着くまで結構かかりました。
冒頭でも書いた当スキンの公開についてですが、こちらの著作権利用に関するガイドラインを見た限りは問題ないような気がするのですが、はっきりわからないので現在問い合わせメールの返答待ちをしています。はっきりし次第公開できれば良いなと思っています。ソースの方は問題ないと思うので、スキン作りの参考になれば幸いです。
喋るraspberry piです。 pic.twitter.com/IF1PRYHnJy
— わっさん (@wassan128) 2016年8月24日
ふと、VirusTotalでAPIが提供されていたことを思い出し、なんとなく叩こうという気持ちが高まったのがきっかけです。しかしただ触るだけでは面白く無いので、今回は帰ってきた結果を喋らせてみようかなと独り言を放ちました。すると、昔々某企業様から某イベントの某賞で頂いたRaspberry Pi(Model B)が仲間になりたそうな目でこちらを見てきたので、喋ってもらうことにしました。なお、プログラミング言語にはPythonを、音声合成には非モノローグ音声合成を用いました。
VirusTotalにファイルを投げると、50個くらいのウイルス対策ソフトでファイルをスキャンしてくれます。そのAPIを叩いていくということになりますが、提供されている機能は
と言った感じ(他にもあるので興味のある方は公式ドキュメントを読むと良いと思います)。レスポンスはJSON形式でくれるので、良い感じにパースしてやれば良いです。今回は1, 2を使ってファイルを投げる→結果をパースして喋らせることをやります。
基本的にはドキュメントに書いてあるとおりに通りにやったので、ハマりどころはほとんどありませんでした。
|
|
にファイルを送ります。ドキュメントにも書いてありますが、multipart/form-dataを転送するコードを先人が用意してくださっているので、利用します。なお、httpsでリクエストするように先人のコードに手を加えておかないと、「Bad Request」と怒られてしまうのでここだけ気をつけます。
今回は先人のコードをクラス化してimportして利用しました。それ以外はほぼドキュメント通りです。
sentにはファイル送信に対するレスポンスが入ります。レスポンスは
という形式で、この中の“scan_id”キーに対応する値を使って結果レポートを取得していきます。帰ってきているJSONレスポンスのキー順序が若干ドキュメントに示されているものと前後しているのは気にしない方針でやっていきます(特に困らないので)。
|
|
に取得したスキャンIDを添えてリクエストを投げます。といっても送信後すぐにレポートが見られるわけではなくて、VirusTotalでのファイルスキャンにはある程度の時間(2~5分くらい?)を要します。ので、スキャンが完了してからレポートをパースするような設計にすれば良いです。スキャンが終了しているかどうかは、レスポンスJSON内の“response_code”で識別できます。このキーに対応する値が-2の時はまだスキャン中なので、その間は大人しく待ちます。今回は1待ち間隔を30秒にしましたが、本家では確か5秒に一回更新していたので、もう少し短くても良いかもわかりません。
ここまでで検知結果のJSONが取得できているはずなので、結果を元に音声合成をします。音声合成の部分もサンプルコードとして提示されているものをそのまま使えば良いです(今回ほとんどコード書いてない!w)。base64エンコードされたwav音声が手に入ります。
引数のmessageは
こんな感じで決めてやります。
やっと喋らせるターンです。ステップ3でwavファイルが手に入っているので、雑ですが
で再生してしまいます。aplayはCUI上で音声再生を行えるものです。やるだけ感が半端ないのですが、今回ラズパイが久々の起動だったからかrpi-update, apt-get update/upgrade周りが失敗したらしく、aplayやamixer, alsamixerといったツール群がすべて使用不能になり、やむなくraspbian OSの再インストール・設定を行いました(ここで一番時間溶かした)。OS再インストール後は普通に再生ができました。
今回はRaspberr Piを長き封印から解き放ち、言葉を喋らせることをやりました。VirusTotal本家でファイルを投げてブラウザの画面が忙しく更新され、無機質なレポート(失礼)が表示されるのを待つよりも、待っている間のわくわく感が高まった感じがあります(※個人差が有ります)。ラズパイを採択した理由は本当になんとなくでしたが、今回使用したNICTの音声合成エンジンが元々ROS向けに開発されたもの(らしい)なので、せっかくだしPCではなくこれで、と言った理由がないわけでもないです。まあしかしラズパイの特徴を活かせているかと言われるとう~んという感じなので、個人的には今度はロボットとか作ってみたいです。
pythonのコードをバイナリにできるのは知っていたが、実際に使ったことはなかったのでやってみた。手元のマシンはx64、pythonもx64用しかなかったので、このままではx64バイナリしか吐けない。そこで今回はx64マシンに新たにx86用pythonをインストールし、pythonコードからバイナリを吐き出すユーティリティである「py2exe」(もちろんx86用)を導入してx86バイナリを出力させる。
py2exeはpythonコードからWindows実行形式ファイル(以下、バイナリ)を出力するpythonのユーティリティである。導入にはインストーラを用いる。pipを使わない理由は、pipでインストールできるpy2exeはpython3対応のもののみだから(手元では現在python2.7を使用している)。
インストーラはここから入手する。適当なバージョンを選択し、ダウンロード、インストールを行う。この時、x64のpythonしかない環境でx86のpy2exeをインストールしようとすると、「Python version 2.x required, which was not found in the registry」という感じのエラーが出る。手元にはpython2.7(x64)しかインストールされていないため、レジストリの参照に失敗していると考えられる。これはx86のpythonをダウンロード、インストールすることで解決する。バージョンは2.7で揃えた(特に意味は無いが)。ちゃんと見つかるとこんな感じの画面になる(図1)。あとは通常通りインストールを行えば良い。
py2exeでバイナリを吐き出すには次の手順を踏む。
(1)はそのまま。(2)のsetup.pyだが、py2exeではバイナリ出力のオプションなどをこのファイル内に記述しなければならない。具体的には、
このように。「option」では出力圧縮の有無(compressed[True|False])、最適化の有無(optimize[0|1|2])、ランタイムDLLを含めるか(bundle_files[1|2])を指定できる。「console」では対象のpythonコードを指定する(test.pyの部分は適宜変更)。Zipファイルを生成する場合は「zipfile」にファイル名を指定する。他にも除外するDLLのオプション指定などができるらしいが、今回は試していない。
setup.pyの記述が終わったら(3)実行。
これでdistディレクトリ内にバイナリが出力されているのが確認できるはずである。fileコマンドで確認してみると、
x86バイナリが出力できている。
なお、zipfileがNoneの状態でbunfle_filesが1(ランタイムDLLを含める)だと、Runtime Errorが出てバイナリが生成できなかった。zipfileに適当なファイル名を指定するか、bundle_filesを2(含めない)として実行すればエラー自体は消えるがスタンドアロンのバイナリは出力できなかった。
今回バイナリを出力したpythonコードは
これだけ。IDA Pro Free(x86バイナリを出力したかった理由の一つ)で開いてStringsタブを確認してみる。が、Hello, Worldの文字列は見当たらない。VM上のLinuxで
を実行すると「Hello, World(」の文字が出力される。知識不足でなぜIDAのstringsでは確認できないのかわからなかった。
ランタイムDLLを含めるオプションで実行したにも関わらずスタンドアロンバイナリを出力できなかった。x86バイナリになったことでIDA Pro Freeでファイルを開けたのは良かったものの、出力されたバイナリの構造が知識不足でよくわからず…。バイナリ力がまだまだ足りないので、これからも精進したい。py2exeでのバイナリ出力はこれから活用していくか正直まだわからないが、一つメモとして残しておきたかったので記事に残した。
夏ですね、暑いですね。世間ではこの時期流しそうめんをやったりするのかもしれませんが、僕は手元にそうめんがないので、別の何かを流していきたいと思います。ということで、今回の記事は、プレゼンへのコメントをリアルタイムでスクリーンに流すツールを作って使ったメモです(某科目の学科紹介プレゼンにて使用)。
プレゼン中にコメントを流すというアイデア自体は、1年か2年の頃に見た弊学での「ちびLT」という勉強会(?)でとある先輩が開発・紹介していたものが元なので、オリジナルではないですが、自分でも作ってみたくなったのでやってみました。しかし、当時の先輩がどのように作ったのかわからなかったので、とりあえずいろいろ調べたり考えてやってみたので、その過程をメモします。ちなみに最終的にはComet(Python, JavaScript) on Adobe Airで良い感じにやりました。
くどいようですが、やりたいことは「PowerPointプレゼンテーションのスライド上を、聴衆のコメントが流れていく」ということです。したがって、
の2つが必要になります。1については、ひとまず適当なwebアプリのページを作って、URLを黒板かスライドにでも書いてアクセスしてもらい、コメントを打ってもらえば良いか、という感じで後回しにし、2の方に先にとりかかりました。思いついた当初はだいぶ楽観的で、
「まあ、PowerPointだし、Excelみたいにマクロあるっしょ(おもむろにAlt + F11を押す)。ほらVBA書けるやん、良い感じにDOMのデータ取ってきてテキストオブジェクト作ってアニメーション当てれば行けるっしょ~」
と考えていた時期が僕にもありますた。実際、VBAではInternetExplorerを起動してDOMの操作もでき、さらにreadyState(サイトのロードステータス)を扱った処理もできるようでした(※1)。また、検索の途中で面白そうな資料も発見しました(※2、いつかVBAやらないといけなくなった時にまた見たい)。
そうはいってもreadyStateはブラウザによって実装のされ方が違うらしく、その影響なのかVBAから使う際の良さみが浅い感じでした。また、開発期間もあまり長くない状況で使い慣れない言語を使うよりは”い つ も の”でどうにかしたい気持ちが強くなり、その方向へ転換してグーグリングを継続しました。というかPowerPoint VBAとExcel VBAで若干言語仕様が違って、PPT VBAの資料が圧倒的に少ないのがだいぶ辛かったです。さて、ここからようやく開発本編です(僕の記事は前置きというか無駄話が長いことであまりにも有名)。
やっぱりWebベースで全部やりたくなるんですよ。その願いを叶えてくれたのが、「Adobe Air」でした。恥ずかしながら存在自体を今回の開発時まで知らず、「へーこんなのあるんだー」「Flashと何が違うんや…」「でもActionScriptで開発しないといけないんじゃないの…?」などいろいろ疑問がありました。実際はAir SDKをダウンロードすることで「HTML + JavaScript」で開発ができるので、VBAの沼にはまりかけた時に比べればだいぶ気は楽でした。後はやるだけ。
ただ当初WebSocketで通信できないかなと思ってたんですが、AirではWebSocketがサポートされておらず、独自のSocketAPIが…(※3)とあったので、今回はSocketを捨てて「Comet」方式で実装することにしました(逃げ)。以下の図は全体のイメージをまとめたものです。Cometでファイルの変更を監視し、変更差分を画面に投げます。
OS: Windows7
言語: Python(2.7.11) + JavaScript(jquery(v1.12.4))
PHP+JSでのCometの実装(※4)を参考に、ファイルの差分をJSONで返すPythonのコード(こんなのしか思いつかなかったのでもっと良い書き方あったら教えて下さい)。
と、それを投げたり良い感じにするJS側のコード。
JSコード中のnicoscreen.add関数ですが、これはニコニココメント風にwebページの画面上にに文字を流すjqueryのプラグイン(※5)があったので拝借し、少し中身を改造して使わせていただきました。以下動作確認時のスクリーンショットです(左側が入力用のユーザーが見るページ、右側が拡張ディスプレイに表示したPowerPointスライドと、その上を流れるコメント)。
これについてはAdobe Airの力でして、Airのアプリを書く際はまずxmlを書くんですが、その中でウィンドウを透明にしたり、フルスクリーンモードをオンにしたりなど設定ができます。また、詳しくはHTML + JavaScript開発者用ドキュメント(※6)を読めばわかりますが、簡潔に言うとSDKにJSを拡張するJSが入っていて、そいつを読み込んでAir JSなコードを少し書くとAirアプリのウィンドウを最前面に配置したりできます。
最初からVBAじゃなくてWebの方法にあたりをつければよかった(VBAでしばらくはまり、Webベースに切り替えてから2~3日で作ったので)です。まあでもこんな機会でもなければVBA(ましてやPowerPoint VBA)を触る機会がない(ような気がする)ので良い経験にはなったかな、と思うようにしてます。
実際に使ってみて受けが良かったのかは正直よくわかりませんが、コメント書き込んでもらえて良かったです(誰もPC開いてない or コメント書いてくれないケースを想像すると…())。今後このツールを使う機会があるかは謎ですが、同じようなことをしようと考える方の参考に少しでもなれれば幸いです。以上です。
※1 VBAのIE制御入門 | IE操作の自動化
※2 こじらせVBA - SlideShare
※3 Adobe Flash Platform * AIR でサポートされていない WebKit の機能
※4 PHPとjQueryでCometっぽいモノを実装する
※5 NicoScreen.js:画像や動画の上に、ニコニコ動画のような文字を流すことが出来るjqueryプラグイン
※6 Adobe Air用HTML開発ガイド
高校5年生なので、HSCTF(High School CTF)に登録して参加してみました。というのはもちろん嘘で、実際は大学生枠(?)で参加してみたんですが、その中でも「Egyptian Tomb」という問題についてメモしておきたくなったので、ブログに備忘録的に書き残そうかと思いました。
ちなみにチーム制CTFで、最終的にはラボの同級生と先輩と僕という感じのチームでした。もっと貢献したかった(´・ω・`)
Keithさんという人がいて、エジプトに行きましたと。ピラミッドを見に。するとKeithさんはこんなパズルを見つけたそうです。
$$
\begin{pmatrix}
1 & 2 \\ 3 & 4
\end{pmatrix}
$$
このパズルの答えは「20」になるそうです。ほーん。と思ったあなたには良いものを上げましょう(おもむろに$ 10000 \times 10000 $の数列を投げつけられる)。ではどうぞ、解いてください!
ざっくりいうとこんな感じです。ここからいろいろ考えたり殴ったりするターンになります。
このパズルは問題文によると「sum of all sums of subsquares」、つまり$ n \times n $の正方形の中の$ 1 \times 1, \cdots (n - 1) \times (n - 1), n \times n $までの全ての正方形(all subsquares)の中の数字の和を、足したものがパズルの答え、ということだそうです。上の例だと$ 1 \times 1 $の正方形が4つ、$ 2 \times 2 $の正方形が1つなので、
$$
1+2+3+4+(1+2+3+4)=20
$$
ということになります。解き方がわかったので、早速$ 10000 \times 10000 $の数列をこの方法で解いてみましょう!ところで、$ 2 \times 2 $の数列内には5個の正方形がありましたが、$ 10000 \times 10000 $だといったいいくつの正方形があるんですかね?$ n \times n $の数列内には
$$
\sum_{k=1}^{n}k^2
$$
個の正方形があるので、$ n=10000 $では
$$
\sum_{k=1}^{10000}k^2=1+2^2+3^2+\cdots+10000^2=333383335000
$$
個の正方形があることになります。たったの3000億個か~/(^o^)\
…これを上の式みたいにのんびり解くと大変なことになりそうなので、他の解き方を考えます。
上の式を見ると、数列の要素$ \{1, 2, 3, 4\} $がそれぞれ2回ずつたされていることに気づきます。つまり、
$$
1\times2+2\times2+3\times2+4\times2=20
$$
というように、「{各要素の値} $ \times $ {各要素が足される回数}の総和」で計算できると考えられます。今回問題は$ 10000 \times 10000 $なので、$ n \times n $の$ n $は偶数と考えた上で、各要素が足される回数を要素とした係数数列を考えると、$ 2 \times 2 $の場合は、
$$
\begin{pmatrix}
2 & 2 \\ 2 & 2
\end{pmatrix}
$$
となりました。同様に、$ 4 \times 4 $、$ 6 \times 6 $ではそれぞれ
$$
\begin{pmatrix}
4 & 6 & 6 & 4 \\
6 & 10 & 10 & 6 \\
6 & 10 & 10 & 6 \\
4 & 6 & 6 & 4 \\
\end{pmatrix},\quad
\begin{pmatrix}
6 & 10 & 12 & 12 & 10 & 6 \\
10 & 18 & 22 & 22 & 18 & 10 \\
12 & 22 & 28 & 28 & 22 & 12 \\
12 & 22 & 28 & 28 & 22 & 12 \\
10 & 18 & 22 & 22 & 18 & 10 \\
6 & 10 & 12 & 12 & 10 & 6 \\
\end{pmatrix}
$$
が係数数列となります。この値は何か計算をして出したわけではなくて、友人(@koreander2001)と「$ 1 \times 1 $の時は全て1回ずつ足されて、$ 2 \times 2 $の時は$ 1, 2, 2,…, 2, 1 $で…」というように数え上げてそれぞれ何回足されるか書き出してみたものです:-)
これを見ると、それぞれ図の赤い三角形部分の数字を求められればどうにか全ての要素を網羅できそうな気がしてきます。実際できるので、これを元に頑張って一般化します。
例えば、$ n=6 $だった場合、$ \frac{n}{2} $ すなわち$ 3 \times 3 $ の、さらに右上三角地帯を計算すれば良く、係数数列の当該部分は
$$
\begin{Bmatrix}
\begin{pmatrix}
1 & 1 & 1 \\
& 1 & 1 \\
& & 1 \\
\end{pmatrix}+
\begin{pmatrix}
1 & 2 & 2 \\
& 4 & 4 \\
& & 4 \\
\end{pmatrix}+
\begin{pmatrix}
1 & 2 & 3\\
& 4 & 6\\
& & 9\\
\end{pmatrix}
\end{Bmatrix}
\times2
$$
のように分解できます。それぞれ$ 1 \times 1 $、$ 2 \times 2 $、$ 3 \times 3 $数列で足される回数をカウントしたものです。$ \times2 $をする理由は、$ 1 \times 1 $行列の正方形の個数と$ 6 \times 6 $、$ 2 \times 2 $と$ 5 \times 5 $、$ 3 \times 3 $と$ 4 \times 4 $でそれぞれ足し合わせの回数が対応している、すなわち$ 1 \times 1 $~$ 3 \times 3 $で折り返しているので、全体の足し合わせの回数は$ 1 \times 1 $~$ \frac{n}{2} \times \frac{n}{2} $までの和を2倍すると導出できるためです。
実際に計算をして、上で示した$ 6 \times 6 $の係数数列の値と対応しているか確認しつつ一般式の立式を目指します。座標$ (m, l) $が$ (1, 1), (2, 1), (3, 1) $のときそれぞれ
$$
(1, 1) = (1+1+1) \times 2 = 6\\
(2, 1) = (1+2+2) \times 2 = 10\\
(3, 1) = (1+2+3) \times 2 = 12\\
$$
となります。同様に$ (2, 2), (3, 2) $では、
$$
(2, 2) = (1+4+4) \times 2 = 18\\
(3, 2) = (1+4+6) \times 2 = 22\\
$$
となり、$ (3, 3) $では、
$$
(3, 3) = (1+4+9) \times 2 = 28\\
$$
が求まります。
ここで、$ (3, 3) $の式が
$$
\sum_{k=1}^{3}k^2
$$
を含むことに気づきます。各座標にも、部分的に二乗の総和の式が当てはまっています。これらを利用して、例えば$ (m, 2) $での部分的な一般化を試します(実際は$ n=8 $なども試したほうが良い(というか試した)ですが、今回は記事が長くなりすぎるので、割愛します)。
$ (m, 2) $においては、$ 1+4 $までは共通しており、3項目で$ 2 \times m $が足されています。$ n=8, n=10 $などを試すとよりはっきりとわかりますが、これは次のような法則に従って足されています。
$$
(m, 2) = (1+4+6+8+\cdots+2m+\cdots+2m) \times 2
$$
同様に$ (m, 3) $での部分的な一般化を試すと、
$$
(m, 3) = (1+4+9+12+15+\cdots+3m+\cdots+3m) \times 3
$$
という法則が得られます。この式は3つのパートに分けることができ、1つ目のパートが「二乗の和」、2つ目のパートが「mの倍数の和 - 二乗の和との重複部」、3つ目が「$ \frac{n}{2}-m $個の$ l \times m $」です。つまり、$ (m, l) $においては
$$
(m, l) = \begin{Bmatrix}(1+4+9+\cdots+l^2)+l \times ((1+2+3+\cdots+m) - (1+2+3+\cdots+l))+(\frac{n}{2}- m) \times l \times m\end{Bmatrix} \times 2
$$
と表すことができ、これを記号を用いて整理すると、
$$
(m, l) = \sum_{i=1}^{l} i^2 + l \times (\sum_{j=1}^{m} j - \sum_{k=1}^{l} k) + lm \times (\frac{n}{2}- m)
$$
となり、さらにこれを2乗和の公式などを用いて展開して計算すると、
$$
(m, l) = \frac{l(l+1)(2l+1)}{6} + l(\frac{m(m+1)}{2} - \frac{l(l+1)}{2}) + lm(\frac{n}{2}-m)\\
= \frac{l}{3}((l+1)(2l+1) + 3(m(m+1) - l(l+1)+m(3n-6m))\\
= \frac{l}{3}(2l^2+3l+1+3m^2+3m-3l^2-3l+3mn-6m^2)\\
= \frac{l}{3}(3mn-l^2-3m^2+3m+1)\\
= lm(n-m+1)-\frac{l}{3}(l^2-1)\\
\therefore (m, l) = lm(n-m+1)-\frac{l}{3}(l^2-1)\\
(ただし、l \leq m)
$$
という一般式を得られました。
今回はPythonで書いてみました。問題の$ 10000 \times 10000 $数列は「egypt.in」というファイルで与えられたので、それを読み込んで計算させます。
|
|
3分くらい待って出てきた答えがそのままFLAGでした。
この問題はAlgorithm: 300に分類されてました。
以上です。
]]>時は2016年4月。人工知能が世の中で盛り上がりを見せる中、某O高専の学生は「図書館今日開いてたっけ」と思った時、お手元の人工知能に尋ねるわけにもいかず、通常は直接足を運ぶか、インターネット上に公開されている「開館カレンダー」を見ることで開館状況を確認する。しかしそのためだけにいちいちPCを起動し、n回のクリックを経てサイトにアクセスするのは面倒だ。もう少し気軽に開館状況を知ることができれば…。
するとそこへ一羽の青い鳥が颯爽と現れ、大丈夫さ、と呟く…。
――そう、Twitterならね。
ということで、今回はPythonの勉強も兼ねて、開館状況を知りたい日付をリプライすると、その日の開館状況を返してくれるだけのTwitterBotを作りました(なお現在(2016/4/3時点)は動作させていません)。
OS: Windows7
言語: Python(2.7.11)
開館カレンダーは画像に示すように、開館の状況によって日付の背景色を変える表示方法が採用されています。カレンダーはHTMLのtableタグで構成されており、日付がそれぞれtdタグ(セル)に収まっているようです。よって、任意の日付の開館状況を知りたければ、その日付のtdの背景色を取得・判定できれば良さそうです。
上記の通り、カレンダーはHTMLで構成されているため、その要素であるtdにアクセスするためにスクレイピングを行います。今回は、pythonでスクレイピングに使用できるライブラリ
を試用しましたが、今回はBeautifulSoup4(以下bs4)を選択しました。bs4ではPure Python以外のHTMLパーサーが選択でき、試用の際にインストールしていたlxmlをパーサーとして選択することで、パース速度と、パース結果の正確性の向上が期待できそうです。
ここまでで、bs4のfindメソッド(→doc)を用いてtdタグに以下のようにアクセスできるようになりました。
また、スクレイピング等のテストで実際のURLにプログラムから何度もアクセスをかけているとそのうち怒られるような気がしたので、スクレイピングに関する全ての動作テストは、実際のカレンダーを模倣したHTMLファイルを作成し、localhost上で行いました。
今回は定期的に呟くタイプのBot形式ではなく、StreamingAPIを使用してリプライに反応するような仕様にしました。特にStreamingAPIにこだわる理由はありませんでしたが、pythonでStreamingAPIを叩いたことがなかったので、やってみたかったという感じです。ライブラリには「twitter(1.17.1)」を使用しました。
Streamingへの接続方法は以下のとおりです。
反応の仕方は、
「@islibopen islib N」(Nは任意の日付)
というリプライを受け取ったら処理を実行し、結果をリプライする、という感じです。
未定です。
以上です。
]]>昨日書いた記事の中で、Hexoで新しい記事を作成するところについて触れていなかったので、その追記がてら、しれっと追加したコメント機能のところについて書き残しておきます。
さて、「新しい記事を追加する」という作業は記事に書き忘れるほどとても簡単にできます。その作業とは、コマンドプロンプトで作業用フォルダ上まで行き、
とするだけです。簡単ですね…。このコマンドによって「作業用フォルダ > source > _posts」内に「ARTICLE_TITLE.md」というファイルが作成されます。ですので、あとはこの中にMarkdown形式で記事を書いていけばOKです。
次に、コメント機能についてですが、Hexoのテーマによっては最初からコメント欄がついているものもあるみたいですが、このデフォルトのテーマ「landscape」にはついていませんでした。どうやってつけるのか調べていたら、「DISQUS」というディスカッションツール(?)を導入できることがわかりました。
まずDisqusのアカウントを取得、もしくは既存のSNSアカウントでログインします。今回僕はTwitterアカウントでログインしました。その後、歯車アイコンの中の「Add Disqus To Site」というメニューから登録したいサイトのURLとshortnameという項目を設定します。このshortnameという項目に指定したものは後で「_config.yml」に設定します。「Finish registration」というボタンを押して登録完了です。
あとはHexo側の設定をすればコメント欄が自動的に追加されます。Hexo側は手動で「_config.yml」の設定をするか以下のコマンドで
とすることで設定が完了します。これでコメント欄が使えるようになりました!
今回は記事の追加方法とコメント欄の追加について書きました。どちらも簡単にできました。Disqusのようにプラグインを簡単に導入できるのもHexoの強みなんでしょうね。これからも良さげなプラグインがあったら入れてみたいと思います。
長文になるので、今回の説明の大まかな流れを示します。
Node.jsはサーバーサイドで使用できるJavaScriptの事で、従来フロントエンドで使用してきたJavaScriptをサーバーサイドで使おう、というものです。こちらのインストールはWindows環境ということで、インストーラを使って行いました(Node.js 公式サイト)。インストールが終わったら、コマンドプロンプトで
として確認を行いました。npmは、「Node Package Manager」の略称らしいです。その名の通り、Node.js関連のモジュールインストールなどで活躍してくれるに違いありません。今回も何回か使います。
次に、ブログの生成ツールをインストールします。今回は、静的サイトジェネレーターのHexoを使ってブログ本体を生成します。こちらは、先ほど確認を行ったnpmを使ってインストールします。
Hexoでは、コマンドを打ち込むことでブログのひな形を生成したり、記事を作成したりしていきます。まずはひな形を作っていきます。作業用フォルダを生成する場所を決めたらコマンドプロンプトでその場所まで移動して、
というコマンドを実行します。「FOLDER」の部分は、好きな名前にして実行してください(作業用フォルダ名になるだけです)。
次に、
として、モジュールをインストールします。これだけでひな形の作成は完了です。
としてローカルサーバーを起動し、http://localhost:4000/にアクセスしてみましょう。宇宙感あふれるページが表示されているかと思います。
ひな形を作れたのは良いですが、このままでは面白くありませんね。ここで生成したフォルダを見てみましょう。「_config.yml」というファイルがあると思いますが、この中身を編集することでブログの全般的な設定をすることが出来ます。こちら(Hexo公式ページ)を参考にしながら、ブログのタイトル等を編集していきます。それぞれhtmlに変換した際にmetaタグなどに反映されていきます。
そのほかにもいろいろとフォルダやらファイルがありますが、例えば「themes」というフォルダの中にブログのデザインに関するスタイラスのファイルなどが入っていますので、その辺を変更することで見た目を変えることが出来ます。
デフォルトの宇宙感あふれるテーマは「landscape」という名前ですが、ネット上にテーマが多く存在するので、好きに変更することもできます。僕はこのデフォルトのテーマを少しいじったものを使っています。
まずGitHubリポジトリを作成します。GitHub Pagesにブログを置くことももちろんできますが、今回僕はサブディレクトリに配置したかったので「blog」というリポジトリを作成しました。「gh-pages」ブランチを作成したら、お手元のGit Bash等を使ってsshキーをジェネレートしてGitHub側に登録しておきます。これでGitHubとマシンのひも付けができるので、GitHub側の準備は完了です。
(ちなみに僕はこの作業を忘れていたためにデプロイで躓きました…(´・ω・`))
ここまで来たらいよいよデプロイです。先ほど編集した「_config.yml」を開き、
というように先ほど作成したリポジトリ名を指定します。
しかし、このままだと「themes」内の「_config.yml」の内容が悪さをしてアーカイブなどのリンクがうまく生成されないので、ファイルの下の方に
と記述しておきます。その後、
といった形でデプロイ用の設定を記述します。では、デプロイしましょう!
「hexo d」コマンドでデプロイできますが、「-g」オプションを付加するとデプロイ前にhtmlなどを生成してくれます(生成の結果、作業用フォルダ内に「public」というフォルダが作られます)。
エラーが出なければ成功です!指定したURLにアクセスして、確認しましょう。
今回は、Hexoを利用して生成したブログをGitHub Pagesに公開することを目的として作業を行いました。作業にあたって、いろんなサイトを参考にさせてもらいましたが、Windows環境でやって記事にしている方が少なかったので、少し苦労しました(Gitについてよく知らないことが一番の原因だとは思いますが)。
また、この記事はMarkdown形式で書いていますが、まだ書き方がよくわからないのでわかりにくいところや間違ってるところ等あればコメントで教えていただけると幸いです。ブログのテーマについてはファイルをいじることで簡単に変更でき、良さげなので、これからしばらく運営していこうと思います。
ずっと作る作るといって作ってなかったので、夏休みを利用してブログを作ることにしました。
Hexo: 静的サイトジェネレーター
GitHub Pages: 置き場所
gitがまだよくわからないのでいろいろ躓いた…(´・ω・`)
かなり雑ですが、またいつか記事にしますので、今日はここまででさようなら。