ひ孫

犬のこととか書いていきたい

raspbery piをセットアップしたときにはまったこと(NOOBSを使う入れ方)

raspberry piを買ってみたのでセットアップしようと思ったけど色々はまった。

色々サイト見て回るとimgを手に入れてSDに書き込むとか大変そうなことが書いてある。

しかしダウンロードページに行くとNOOBS(New Out Of Box Software)というのが推奨されている。なんだこりゃ(はまった箇所その1)

悩みながら小一時間調べると最近はこのNOOBSというのをSDカードにぽんと放り込めば良いよということらしい。

そんなに簡単なんだ!

と思って入れても

dd: /dev/mmcblk0 Invalid argumet

というエラーが出てしまう (はまった箇所その2)。

改めてもう一度ちゃんと説明を読むとSDカードを「論理サイズ調整」(macなら「論理アドレス調整」)をONにしてフォーマットしなとダメだとか。

ということでここからダウンロード(左のメニューにダウンロードページへのリンクがあってとでもわかりづらい)したツールでフォーマット

できました!

教訓:面倒がらずに説明をちゃんと読みましょう。

intelijでコンソールが文字化けするとき on windows

素敵なIDEのintellij IDEA。 しかしTestNGとか使い出した途端突然文字化けが発生。 化け方も豆腐系ではなくて本当に化けている感じ。

調べてみるとmacの場合はplistの中にオプションを書いてやるようだ。 windowsにはそんなものは無いが代わりに

C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 11.1.2\bin

idea.exe.vmoptions

というそれっぽいファイルがあったので

-Dfile.encoding=UTF-8

と記載してみた。

治った。

よかった。

ant初心者がivyでjarファイルの依存関係をなんとかしたい

npmの依存関係の解決とかを覚えてからJavaを触ってjarの依存関係って何とかならんのかねェ ってのを調べてみた。

すると出てきたやり方は3つ * maven * ivy (+ ant) * gradle

調べるとmavenはあまり良い評判が見られなかったので却下。

残るはgradleとivyでgradle。新規で始めるならこれでもよさそうだけど今回は既にantがあるのでivyを選んだ

公式のQuick startと結構まんまになってしまいそうだけどさらっとまとめる

ivy.xmlを書く

mavenリポジトリから探してこんな感じivy.xmlファイルを書く。

ivy.xml

<ivy-module version="2.0">
    <info organisation="myproject" module="mymodule"/>
    <dependencies>
       <dependency org="com.google.android"
        name="android" rev="4.1.1.4" conf="default->master"/>
    </dependencies>
</ivy-module>

mavenリポジトリからコピーするとついてこないのだがconf="default->master"という記述が無いとjavadocやsourceまで落とそうとする。後述のantで解決しようとした時に「Multiple artifacts of the module」みたいなエラーがでたらこれが原因。

ant タスクを追加

まず全体はこんな感じ

build.xml

<?xml version="1.0" encoding="UTF-8"  ?>
<project basedir="." xmlns:ivy="antlib:org.apache.ivy.ant">
    <property name="ivy.install.version" value="2.1.0-rc2" />
    <property name="ivy.jar.dir" value="./lib" />
    <property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />
    <path id="ivy.lib.path">
        <fileset dir="${ivy.jar.dir}" includes="*.jar"/>
    </path>

    <target name="download-ivy" unless="offline">
        <mkdir dir="${ivy.jar.dir}"/>
        <get src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
             dest="${ivy.jar.file}" usetimestamp="true"/>
    </target>
    <target name="resolve" depends="download-ivy">
        <taskdef resource="org/apache/ivy/ant/antlib.xml"
                 uri="antlib:org.apache.ivy.ant" 
                 classpathref="ivy.lib.path"/>
        <ivy:retrieve pattern="${ivy.jar.dir}/[artifact].[ext]"/>

    </target>
</project>

公式サイトにのっているのを簡略化している。

基本的な部分

<project basedir="." xmlns:ivy="antlib:org.apache.ivy.ant">

にてivy用のxmlnsを追加。*1

ivy用の設定

    <property name="ivy.install.version" value="2.1.0-rc2" />
    <property name="ivy.jar.dir" value="./lib" />
    <property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />
    
    <path id="ivy.lib.path">
        <fileset dir="${ivy.jar.dir}" includes="*.jar"/>
    </path>

ivyを落としてくる場所を設定。このあたりは公式より簡略化している。

download-ivy タスク設定

    <target name="download-ivy" unless="offline">
        <mkdir dir="${ivy.jar.dir}"/>
        <get src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
             dest="${ivy.jar.file}" usetimestamp="true"/>
    </target>

getなんてのを初めて知ったけどこれで落とせるようなので設定。

resolve タスク設定

    <target name="resolve" depends="download-ivy">
        <taskdef resource="org/apache/ivy/ant/antlib.xml"
                 uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
        <ivy:retrieve pattern="${ivy.jar.dir}/[artifact].[ext]"/>
    </target>

先にivy.jarが必要なのでdepends=download-ivyとしている。 <ivy:retrieve pattern="${ivy.jar.dir}/[artifact].[ext]"/>は結構色々やり方がある模様だけど未検証

実行

resolveタスクさえ実行すればよいので

$ant resolve

これで上記のxmlであればlibディレクトリにぐんぐんファイルが落とされてくれるので幸せです。

Intellijだとプラグインでやるようなやり方もありますが、Intellijは標準でant実行機能ついているのでそっちでそのまま走らせてしまうほうが最終的には楽な気がします *2

*1:intellijでなぜか警告されてしまう・・・

*2:Intellijのプラグインは何度かEvent logにエラー出てはまりどころ多し

node.jsのprivateな関数のテストにrewireがすごく便利

node.jsでmodule.exportに書かない部分は外からアクセス出来ないプライベートな関数になる。 困っちゃうのがこれをテストしようとするとき。

結局テストのときだけ外に出したりutil作ったりといろいろ不恰好になって困っていたけど(rewire)rewireというモジュールがとても便利

例えばこんなモジュール

function initParams(input, options, callback){
  if(typeof options === "function"){
    callback = options;
    options = {};
  }
  if(!options) options = {};
  return {
    input : input,
    options : options,
    callback : callback
  }
}

module.exports = function(input, options, callback){
  var params = initParams(input, options, callback)
}

上記の場合、initParamsがprivateな関数になる。 ここでrewireさん登場。

var assert = require("assert")
var rewire = require('rewire');
// ↓rewireでモジュールを呼び出す
var myModule = rewire("../some_package.js");   
// ↓__get__でprivateな関数を呼び出す
var initParams = myModule.__get__("initParams")

//あとは普通にassert
var callback = function(){
};
var result = initParams("hoge", {"foo" :"bar"}, callback)
var expect = {
  input : "hoge",
  options : {"foo" :"bar"},
  callback : callback
}
assert.deepEqual(result, expect)

こんな感じで__get__という関数でprivateな関数を呼び出せる。

__set__というのもあって

myModule.__set__("fooValue", "1111");

myModule.__set__("barFunc", function(err, result){
  assert.equal(expect, result)
});

なんてこともできる

便利!

hubotのscriptを再帰的に読む & hubot-ircでnotice発言させる

はてなダイアリーのテストがてらhubotで詰まった部分&解決した部分

hubot scriptsディレクトリのスクリプトを階層化して読み込みたい

hubotのスクリプトは決め打ちになっている./scriptsか./src/scriptsから読まれる。

しかし一個のフォルダにぶっ込んだらわけわかんなくなってしまうのでさらっと書いてみた。

scriptの中で読ませるというやり方で解決。

__dirnameはnode.js的なこのスクリプトのあるフォルダを差し示している。

globというパッケージを利用しているので npm install glob をする必要アリ

hubot-ircでnotice発言させたい(荒業編)

hubotにirc発言をさせるhubot-ircだが、notice発言はデフォルトではできない。

結構色々な人が悩んでるみたいでforkしたり書き換えたりして解決していたが、書き換えたりするのが嫌だったのでちょっと荒っぽいやり方だけどこんな解決をしてみた。 hubot scriptとして読み込んでしまい、hubot-irc内のbot(実体はircというnodeのirc発言用モジュール)の発言(say)コマンドを上書き。

nickServer使っている部分でsayが呼ばれるのでnickServer使っている場合は使えなそう。

自分の環境ではそういう必要のあるircサーバーは無いのでどうなるかは未検証・・・

forkして書き換えた場合とくらべての利点としてはhubot-irc側に更新があっても基本的には追従できるってことぐらい

node-chromeを一日いじくり回してわかったこと

今朝方
http://www.moongift.jp/2013/02/20130216-2/
という記事を見つけた。
簡単にいえばnode.jsのUI部分をchromeに任せるようなものを作っちゃおう!って代物

過去にこういうことをやろうとしてchrome-extensionを作って挫折したりlocalhostの方をブクマしてたり色々やってた自分には朗報だったので早速node-chromeを触ってみた。

まずは普通にインストール

$mkdir node-chrome-sample
$cd node-chrome-sample
$npm init 
$npm install node-chrome

windowsだとインストール時にエラーが出る。ここについては後述するが、簡単に言うとエラー出ても問題なく動くっぽいのでこの場ではひとまず気にせず進める。

ソースを見てみる

https://github.com/hij1nx/node-chrome
メインとなるのはlib/index.jsだけでとても簡素。
肝になっているのは

  var args = [
    '--app=http://localhost:' + (opts.port || 8080) + opts.index,
    '--force-app-mode',
    '--app-window-size=' + (opts.width || 1024) + ',' + (opts.height || 760),
    '--enable-crxless-web-apps',
    '--user-data-dir=' + __dirname
  ];

このあたり。
なるほど。appモードとして起動するのか。その後のほうはサーバー起動をしてるみたい。
user-data-dirも別になっているのでchrome通常起動時とは独立した状態になっている。

デモを動かす

node-chrome/exampleにサンプルがあるのでとりあえずサンプルを起動

$cd node_modules/node-chrome/example
$node demo

ん?動かん。
とソースを見ると

       :
var opts = {
  runtime: "/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome",
     :

あー・・・はい。すいません。macなんて高貴なもの持ってないんです。でも警告ぐらい出してくれても・・・
なので下記のように書き換え

      :
var opts = {
  runtime: process.env.LOCALAPPDATA+"\\Google\\Chrome\\Application\\chrome.exe",
}
    :

再度起動。
動く。うむ。問題ない。
runtimeを決めてくれないのはなかなか痛い。パッケージで配布するときに困りそう。

とりあえず自分の何かをおいてみる。

demoが問題なかったのでちょっと簡易に作ってみる

index.js

var opts = {
  runtime: process.env.LOCALAPPDATA+"\\Google\\Chrome\\Application\\chrome.exe",
  files: "./view",
  port: port,
  index:  "/index.html",
};
var fs = require("fs")
var client = require(".server.js");
cn(opts, function(websocket, chrome) {
  console.log("foo")
  chrome.on('exit', function (code) {
    process.exit(0);
  });
});

view/index.html

<html>
  <body>
   foo
  </body>
</html>

で、起動

$node index.js

・・・・あれ?console.log(foo)としているのでコンソール上になにかしら出力がありそうなのに黙りこくられる。なんで・・・?
コードをもっかい見てみる

    var wss = new WebSocketServer({ server: httpserver });

    wss.on('connection', function(ws) {
      callback.call(this, ws, chrome);
    });

ハッ!callbackがwebsocketコネクション確立後に来ている!なんてこった!*1 *2
確かにdemoもwebsocketコネクションやっとる。
なのでwebsocketへの接続を追加。

<html>
  <script>
  var ws = new WebSocket("ws://localhost:8080");
  </script>
  <body>
   foo
  </body>
</html>

これで再度起動してみたら動く。うん。動いた・・・
言いたいことはあるけどまとめにて後述。

小ネタとか。

色々やってみて気づいたこともあるのでメモ。

ウィンドウサイズ

ウィンドウ画面のサイズが起動時に固定されているので
画面をサイズを変えて閉じる→再起動 とすると元の大きさに戻ってしまう

'--app-window-size=' + (opts.width || 1024) + ',' + (opts.height || 760),

という部分をコメントアウトしてやると保存されるようになるのでこれはぜひオプションが欲しいところ。*3

ポート

きっとクライアントサイドで複数立ち上げたりすることもあるのでポートが固定だと困っちゃう。
こういうやり方で空きポート見つけて決めたい!
けどポートが変わったら変わったでclientサイドでwebsocketにどうやって渡せばいいの!?
ってなる。そんな時は

<script>
  var ws = new WebSocket("ws://"+location.host);
</script>

こうしてやればOK。わーい。
ちなみにhost名は今のところnode-chrome側でlocalhostに固定されているので変えられない

まとめ

  • 最終的に起動されたときの感じはすげえいい。素敵。
    • node.jsのコードをローカルで起動してブラウザでlocalhost:8080と入力せずその場で開いてくれる&chrome終了時にスクリプトも終了できるというのはとても素敵。
  • ただ結構不満がいろいろ・・・
    • モジュールの方針としてchromeをうまいこと起動するだけにしてはruntime必須とかでちょっと気が効いておらず、サーバー周りについてはwebsocket部分に関してはws強制で自由度効かなくて辛い感じがあってちょっとそのまま使うのは辛い。
      • どういうモジュールとして振りたいのか図りかねるので何かpull request投げづらい感強い。
        • 個人的にはchrome起動のモジュールとして特化してくれたらありがたい。
    • runtimeの指定をうっかり間違うと無言で黙りこくられて捗らない。
    • wsがwindowsでエラー出るしあんまり使いたくない。どうせローカルなんだしsocket.ioとかでも良いしなあ感。*4
    • callbackイベントがwebsocketのconnection確立後に発動してるのでchromeの起動に成功したけどサーバー起動に失敗した時はchrome終了するとかも出来ないの辛い。
  • コード量も大したことないので今のところprocess.spawnして自前するという選択肢もありそう。
  • 兎にも角にもchromeの起動部分は超有用なのでガンガン使って行きたい。

*1:これに気づくのに結構な時間を要した

*2:ちなみにコールバックの第一引数はerrorにすべきって偉い人が言ってた気がするけどどうなんだろう

*3:まあ固定したほうが良い事のほうが多そうだけど

*4:英語自信無いけどwsのエラーは多分この[https://github.com/einaros/ws/issues/155:title=ssue]にひっかかっている