HaskellとGoとRustを調べた
研究室で書いているプログラムはC言語だけど、文字を筆頭に配列の扱いがめんどうでなかなか書く気がおきない。それに、なにか新しいコンパイル言語を勉強してみたいのでHaskellとRUSTとGoを調べてみた。配列だけじゃなくてメモリ管理、並列化が簡単にかける言語がいいな。
Go
GoはCの代替のためにGoogleが開発した言語だ。ポインタを排除したり、GCを導入したり、オブジェクト指向だったりと、CからJavaやC#への移り変わりと似ている。Goではクラスや継承という概念はないがインターフェイスというものがあるらしい。
Goのインターフェイスは、C++でいえば、純粋仮想関数に似ているという。データメンバがなく、すべての関数が仮想関数であるようなクラスだ。Goでは、あるインターフェイスが定義するメソッドをすべて実装した型は、そのインターフェイスを実装しているものと見なされる。こうして個々のメソッドという実装をクラスという概念でまとめるよりも、より柔軟な型とメソッドの対応付けが可能になるのだという。[1]
ダックタイピングでプロトタイプ継承みたいな感じかな? オブジェクティブにかけたりGCしてくれるのはとても嬉しいけど、計算プログラムでのその恩恵とCから書き換えることの労力を比べるとCのままでいいんじゃないって思ってしまった。でも、Goルーチンは気になる。
参考文献
Rust
RustはMozillaが開発している言語。まだ開発途中で遅いらしい[2]。遅いのは残念ながらダメだ。文法はC++に酷似している。並列計算に力を入れているそうなのでそこのところをくわしく調べてみたい。
参考文献
Haskell
Haskellは1990年から開発が始まった純粋関数型プログラミング言語。Wiki読んで意味が分かったのは型推論と参照透過性と遅延評価ぐらい。モナドとかよくわからない。純粋関数型ということで関数を実行してもモナドを使わなければ副作用なしで返ってくる。数値計算プログラムは書きやすそう。手続き型プログラミング言語とはかなり書き方が違うみたいでおもしろそう。並列かとかは簡単にできるのかしら。返り値の使用時に値を評価する遅延評価ってのがどれくらい自分がする計算に効果を発揮するのか計測してみたい。ほかの言語とは毛色の違う言語なので勉強するのはおもしろそうだ。
参考文献
Dropbox API メモ
Dropbox API メモ
エラー
ステータス | 説明 |
---|---|
400 | 入力パラメータが不正。 |
401 | tokenが不正または期限切れ。もう一度認証の必要がある |
403 | OAuthリクエストが不正。開発側の責任 |
404 | ファイルまたはフォルダーが指定の場所に存在しない |
405 | リクエストメソッドが不正(GETかPOSTのみ) |
429 | リクエスト回数過多(アプリ・ユーザーごとに存在する) |
503 | 一時的なサーバーエラー |
507 | ユーザーの容量不足 |
5xx | サーバーエラー |
認証
1. 認証コードを発行する方法
flow = DropboxOAuth2FlowNoRedirect.new(APP_KEY, APP_SECRET) authorize_url = flow.start() # authorize_urlにアクセスして連携を許可する。その後出てくるコードを入力させる code = gets.strip access_token, uer_id = flow.finish(code)
2. 認証後リダイレクトする方法
flow = DropboxOAuth2FlowNoRedirect.new(APP_KEY, APP_SECRET, REDIRECT_URI, SESSION, CSRF_TOKEN_SESSION_KEY) authorize_url = flow.start() # redirect_uri先でquery_paramsにはDropboxから来たrequestのpqramsを入れる access_token, user_id = flow.finish(query_params)
参考にしたもの
SQLインジェクション
ActiveRecordにおけるSQLインジェクション
ActiveRecordを用いた以下のコードはプロジェクトテーブルからプロジェクト名の一致するレコードをSELLECTするクエリであるが、ある危険を孕んでいる。
Project.where("name = '#{params[:name]}'")
このコードはSQL Queryとしては以下のように解釈される。
SELECT * FROM projects WHERE name = '#{params[:name]}'
この時#{params[:name]}
に以下の検索語が挿入されたらどうなるだろうか。
' OR 1 --
--
はそれ以下の文字をコメントとして解釈することを示している。また、OR 1
とすることで常にtrueを返すようにしてしまっている。つまり以下のようになるSQL QueryはProjectテーブルのレコードを全件取得してしまうのだ。
SELECT * FROM projects WHERE name = '' OR 1 --'
このように、開発者の意図しないようなSQL Queryを発行し、認証をすり抜けたりSQL内のデータ改ざんや身勝手な閲覧をすることをSQLインジェクションという。
対抗策
このような不正に対してRoRは特殊文字をフィルターすることで対応している。フィルターするためには以下のように?を用いる。
Project.where("name = ?", params[:name])
また、以下のようにhashでわたすことも可能だ。
Project.where(name: params[:name])
参考にしたもの
MacBookPro Late 2013, MacBookAir Late 2010 の解体・清掃をする
最近、MacBookProがただ起動しているだけでファンをまわすようになった(これじゃ艦これがままならない!)。購入してから8ヶ月近く経っている訳だし、ファン周りの掃除をしてもいい頃合いかなと思って早速解体掃除してみた。
保証は?
解体の前に一つ確認する。解体することで製品保証がどうなるか、だ。Appleの保証規定(Apple - Legal)に保証が適用されない条件が書いてある。
本保証は、以下のいかなる場合においても適用がありません:(a) バッテリー等の消耗品の場合、ただし損害が材質上または製造上の瑕疵により生じた場合はこの限りではありません、(b) 表面的な損傷の場合、なおこれには、かすり傷、へこみ、ポートのプラスチックの欠損を含むものとしますが、これに限りません、(c)別の製品とともに使用することによって生じる損害の場合、(d)事故、乱用、誤使用、液体接触、火事、地震または他の外的原因による損害の場合、(e) Appleの発行するガイドラインに定める以外の方法でApple製品を作動させたことにより生じる損害の場合、(f) Appleの担当者またはApple正規サービスプロバイダ(以下「AASP」といいます)以外の者が履行したサービス(アップグレードや拡張を含みます)によって生じる損害の場合、(g) Appleの書面による許可なく機能性もしくは性能を変更するためにApple製品が改造された場合、(h)自然損耗やその他Apple製品の経年劣化による瑕疵の場合、(i)Apple製品からシリアル番号が剥がされたり汚損されたりしている場合。
改造は保証適用外みたいだけど、解体することについては触れていない。内部を傷つけないようにすれば解体しても大丈夫だよね??
使用した工具
調べてみると解体にはペンタローブドライバとT5トルクスドライバが必要って記事が出てくるけど、とりあえず背面カバーをあけるだけならペンタローブドライバだけでいいっぽい。使用されているネジの軸径は1.2mmだけど、同じ径でも入らなかったドライバもあったので購入時にちゃんと確認した方がいい。僕が購入したのはCellphone Precision Screwdriver /PENGGONG No.8024。千石電商で売ってた。
ほこりを吹き飛ばすためのエアダスターは工具のホーザン■Z–282/283 エアダスターを買った。ついでにSunhayatoのクリーニングクロスも購入。
MacBookAirの掃除
興奮しててMacBookProの掃除の様子は撮り忘れたぜ。
まず開ける。
きたねー。
エアダスターとクリーニングクロスを使って掃除! めっちゃきれいになる。
最後に起動を確認して終了。
解体・掃除してみて
- わりと簡単に解体できる。背面カバーを外すときはピン止めされているので少し強め力を入れる
- ファンが一番汚い
- なんか掃除後にDesktopの背景が初期化されてる
brew で python3 を入れる
とりあえず brew update & upgrade する
$ brew update $ brew upgrade
pyenvでpythonをバージョン別に導入する
$ brew install pyenv
.zshrcに以下を追加する。
eval "$(pyenv init -)" export PYENV_ROOT=/usr/local/opt/pyenv
source .zshrc
をした後にpyenvでpythonを導入する。pyenvで導入できるバージョンは
$ pyenv install -l
で確認できる。以下のコマンドでinstallできる。
$ pyenv install <入れたいpythonのバージョン>
pyenv-virtualenv
を brew でいれればさらにsandbox化もできるらしい。
追記
numpyとscipyを入れる。3.4.0はdefaultで pip が入っているので以下のコマンドでOK。ただしfortranのscipyはfortranのコンパイルが必要なのであらかじめbrew install gfortran
でもしていれておく。
$ pip install numpy $ pip install scipy
Rakefileで快適コンパイル生活
コンパイルしたいときはたった四文字打つだけ。
$ rake
Rubyをよく使うのでC言語のコンパイル処理をRakefileに書いた。
require 'rake/clean' CLEAN.include("**/*.o") CLOBBER.include("*.out") CC = "gcc" GFLAGS = "-g -Wall" OPT = "-O3" INCDIR = "lib" SRCS = FileList["**/*.c"] OBJS = SRCS.ext('.o') PROGRAMS_DIR = FileList.new("**/*.c").exclude("lib/*").ext('.out') PROGRAMS = PROGRAMS_DIR.map{|p| File.basename(p)} DATA_DIR = "data" directory DATA_DIR task default: PROGRAMS desc "初期化" task init: [DATA_DIR, :reset] desc "中間ファイルを削除してからビルド" task refresh: [:clean, :default] desc "実行ファイルを削除してからビルド" task reset: [:clobber, :default] desc "依存ファイルのビルド" task dist: OBJS def dep_obj program headers = [program.ext('.o')] open(program.ext('.c')){ |f| headers.push "/#{$1.ext('.o')}" if $_ =~ /#include\s+"(.+)"/ while f.gets } OBJS.select{|obj| obj =~ Regexp.union(headers) } end PROGRAMS_DIR.each do |program| desc "#{File.basename(program)}をビルド" file File.basename(program) => dep_obj(program) do |t| sh "#{CC} #{OPT} #{GFLAGS} -o #{t.name} #{t.prerequisites.join(' ')}" end end rule '.o' => '.c' do |t| sh "#{CC} #{OPT} #{GFLAGS} -c #{t.source} -o #{t.name} -I#{INCDIR}" end
固定タスクは init
と refresh
と reset
で文字通りのことしてる。rake/cleanを require することでcleanとclobberというタスクが追加される。
CLEAN.include("**/*.o") CLOBBER.include("*.out")
このようにして削除したいファイルをincludeしておくとタスクを実行したときに消してくれる。いちおうcleanは中間ファイル、clobberをclean + 実行ファイルを消すためのものらしいけど、違いはいまいち分からない。
PROGRAMS_DIR = FileList.new("**/*.c").exclude("lib/*").ext('.out') PROGRAMS = PROGRAMS_DIR.map{|p| File.basename(p)}
defaultタスクは配下のすべてのプログラムをコンパイルしている。libを除いたフォルダの中のC言語をそれぞれ実行ファイル形式(.out)にコンパイルしている。FileListでCファイルのPATHを求めて実行ファイル名を作成している。ext()はFileListの関数で拡張子を任意の文字列に変換できる。
DATA_DIR = "data" directory DATA_DIR ...ruby task init: [DATA_DIR, :reset]
directoryはFileUtilsの関数だけど[1]タスクのように指定することでディレクトリを作成してくれる。
PROGRAMS_DIR.each do |program| desc "#{File.basename(program)}をビルド" file File.basename(program) => dep_obj(program) do |t| sh "#{CC} #{OPT} #{GFLAGS} -o #{t.name} #{t.prerequisites.join(' ')}" end end
動的に実行ファイルのコンパイルタスクを生成している。
def dep_obj program headers = [program.ext('.o')] open(program.ext('.c')){ |f| headers.push "/#{$1.ext('.o')}" if $_ =~ /#include\s+"(.+)"/ while f.gets } OBJS.select{|obj| obj =~ Regexp.union(headers) } end
Cファイルを開きincludeされているものを読んでいる。 if $ =~ /#include\s+"(.+)"/
は$が暗黙の変数なので if /#include\s+"(.+)"/
でもOK。でもwarningが出るので極力やめよう。
rule '.o' => '.c' do |t| sh "#{CC} #{OPT} #{GFLAGS} -c #{t.source} -o #{t.name} -I#{INCDIR}" end
rakeのruleでOファイルが同名のCファイルから作成できることを書いた。
MacBookAir'11 OSX 10.9 Mavericks でRailsアプリケーションサーバー構築
1. nginxはhomebrewでインストール。
$ brew install nginx
設定は /usr/local/etc/nginx/nginx.conf
に記述する。Mac + unicorn + nginx + Rails - Giworldを参考した。
worker_processes 2; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream unicorn.rails_app { # 自分のrailsアプリの場所 server unix:/Users/kazukitash/ruby_src/jitaku/tmp/sockets/unicorn.sock fail_timeout=0; } server { listen 8080; server_name jitaku-app.com; charset utf-8; location / { alias /Users/kazukitash/ruby_src/jitaku/public; index index.html index.htm index; try_files $uri/index.html $uri.html $uri @unicorn_rails_app; } error_page 500 502 503 504 /50x.html; # location = /50x.html { # root html; # } location @unicorn_rails_app { proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://unicorn.rails_app; } } }
nginxのコマンドは次の通り。
- 起動
nginx
- 終了
nginx -s stop
- 再起動
nginx -s reload
- 設定の検証
nginx -t
2. 次にunicornをgemで入れる。
$ gem install unicorn
[RAILS_DIR]/config/unicorn.rbを作成し、編集。これもMac + unicorn + nginx + Rails - Giworldを参考した。
#ワーカー数 worker_processes 2 #ソケット経由で通信する listen File.expand_path('tmp/sockets/unicorn.sock', ENV['RAILS_ROOT']) # ログ stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT']) stdout_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT']) # ダウンタイムをなくす preload_app true before_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! old_pid = "#{server.config[:pid]}.oldbin" unless old_pid == server.pid begin # StGTTOU だと worker_processes が多いときおかしい気がする Process.kill :QUIT, File.read(old_pid).to_i rescue Errno::ENOENT, Errno::ESRCH end end end after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end
unicornに必要なgemをGemfileに書く。
group :production do gem 'unicorn' gem 'execjs' gem 'therubyracer' end
bundle install
をしたら以下のコマンドでunicornが起動する。
unicorn_rails -c config/unicorn.rb -E production
デーモンにしたかったら以下のようにする。
unicorn_rails -c config/unicorn.rb -E production -D
ちなみにデーモンにしたときは kill #{pid}
で終了させる。pidはpsで見れる。
ps -ef | grep unicorn_rails
localhost:8080でrailsアプリが表示されたら成功。
参考にしたサイト
Mac + unicorn + nginx + Rails - Giworld nginxにreloadシグナルを送っても設定を再読み込みしてくれなかったりなかなかKILLされなかったり - There’s an echo in my head nginx入門