以下の方法で5~10までの乱数が取得できる。
int rand = 5.0 + arc4random() % 6;
上述では初期化と生成がセットになっている。
■おまけ
C由来の方法も使用できる。
srand([[NSDate date] timeIntervalSinceReferenceDate]); int rand = rand();
初期化にはユニークな値を使用する。
以下の方法で5~10までの乱数が取得できる。
int rand = 5.0 + arc4random() % 6;
上述では初期化と生成がセットになっている。
C由来の方法も使用できる。
srand([[NSDate date] timeIntervalSinceReferenceDate]); int rand = rand();
初期化にはユニークな値を使用する。
忘れやすいのでメモっておく。
env('HTTP_USER_AGENT');
try { InputStream inputStream = openFileInput(FILENAME); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); String str; while((str = reader.readLine()) != null) { } reader.close(); inputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
try { OutputStream outputStream = openFileOutput(FILENAME, MODE_PRIVATE); PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(outputStream, "UTF-8")); printWriter.append(str); printWriter.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); }
巨大なファイルの場合に同期読込がANRを発生させることがある。従って、AsyncTaskを使って非同期にファイルの読込書込を行う。
package info.justoneplanet.android.sample.localfile; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import android.content.Context; import android.os.AsyncTask; public class AsyncFileReadTask extends AsyncTask<String, String, String> { private Context mContext; private Observer mObserver; AsyncFileReadTask(Context context, Observer observer) { mContext = context; mObserver = observer; } @Override protected String doInBackground(String... params) { String data = ""; try { InputStream inputStream = mContext.openFileInput(params[0]); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); String str; while((str = reader.readLine()) != null) { data += str; } reader.close(); inputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return data; } @Override protected void onPostExecute(String result) { mObserver.onReadFile(result); } public interface Observer { public void onReadFile(String result); } }
package info.justoneplanet.android.sample.localfile; import java.io.FileNotFoundException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import android.content.Context; import android.os.AsyncTask; public class AsyncFileWriteTask extends AsyncTask<String, String, Boolean> { private Context mContext; private Observer mObserver; AsyncFileWriteTask(Context context, Observer observer) { mContext = context; mObserver = observer; } @Override protected Boolean doInBackground(String... params) { try { OutputStream outputStream = mContext.openFileOutput(params[0], Context.MODE_PRIVATE); PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(outputStream, "UTF-8")); printWriter.append(params[1]); printWriter.close(); return Boolean.TRUE; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return Boolean.FALSE; } @Override protected void onPostExecute(Boolean result) { mObserver.onWriteFile(result); } public interface Observer { public void onWriteFile(Boolean result); } }
上述の2つのクラスは以下のように使用する。
package info.justoneplanet.android.sample.localfile; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.widget.EditText; public class LocalFileActivity extends Activity implements AsyncFileReadTask.Observer, AsyncFileWriteTask.Observer { private static final String FILENAME = "sample.txt"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // ファイルの読込 AsyncFileReadTask task = new AsyncFileReadTask(getApplicationContext(), this); task.execute(FILENAME); } @Override protected void onPause() { super.onPause(); EditText editText = (EditText) findViewById(R.id.edit_text); String str = editText.getText().toString(); if (str.length() == 0) { deleteFile(FILENAME); return; } // ファイルの書込 AsyncFileWriteTask task = new AsyncFileWriteTask(getApplicationContext(), this); task.execute(FILENAME, str); } @Override public void onReadFile(String result) { EditText editText = (EditText) findViewById(R.id.edit_text); editText.append(result); } @Override public void onWriteFile(Boolean result) { Log.e("file", "written"); } }
deleteFile(FILENAME);
以下のような手順で行う。
[sdkdir]/extras/google/market_billingに保存される。
String base64EncodedPublicKey = "your public key here";
プロジェクトで右クリックし新規プロジェクトを選択し、androidのプロジェクトを新たに作る。
※但し、既存のソースから新規作成するようにしてください。
com.exampleというパッケージ名は使用できないのでパッケージ名を変更する。
以下の項目を変更する。
以下の部分を
public static final boolean DEBUG = false;
以下のように変更する。
public static final boolean DEBUG = true;
通常のアプリと同様に署名してマーケットにアップする必要がある。
但し、公開せずに下書きのまま保存する。
ダッシュボードのアプリケーションのタイトルの下の「アプリ内サービス」からアイテムを登録する。
サンプルアプリのアプリ内サービス IDはそれぞれ「sword_001」と「potion_001」で公開する必要がある。
署名されているアプリケーションからリクエストをする必要があるので、以下のコマンドをクライアントで実行しアップロードしたapkファイルを直接端末にインストールする。
./adb install Dungeous.apk
※USBから直接インストールすると、RESULT_DEVELOPER_ERRORというエラーが返ってきて正しくテストできない。
あんまり書くこともない気がする。
int counter = 0;// グローバル int main(int argc, char *argv[]) { int counter = 5;// ローカル printf("%d", counter); }
ちなみにブロックスコープはちゃんと存在する。
int main(int argc, char *argv[]) { int counter = 5;// ローカル printf("%d", counter); if(1){ int x = 10; } // この空間ではxは不可視 }
関数に紐づいた静的な変数で呼び出しごとに初期化されない変数。
int count() { static int counter = 0; return counter++; } int main(int argc, char *argv[]) { printf("%d", count());// 0 printf("%d", count());// 1 printf("%d", count());// 2 }
「緊急地震速報 by Extension」を作って経験したことなどをまとめました。今回は後編です。前編は会社のブログに書きました。
僕は生産設備を持っていませんので食料をはじめとした物流における支援は難しいのかもしれません。しかしながらシステムエンジニアとして間接的な支援や情報における支援はできます。僕は、天災における「破壊」を修復するのは人々の「生産」と考えるとともに、その「生産」の一部分を担う者として頑張っていきたいと思います。
東北地方太平洋沖地震の後、余震が頻発し緊急地震速報の警告音も頻繁に耳にするようになりました。警告音に焦らされる一方で、本当は落ち着いて揺れに対処しなければならないと思っていました。そこで緊迫感を与えないような緊急地震速報を出せないものかと今回の制作にいたりました。(なので初期バージョンには音がなかったのです)
また、本当は「緊急地震速報 by Chrome Extension」という名前で登録しようとしたのですが「Chrome」というワードは使用ができないので「緊急地震速報 by Extension」という名前になりました。
大きな会社などではプロキシ経由でインターネットに接続するようになっていて配信サーバと接続ができないようでした。
ポート12001番を使用していました。
var hosts = [ '123.123.123.123:12001' ];
ポート443番を使用するように変更しました。
var hosts = [ '123.123.123.123:443' ];
HTTPSで使用するポートを用いることにより一部の方の接続が可能になりました。
ポート443番、80、8080番、12001番を使用するように変更しました。
var hosts = [ '123.123.123.123:443', '123.123.123.123:80', '123.123.123.123:8080', '123.123.123.123:12001' ];
これによって判明したのは1/3〜1/4の利用者の方は443にしか接続できなかった事です。
今回、Websocketサーバからbroadcastする際、node-websocket-serverを使用したのですが日本語を正しく送信できませんでした。
wsServer.broadcast('\\u3092');
こうすることでクライアント側には\u3092という文字列が送信されるようになります。
ちょっとライブラリの中をのぞいてみます。
broadcastメソッドです。
this.broadcast = function(data) { manager.forEach(function(client) { clientWrite(client, data); }); };
上述のとおりforEachで回してます。clientWriteメソッドも確認します。
function clientWrite(client, data) { if (client && client._state === 4) { client.write(data, 'utf8'); } }
utf8としていされてwriteされています。
Manager.prototype.forEach = function(callback, thisArg) { var current = this._head; while (current !== null) { callback.call(thisArg, current.connection); current = current._next; } };
this._headは連結リストの先頭の要素のようです。
this._head = client;
clientオブジェクトが入っているようです。
var client = { id: connection.id, _next: null, connection: connection };
接続IDと接続、次の要素を保持しています。
function write(connection, data) { debug(connection.id, 'write: ', (new Buffer(data)).inspect()); if (connection._socket.writable) { return connection._socket.write(data, 'binary'); } return false; }
binaryと指定されていますね。完全に読み切るには少々時間がかかるので適宜更新します。
情報はtwitterのUser Streams API経由で取得していたのですが、ご利用者の方から震度やマグニチュードだけを簡略化して欲しいとの要望がありました。そこで正規表現を使用し文字列を整形して表示することにしました。ところが一部のご利用者には元の文章がそのまま表示されていました。
以下のようにして日本語をマッチさせるときに16進表現を使用することで解決しました。
var reg = new RegExp('\u9707\u5EA6([3-9]\u5F37*\u5F31*)', 'ig'); text.match(reg); var scale = RegExp.$1; // filter : simplify if(localStorage["simplify"] !== "false"){ var reg = new RegExp('([0-9]*/[0-9]*/[0-9]*)', 'ig'); text.match(reg); var date = RegExp.$1; var reg = new RegExp('([0-9]*\:[0-9]*)', 'ig'); text.match(reg); var time = RegExp.$1; var reg = new RegExp('\u30DE\u30B0\u30CB\u30C1\u30E5\u30FC\u30C9([0-9\.]*)', 'ig'); text.match(reg); var magnitude = RegExp.$1; var reg = new RegExp('\u3001(.*?)\u306E', 'ig'); text.match(reg); var place = RegExp.$1; if(date != '' && time != '' && place != '' && scale != '' && magnitude != ''){ text = date + " " + time + " " + place + "\n\u9707\u5EA6" + scale + "\n\u30DE\u30B0\u30CB\u30C1\u30E5\u30FC\u30C9" + magnitude; } } // filter : scale switch(localStorage["scale"]){ case "7": if(parseInt(scale, 10) < 7){return false;} break; case "6": if(parseInt(scale, 10) < 6){return false;} break; case "5": if(parseInt(scale, 10) < 5){return false;} break; case "4": if(parseInt(scale, 10) < 4){return false;} break; }
ブラウザ側の言語設定は各々異なります。通信時の文字コードを指定しても解決するかもしれません。
node.jsを使い、以下のようなコードでtwitterと接続してます。
var client = http.createClient( 80, "stream.twitter.com", false, false, { "username" : "hogehoge", "password" : "fugafuga" } ); var request = client.request( "GET", "/1/statuses/filter.json?follow=123456789", { "host" : "stream.twitter.com" } ); request.end(); request.on( "response", function(response){ //sys.puts("response"); var chunk = ''; response.on( "data", function(data){ // データ受信処理 } ); response.on( 'end', function(){ // twitterから接続を切られた時 } ); } );
実はたまに接続を切られます。切断される可能性を考慮し以下のようなコードを使用してます。
var getRequest = function(){ var request = client.request( "GET", "/1/statuses/filter.json?follow=123456789", { "host" : "stream.twitter.com" } ); request.end(); request.on( "response", function(response){ response.on( "data", function(data){ // データ受信処理 } ); response.on( 'end', function(){ // twitterから接続を切られた時 r = getRequest();// 再接続 } ); } ); return request; } var r = getRequest();
通信は必ず切れるものと考えてコードを書かなくてはいけませんね。さらに実は以下のようなスクリプトも実行してます。
request.on( "response", function(response){ //sys.puts("response"); var chunk = ''; response.on( "data", function(data){ // データ受信処理 } ); response.on( 'end', function(){ // twitterから接続を切られた時 throw new Error('twitter disconnected me!!'); } ); } );
node.jsにおいてcatchできなかったErrorはプロセスを終了させます。従って以下のようなシェルスクリプトと組み合わせてプロセスが終了してないか定期的にチェックし、終了していた場合は再起動することで接続を維持しています。
#!/bin/sh while true do isAlive=`ps -ef | grep "my-websocket-server.js" | grep -v grep | wc -l` if [ $isAlive -ge 1 ]; then echo "process is alive" else node my-websocket-server.js.js echo "process is dead" fi sleep 3 done
拡張機能のアップデートは自動で行われますが、新バージョンを登録してすぐに全ユーザのアップデートが完了するわけではありません。意外にも早く直後にアップデートされる方もいれば、時間がかかる方もいます。1時間で10%程度の方がアップデートされるようです。一方、90%のユーザはアップデート前のクライアントでサーバに接続しますので考慮して更新しなければなりません。
ちなみにですが以下のコマンドでWebSocketサーバを起動してます。
nohup ./check.sh > log.txt &
接続数を調べるには以下のようなコマンドを使ってます。
lsof -i:12345 | grep "node" | wc -l
システムの設計の問題にもなりますが、twitterからの文字列が正しくパースできないようなケースが稀にあります。入力は受け手側が意図する形式になるとは限らないということです。
node.jsの素晴らしさを実感する毎日ですが、接続数が1万数千を超えるとさすがに0.5〜1秒程度遅延します。早く多くの方に届けるべき情報ではあるものの、一方で多くの方が接続すると遅延が生じやすくなります。サーバは個人で賄っているので限度があります。非常に難しい問題です。財閥の末裔だったらデータセンターごと買うのになと思う毎日です。
僕は水や電気の節約には賛成です。しかしながら根拠が不明瞭な自粛ムードには反対です。冒頭で述べました通り、破壊を修復するのは生産であり、手を止めて遠慮する事では無いと思います。何もできることがないと考えた結論の自粛より、いつも通り働き、学び、生活する方が生産的だと僕は考えます。まだまだ対応できていない事ばかりで完璧ではありませんが今後とも宜しくお願いいたします。早く余震が収まるといいですね。(●´⌓`●)
今まで通り@mi_eqbotまでお願いいたします。自分のブログよりも確実にチェックしてます。w
@mitsuaki_iまでお願いいたします。
盗聴の可能性のある通信路を使って、暗号鍵の共有を可能にする暗号プロトコルである。
#python g = 3; p = 2147483647; #A a = 11; A = g**a % p; #B b = 10; B = g**b % p; #A B**a % p; #B A**b % p;
以下のようなコードを考える。
var sys = require('sys'); var dog = { "pochi" : 16, "john" : 10 }; var getDogAge = function(name){ return dog[name]; } sys.puts('pochi is ' + getDogAge('pochi') + ' years old.');
以下のようにモジュール化すると非常にすっきりする。
以下のように記述する。ちなみにgetメソッドなどは予約されていて使用できないようだ。
var dog = { "pochi" : 16, "john" : 10 }; exports.getAge = function(name){ return dog[name]; }
クライアント側から使用するメソッドやプロパティはexportオブジェクトのプロパティとする。それ以外のグローバル空間にある変数や関数はクライアント側からは見えず、プライベート扱いとなる。
以下のようにして使用する。
var sys = require('sys'); var dog = require('./dog.js'); sys.puts('pochi is ' + dog.getAge('pochi') + ' years old.');
また以下のようにした場合は
var Dog = function(name){ var self = this; self.name = name; self.cry = function(){ sys.puts(self.name); } } module.exports = Dog
以下のように使用することができる。
var Dog = require('./dog.js'); var dog = new Dog();
すっきり。簡単。(●´ω`●)
UITextFieldでは以下のようにすることでプレースホルダーを使用することができる。
UITextField *field = [[UITextField alloc] init]; [field setFrame:CGRectMake(10, 120, 190, 35)]; [field setPlaceholder:@"入力してください"];
複数行のテキスト入力欄が必要な場合はUITextViewをEditableにして対応するが、上述のような手法でプレースホルダーを用いることはできない。
#import "UIPlaceHolderTextView.h" @implementation UIPlaceHolderTextView @synthesize placeholder; @synthesize placeholderColor; @synthesize placeholderLabel; - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [placeholderLabel release]; placeholderLabel = nil; [placeholderColor release]; placeholderColor = nil; [placeholder release]; placeholder = nil; [super dealloc]; } - (void)awakeFromNib { [super awakeFromNib]; [self setPlaceholder:@""]; [self setPlaceholderColor:[UIColor lightGrayColor]]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil]; } - (id)initWithFrame:(CGRect)frame { if((self = [super initWithFrame:frame])) { [self setPlaceholder:@""]; [self setPlaceholderColor:[UIColor lightGrayColor]]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:nil]; } return self; } // 表示テキストに変更があった時 - (void)textChanged:(NSNotification *)notification { if([[self placeholder] length] == 0) { return; } if([[self text] length] == 0) { [[self viewWithTag:999] setAlpha:1]; } else { [[self viewWithTag:999] setAlpha:0]; } } - (void)setText:(NSString *)text { [super setText:text]; [self textChanged:nil]; } // drawRect時にplaceholderのUILabelを準備してViewに追加する - (void)drawRect:(CGRect)rect { if([[self placeholder] length] > 0) { if (placeholderLabel == nil) { placeholderLabel = [[UILabel alloc] initWithFrame:CGRectMake(8,8,self.bounds.size.width - 16,0)]; placeholderLabel.lineBreakMode = UILineBreakModeWordWrap; placeholderLabel.numberOfLines = 0; placeholderLabel.font = self.font; placeholderLabel.backgroundColor = [UIColor clearColor]; placeholderLabel.textColor = self.placeholderColor; placeholderLabel.alpha = 0; placeholderLabel.tag = 999; [self addSubview:placeholderLabel]; } placeholderLabel.text = self.placeholder; [placeholderLabel sizeToFit]; [self sendSubviewToBack:placeholderLabel]; } if([[self text] length] == 0 && [[self placeholder] length] > 0 ) { [[self viewWithTag:999] setAlpha:1]; } [super drawRect:rect]; } @end
以下のようにすることで使用することができる。
UIPlaceHolderTextView *view = [[UIPlaceHolderTextView alloc] init]; [view setPlaceholder:@"(^o^)"];
vi /home/pywebsocket-0.5.2/src/mod_pywebsocket/standalone.py
以下の部分を
parser.add_option('--allow-draft75', dest='allow_draft75', action='store_true', default=False, help='Allow draft 75 handshake')
以下のように変更する。
parser.add_option('--allow-draft75', dest='allow_draft75', action='store_true', default=True, help='Allow draft 75 handshake')
python /home/pywebsocket-0.5.2/src/mod_pywebsocket/standalone.py -p 8800 -d /home/pywebsocket-0.5.2/src/example
WebSocketで8800ポートにアクセスする。(●´ω`●)
yum install http-devel
wget http://archive.apache.org/dist/httpd/modpython/mod_python-3.3.1.tgz tar xvzf mod_python-3.3.1.tgz cd mod_python-3.3.1 ./configure –with-apxs=/usr/sbin/apxs –with-python=/usr/bin/python make make install
vi /etc/httpd/conf.d/python.conf
以下の記述の下に
LoadModule python_module modules/mod_python.so
以下の記述を付加する。
AddHandler mod_python .py
wget http://pywebsocket.googlecode.com/files/mod_pywebsocket-0.5.2.tar.gz tar xvzf mod_pywebsocket-0.5.2 cd pywebsocket-0.5.2/src python setup.py build python setup.py install
vi /etc/httpd/conf.d/python_mod_pywebsocket.conf
以下を記述する。
<IfModule python_module> PythonPath "sys.path+['/usr/lib/python2.4/site-packages/']" PythonOption mod_pywebsocket.handler_root /var/www/html/wsh PythonHeaderParserHandler mod_pywebsocket.headerparserhandler PythonOption mod_pywebsocket.allow_draft75 On </IfModule>
/etc/init.d/httpd restart
cp /home/pywebsocket-0.5.2/src/example/echo_wsh.py /var/www/html/wsh/
WebSocketクライアントで/echoにアクセスする。(●´ω`●)
正確性は微妙だが100クライアントからの接続でのロードアベレージは、「node : pywebsoket(standalone) : pywebsoket(apache) = 0.15 : 0.25 : 0.8」となった。最初の2つの差は微妙だったが、Apacheモジュールとして動作させた時のリソースの消費量は明らかに大きいようだ。