午後から→オーバークロック

駆け出しハッカー()によるプログラミング・サービス開発備忘録。

PowerPointでカードソートを行うために、VBAマクロでファイルから単語を読み込み、スライドに単語カードを順に作成していく

カードソートっていうのはユーザから見たときにコンテンツがどう分類されるかを認識するためのUI手法ですが、
カードソートを実現するOptimalSortなどのサービスは、有料or自由度が低かったりしたので、
PowerPointでカードソートを行えるようマクロを組んでみました。

手順

テキストファイルの準備

今回は、複数の単語が改行(LF)で区切られたテキストファイルを用意しました。

マクロの作成

マクロを作成したいんですが、そもそもVBA全く知らないのでお勉強。

VBAについて

Visual Basic for Applicationsという、Officeを扱うための言語らしい。
今回はPowerPoint2013を使ったが、
これの場合表示タブ>マクロでマクロ名入力して作成を押すとマクロの編集画面に移行出来た。

ソースコード

いきなりソースコード

(自分のための)補足説明

  • VBAではimportの代わりに参照設定という項目でライブラリを読み込むみたいです。
    • ツールタブ>参照設定で設定出来ます。
    • 今回インポートしておいたライブラリは以下です(一部余計かもしれません)。
    • ライブラリが足りない場合でも、不親切なエラーしか出ないので注意してください。
  • Setで変数の宣言ぽい。
  • LoadFromFileではフルパスを指定した方が良いかもしれないです。あとMacでは試してないです。
  • With ** ~ End With内では、ドットから始めた場合自動的に**が補完されます。
  • スペース+アンダーバーで複数行に1ステートメントを書けます。
  • Type:=っていう書き方は省略しても良いけど変数名明示できる丁寧な書き方。
  • mougさんにaddShapeメソッドなど色々なリファレンスが掲載されてます(Excel VBAですが)。
  • Debug.Print "ABC"でイミディエイトウィンドウにデバッグ文を表示出来ます。
    • 表示タブ>イミディエイトウィンドウでウィンドウを表示
  • adTypeTextadReadLineは定数です。

保存

pptm拡張子で保存しましょう。

結果

f:id:nemupm:20141009002117p:plain

すごいカオス!!

PowerPointの中身を直接編集してみる

ちょっとやりたいことがあってパワポのマクロを組もうと思ったのですが、
マクロのやり方調べるのも面倒だなと思って直接編集しようとしてみました。

pptxファイルの解凍

pptxファイルは要するにzipアーカイブなので、
拡張子をzipに変えると解凍できます。

f:id:nemupm:20141008210057p:plain

解凍すると分かりますが、図のようにxmlファイルで主に構成されてます。

diffで解析

どうやっていじれば好きなように改造出来るかこのままだと分からないので、
何も無いスライド(raw.pptx)と、変更を加えたスライド(modified.pptx)を解凍したディレクトリをdiffで差分解析します。

$ diff -r raw modified
diff -r raw/docProps/app.xml modified/docProps/app.xml
<差分>
...

こんな感じで、差があったファイルとその内容を羅列してくれます。
結構色々あって面倒そうですが、とりあえずslide1.xmlが1枚目のスライドに対応しているみたいなので、差分を見ながらmodifiedの方のslide1.xmlを編集してみます。

pptxファイルを復元

編集し終わったら、modifiedを圧縮して、pptxファイルに復元します。
このとき、modifiedディレクトリでは無く、modifiedディレクトリ以下にあるファイル群をまとめて圧縮してください(冷静に考えたら当然なんですが、僕はここで最初詰まってしまい、復元したpptxファイルが壊れていると何回も言われました。)

$ zip -r modified.zip *

あとは拡張子を変えてクリックするだけですが…、ここでやっぱり壊れてると言われてしまいました。

f:id:nemupm:20141008212236p:plain

一応ここで修正を押す事で一旦開く事は出来ましたが、
上書き保存して開き直すと、また同じダイアログが出てしまいました。

素直にあきらめてマクロ組もうかな…

初心者二人でISUCON予選に突撃して予想通り撃沈したよ

f:id:nemupm:20140929061144p:plain

結局ISUCONの予選は惨敗の結果だったわけですが、当日の流れを書き起こしておきたいと思います。

ISUCONとはIikanjini Speed Up Contestの略で、

お題となるWebサービスを決められたレギュレーションの中で限界まで高速化を図るチューニングバトル

です。
最近友人(@__shiki49__)がYAPC::Asia 2014に行った際にその存在を知ったらしく、
「こんなコンテストがあるよ!」ということで紹介してくれました。

サーバはちょっと立ち上げた事があるくらいでほとんど大した知識もなく、
ましてやチューニングなんて出来る訳無いなどと最初は思ったのですが、
こういう機会を大切にしたいし、何事もチャレンジが大事かなと思い、
初心者二人で予選に参加する事にしました。

準備したこと

方針

まずWebアプリの言語について決めました。
友人が普段扱う言語はPHPで僕はPythonだったのですが、
「予選の突破も大事だけど、やっぱり勉強のためというモチベーションも大事にしたいから、
どうせなら新しい言語でやろう!」ということでNode.jsに決定しました。

情報収集

事前に色々な先人達のブログを読んでみました。

  • 最初にサービス全体を把握する事が大事そうだ。
  • ボトルネックを認識するのが鍵となりそう。
    • 一体どうやってするの?勘なのか、セオリーがあるのか。
  • データベースばりばり扱いそうだけど、SQLとかそんな詳しく無いぜ!
    • とりあえずインデックス作れば速くなるんでしょ、くらい
    • 扱うデータ容量が少なければオンメモリで扱う(Redis, Memcached?)のが良さそう
    • キャッシュ・キャッシュ・キャッシュ

過去問を解いてみる

去年のISUCON3の環境がAWSのAMIの形で提供されていたので、前日の夜から少しいじってみる。

  • まず二人ともそれぞれAWS立ち上げ。MySQLが立ち上がらなくて困る。
    • service mysql startじゃなくて、/etc/init.d/mysqld startだと立ち上がった。なんじゃそりゃ!(おかげでプロセスの監視とかのコマンドにちょっと詳しくなった)
  • ベンチマークを走らせる。1400くらい。
  • nginxというサーバが速いらしいので、Apacheからnginxに移行してみる。
    • そういれば、Webアプリケーションは初期状態でPerlが動いているらしいのだが、ApacheはどこでPerlに処理を渡してるんだ?
    • どうやらlocalhost:5000に投げているみたい。
    • nginx.confでルートに来たリクエストを全部5000に投げるように編集。ここでCSSが読み込まれない自体発生。
    • 要素を検証でリクエストヘッダ読んでみると、なんかCSSlocalhost:5000から読もうとしてる…。
    • 調べまくってproxy_set_header Host $host;書いたら直った。スコアは50くらいアップ。しょぼい…。
  • なんとなくNode.js周りを読んで理解してみる。
    • npmでパッケージ入れれるっぽい。
      • 最初自分だけなぜかパス通ってなくてはまった。
    • Node.jsに切り替えてみた結果、スコアが数百くらい下がった。お、おぅ…。

ここで予選当日の朝5時くらいだったのでもう寝ました。

予選詳細

とんだ失態だったのが、二人とも朝寝坊し、10:30くらいに起きたことでした(しかも友人のSkypeで起こされる)。
しかも、「まあ8時間もあるし大丈夫でしょ!」と、
今では目も当てられない、インフラ経験が少ない事によるあまりに浅はかな言葉を放っていました。

まず最初は予習を生かしてとりあえずnginx+Node.jsに環境を変えて動かしてみよう!ということで作業に入りました。 そしたら最初からまさかのnginxだったので、アプリをNode.jsに変えてサービスにアクセスしてみました。
そして動いているのを確認した後、ベンチマークを動かしました。
ここでスコア1400くらいで、ISUCONの予選専用サイトで順位を確かめると70位くらい。
49ersというチーム名(同じ高校の49期生)だったので、とりあえず49位目指すか、という感じで作業に取りかかり始めました。

現状分析

ボトルネックを把握しよう!ということで友人が調べて来たnewrelicというサービスを使ってサービスを解析してみました。
ただ、結局得た情報は「/loginへのリクエストが時間掛かってるな!」というだけ。そりゃそうかという感じ。

次に、色々いじりまくってベンチマーク通らなくなったら大変だから、gitで管理しようかー、ということで
gitで管理し、BitBucketにプライベートリポジトリつくってpushする形式にしました。
同一サーバのプロジェクトを複数人で直接編集する場合の方法は何が良いのかっていうのは、
普段の開発じゃなかなか無さそうなんでISUCON永遠の命題なのでは無かろうか。

それじゃあソースコードを読んでみようかということで、App.jsを読み始めました。
中で結構SQLクエリが実行されていたので、友人がslowqueryというものを導入して、
時間のかかったクエリを検知する様に、そのクエリを中心に解読していきました。

分かった事は、

  • ログインしてmypageに飛ぶ機能だけがあるフィッシング銀行サイト
  • 3・10回連続でログインミスったユーザ・IpはBANする
    • サーバでアクセスログを管理してて、最後に成功して以降のミスった回数とかカウントしててめっちゃ重そう
  • データベース自体の容量は数十MBと、そんなに大きくない。

ということ。そこで以下のような作戦を取る事にしました。

本当はNode.js上でずっとデータを保持しておけばいいんじゃないかと思いましたが、
リクエストを処理するプロセスは1つでは無いのでデータ共有が難しそうだし、
かといってプロセスを1つにするとマルチコアの恩恵が受けられなくなるのでmemcachedにしました。

実装

僕は初期化スクリプトPythonで書いて、友人はApp.jsの、現在SQLクエリを毎回発行して処理している部分を書き換える事にしました。
結果、init.pyの完成にめちゃくちゃ時間がかかり、その後App.jsとの連携をデバッグしながら毎回修正していったものの、
結局時間が無さ過ぎてベンチマークがfailするままに終わってしまいました(最後のスコアは2でした(エッ)。

予選終了後

時間内までに結果を出せなくて悔しかったですが、立てた作戦通りの実装をした場合にどれだけのスコアが出るか知りたかったので、
そのまま寝ずに実装してみました。
休憩をしたりサッカーを見たりしながら朝まで頑張った結果、failしないようになって、最終スコアが5500くらいでした(nemupm/isocun4_pre・GitHub)。

実装でつまづいてた点は、

  • データがmemcachedのメモリサイズ上限値を超えてて一部が消えてた。
  • memcachedとのやり取りの際にJSONシリアライズとかしないといけないことに後で気付いた。
  • リクエストのうちカバーできていないパターンが結構あった

という感じでした。

また、後で見直してみて、結局毎回シリアライズとかに時間掛かってるだろうから、
初期化もjsでやってシリアライズ不要にしたほうが良かったんだろうなと思いました。

まとめ

以下感想です。

  • デバッグがすごく難しかったです。
    • 他の方のブログとか読んでると、nginxのアクセスログを独自に分析したりして必要な情報を集めていて、感心した。
  • 方針は割と本質とずれてなかったと思うけど、実装力なさ過ぎぃ!
  • インフラ知識が無さすぎて、「こういう時はこうする」という常識が無くて時間がかかったり、SQL以外のボトルネックの把握が出来なかった。

ISUCONに参加してみて今回本当に良かったなと思ったのは、僕に足りない知識の部分ってのが具体的に見えたことです。
しかも、それが勉強って感じではなく、与えられた課題を楽しんで解いていって、
終わった後もidobataでチャットを眺めたりブログを読んで色々考えて、というように、
すごく楽しく取り組めたのが最高でした。
みなさん本当にありがとうございます!

是非、次は予選突破を現実的に狙えるだけの知識をつけて、再度挑戦したいです!

MacからCentOSにVNC接続した際の日本語入力切り替え

Macのキーボードだと当然全角/半角変換キーが無いので、
VNCでリモート・デスクトップ接続していた際にどうすれば良いのか暫く悩んでいたのですが、
結構見当違いなところをいじっていたので、ログを一応残しておきます。

日本語入力切り替えのキーバインド

設定ウィンドウの表示

標準の英字入力の状態だと、ツールバーに「IBusインプットメソッドフレームワーク」というキーボードのアイコンがあると思うので、
それを右クリックして、設定を押します。

f:id:nemupm:20140926211335p:plain

キーバインドの追加

あとは、表示された設定ウィンドウの一般>キーボードショートカット>切り替え、のところに、
好きなキーバインドを追加するだけです。 僕の場合は、かなキーを設定しました。

f:id:nemupm:20140926211833p:plain


これで、ようやくリモートでも安心してAnthyに切り替え出来る…。

CentOS6のサービスやファイアーウォールの設定をGUIで行う

別にファイアーウォールの設定を/etc/sysconfig/iptablesでやっても良いんですが、
GUIがあるなら絶対そっちの方が楽だろ、ということで導入しました。

ファイアーウォールのGUIツール

f:id:nemupm:20140926173924p:plain

システム>管理>ソフトウェアの追加/削除でa graphical interface for basic firewall setupというパッケージを導入すれば、
以降システム>管理>ファイアーウォールで以下のようなGUIツールを動かせます。

f:id:nemupm:20140926174151p:plain

サービスのGUIツール

f:id:nemupm:20140926174217p:plain

同様の手順で、今度はUtility to start and stop system servicesというパッケージを導入すれば、
以降システム>管理>サービスで以下のようなGUIツールを動かせます。

f:id:nemupm:20140926174309p:plain

その他

今まで/etc/sysconfig/iptalbesで設定した内容がGUIツールに反映されている訳じゃなさそうなので、注意してくだしあ。

MeCabにWikipedia辞書を追加

f:id:nemupm:20140926043559j:plain

MeCab自然言語処理の分野でよく使われる形態素解析ツールです。
ただ、辞書には一般的な単語しか登録されていないため、
Twitterなどを解析する場合はそのままだとあまり精度がよくありません。

そこで、今回はWikipediaの記事のタイトルを辞書として追加することで対応してみます。

追記: 最近は、mecab-ipadic-neologdなるものがオープンソースで存在しており、 それらは十分な辞書数でありながらノイズも少ないので、そちらがオススメです。(ドキュメントもわかりやすいです)

参考になるサイト

インストール

インストールしてない場合は、公式ドキュメントに従い、インストール。
追記:brew install mecab mecab-ipadicが正直楽です。
あと、バインディングもvirtualenvに入れたいなら、タルボールをpipで入れる方が良い。

MeCab

./configure
make
sudo make install

IPA辞書

辞書の文字コードにだけは注意してください。

./configure --with-charset=utf8
make
sudo make install

バインディング

READMEが入っているので、それに従ってインストール。

python setup.py build
sudo python setup.py install

手順

やることはWikipediaのタイトル一覧テキストを整形してMeCab辞書に変換するだけです。

Wikipediaタイトル一覧

落としたら解凍しましょう。

gunzip jawiki-latest-all-titles-in-ns0.gz

タイトルの整形

MeCabを使う上でアルファベットは小文字・全角カタカナ・記号や数字は半角で統一しようと考えているので(Unicode正規化-NFKC)、
タイトルのテキストファイルをフォーマットしておきます。

CSVファイルを作成

辞書を作るにはコストなどの情報を加えてCSVファイルに変換する必要が有ります。
perlスクリプト上記サイトさんを参考に、少し改変しました。
(さらに改変したい場合はバインディングの使い方を参照してください)

ただし、CSVを作る際

  • 必要の無い単語はパス
  • Wikipediaのタイトルでは空白をアンダーバーとして表記しているので元に戻す
  • 既に辞書に登録されている単語は上書きしない

などの処理をしています。 また、コスト(MeCab形態素解析時に参考にする各単語の固有値)も設定していますが、単語長に少し比例する以外はかなりざっくりした設定なので、
調整した方が良いかもしれません。

辞書ファイルを生成・追加

CSVファイルを辞書ファイルに変換します。

$ /usr/local/libexec/mecab/mecab-dict-index -d /usr/local/lib/mecab/dic/ipadic \
> -u wikipedia.dic -f utf8 -t utf8 wikipedia.csv

あとは/usr/local/etc/mecabrcを編集してユーザ辞書として登録するだけです。

userdic = /home/user/Documents/wikipedia.dic

追記

作成した辞書で色々試していたのですが、

名探偵コナン->名探偵コナン
攻殻機動隊->攻殻+機動隊

となってしまいました。これは、攻殻と機動隊が両方ともwikipedia_wordとして登録されているため、
それらを足したコストが攻殻機動隊単体のコストよりも低くなっているのが原因と考えられます。

荒療治ではありますが、コストの計算で、単語長の1.5乗だったのを2乗に変えると無事改善しました。

また、僕も最初ひっかかってしまったのですが、
以前ユーザ辞書を作って追加した事がある人は、一旦それを解除してスクリプトを実行してください。

Dropboxの容量を増やすためにクラウドソーシングを利用してみた

f:id:nemupm:20140924075741p:plain

近頃Dropboxの容量が圧迫されて始め、有料プランに移行しようかと真剣に考えていました。
ただ、その時は一番安価な有料プランが月額9.99ドルまたは年額99ドルで容量100GBで(現在は1TB)、
正直10GBちょっとあれば良かったのでずっと悩んでいました。

ところが最近クラウドソーシングの話を良く聞く様になり、その時同時にふとDropboxの友達招待のシステムを思い出しました。
Dropboxでは、友達を招待する事で、招待した側とされた側両方が500MBの追加容量を獲得する事が出来ます。

ということで、思い切ってクラウドソーシングで友達招待しまくって容量を獲得しようという作戦を実行に移してみました。

クラウドソーシングについて

日本のクラウドソーシング市場の代表的な会社にcrowdworksがあります。

crowdworksは最近流行っているAirBnBやUBERのような、「個人がダイレクトに情報をやり取りする」という時代の流れの中にクラウドソーシングも位置すると考えて、
いち早くクラウドソーシング市場を開拓して来た会社です。

仕事を依頼するとなると、やはり大勢の仕事人が欲しいので、今回はcrowdworksでクラウドソーシングを行いました。

準備

とりあえずcrowdworksのアカウントを作成して、早速仕事を依頼したいところですが、
その前にプロフィールを更新した方が良いです。

なぜかというと、仕事を受注してくれる方たちにとって、仕事の依頼者が信用できるかというのは最も重要な要素の一つで、
それを判断するための唯一の情報がプロフィールだからです。

本人確認書類提出

よってプロフィールを設定していく訳ですが、crowdworksのプロフィールには、住所などを入力する基本情報の他に、
「本人確認書類提出」という項目があります。

これは、基本情報に記載されている名前や住所が本物かどうかを、免許証などの写真を提出する事で証明するプロセスです。

このプロセスは無くても仕事は依頼できるのですが、確実に素早く仕事を受注してもらうためにも、是非登録しておきましょう。
(注意点として、免許証などに記載されている住所を基本情報の住所として設定する様にしてください。)

仕事の依頼

仕事内容の記述

早速仕事を依頼します。依頼内容などの設定は、図の様にほぼ1ページで終わります(但し、今回はタスク形式の仕事依頼しか試していません)。

f:id:nemupm:20140924071009p:plain

f:id:nemupm:20140924071354p:plain

STEP4がちょっと分かりにくいですが、これは実際に受注者に仕事の成果物を提出してもらったり、一連の仕事を行ったかどうかの確認をしたりするためのSTEPだと(僕は)理解して、図の様に記入しました。

それでも分かりにくい場合は、crowdworks上に依頼されている色々な仕事を覗けば作業内容も一緒に見れるので(非表示設定されている場合は無理ですが)、参考にしてみてください。

f:id:nemupm:20140924072201p:plain

最後に依頼する仕事の件数とその報酬を設定します。早く仕事を消化してほしい場合はより高く設定すれば良さそうですが、
今回はそんなに急ぎの用事でもなかったので1件100円とかにしてみました
(後で知りましたが、実際はもっと安い仕事も溢れてるみたいですね)。
件数は、Dropboxの招待システムの上限である32件(32*0.5GB=16GB)に設定しました。

仮払い

f:id:nemupm:20140924073242p:plain

crowdworksでは、受注者が出来るだけ安心して仕事を受注できる様に、発注者が仕事を依頼する時には先に報酬(+マージン)のお金を払っておくシステムを採用しています。

なにやら発注者にとってリスクが有りそうに聞こえますが、実際には仕事が受注されなければ返金も選択できるので、リスクは無いと考えてよいと思います。

詳細画面

f:id:nemupm:20140924073738p:plain

仕事の登録は以上で完了です。思った以上に大分早く終わりました。
僕は登録完了後も仕事が受注されるかかなり気になったので、何回も更新ボタンを押して図の丸の所の数字がどんどん増えていくのを見張ったりしてました(暇人)。

今回は登録完了して数分後にはもう「500MBの追加容量を獲得しました」というメールがDropboxから届き始め、初日だけで5人以上の方に仕事を行っていただきました。

仕事のコピー

今回は一回目の仕事依頼では募集期間中に19件しか捌けなかったので、同じ仕事を再度依頼する事にしました。

f:id:nemupm:20140924074549p:plain

やり方は、マイページに行って図の様に操作するだけです。「コピーして新しい仕事を依頼する」を選ぶと、また仕事内容の記述画面に遷移します。

感想

なんとか2回目の依頼で、32件全てのタスクを捌く事が出来ました。

感想としては、

  • 思ったよりずっと仕事依頼までのプロセスが簡単
  • (今回の様に)どんなに特殊な仕事でも、報酬さえ用意すれば簡単に仕事として依頼できるのは便利

というところでしょうか。

すごい簡単なので、是非皆さんも利用してみてください。