imagemagickをインストール
公式のFAQや、似たような記事は多数あるのですが、それでも嵌ったのでメモ残しときます。
事前準備
Install XQuartz
結果を出力するときに、ウィンドウ(X11)に出す場合は、先にXQuartzをインストールしておく必要があります。
display: delegate library support not built-in `' (X11) @ error/display.c/DisplayImageCommand/1909.
Unsatisfied dependency: XQuartz· Homebrew does not package XQuartz. Installers may be found at: https://xquartz.macosforge.org
こんなエラーが出る場合は、XQuartzが入ってないです。
エラーが教えてくれている通りに、 https://xquartz.macosforge.org からインストールします。
Install libtool
なかったら入れておきます。
sudo brew install libtool
動かしたときに、以下のエラーが出る場合はリンク張りましょう
Library not loaded: /usr/local/lib/libltdl.7.dylib (LoadError)
sudo brew link --force libtool
set display
表示先を指定しておきます
export DISPLAY=:0.0
Install imagemagick
デフォルトだと、X11(XQuartz)利用しないので、オプションに指定してインストールします。
sudo brew install imagemagick --with-x11
お疲れ様です。インストール完了です。
動かしたときに、以下のエラーが出る場合は、X11が起動してません。
`display': unable to open X server `' @ error/display.c/DisplayImages/1666 (Magick::ImageMagickError)
/Applications/Utilities/XQuartz をダブルクリックして起動してやりましょう。
やれやれ、インストールで力つきちゃったよ。。。
バイナリ形式にするだけでメモリ節約プログラミング
比較条件に関係しない値なら、バイナリにする価値あり
小さい数値を多く扱う場合は、バイナリ(可変長表現)にすると結構小さくできます。
データ量が小さくなれば、DBからの取得速度が向上し、アプリのメモリ上にもより多くのデータを保持できるようになります。
ただ、バイナリ形式のままだと大小比較などの計算ができないので、必要に応じて数値型に戻してあげる必要があります。
コード
今回比較に利用したコードは、githubに上げてあります。
https://github.com/TakiTake/seiseki
数値とバイナリの速度比較
学校の生徒100人が毎日テストを5科目受けたときの成績管理用DBを想定
バイナリ形式のDBは、科目カラムに5科目分のデータを保持させます。
テストデータなんで、土日祝日お構いなしにテスト受けてますw
ノーマルなDB
カラム名 | 型 |
日付 | text |
学籍番号 | text |
科目1 | integer |
科目2 | integer |
科目3 | integer |
科目4 | integer |
科目5 | integer |
バイナリ形式のDB
カラム名 | 型 |
日付 | text |
学籍番号 | text |
科目 | blob |
結果
1年分のデータ
size
normal 1.9MB binary 1.7MB
insert
user system total real normal 4.740000 11.920000 16.660000 ( 94.378284) binary 4.660000 11.920000 16.580000 ( 93.093927)
select
user system total real normal 0.210000 0.010000 0.220000 ( 0.221661) binary 0.190000 0.010000 0.200000 ( 0.201906)
5年分のデータ
size
normal 9.6MB binary 8.8MB
insert
user system total real normal 23.860000 58.860000 82.720000 (476.608330) binary 23.530000 58.400000 81.930000 (507.330652)
select
user system total real normal 1.190000 0.070000 1.260000 ( 1.300539) binary 0.980000 0.070000 1.050000 ( 1.078891)
10年分のデータ
size
normal 19MB binary 18MB
insert
user system total real normal 47.350000 118.030000 165.380000 (920.600014) binary 46.610000 118.380000 164.990000 (935.340207)
select
user system total real normal 2.140000 0.100000 2.240000 ( 2.236974) binary 1.790000 0.100000 1.890000 ( 1.891564)
なぜ、サイズが小さくなるのか?
小さい数値を表すのに、8 byte もいらないよね
環境差分はありますが、自分の環境ではRubyのFixnumは、8 byte でした。
0~255までの数値なら 1byte で表すことができるので、固定長ではなく可変長で数値を扱えば、 7byte 削減できというわけです。
どうやって変換すればいいの?
数列 -> バイナリ文字列
Array#pack のテンプレートに w(BER-compressed integer) を指定するだけです。
http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-pack
バイナリ文字列 -> 数列
String#unpack テンプレートに w(BER-compressed integer) を指定するだけです。
http://www.ruby-doc.org/core-1.9.3/String.html#method-i-unpack
応用編
ただの文字列なので、文字列結合もできます
[33, 49, 300, 99, 1000].pack('w5') // "!1\x82,c\x87h"
'abc' + [33, 49, 300, 99, 1000].pack('w5') // "abc!1\x82,c\x87h"
また、こういった文字列処理には、StringScannerが便利です。
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/strscan/rdoc/StringScanner.html
先頭から、3 byte 取得
str = 'abc' + [33, 49, 300, 99, 1000].pack('w5') ss = StringScanner.new(str) ss.peek(3) // "abc"
3 byte 分ポインタを進める
ss.pos += 3
ここから後ろは、可変長なので何byte分取得すればいいかわかりません。
そんなときは、文字列中にbyte数を持たせてあげれば、そこから判断できます。
サイズを含む文字列
packed = [33, 49, 300, 99, 1000].pack('w5') # packした文字列のサイズをさらに、packする # C(8-bit unsigned)にすることで、この1byteを読めば続く文字列のサイズが分かる # 文字列のサイズが、8bitで表しきれない場合は、テンプレートにS, L, Qを適宜使う packed_size = [packed.size].pack('C') str = 'abc' + packed_size + packed ss = StringScanner.new(str) # "abc"の3byte分進める ss.pos += 3 # 1byte取得して、unpackすることで保存しておいたサイズを取得 # unpackは、配列で返ってくるので、最初の要素を取得している ss.peek(1).unpack('C').first // 7 # サイズを格納している、1byte分進める ss.pos += 1 # 最後に、先ほど判明した7byte分取得して、unpackすると # めでたく最初の数列が取得できる ss.peek(7).unpack('w5') // [33, 49, 300, 99, 1000]
heroku上にsinatraで作ったアプリ上げるときのハマりどころ
herokuもsinatraも初心者な自分がハマった所と、対処法書いときます。
基本は、ユーザ登録をして
https://devcenter.heroku.com/articles/ruby
の通りに進めていけば良いのですが
HTMLのテンプレート使いたい
風の噂で、hamlがサクサク書けて良いと聞いたので、hamlを選択
Gemfileにhamlを追加
gem 'haml'
bundle installでhamlをインストール
bundle install
同じようなコードで毎回テンプレート名指定するのがめんどくさい
パスと同じテンプレートファイル名ならば、これでいけた。
get '/:path' do path = params[:path] haml path.intern end
hamlでちょっと凝ったことしたい
HTMLエスケープも自動でしたい
エスケープ設定も追加で
set:haml, :format => :html5, :escape_html => true
共通部分はレイアウトとしてまとめたい
layout.hamlという名前でレイアウトファイルを作成すれば
自動的にレイアウトとして認識してくれます。
ビューファイルは、= yieldで呼べる。
以下、body宣言までのレイアウトが、ビューを呼ぶ例。
!!! %html{:lang => "ja"} %head %meta{:charset => "UTF-8"} %body / ここでビューを呼ぶ / =ではなく、!=にしないとエスケープされるので注意 != yield
呼ばれるビューファイル側のインデントは、インデント無しの状態から始める。
bodyの子要素だからと、インデント2つ分から始めたら怒られた。
要素の属性値がたくさんあって、1行が長くなるのがいや
rubyのハッシュに詰めてから渡すと多少改善される
:ruby opts = { :src => "https://www.google.com/calendar/embed?src=XXX :style => "border: 0", :width => "800", :height => "600", :frameborder => "0", :scrolling => "no" } %iframe{opts}
herokuでアプリの名前変えたらコミットできなくなっちゃった
# 現在の設定確認 % git remote -v heroku git@heroku.com:strong-day-3354.git (fetch) heroku git@heroku.com:strong-day-3354.git (push) # 変更 # アプリ名をAAAに変えた場合 % git remote set-url heroku git@heroku.com:AAA.git # 反映確認 % git remote -v heroku git@heroku.com:AAA.git (fetch) heroku git@heroku.com:AAA.git (push)
社内の開発環境とローカルの開発環境の連携方法
どんな時に便利か?
全てのサービスをローカル環境として構築できれば良いのですが
それがあまり現実的ではなく、基本は外部のアプリを利用して
一部アプリだけローカルのアプリを利用したいとい時に便利です。
ローカル環境構成図
PAC(Proxy Access-Control)ファイルを利用して
まずは、ローカルとそれ以外へのアクセスを振り分けています。
ローカルでは、nginxがアクセスを集約しています。
これは、80番や443番ポートを複数のアプリで利用するためで
ホスト名によって各アプリへリクエストの振り分けをしています。
PACファイル
開発環境用に社内プロキシが無い場合は、設定不要です。
JavaScriptの文法で、proxyの設定が書けるファイルです。
Firefoxだと、下記の場所からから設定できます。
オプション > ネットワーク > 接続設定 > 自動プロキシ設定スクリプト URL
proxyを通さない場合(今回はローカル環境)は、"DIRECT"という文字列を返しておきます。
ドメイン名に"hatena.ne.jp"が入る場合は、開発環境用のproxyを通したい。という場合は、
組み込みのshExpMatch関数を使い、host名とマッチングをかけ、PROXYのIPとポートを返します。
セミコロンでproxyもしくは、"DIRECT"をつなげると、順番に接続を試みてくれます。
function FindProxyForURL(url, host) { if (isInNet(host, "127.0.0.1", "255.255.255.255")) { return "DIRECT"; } else if (isDevHost(host)) { // dev.proxy:9999 return "PROXY 172.16.0.2:9999"; } // default.proxy:9999 return "PROXY 172.16.0.3:9999; DIRECT"; } function isDevHost(host) { return shExpMatch(host, "*.hatena.ne.jp"); }
hostsの設定
isInNet(host, "127.0.0.1", "255.255.255.255")でローカル環境として判定をさせるために
/etc/hosts で、ローカルアプリのドメインのIPを、127.0.0.1として登録しておきます。
# local env 127.0.0.1 d.hatena.ne.jp
これで、http://d.hatena.ne.jp/とアクセスした場合は、127.0.0.1:80へのアクセスに
それ以外のはてなドメインは、172.16.0.2:9999のproxy経由でのアクセスが可能になりました。
nginxの設定
ほぼ、デフォルトの設定のままですが、肝はinclude文です。
これで、各アプリに振り分けるようの設定を読み込んでいます。
error_log /usr/local/var/logs/nginx/error.log; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include params/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /usr/local/var/logs/nginx/access.log main; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; keepalive_timeout 65; sendfile on; gzip on; include /usr/local/var/nginx/conf/extra/backends/*.conf; }
/usr/local/var/nginx/conf/extra/backends/d-hatena-ne-jp.confの場合
d.hatena.ne.jp用のtomcatアプリが、8080ポートで動いている場合は
以下のような設定になります。
server { listen 80; server_name d.hatena.ne.jp; location / { proxy_pass http://127.0.0.1:8080; } }
アプリを増やしたい場合は、hostsファイルへの追記とconfファイルの新規作成で簡単に行えます。
魔術でデプロイ
1文字に飽きたら、詠唱でも
準備
# ホームディレクトリへ移動 function I(){ cd ~/ } # バックアップ function Steel(){ cp /usr/local/tomcat/webapps/UBW.war ./UBW.war } # リリースファイルをSTGサーバから取得 function Unknown(){ scp stg:UBW.war ~/UBW.war } # tomcat停止 function Nor(){ sudo -u tomcat /usr/local/tomcat/bin/shutdown -force } # アプリ削除 function Have(){ sudo -u tomcat rm -rf /usr/local/tomcat/webapps/UBW } # warファイル入れ替え function Yet,(){ sudo -u tomcat cp ./UBW.war /usr/local/tomcat/webapps/UBW.war } # tomcat開始 function So(){ sudo -u tomcat /bin/sh usr/local/tomcat/bin/startup.sh }
詠唱
I am the bone of my sword. Steel is my body, and fire is my blood. I have created over a thousand blades. Unknown to Death. Nor known to Life. Have withstood pain to create many weapons. Yet, those hands will never hold anything. So as I pray, unlimited blade works.
1文字シリーズ
毎日、毎日タイプするコマンドならば、タイプ数を減らすに限るよね。
抜けてるところには、何を入れよう?
1文字alias
alias a="sudo aptitude" alias b="" alias c="cat" alias d="diff" alias e="echo" alias f="find . -type f -name" alias g="grep" alias h="head" alias i="/sbin/ifconfig" alias j="" alias k="" alias l="ls -ltrah" alias m="" alias n="node -e" alias o="" alias p="perl -wnl -e" alias q="" alias r="reset" alias s="sqlplus user_name/password@host[:port][/service_name]" alias t="tail -f" alias u="" alias v="view" alias x="xargs" alias y="" alias z=""
1文字変数
aliasよりさらにネタが無いな
export a="access_`date +%Y%m%d`.log" export b="" export c="" export d="`date +%d`" export e="error_`date +%Y%m%d`.log" export f="" export g="" export h="" export i="" export j="" export k="" export l="" export m="`date +%m`" export n="" export o="" export p="" export q="" export r="" export s="" export t="" export u="" export v="" export w="" export x="" export y="`date +%Y`" export z=""
node.jsでsocket通信
みんな大好きエコーサーバ
Install websocket server module
% npm install websocket-server
Server side
httpとwsプロトコルで、返す値を変えられる。
サーバの監視用にする、クライアント側のコードを返すなどの利用方法が考えられる。
var http = require('http'); var ws = require('websocket-server'); // http server = http.createServer(function(req, res){ res.writeHead(200, {'Content-Type': 'text/html'}); res.end("<html><body><h1>It's Works!</h1></body></html>"); }); server.listen(10003); // WebSocket var socket = ws.createServer({'server': server}); socket.on('connection', function(conn){ conn.on('message', function(msg){ conn.send(msg); }); conn.on('close', function(){ console.log('closed'); }) });
Client side
今回は、サーバのコードとは分けてあるので、httpでアクセスできる場所に適当に置く。
ローカルファイル(file://)だと、セキュリティに引っかかりWebSocket通信ができない。
<script> var ws = new WebSocket('ws://127.0.0.1:10003/'); ws.onopen = function() { ws.send('hello world'); } ws.onmessage = function(evt) { console.log(evt.data); } ws.onclose = function() { console.log('closed'); } </script>