Scalaでフィボナッチ数列のメモ
なんか面接とかでたまに書かされるらしいので
Listで再帰
// ListFib.f(100) object ListFib { def f(lim: Int): List[Int] = { 1 :: 2 :: f(1, 2, lim) } def f(a: Int, b: Int, lim: Int): List[Int] = if (b > lim) { Nil } else { b :: f(b, a + b, lim) } }
Streamで再帰
// StreamFib.f().take(10).toList object StreamFib { def f(a: Int = 1, b: Int = 1): Stream[Int] = b #:: f(b, a + b) }
文字列内の数値をインクリメントする
/** * 文字列内の数値をインクリメントする * ex) TextIncrementer("abc123efg456hij").++() // abc124efg457hij * ex) TextIncrementer("あいう1 2 3えお").++() // あいう2 3 4えお * @param t インクリメントしたい文字列 * @param incrValue いくつインクリメントするか * @return インクリメントした文字列 */ case class TextIncrementer(t: String, incrValue: Int = 1) { def ++(i: Int = 0, n: String = ""): String = { n match { case "" => ++(1, t.slice(0, 1)) case _ if (i > t.length) => n // end case _ => { //println(i, n) n.takeRight(1).exists(_.isDigit) match { // abc1 1が数値か case true => { val c = sequenceNumberCount(i) val nn = n.dropRight(1) // abc1 -> abc val inc = t.slice(i - 1, c).toInt + incrValue ++(c + 1, nn + inc + t.slice(c, c + 1)) } case false => ++(i + 1, n + t.slice(i, i + 1)) } } } } private def sequenceNumberCount(i: Int): Int = { t.slice(i, i + 1).exists(_.isDigit) match { case true => sequenceNumberCount(i + 1) case false => i } } }
オートマトンにしようかと思ったけどまぁ...
正規表現版
"hoge1 = 9999;".gsub(/\d+/) {|i| i.to_i + 1 } // "hoge2 = 10000;"
Fluentdまとめ
Fluentdとは?
ログを収集・集約するruby製のミドルウェアです。いままではrsyncやscpでログを全サーバーから回収したりしてたと思いますが、fluentdを使えば便利に色んな方法でログを集めることができます。
仕組み
Fluentdは、Input・Buffere・Outputというモジュールで構成されています。
- Input
- ログファイル・TCP・UNIXドメインソケット等で受け取ります。
- Buffer
- 受け取ったログを一時的に保管しておくところです。ファイルに保管するかメモリに保管するか選べます。
- Outputは
- Bufferに積まれたログをファイル・MySQL・HBase・MongoDBなどに書いたりします。別サーバーのFluentdに渡すこともできます。
概念図
インストール
yumリポジトリ設定
vi /etc/yum.repos.d/td.repo cat /etc/yum.repos.d/td.repo [treasuredata] name=TreasureData baseurl=http://packages.treasure-data.com/redhat/$basearch gpgcheck=0
インストール
yum install td-agent
準備
mkdir /var/log/fluent chown td-agent:td-agent /var/log/fluent
起動
service td-agent start
送信側サーバー
vi /etc/td-agent/td-agent.conf <source> type forward # TCPで受け取る指定 tag app.file # ここのtagが<mtach>で使われる </source> <match app.file> type forward host 192.168.56.101 # 集約サーバーのhost flush_interval 1s </match>
受信側サーバー
vi /etc/td-agent/td-agent.conf <source> type forward # 送信側サーバーから受け取る(TCP)指定 tag app.file </source> <match app.file> type file # ファイルに書く指定 path /tmp/fluentoo.log </match>
気をつけるパラメータ
buffer_chunk_limit buffer_queue_limit
chunkにログがたまります。
queueにchunkがたまります。
以下の設定だと、2Gなのでサーバーのメモリはそれ以下にしないといけない。
buffer_chunk_limit 8m buffer_queue_limit 256 8MB * 256個 = 2048MB
パフォーマンス
てきとうにVM1からVM2に書くだけのシンプルな環境で計測してみた。
どっちのVMも2coreのメモリ4GのCentOS6。
- 1ログ100Byteを100万回書いた。
- 10,000QPSくらいでた。
- 1書き込み1msもかからない。
- 1ログ30KBを5万回書いた。
- 1500QPSほど。
- 1書き込み1msかからない。
非同期で書くのでかなり速い。
情報
- http://www.slideshare.net/hotchpotch/20120204fluent-logging
- http://www.slideshare.net/tagomoris/oss-nhntech
- http://www.slideshare.net/baguzy/fluentd-meetup-2-14073930
- http://d.hatena.ne.jp/mikeda/20120704/1341363870
http://docs.fluentd.org/articles/quickstart
- ここのチャットで、日本語で気軽にFluentd開発者に質問できます。
まとめ
きっとこれからは各種ログ(/var/log)はFluentdで収集するようになるんだろうなぁと。
グラフ化もGrowthForecastで簡単にできるので、データの見える化が簡単にできますね。
Hbaseへ複雑に書く場合は、rubyだとHbaseのjarを呼んだりしないといけないので同じログ収集ツールであるJava製のFlumeを使うといいです。
有名フレームワークのCSRF対策方法を調べたまとめ
ZendFramework
流れ
- 表示時 : token生成→hiddenセット + セッションにセット
- 送信時 : 送られてきたtokenをセッションにあるものと同じかでチェック
token生成方法
ランダム値 + salt + 固定値 + ランダム値
md5( mt_rand(1,1000000) . $this->getSalt() . $this->getName() . mt_rand(1,1000000) );
まとめ
ランダム値をセッションにいれて、送られてきたものとチェック。
cakephp
流れ
- 表示時 : token生成→hiddenセット + セッションにセット
- 送信時 : 送られてきたtokenをセッションにあるものと同じかでチェック。有効期限設定可。
まとめ
ランダム値をセッションにいれて、送られてきたものとチェック。
fuelphp
流れ
- 表示時 : token生成→hiddenセット + クッキーにセット
- 送信時 : 送られてきたtokenをクッキーにあるものと同じかでチェック。有効期限設定可(=クッキーの有効期限)。
まとめ
jsにも対応してるのでjsでクッキー書いたりしたいからクッキー使ってるみたい。
ruby on rails
流れ
- 表示時 : token生成→hiddenセット + セッションにセット
- 送信時 : 送られてきたtokenをセッションにあるものと同じかでチェック
まとめ
ランダム値をセッションにいれて、送られてきたものとチェック。
結論
あいだをとって
- ランダム値をセッションにいれて、送られてきたものとチェック
- 有効期限チェック
- salt + shha1で生成
が一番よさそう。つまりcakeのが一番よさそう。
JavascriptでSingletonパターン
Singletonで実装したい要件があったが、ググッっても良いのがなくて本読んでも残念なものしかなかったので自分で実装してみた。ちなみに本は、JavaScriptパターン ―優れたアプリケーションのための作法。
要件
- newできないようにする。
- 同一オブジェクトを返す。
クラス名は本にあったものと同じUniverseにしたが別になんでもok。
最初にテストコード
newできないか
try { new Universe() } catch(e) { console.info("ok", e); }
new したら例外が吐かれるようにする。
実装
/** * Description of this class. * Singleton Class. * * @class Universe */ var Universe = (function() { var _fromGetInstance = false; var _instance; function _construct() { if (_fromGetInstance !== true) { throw new Error("must use the getInstance."); } _fromGetInstance = false; } /** * @method getInstance * @return {Object} */ _construct.getInstance = function() { if (_instance) { return _instance; } _fromGetInstance = true; return _instance = new this(); } return _construct; })(); /** * func1. * * @method func1 */ Universe.prototype.func1 = function() { console.log("called func1"); }
使い方
var universe = Universe.getInstanse(); universe.func1();
まず、privateにしたいプロパティがあったのでクロージャにした。
returnされるfunctionをnewできないようにしたいので、getInstanceメソッドからでなければ呼べないようにしてしまう。判定方法は、変数_fromGetInstanceがtrueなのかfalseかなのかというだけ。getInstanceでは一度生成したら次からはそのインスタンスを返すだけ。phpの実装と似た感じ。あとはprotptypeに実装したいメソッドを書いていけばてつもどおりになる。
クロスドメインでcookie書き込む方法 +クロスブラウザで
あるサイトから別ドメインのクッキーを書き込む。こういうクッキーは、サードパーティクッキーと呼ばれる。FirefoxとChromeはデフォルトでサードパーティクッキーが書き込めるようになっているが、IEとSafariが問題になる。IEはコンパクトポリシーというものを設定すればいけるが、Safariは出来ない。Safariはデフォルトで”知らないとサイトや広告のみCookieをブロック”となっている。でも、GoogleAdsenseとかは書き込めている。なので調べた。
ポリシーの設定 (P3P) (以下IE対策用)
webサイトで個人情報などを取り扱う場合、ブラウザで設定されたポリシー設定とアクセスしているサイトのポリシーがマッチするか確認する仕組みがある。詳しくは参考サイトを参照。
Platform for Privacy Preferences 1.0 (P3P1.0) 仕様書
http://www.iajapan.org/trans2japanese/w3c/rec-p3p-20020416j.html
【絵で分かるキーワード】P3P
http://ascii.jp/elem/000/000/338/338065/
P3Pコンパクトポリシーをコピペするのが流行らないことを祈る
http://bakera.jp/ebi/topic/3594
今回は下記をHTTPヘッダーに加える。
header("P3P: CP='UNI CUR OUR'");
phpでセッションに書き込むサンプル (以下Safari対策用)
<?php session_start(); header("P3P: CP='UNI CUR OUR'"); var_dump($_SESSION); $_SESSION['writetest'] = 'waaaa';
できない方法
iframeでクロスドメインのURLにアクセスする。
セッションを張るために、HTTPヘッダーでSetCookie: PHPSESSION=****が返ってくるがクロスドメインなので書き込めない。
test-cookie-sample.html
<!DOCTYPE html> <html lang="ja" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Cookie write test of Cross Domain.</title> </head> <body> <iframe name="ifr" src="http://sample.com/test-cookie-send.php"></iframe> </body> </html>
できる方法
iframeの中にform送信すると、クロスドメインのクッキーも書き込める。詳細は不明だが、GoogleAdsenseがこのロジックで書き込んでいる(実際はもっと複雑な行程だが)。つまりGoogleAdsenseは、Safariで広告のクッキーを書き込まないとしているにも関わらず書き込んでいるのだ。良い子は真似しないように。
test-cookie-sample.html
<!DOCTYPE html> <html lang="ja" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Cookie write test of Cross Domain.</title> </head> <body> <form id="postform" method="GET" action="http://sample.com/test-cookie-send.php"target="ifr"> <input type="hidden" name="cookiewrite" value="cookiewritevalue" /> </form> <iframe name="ifr"></iframe> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> $(function(){ $("#postform").submit(); }); </script> </body> </html>
iPhoneアプリでNode.js
iphoneアプリでnode.jsと通信する。
ネイティブアプリでリアルタイムな通信ができるので幅が広がりそう。
環境はMacOSX10で、今回は全部ローカル作業。
objective-cでWebSocket通信
iPhoneアプリとnode.jsで双方向通信するのは、もちろんWebSocketで行う。node.jsをインストールしたことある人はわかると思うが、WebSocket通信はsocket.IOモジュールで行っているのでクライアントサイド(objective-c)もsocket.IOにしたい。ライブラリはsokect.IO-objcを使う。
インストール
xcode側
socket.IO-objcの依存ライブラリをインポート
- cocoa-websocket
- RegexKitLite
- json-framework
- ASIHTTPRequest
cocoa-websocket
https://github.com/erichocean/cocoa-websocket
git cloneでダウンロードし、以下をプロジェクトにインポート。
AsyncSocket/
SocketIO.h
SocketIO.m
RegexKitLite
http://regexkit.sourceforge.net/RegexKitLite/
tarでダウンロードし、以下をプロジェクトにインポート。
RegexKitLite.h
RegexKitLite.m
あとFrameworksに以下をインポート
libicucore.dylib
json-framework
https://github.com/stig/json-framework/
git cloneでダウンロードし、以下をプロジェクトにインポート。
Classes/
ASIHTTPRequest
http://allseeing-i.com/ASIHTTPRequest/
git cloneでダウンロードし、以下をプロジェクトにインポート。
ここに詳しい説明がある
http://allseeing-i.com/ASIHTTPRequest/Setup-instructions
socket.IO-objcをインポート
https://github.com/pkyeck/socket.IO-objc
git cloneでダウンロードし、以下をプロジェクトにインポート。
SocketIO.h
SocketIO.m
node.js(サーバー側)
node.jsとsocket.ioモジュールのインストール
nodeのインストールはnvmコマンドで行う。
git clone https://github.com/creationix/nvm.git ~/.nvm . ~/.nvm/nvm.sh nvm install v0.4.7 nvm use stable npm install socket.io
サンプル
説明
iPhone側から接続し、接続完了後にnode.js側へobjcイベント発火。(もちろんこのobjcという名前はてきとうにつけたイベント名)
node.js側でobjcイベント受信したら3秒後にiPhone側へメッセージを送信。
xcode側
まずxcodeで空のプロジェクトを作る。
名前はSocketIoSampleとした。
SocketIoSampleViewController.h
SocketIODelegateをデリゲート。
#import#import "SocketIO.h" @interface SocketIoSampleViewController : UIViewController @end
SocketIoSampleViewController.m
viewDidLoadメソッドに下記を追記。
- (void)viewDidLoad { [super viewDidLoad]; // WebSocket接続 SocketIO *socketIO = [[SocketIO alloc] initWithDelegate:self]; [socketIO connectToHost:@"localhost" onPort:3000]; } // WebSocket接続完了した場合 - (void) socketIODidConnect:(SocketIO *)socket { NSLog(@"-- socketIODidConnect()"); // objcイベント発火。(node.js側でon('objc', function() {...})でキャッチ) [socket sendEvent:@"objc" withData:[NSDictionary dictionaryWithObject:@"hoge" forKey:@"Key"]]; NSLog(@"-- sendEvent()"); } // node.jsからWebSocketでメッセージが送られてきた場合 - (void) socketIO:(SocketIO *)socket didReceiveEvent:(SocketIOPacket *)packet { NSLog(@"-- didReceiveMessage() >>> data: %@", packet.data); }
node.js側
conn-objc.js
var io = require('socket.io').listen(3000); var timer = require('timers'); // WebSocket接続時 io.sockets.on('connection', function (socket) { console.log('CONNECTION ok'); // iPhoneからのobjcイベント受信時 socket.on('objc', function (data) { console.log('CATCH EVENT ok', data); // iPhoneからのメッセージ受信3秒後に、node.js側からメッセージ送信 timer.setTimeout(function() { socket.emit('messages', { echo: 'from node.js!' }); console.log('SEND MESSAGE ok'); }, 3000); }); });
node.jsを起動
node conn-objc.js
xcodeでビルド
xcode側のログ
SocketIoSample[19935:b303] Opening ws://localhost:3000/socket.io/1/websocket/222774812681844920 SocketIoSample[19935:b303] Connection opened. SocketIoSample[19935:b303] onData 1:: SocketIoSample[19935:b303] connect SocketIoSample[19935:b303] onConnect() SocketIoSample[19935:b303] -- socketIODidConnect() SocketIoSample[19935:b303] send() SocketIoSample[19935:b303] send() >>> 5:::{"args":{"Key":"hoge"},"name":"objc"} SocketIoSample[19935:b303] -- sendEvent() SocketIoSample[19935:b303] doQueue() >> 0 SocketIoSample[19935:b303] setTimeout() SocketIoSample[19935:b303] onData 5:::{"name":"messages","args":[{"echo":"from node.js!"}]} SocketIoSample[19935:b303] setTimeout() SocketIoSample[19935:b303] event SocketIoSample[19935:b303] -- didReceiveMessage() >>> data: {"name":"messages","args":[{"echo":"from node.js!"}]}
node.js側のログ
info - handshake authorized 222774812681844920 debug - setting request GET /socket.io/1/websocket/222774812681844920 debug - set heartbeat interval for client 222774812681844920 debug - client authorized for debug - websocket writing 1:: CONNECTION ok debug - websocket received data packet 5:::{"args":{"Key":"hoge"},"name":"objc"} CATCH EVENT ok { Key: 'hoge' } debug - websocket writing 5:::{"name":"messages","args":[{"echo":"from node.js!"}]} SEND MESSAGE ok debug - emitting heartbeat for client 222774812681844920 debug - websocket writing 2:: debug - set heartbeat timeout for client 222774812681844920 debug - websocket received data packet 2::
特に問題なく通信できた。
これでリアルタイム操作が可能なアプリ作れますね。(・・`。