時計を壊せ

駆け出してからそこそこ経ったWebプログラマーの雑記

GeoHex v3のC99実装ができた

掲題の通り。詳しくはREADMEを読んでみて欲しい。 karupanerura/c-geohex3 · GitHub

GeoHexとは何なのかと言うと世界を六角形により分割するためのアルゴリズムだ。 サイバーでかっこいいデモが公開されている。 デモサイト: GEOHEX.net

幾つかインターフェースや名前や実装方法を変更しているが、基本的にはJavaScriptにより実装された原始コードの移植と言って差し支えない。 元コードとアルゴリズムはMITライセンスで提供されており、本コードもMITライセンスで提供している。

現状で提供されているテストケースは全てパスしており、 以下のようなコードが動く。

#include <geohex3.h>
#include <stdio.h>

int main (int argc, char *argv[]) {
  for (int i = 1; i < argc; i++) {
    printf("/********* geohex:%s **********/\n", argv[i]);
    const geohex_verify_result_t result = geohex_verify_code(argv[i]);
    switch (result) {
      case GEOHEX3_VERIFY_RESULT_SUCCESS:
        {
          const geohex_t geohex = geohex_get_zone_by_code(argv[i]);
          printf("code  = %s\n", geohex.code);
          printf("level = %zu\n", geohex.level);
          printf("size  = %Lf\n", geohex.size);
          printf("[location]\n");
          printf("lat = %Lf\n", geohex.location.lat);
          printf("lng = %Lf\n", geohex.location.lng);
          printf("[coordinate]\n");
          printf("x = %ld\n", geohex.coordinate.x);
          printf("y = %ld\n", geohex.coordinate.y);
        }
        break;
      case GEOHEX3_VERIFY_RESULT_INVALID_CODE:
        printf("code:%s is invalid.\n", argv[i]);
        break;
      case GEOHEX3_VERIFY_RESULT_INVALID_LEVEL:
        printf("code:%s is invalid level. MAX_LEVEL:%d\n", argv[i], GEOHEX_MAX_LEVEL);
        break;
    }
  }
}

せっかくなのでXSを使ってPerl Bindingを書いた。

Geo::Hex::V3::XS - GeoHex implementation with XS. (c-geohex3 Perl5 binding.) - metacpan.org

近いうちにSwiftのbindingも書くつもり。

宣伝

gotanda.pm.org

いますぐ応募!

宣伝2

yapcasia.org

聞きたい!という人はイイね!なりツイートなりお願いします!

npmに上がっていないブラウザ向けに書かれたJavaScriptをnode.jsから雑に使うの術

ブラウザ向けに書かれたJavaScriptだと、windowに対してexportしていて、nodeから使いにくくて困ることがある。 nodeでも動くようなpatchを書けばいいという話ではあるが、githubにコードが上がっていないとやりにくくてつらい。

そこで、適当なObjectをcontextにして、vmでぶん回すことで、雑に解決することができた。 以下はGeoHexというライブラリのJavaScriptの実装がwindow.GEOHEXにエクスポートする実装であったために困ったので雑に解決した例。

"use strict";

var http = require('http');
var co   = require('co');

var get = function (url) {
  return new Promise(function (resolve, error) {
    http.get(url, function (res) {
      res.setEncoding('utf8');

      var buf = "";
      res.on('data', function (chunk) {
        buf += chunk;
      });
      res.on('end', function (chunk) {
        resolve(buf);
      });
    }).on('error', error);
  });
};

var getGeoHex = co(function *() {
  var window = {};

  var vm = require('vm');
  vm.createContext(window);

  var body = yield get("http://geohex.net/src/script/hex_v3.2_core.js");
  vm.runInContext(body, window);

  return window.GEOHEX;
});

getGeoHexを、以下のようにyieldしてやるといいかんじにwindow.GEOHEXが取得できていることがわかる。

co(function *() {
  var GEOHEX = yield getGeoHex;
  cosole.log(GEOHEX);
});

雑だけど問題は解決できた。べんり。

このへんで使った: c-geohex3/dump.js at master · karupanerura/c-geohex3 · GitHub

Implicitly Unwrapped Optionalは基本的に使うべきではない

Swiftのはなしです。

Swiftは言語標準でOptionalが入っていて、Optionalを除く全てのデータ型はnilを表現できません。 その中で、特殊なOptionalとして、Implicitly Unwrapped Optionalと呼ばれるものがあります。 これは、勝手にunwrapしてくれるので普通のデータ型と同じようにアクセスできるけど、中身がnilだったらunwrapに失敗するので死ぬという、特殊なOptionalです。 つまり、こいつを使うと、Optionalがせっかく解決してくれているはずの「ぬるぽリスク」が再び我々の目の前に現れることになり、つらい思いをすることになります。 どうしても使わなければならない場面でなければ、普通のOptionalを利用するべきです。

しかし、アクセスするタイミングでは「絶対に」nil にならないんだけど、一時的にnilになり得る場合がある。といったケースもあると思います。 具体的にはUIViewControllerdidViewLoadedで初期化するケースなどです。 そういったケースでは、(無理やりnilを代入して初期化するといったことをしていない限り、)Implicitly Unwrapped Optional による「ぬるぽリスク」も少ないのである程度安心して利用できます。

  • どうしてもnilの代入は裂けられないのか?
  • どうしても初期化でnil以外の値を入れることはできないのか?
    • せめて、初期化のタイミングでnil以外の値がくることを保証できないか?
    • e.g.) NG: let timeZone: NSTimeZone! = NSTimeZone(name: "Asia/Tokyo")
    • e.g.) OK: let timeZone: NSTimeZone? = NSTimeZone(name: "Asia/Tokyo")
    • e.g.) OK: let timeZone: NSTimeZone = NSTimeZone(name: "Asia/Tokyo")!
  • nilのタイミングでは絶対にアクセスしないか?

というあたりにすべてYESと答えられない限り、Implicitly Unwrapped Optionalは使うべきでないです。 やすやすと手をだすと忘れた頃に痛い目を見ることになるでしょう。

現場からは以上です。

Akka 2.4を雑にためす: その1

※ メモです

Scalaもくもく会に参加した。 Gitterでわいわいしながら自分のペースでもくもくできてよかった。
第1回 Scalaもくもく会@Volare - connpass
第2回 Scalaもくもく会@Volare - connpass

ぼくは、Actorが使ってみたくてScalaでAkkaをためしてみた。 ドキュメント長すぎて読むのに気力と体力が要求されたので、 とりあえずドキュメントを読まずにサンプルコードを書き換えてみるという、 非常にカジュアルな試しかたをした。

まずはbuild.sbtを書く。

lazy val root = (project in file(".")).
  settings(
    name := "tut",
    version := "1.0",
    scalaVersion := "2.11.6",
    libraryDependencies += "com.typesafe.akka" % "akka-actor_2.11" % "2.4-SNAPSHOT",
    libraryDependencies +=  "org.scalaj" %% "scalaj-http" % "1.1.4",
    resolvers += "Akka Snapshot Repository" at "http://repo.akka.io/snapshots/"
  )

雑に1秒遅れてEchoするActorを書く。

import akka.actor.{Actor,ActorSystem,Props}
import akka.pattern.ask
import akka.pattern.gracefulStop
import akka.util.Timeout
import scala.concurrent.Future
import scala.concurrent.Await
import scala.concurrent.duration._

class DelayEchoActor extends Actor {
  def receive = {
    case msg: String =>
      Thread.sleep(1000)
      sender ! msg
  }
}

object HelloWorld {
  def main(args: Array[String]) = {
    var sys = ActorSystem("system")
    val echo = sys.actorOf(Props[DelayEchoActor])

    implicit val timeout = Timeout(10 seconds)

    val futures = scala.collection.mutable.ArrayBuffer.empty[Future[Any]]
    futures += echo ? "あれ?"
    futures += echo ? "文字列が"
    futures += echo ? "遅れて"
    futures += echo ? "流れて"
    futures += echo ? "くるよ?"

    for (future <- futures.toArray) {
      val res = Await.result(future, timeout.duration)
      res match {
        case msg: String => println(msg)
      }
    }

    sys.shutdown()
  }
}

動かしてみると、たしかに遅れて流れてくる。 では、並列に動かすには?

とりあえず、systemを複数作ってみる。ついでなのでHTTPでgoogleのトップページも雑に叩く。

import akka.actor.{Actor,ActorSystem,Props}
import akka.pattern.ask
import akka.pattern.gracefulStop
import akka.util.Timeout
import scala.concurrent.Future
import scala.concurrent.Await
import scala.concurrent.duration._
import scalaj.http._
import java.lang.Object

class DelayEchoActor extends Actor {
  def receive = {
    case msg: String =>
      import dispatch._, Defaults._
      Thread.sleep(1000)
      sender ! msg
  }
}

class HttpGetRequestActor extends Actor {
  def receive = {
    case url: String =>
      val response: HttpResponse[String] = Http(url).asString
      sender ! response
  }
}

object HelloWorld {
  def main(args: Array[String]) = {
    val echo1Sys = ActorSystem("echo1")
    val echo2Sys = ActorSystem("echo2")
    val http1Sys = ActorSystem("http1")
    val http2Sys = ActorSystem("http2")
    val echo1 = echo1Sys.actorOf(Props[DelayEchoActor])
    val echo2 = echo2Sys.actorOf(Props[DelayEchoActor])
    val http1 = http1Sys.actorOf(Props[HttpGetRequestActor])
    val http2 = http2Sys.actorOf(Props[HttpGetRequestActor])

    implicit val timeout = Timeout(10 seconds)

    val futures = scala.collection.mutable.ArrayBuffer.empty[Future[Any]]
    futures += echo1 ? "あれ?"
    futures += echo2 ? "文字列が"
    futures += echo1 ? "遅れて"
    futures += echo2 ? "流れて"
    futures += echo1 ? "くるよ?"
    futures += http1 ? "http://www.google.co.jp/"
    futures += http2 ? "http://www.google.co.jp/"

    for (future <- futures.toArray) {
      val res = Await.result(future, timeout.duration)
      res match {
        case response: HttpResponse[String] => println(response.body)
        case javaObject: Object => println(javaObject.toString())
      }
    }
  }
}

なるほど。並列に動く。 しかし、こんなめんどくさい感じなわけがないし、なんか、resに変なのがくるし、おかしい。(とりあえずjava.lang.Objectで受けてtoStringするという漢らしいことをしている。)

コードを追ってみるとActorSystem -> LocalActorRef -> ActorCell -> Deployerという要素が見えてきたがキリが無いので諦めてドキュメントに目を移す。 ドキュメントを斜め読みする。ふむ。なんかconfigというのがあるらしい。 akka.actor.deploymentnr-of-instancesというやつがいる。これか?

となったところで、電池が切れそう。

結論

ドキュメント読んでから使え。

支援

Vol.3もあるようです:

第3回 Scalaもくもく会@Volare - connpass

気が向いたらその2も書く。

情熱と仕事と休息

仕事をやっていると、無条件で楽しいときもあれば、苦しいときもある。 苦しいときに、めげずに前向きに仕事をするためには情熱が必要だ。 情熱があれば、苦しいときでもがんばれるし、ときにはすごい力を発揮出来るかもしれない。

人はそれぞれ、違うところに情熱を燃やしている。 ときには、情熱を燃やすところががチームや組織の目指すところと衝突することもある。 そんな状況が続いてしまうと、疲れてしまい、情熱はやがて枯れてしまう。 人によっては、情熱を枯らさないために、環境を変えるという選択もするかもしれない。 一度枯らした情熱に再度火を灯すためには、とてもエネルギーを使うから。

だから、情熱を枯らさないように、疲れたら気軽に休むのが大事だと思う。 気軽に休めない環境を作ってしまうとみんな不幸になると思う。 だから、みんな気軽に休んで、気軽に休める環境を作っていくと、みんな幸せになれるんじゃないかな。 逆に、休みにくい環境を作ってしまうと、最終的には、情熱が枯れても逃げられない人だけが残った無気力な組織になってしまうと思う。

情熱を枯らしてしまうまえに、疲れたら臆せず休んで、情熱が回復したら、また仕事に打ち込む。 そんな働き方をしませんか。だれとなく。

きょうは会社休みます。 1 (マーガレットコミックスDIGITAL)

きょうは会社休みます。 1 (マーガレットコミックスDIGITAL)

っていうアフィ記事でした。

追記: ※自分や自分の環境の話じゃないです。自分の環境は気軽に休めていい感じなので、そんな環境がもっと一般的になればいいなと思って書きました。

JavaでDH鍵交換の初期化ベクトルを生成する

20億のデバイスでDH鍵交換の初期化ベクトルを生成できます。
以下のような具合のJavaコードをCreateDiffieHellmanIv.javaとして保存しましょう。

import java.security.AlgorithmParameterGenerator;
import javax.crypto.spec.DHParameterSpec;

public class CreateDiffieHellmanIv {
    public static void main (String[] args) throws Exception {
        int bitlen = 1024;
        if (args.length == 1) {
            bitlen = Integer.valueOf(args[0]).intValue();
        }
        System.out.println("Generating DiffieHellman initialization vector... " + "bitlen:" + String.valueOf(bitlen));

        AlgorithmParameterGenerator gen = AlgorithmParameterGenerator.getInstance("DH");
        gen.init(bitlen);

        DHParameterSpec spec = (DHParameterSpec)gen.generateParameters().getParameterSpec(DHParameterSpec.class);
        System.out.println("P: " + String.valueOf(spec.getP()));
        System.out.println("G: " + String.valueOf(spec.getG()));
    }
}

コンパイルします。

javac CreateDiffieHellmanIv.java

実行します。

java CreateDiffieHellmanIv

生成されます。

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
Generating DiffieHellman initialization vector... bitlen:1024
P: 145092357773036288785759831358363532457242150558361433565637207115514679411584100914869369530346476337051157705709858973344162440367967367833131503361926409583294585834757269998763188665426891871955393171079827134223234474237577100562967866893704671731464827466258191400928247383857555225260521584462646243757
G: 12076877650358872723433720596980214708516091408794486767543845481119286250958515342123571307476546309975921911735092979287081062213826767342459759424622360942234980320288127473825416480708591619721965721848952913500501787074997260325092958513471288533670082527450298168344704575797601113639175082590501897125

べんり。