cross-originでiframeが埋め込めないとき
What I want to do
あるサービスをwww上で展開しているのだが、元のドメインのURLをそのまま晒すのがちょっと嫌なのでそれを隠すためにurl-forwardingをしたい。
tkドメインを試す
*.tkとかいうドメインはタダで手に入る。(但し有効期限がある) 登録画面は割と癖のある挙動。登録から割り当てまで時間がかかるので注意。メアドを登録せずに匿名でも登録できるのがウリか。信頼性は低そう。 無料版の範囲だとhttps対応していない。
これでURL-forwardingを試してみたが、やっていることはforward先のurlをiframeで埋め込むことだった。 但し、あるサービスはX-Frame-Options:SAMEORIGINであったので、このままではcross-originエラーが出て何も表示されない。
URL-forwardingといっても結局はforward先のurlをiframeで埋め込むのであれば、わざわざ独自ドメインをとらなくてもどこか信頼性の高そうなドメインにホスティングすればよいということになった。
動的にiframeを埋め込むようにする
人力検索はてなでも質問がされていた。
が、Stackoveflowが解決策としては一番わかり易かった。
cross-originを外すために、以下のサイトを媒介する。
An open source alternative to AnyOrigin
このサイトにパラメータとしてurlを渡すと、html部分を含んだ結果をJSON形式で取得できるので、コールバックでcontentsだけを取得して、divに注入するようにすればよい。ただしリンクは元のドメインのURLのままなので、このページからのリンクもそれぞれ静的なページで用意して、……としない限りはリンク先がおかしいぞ、となってばれてしまう。(もちろんソースコードを見れば一発だけれど) さすがに全ページを静的なページでプロキシするのは現実的でないので、トップページだけiframeの埋め込みでごまかすことで妥協しようと思う。
Dockerでサーバーを立てる(1)
はじめに
様々なところで語られていますが、Dockerはコンテナ型のサーバー仮想化のエコシステムとして知られている。ここでは、DockerでRailsアプリを立てることを目標とする。
大まかな概略をつかむには以下のページが参考になった。
Dockerについての調査まとめ、基本機能+主な特徴+Vagrantの連携 あたり · GitHub
細かなtips
具体的な構成は次に譲るとして、ここでは細かいtipsや周辺技術を書き留めておくこととしたい。
モニタリング
モニタリングツールは群雄割拠していてどれを選ぶかは難しいが、ここでは
これを利用して、コンピュータ上でどのコンテナが立っているかをモニタリングする。
docker run -d -p 9000:9000 --privileged -v /var/run/docker.sock:/var/run/docker.sock dockerui/dockerui
一度立てた後は
docker start dockerui
で起動可能。
コンテナ内に入る
docker exec -it nginx bash
supervisordを使う
本来のdocerは1コンテナ1プロセスが基本ですが、複数プロセスを立ち上げたいことがあるかもしれません。 そのときにこれを使います。
実際にそれを使ってRoR4のコンテナを立ち上げた例がこちら。
データボリュームについて
しばしばbusyboxなどでデータボリュームコンテナを立てて、その上にマウントした設定ファイルやログ用のフォルダをsqlやnginxなどのコンテナで共有するパターンがあります。こうすることで、ログ等を永続化できます。
そのとき、dockerコマンドのオプションをどう設定するかのtipsが、以下にまとまっています。
sshdを立てる
dockerでsshdを立てることはどうなのよ、という意見もありますが、立てている例があります。
gentoo/stage3-amd64でemergeする
docker run -v /home/#{name}/gentoo:/usr/portage/ -it gentoo/stage3-amd64 bash
みたいにすれば、emergeコマンドによるrsyncを永続化できます。これでDocker上で手軽にGentoo LinuxのPortageシステムを体験することができます。
DockerでMattermostサーバーを立てる
自前のサーバーでSlack, Hipchat系のチャットサービスを使いたいと思った時に。Golang製。
立ててみる
Local Machine Setup and Upgrade — Mattermost 2.0 documentation
docker run --name mattermost-dev -d --publish 8065:80 mattermost/platform
http://localhost:8065/にアクセス。それ以後は一回立てた後はこれでOK。
docker start mattermost-dev
他のチャットサービスとの比較
slack
みんな大好きSlack。日本のスタートアップ企業でも圧倒的シェアを誇っています*1。
Slackではできるけど現段階のバージョンでのMattermostでできないこと。
- slackbotみたいな存在がない。
- snippet, postを貼れない。
- htmlを入力してもogが表示されない。
- スラッシュコマンドが乏しい。
- Androidネイティブアプリがまだ正式リリースされていない。
Rocket.Chat
デモは以下。
こちらはjsフレームワークのMeteor製。Meteorには割と注目しているのだが、若干洗練されていないデザインであるという印象。
トラブルシューティング
このサーバーで実際に複数人が接続して試してみたときの備忘録です。
- 他のユーザーが登録できない!
- 最初のユーザーはteamを作るときに登録できますが、そうでないユーザーはチームの画面に行ってもsign upできずに何もできません。実は招待urlから入るしかないので、最初のユーザーはメニューからInviteを選択しましょう。
- 最新版にアップデートしたい!
- 公式ドキュメントによれば、これはPreview版にすぎないため一度dockerイメージを削除してからpullするしかないようです。もちろんデータは全部消えてしまいます。
- 日本語のUIがない
- Slackも同じなのでがんばりましょう。
- Admin Consoleでユーザーの権限を誤ってSystem_adminから格下げしてしまった!
- これを一度してしまうと、System_adminでないとユーザー権限を変更できないので、二度とAdmin Consoleにログインできなくなり、設定を戻せなくなって詰みます。
しかも、docker内にはplatformというバイナリがあって、それを用いて本来はユーザーの権限が変更できそうなのですが、docker exec
で中に入ってバイナリを実行しようとしても動かなくなります。というわけで、一度dockerイメージを削除して立ち上げ直しました。
インターンシップを終えて
IT系のインターンシップに1週間ほど行っていたので、感想を簡単に記す。
概観
求められる水準は高く、仕事中は常に頭脳をフル回転させていなければならなかった。そのためインターンシップの期間中は全くといっていいほど、それ以外のことに手がつけられなかった。寝まくったがいくら寝ても体力が回復せず、自らのバイタリティーの乏しさを感じた。
学んだこと
- Macの使い方
- gitの活用。プルリクとイシューの立て方
- GitHub Frow による開発
- Ruby on Railsの開発、きれいなコードの書き方
- Atomの使い方、Slackを使ってみた
- Rspecの書き方(web mocksによるスタブの活用)
- フィーチャーテストの書き方
- Hamlの書き方
- Coffee scriptの解読
- APIの叩き方。アクセストークンの設定方法
- Active recordのクエリの書き方
- 大規模サービスを影で支える人たちの存在
更に学んでいること
今後の展望
Devise, Rake, Redisへの理解を深める必要がある。 特にRakeコマンドは、単なるおまじないとしての取り扱いが大きかったように感じるので、使いこなせるようになりたい。 Coffee scriptぐらいは書けるようになりたい。 Atomは大きいデータを扱い出すと途端に重くなり、ハングアップすることがあるので、やはりvimに戻ろうかと思う。
インターン中に読んだ本
Unix哲学に触れた。1つのプロセスが1つだけのことをするのが良いというのはDockerの思想ともつながっており、とても興味深かった。
- 作者: Mike Gancarz,芳尾桂
- 出版社/メーカー: オーム社
- 発売日: 2001/02
- メディア: 単行本
- 購入: 40人 クリック: 498回
- この商品を含むブログ (142件) を見る
Python2を高速化するtips(続)
これの続き。
単純に高速なアルゴリズムを使う
例えば"ham"という文字列がある配列に含まれるか?という問いに対して、
some_list = ["spam", "ham", "eggs"] if "ham" in some_list
というリスト検索ではO(log(n))ですが、RubyにおけるHashと同様のものがPythonでも辞書(Dictionaly)として提供されており、
some_dict = {"spam":1, "ham":1, "eggs":1} if "apple" in some_dict
とすればO(1)になります。もちろんこれが使えるのには条件がありますが、これで数秒程度早くなりました。
並列計算する
pythonの律速となっているのはだいたいfor文であり、このfor文の実行回数をいかに減らせるか、ということがポイントとなります。 並列計算には、スレッド並列化(メモリを共有する)とプロセス並列化(メモリを共有しない)の2種類があります。しかしCPythonの実装ではGIL(Global Interpreter Lock)というものがあるので、プロセス並列化ぐらいしかできません。
GILとは、並列実行したときに安全でないコード(例えばグローバル変数を書き換えるような、スレッドセーフでないコード:しばしばCのモジュールに存在する)を実行しないようにするために、そのコードを他のスレッドで呼ばれないようにする排他ロックのことで、pythonやrubyといったインタプリタ言語では一般に1つのプロセスに対して1つのGILが存在する。
GILがない実装としてJPython(JAVAによる実装)やIronPython、PypyのSTM版があげられますが、ここでは措きます。
CPythonでプロセス並列化によって高速化するには、for文の区間を分割して部分和を並列で計算し、あとでその総和をとるという手段が用いられます。しかしCのopenMPのように動的にfor文の処理をスレッドに割り当てるといったことは標準では用意されていないので、自分で実装するなりする必要があります。
Boost.pythonを使う
結局pythonで計算させるには限界があるので、C++で書いたコードをコンパイルしたものを共有ライブラリとしてpython側から呼び出す実装にしてみましょう。
#define BOOST_PYTHON_STATIC_LIB #include <boost/python.hpp> static void image_putpixel(image &i, const boost::python::tuple &x, const boost::python::tuple &y){ double point[2] = {boost::python::extract<double>(x[0]), boost::python::extract<double>(x[1])}; uchar color[3] = {boost::python::extract<uchar>(y[0]), boost::python::extract<uchar>(y[1]),boost::python::extract<uchar>(y[2])}; i.putpixel(point, color); } BOOST_PYTHON_MODULE(brush) { using namespace boost::python; class_<image>("image") .def("show", &image::show) .def("brush", &image_brush) .def("putpixel", &image_putpixel) .def("load", &image::load) .def("get", &image::get); }
上記でわかるように、C++のクラスをpythonのクラスにみなせたり、pythonのtupleを引数としてとるような関数を定義することができます。
g++ -std=c++11 -O2 -I`python -c 'from distutils.sysconfig import *; print get_python_inc()'` -DPIC -fPIC -shared -o brush.so src/brush.cpp -lboost_python
-Iにインクルードパスを指定したいのですが、そのパスが異なるコンピュータ上でも共通に実行できるように、``でpythonを実行するコードを囲うことでそれをシェル上で評価した結果が返ってきます。
python側からは、soファイルを同じディレクトリに置いてファイル名でimportすればOKです。さらに、openMPで実装したC++のコードをpython側から呼び出すこともでき、さらに速度が上がる可能性もあります。
APIサーバーが必要となった時のために
自前で実装する
サーバー側にけっこう大きなロジックが必要となる場合。この場合は、単なるRESTなリソースを提供するだけでなく、返り値のロジックが必要となるので、結局自分で全部書いたほうがラクになるということになる。HerokuやOpenShiftといったPaaSに立てることとなる。
Ruby on Railsの場合
Grapeというのがやりやすいらしい。
Pusherを使う
APIにしてスマホのネイティブアプリを作るのならばともかく、ブラウザでアクセスしてもよいということにして、かつWebSocket的なことがやりたいのであれば、Rails5を待つかコレを使う。
Pusher | Leader In Realtime Technologies
例えば、クライアントはpythonでも書ける。
Golangの場合
作ろうとするAPIがRESTfulなものでなくてよいなら、むしろこの程度シンプルなもののほうが作りやすいかもしれない。こっちのほうが当然ながら早い。
BaaSサーバーの候補
サーバーは単にデータストア程度でよいとするならば、BaaSサーバーを使うという手がある。2015/10現在で試用が期限なし無料のサービスを列挙してみた。
国産
Kii jp.kii.com
Appiarie
無料だとpush数が少ないのが劣る点。 www.appiaries.com
海外産
- Parse
実質最大手。 www.parse.com
- Quickbox
変わり種
- Mongolab
mongodbがクラウドで扱えるらしい。
参考
Python2のコードを高速化するための覚書
実行時間の測定方法
CPythonでpythonの素のコードを実行するとヤバイぐらいに時間がかかる。実際にどのぐらいかかるのかを調べる。
import time def main(): start = time.time() hoge() elapsed_time = time.time() - start
まあこれでもよいのだが、
python -m cProfile -c totaltime hoge.py
以上を実行すれば、それぞれの関数呼び出しの回数と、totalの実行時間が明らかになる。明らかになったところで、律速段階となっている関数の高速化に取り組みたいと思う。
高速化手法
numbaでjitを使う
from numba.decorators import jit @jit def hogehoge():
@jitをつけるだけでllvmでjitしてくれる。あまり早くならなかった。
numpy.vectorizeを使う
numpy.vectorizeは配列を引数に取って配列として返す関数を作るものである。ここで、対象となる関数は引数が複数あってもよく、それぞれの引数についてベクトルを渡せばそれぞれの値に対して処理された結果が帰ってくるし、スカラーを渡せばそれはどのベクトルに対しても同じ値が引数として呼ばれる。
import numpy as np def hogehoge(t, anchor): return "hogehoge" def main() vhogehoge = np.vectorize(hogehoge, excluded=['anchor']) mlist = list(vhogehoge(np.arange(0.0, 1.01, 0.01), anchor=anchor))
引数のexcludedでanchorを除外することで、引数に配列を渡したいときにはその配列が分解されずにその関数に渡すことができる。 一方で、渡したいarray of arrayとなっている場合、引数に渡した配列excludedされては"array of array"のまま渡されるか、さもなければ1つのcellごと渡されることになるので、二次元配列を一次元分だけ渡すということはできない。
pypyを使う
これが現時点では最も効果が得られた。 pypyは、CPythonではないpythonの処理系の実装であり、JITコンパイルを適宜行って実行速度の改善が図られている。但しpypyではCPythonのCバインディングのところや、ライブラリの対応がまだ中途半端ということらしいが少なくとも、python2~3の互換性よりはpypyの方がスムーズに移行できた。つまり、コードの書き換えをほとんど必要としないということである。 実行するときは、公式サイトからダウンロードしたバイナリファイル(bin/pypy)をpythonの代わりに実行すればよい。 これを用いると、あるプログラムで11倍ほど高速化された。
Boost.Pythonを使う
これはpythonの範疇からはみ出してしまうが、C++でコードを書き、それをpythonでラッパーとして呼び出して実行する方法としてBoost.Pythonがある。 これについてはまだ研究中であり、ここでの詳述は避けたい。
Bootstrapの導入時に発生するエラーと解決法
ActionController::RoutingError (No route matches [GET] "/fonts/glyphicons-halflings-regular.woff")
Ruby on Rails4の開発で/vender/assets/stylesheets/によそからもってきたbootstrap.cssを入れているとき、上記のエラーが発生することがある。 その場合、フォントを/vendor/assets/fontsに置き、config/application.rbに
config.assets.paths << "#{Rails}/vendor/assets/fonts"
を挿入する必要があるが、もう1点しなければならないことがあり、それは/app/assets/stylesheets/custom.css.scssなどではなく、/vender/assets/stylesheets/bootstrap.cssを改変することである。
@font-face { font-family: 'Glyphicons Halflings'; src: url("../assets/glyphicons-halflings-regular.eot"); src: url("../assets/glyphicons-halflings-regular.eot?#iefix") format("embedded-opentype"), url("../assets/glyphicons-halflings-regular.woff2") format("woff2"), url("../assets/glyphicons-halflings-regular.woff") format("woff"), url( "../assets/glyphicons-halflings-regular.ttf") format("truetype"), url("../assets/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") format("svg"); 1215 }
上記に書き換えたところ、うまく動いた。
Note
POH6をPythonで解く
動機
最近、学科内でPythonがブームとなっているようなので便乗して勉強してみた。 ただ勉強するだけでは面白くないので、オンラインハッカソンに挑戦して実際に書きながら学んでみたいと思う。
コード
input_lines = int(raw_input()) water = 0.0 powder = 0.0 for i in xrange(input_lines): s = raw_input().rstrip().split(' ') if s[0] == '1' : water += int(s[1]) elif s[0] == '2' : powder += int(s[1]) else : total = water+powder water -= int(s[1])*water/total powder -= int(s[1])*powder/total print int(100*powder/(water+powder))