(家電レビュー)ジアイーノ感想

ジアイーノを購入しました。

panasonic.jp

定価15万ですが、普通に12-13万程度で買えました。急いでなければもっと安くお得に買えたでしょう。

ジアイーノとは何か?

もともとサンヨーが開発していた技術を使って、パナソニックが発売している脱臭機です。

空気清浄機とは違い、花粉やハウスダストは集塵できませんが、本体で生成する次亜塩素酸水を用いて部屋の臭いを脱臭することができます。

どういう仕組みで動いているのか?

簡単にいうと、食塩水を電解した水(次亜塩素酸水)を使った気化式加湿器です。

本体に水タンク+食塩の錠剤をセットし、電源をONすることにより、次亜塩素酸水の生成(電気分解)が始まり、同時にファンや気化式加湿器のロールの働きにより、

  1. 本体を通過した室内の空気の浄化
  2. ジアイーノから出る空気に含まれる次亜塩素酸水による周囲の除菌

を行うことができます。

具体的に中身がどうなっているか知りたい方はパナソニック公式のお手入れ動画などを見るといいでしょう。

効果はどれほどのものか

すごい!効果てきめん!ってぐらいに家の困った臭いが消えます。

特にキツイ💩介護臭💩に効果的です。本当にあの臭いはキツいですが、キツさに悩むぐらいならポンとこれを買ったほうがいいでしょう。

下記のような臭いもわからないぐらいに消してくれます。

  • トイレシートに放置されている犬のウンコ、オシッコ
  • 大便直後のトイレ
  • 生ゴミ
  • 料理後の臭い
  • 芳香剤の香り

おそらく消臭という部分で言えば、空気清浄機は比較にならない性能の低さでしょう。

あとは心理的な効果として、家が除菌されていることで色々な面で安心感があると思います。(壁に付着した菌とか)

超ざっくりランニングコスト: 2,000円/月

15畳に対応するタイプを購入しましたが、

  1. 本体は10年運用するとしたら(そこまで頑張ってくれるか?!)、毎年1.2万。
  2. 各種消耗品が5年(約3.5万程度)、塩タブレット(約0.35万)が1-2年ちょいぐらいで無くなるそうです。これでだいたい毎年1万弱。

上記計で、毎年2.2万。これにランニングの電気代とかですね。そうなると毎月2,000円程度。安くはない。

でもあの臭いに悩むよりは全然いい。

日々のメンテナンスはどうなのか?

  • 水の補充(毎日)
  • タブレットを入れる(週に2回)
  • 水を捨てる(週に1回)。この時は上記を2つ行う。塩タブレット投入2回のうち1回が水捨てになるかなあという具合。
  • 部品を洗う(毎月ぐらい?)

小さな加湿器みたいなものなので、水の補充が必要です。

また、塩を電気分解しているので、塩の補充が必要です。

そのうちゴミがたまるのか、電解水の濃度がよくわからなくなるのか、水を一旦捨てることが必要です。

これらについてはジアイーノ本体に、それぞれサインが出るので、自分で判断しなくとも、機械の指示に従えばいいです。

あと、たまに一部のパーツを洗うことが必要です。(単純に汚れがたまるので)

僕は洗浄は面倒なので、食洗機に低温コース(40度以下)でパーツまるごと洗浄にかけてしまっています。良い子は真似しないでね。

身体に悪そう

僕もそう思ってました。韓国での事件を思い出したからです。

ただ、今のところは何も身体に影響してないですし、そもそも次亜塩素酸水は次亜塩素酸ナトリウム(俗に言うハイター)と違って安全らしく、愛犬家の人はよく使っているそうです。(この装置の偉大なところは不安定な次亜塩素酸水をその場で作って新鮮なまま使えることなんですね。)

長期的に見た場合、安全かどうかはわからないですね。まあ安全だと思って使ってますし、そもそも臭いがしなくなるなら、別にどうでもいいや…

総合的な感想

介護臭に悩んでいる人はお金があるなら買ったほうがいい。

当然ですが、異臭源の間近では効果は発揮されません。しかし、異臭が家中を漂うなんてことはなくなりますし、異臭源さえ除けばそのうち無臭(or やや薄い塩素臭)にできるという点で安心です。

また、壁などに汚物がやや付着したとしても(何らかの清掃は必要だとは思いますが)結果的に除菌はされるので、心理的な負担感が全然違います。

あとは、最近増えている高気密住宅の場合、何か臭いが発生しても空気交換が従来の家のように窓を開けて豪快にできない(したくない)ケースも多いかと思われます。そういう家での脱臭という点でも優秀です。

個人的にはジアイーノは超おすすめなのですが、やはりネックは価格。そこまで臭いに悩んでない人にとっては少々贅沢な値段と言わざるをえませんが、iPad Proを買ったと思えば…

Jenkins 2.0 以降のDockerイメージを1系のパスワード入力不要etcの仕様に戻してみる

Jenkins 2系LTSバージョンのDockerイメージがいよいよ使えるようになりました。

docker pull jenkins:2.7.1

2系も1系と同じように扱える、と思いきやちょいちょい引っかかりポイントはあります。

使ってて気づいたのは以下。

  • クリーンインストール時)最初にadminの認証パスワードを、 自動生成のファイル ${JENKINS_HOME}/secrets/initialAdminPassword or インストール時のログから拾って入力することを強制させられるようになった。またログインが初期状態で強制されるようになった。
    • 1系は初期状態であればログイン無しで使えます。
  • 最初に推奨プラグインのインストール画面が出るようになった。
    • 1系は出ません。
  • LDAP認証がプラグインをインストールしないとできないようになった。
    • 1系はデフォでLDAP認証が可能でしたが、2系から LDAP Plugin をインストールしないとLDAP認証ができません。
    • LDAPにかぎらず、あると思っていたプラグイン(e.g. Subversion Plug-in)が初期インストールされていない状態です。

LDAPやなくなってしまったプラグイン類のことはおいておくとして、基本的に上記の性質はありがたいのですが、環境を自動でセットアップするとかいうことをやっていると、邪魔な性質でもあります。

初期画面・ログイン必須化をスキップする方法

(下記のサンプルは Githubにて入手可能 です。)

1系の動きに退化させたい場合は、下記のようなファイルを /usr/share/jenkins/ref/ にマウントしてしまえばOKです。

  • /usr/share/jenkins/ref/jenkins.install.UpgradeWizard.state にマウント
2.7.1

初期adminパスワード強制ログインは要らないけど、インストール画面だけは出てほしいという場合は、下記のようなGroovyスクリプトをマウントすればセキュリティ設定をOFFにすることができます。

  • /usr/share/jenkins/ref/init.groovy.d/disableSecurity.groovy にマウント
import hudson.model.*
import jenkins.model.*

Thread.start {
    sleep 10000
    File securityInitFile = new File(Jenkins.instance.rootDir, 'badass-security-init')
    if(! securityInitFile.exists()) {
        Jenkins.instance.disableSecurity()
        securityInitFile.setText('initialized', 'UTF-8')
    }
}

まとめ

気に入らない動作があったら /usr/share/jenkins/ref/ にファイルおけばだいたいなんとかなる。( /usr/share/jenkins/ref/ は開始時に JENKINS_HOME の内容を上書きするようになっているようです。 )

Amazonプライムビデオが神

突然だけど、Amazonプライムビデオは神!

www.amazon.co.jp

動画のラインナップは悪いけど、なんとスマフォに動画をダウンロードできちゃう。

長い電車移動中とかに、映画やテレビ番組を思う存分パケットを気にせず視聴できるわけです。

モバイルネットワークで動画なんて視聴したら、帯域がすぐに狼煙レベルに下がりますからね。事前にダウンロードできる、これはデカい。

HuluやNetflixやってて1ヶ月に映画なんて1本見ればよかったのが、週に数本消化するようになりました。(映画見るのに飽きたら消化しなくなるかもしれないけど…)

最初はただのプライム配送サービスのおまけと思ってましたが、今ではHuluやNetflixよりいいと思えます。

逆にHuluやNetflixが動画ダウンロードをサポートしたら、その時は考えちゃいますね。

JavaでStringのリストの内容にマッチする正規表現オブジェクトを作る

小ネタ。

たとえば下記のようなStringのリストがあったとして、

List<String> strList = Arrays.asList("alpha", "beta", "gamma", "delta");

リストの文字列にマッチする正規表現を作りたいといった場合は下記のようにすればいいです。

// (alpha|beta|gamma|delta) 相当の正規表現を得る
Pattern strListRegexp = 
  Pattern.compile("((?!.)." + strList.stream().map(Pattern::quote).map("|"::concat).collect(Collectors.joining()) + ")");

以下解説。

  • .map("|"::concat) は文字列のリスト(ストリーム)の全要素の前に | をくっつけるものです。
  • Collectors.joining() は文字列のリスト(ストリーム)を、全部くっつけるものです。
  • そういうことで、基本は文字列のリストを | でつないだものを作っています。
    • 単純に | でリストを結合して () カッコで囲めばいいところを、 ((?!.).) で囲うようにしているのは、たとえば仮に文字列のリストが空の場合、何にもマッチしない正規表現を作るためにしています。 この場合、空のリストを入力すると ((?!.).) となりこれは何にもマッチしません。ただ単に () を生成してしまうとどこにでもマッチする表現になってしまいます。 だいたいの、こういう単語などの文字列リストをマッチさせるという用途の場合、空のリストの場合は何にもマッチしない動作が望ましいと考えています。
    • (?!.).は何にもマッチしない正規表現として使用していますが、同じことができるなら他の表現でも問題ありません。 何にもマッチしない正規表現は過去のエントリにも書きました http://knjname.hateblo.jp/entry/2014/03/19/024810 が、過去のエントリの $^ だと、空の文字列にマッチしてしまうようです。($^にとって、空の文字列の開始位置は行末とも言えるし、行頭とも言えるのでマッチできる。$^. とかなら問題ないかも。 )
  • Pattern.quote(文字列) というのは正規表現のメタ文字などを無害な文字列にするメソッドで、今回のリストの文字列要素では必要にはなりませんが、一般的な文字列のリストを処理する場合必要です。 https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html#quote-java.lang.String-

最近の生活傾向

あまりにも太りすぎたので、最近ダイエットしてます。

毎日Withing社のWi-Fi体重計にのって、風呂以外の時は同Withing社のActiviteというスマートウォッチを身につけることにより、体重・体脂肪率、睡眠時間や傾向、時間ごとの歩数が自動で記録されてグラフになります。これは面白い。自分の睡眠時間の短さを自覚しつつあります。

ダイエットはじめてからiPhoneのヘルスケアという機能にはじめて気付きましたが、今のところはWithingsだけで満足かなあという感じ。

運動としては、とりあえず毎日1時間ぐらい散歩をしています。散歩の様子はRunKeeper(非プロ)でGPSトラックしてます。RunKeeperはWithingsと連携させているので、双方にデータが反映されるようになってます。

散歩中は考え事をするなどして過ごしていましたが、最近はNHKラジオ講座とか聞きつつ、シャドーイングしたりして適度に脳みそを使うようにしてます。こうすると歩いている距離をほとんど意識しなくていいです。これからの季節、暑い中歩くのどうしようと今から対策を考えています。

食事は朝昼晩わりと食べています。ただ間食、極端に脂っこいもの、あと炭水化物は基本避けています。炭水化物を避けていると書きましたが、ご飯は1日1回は食べることにしています。家での食事は、品数増やしつつ、汁物は絶対に欠かさないように(満腹感が違う)。

平日、昼以外は自炊率ほぼ100%なのですが、帰宅時スーパーに行くのも面倒だし、何よりレジに並んだりとロクなものじゃないので、毎週土曜日にネットスーパーで1週間分食材をまとめ買いして、まとめて調理したり下ごしらえしてZipLocコンテナにつめまくって1週間の食事をまかなっています。

ネットスーパーといえば、とうとうドラッグストアやらに寄るのも嫌になってきたので、日用品も通販で済ますようになりました。ステマじゃないですけど、ヨドバシの通販は品揃えは控えめですが、日時指定できるのでアマゾンより使いやすいです。

日々軽く料理はしますが、基本的に作り置き料理で大部分カバーできるように工夫しています。小松菜なんか切って冷凍して解凍するだけおひたしになりますから、それに鰹節だのかければ栄養まるごとおいしくいただけます。ダイエット始めてから普段使わない食材を使うようになったような気がします。

そういえば、セブンイレブンとかで売ってるサラダチキン。ダイエットにもおすすめです。ダイエットじゃなくてもおやつにいい感じ。200円、糖質もなくタンパク質が豊富で130kcal程度、まあまあ腹にたまります。

まあ、最近だいたいそんな感じ。

knjname式 Excelマクロブックスタイリング

みなさんExcelマクロでツールを作るとき、ユーザ入力を受け取るために意味もなくダイアログ開いてませんか?取り扱い説明書を別に作っていませんか?

ちょっと力んでいますね。そのマクロツールプログラマ向けであるなら、力む必要はないのです。

力を抜いて、このスタイリングに従えば幸せになれます。

f:id:knjname:20150410015151p:plain

このスタイリング方法は、私がいつもやっている方法で、今のところ不満を聞いたことがありません。

Javaソースコードへのよくある指摘 その1

僕の仕事の一環で他人のJavaソースを見ることがあるので、その時によく出る指摘をちょっと書き出してみた。

とーってもレベルの低い記事なのでJavaをまともにやっている皆さんは読む必要無しです。ただの愚痴エントリだよ。

不要な代入

String name = null; // ここの代入は不要
if (conditionA) {
  name = "foo";
} else {
  name = "bar"
}

これまじやめて。

C言語(C89)から来た人はローカル変数を一番上に宣言したり、初期値を代入しなきゃいけないものだと思ってて困る。 またそういうC言語特有のローカルルールをJavaの初心者に教え込んで嘘を広めていて困る。 (もうC言語から来る人はそうそう出てこないと思うが。)

だいたい、nameに代入しわすれるバグも引き起こすのでやめてほしい。

if分岐の都合上、ありえないけどnameに代入されない分岐パスが出てくるなら、例外でも投げればいい。 まさしく例外だから遠慮せずに投げればいい。

String name;
if (conditionA) {
  name = "foo";
} else if (conditionB) {
  name = "bar"
} else {
  throw new AssertionError("Unexpected condition!");
}

System.out.println(name);

ループで初期代入されるって?上手なかわし方を考えるか、諦めてください。

同じ式

String feces = kuso.getUnko().getShit().get("poo");
String urine = kuso.getUnko().getShit().get("piss");

こういうの本当に多い。似た式は変数かメソッドにまとめてください。そういう作業がいちいち面倒ならIDEの使い方覚えて下さい。

思考停止の StringBuilder

// ファッ!?
StringBuilder sb = new StringBuilder();
sb.append("The specified value = [");
sb.append(hoge);
sb.append("] is illegal.");
String result = sb.toString();

// これでいい。(あるいは String.format("[%s]", hoge) 使いましょう。 )
String result = "The specified value [" + hoge + "] is illegal."

見づらいのでやめていただきたい。

きっとどこかでStringの結合演算子(+)使うなっていうコーディングルール見て、その使うな、だけが脳みそに残ったか、単純にそのコーディングルールがイカれていたかなんでしょう。

ちなみにStringBuilderの多くの使いどころはループ処理で文字列結合する場合だと思いますが、Java8だと以下のようにListからStringに変換できたりするので、使う機会は減ると思います。

// Java7まで
StringBuilder sb = new StringBuilder();
for(Elem e : list){
  if(sb.length() > 0) sb.append(", ");
  sb.append(e.getVal());
}
String result = sb.toString();

// Java8から
String result = list.stream().map(Elem::getVal).collect(Collectors.joining(", "));

tryでcatchしなきゃいけないものだと思っている

try文にcatchは必須ではありません。 try {} finally {} だけでもいいのです。

// (そもそもtry-with-resources使えよっていうツッコミは無しで)

Connection c = null;
try {
  c = acquireConnection();
  transactionalProcessing(c);
} catch (HogeException e) {
  throw e; // 何もしないのにcatchして例外をもっかい投げるのは無駄
} finally {
  closeQuietly(c);
}

final配列を定数だと思っている

finalつけりゃいいってもんじゃないんだよ。時代はイミュータブルなんだよ。

// これ定数じゃない! CONSTANT_LIST[0] = "Unko" で更新できてしまう。
public static final String[] CONSTANT_LIST = {"One", "Two", "Three", "Four"};

// これが定数!
public static final List<String> CONSTANT_LIST = Collections.unmodifiableList(Arrays.asList("One", "Two", "Three", "Four"));

Collections.unmodifiableListArrays.asList の組み合わせはよく使うので、どっかにそれ用のユーティリティ用意しておくのが普通です。

nullありのObjectの比較

java.util.Objects クラス使いましょう。

// String lhs;
// String rhs;

if (Objects.equals(lhs, rhs)) {
  // lhs == null && rhs == null の場合もOK
}

番外編・メソッドを上手にEclipseで抽出する方法

メソッドのまとめ方ですが、Eclipseならこういうふうにできます。あんまりこういうやり方を解説している人が少ないので、一応解説しておきます。

以下のソースを見て下さい。

// Map<String, String> barMap, fooMap, bazMap;

if ( Objects.equals(barMap.get("hoge"), fooMap.get("hoge")) ) {
  bazMap.put("hoge", retrieveValue("hoge"));
}

if ( Objects.equals(barMap.get("fuga"), fooMap.get("fuga")) ) {
  bazMap.put("fuga", retrieveValue("fuga"));
}

これがこうなったらわかりやすそうです。

private void setRetrievedValueIfEq(String key, Map<String, String> barMap, Map<String, String> fooMap,  Map<String, String> bazMap) { ... }

setRetrievedValueIfEq("hoge", barMap, fooMap, bazMap);
setRetrievedValueIfEq("fuga", barMap, fooMap, bazMap);

上記のようなコードにさっさとEclipseで変更するには、まずは下記のように変数を抽出(Alt-Shift-l)し、

// Map<String, String> barMap, fooMap, bazMap;

String key = "hoge";
if ( Objects.equals(barMap.get(key), fooMap.get(key)) ) {
  bazMap.put(key, retrieveValue(key));
}

String key2 = "fuga";
if ( Objects.equals(barMap.get(key2), fooMap.get(key2)) ) {
  bazMap.set(key2, retrieveValue(key2));
}

if部分を選択してメソッドを抽出すれば(Alt-Shift-m)下記のようになります。同じ構造しているものもメソッドに抽出されます。

要するにパラメータにしたいものをローカル変数として抽出してIDEが見つけられるようにしておくのがメソッド抽出のミソなんですね。

private void setRetrievedValueIfEq(String key, Map<String, String> barMap, Map<String, String> fooMap,  Map<String, String> bazMap) { ... }

String key = "hoge";
setRetrievedValueIfEq(key, barMap, fooMap, bazMap);
String key2 = "fuga";
setRetrievedValueIfEq(key2, barMap, fooMap, bazMap);

それぞれのパラメータになった変数は不要なのでインライン化(Alt-Shift-i)しましょう。

setRetrievedValueIfEq("hoge", barMap, fooMap, bazMap);
setRetrievedValueIfEq("fuga", barMap, fooMap, bazMap);

これらの操作をもうちょっとショートカットを駆使しながらほぼ無意識でできるようになるとJavaに対する見方がかわるでしょう。

(識別子をたぐる言語に見えてくるはず。)

総評

大概、知識が手習いで学んだJava1.4やってた頃でとまってる。

今日のところはこれぐらいにしておいてやるよ!