プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

モバイルプロジェクター買いました

以前からモバイルプロジェクターには興味があったんですが、最近は伊勢IT交流会の開催場所も、プロジェクター付きのところが安定して借りられていたので、少し遠ざかっていました。

ですが、先日、伊勢IT交流会の納涼会を開催することになった際に、LT希望者を募ったら、宴会にも関わらず希望する方がいらっしゃいました(ありがたいことですよね)。

なので、これは頑張って準備せねば、と思い、モバイルプロジェクターを購入して、なんとかLTができるようにしましたので、その時の話を簡単にメモっときます。

機種選定

さて、モバイルプロジェクターの機種って、どんなのがあるんでしょうか? 全然知らなかったのですが、下記サイトなどを見ると、 DLP という形式のものが、小型軽量で実際問題として持ち運びができそうです。

sakidori.co

参加人数をおおよそ確定して、LTやる方向で決定してから会場選定まで、日にちが全然なかったので、大急ぎでプロジェクターの手配も行いました。

こういう時はお急ぎ便も使えるAmazon で調べます。
色々見てると、サンワサプライのモバイルプロジェクターの型落ち品が1万円台でお安く出ていました。

サンワサプライ MHL内蔵モバイルプロジェクター PRJ-5N

サンワサプライ MHL内蔵モバイルプロジェクター PRJ-5N

この機種だと、解像度が 854x480 まで対応していて、お値段も安いのでいい感じです。接続は HDMI のみ。細かいスペック等は製品のページ見てください。

www.sanwa.co.jp

この機種の後継機種だと、台形補正とかもついているようですが、お値段的にずいぶんとお高くなるので、こちらにしました。 ちなみに、同じぐらいの価格帯でサンワダイレクトの 400-PRJ023 もあったのですがこちらは解像度が 640x360 だったのでやめました。

一応、参加者のPCがVGAのみの場合に備えて、 VGA -> HDMI の変換ケーブルも用意しておきました。

実際に使ってみる

さて、実際に使ってみました。 普段の懇親会は居酒屋さんパターンが多いのですが、今回は遠方から来てる方もいらっしゃったので、割烹大喜さんでお部屋を取っていただきました。

プロジェクターを使いたい旨をお伝えしておいたら、壁は継ぎ目はあるものの薄めの平面の壁の部屋をご用意していただきました。

f:id:junichim:20190826161153j:plain

これなら十分投影できそうです。

さて、実際のLTまでに、事前に試す余裕がなかったので、ぶっつけ本番になりました。こんな感じでテーブルにセットして、

f:id:junichim:20190826161321j:plain

実際に投影してみると

f:id:junichim:20190826161228j:plain

いい感じですね。壁まである程度距離を取るとそれなりに大きなサイズでも十分見ることができます。

とはいえ、LT前はこの写真みたいに、照明がある状態でも十分明るいと思っていたのですが、さすがに文字を写すときつくなったので、照明を落として対応しました。 少し暗くなれば十二分に使えました。
スペック上は、100 ANSIルーメンってあり、これが体感としてどのぐらいの明るさかピンと来てなかったのが、これでよくわかりました。簡易用途なら十分ですね。

残念ながら、実際のLT中の写真は、スマホのバッテリーがなくなったため、取り損ないました。すいません。

まとめ

モバイルプロジェクターといっても、持ち運びが嫌になるようなイメージがあったのですが、これだったら十分に持ち運びして使えそうです。 もっとも、電源の延長ケーブルとか VGA->HDMI の変換ケーブルとかのほうがかさばるぐらいでした。

ちなみに納涼会はこんな感じでした。

f:id:junichim:20190826162457j:plain

さて、次はどこで活用しようかな。

修正UTF-7 のエンコード/デコード処理について

はじめに

メインのメールとして、さくらインターネットのレンタルサーバーのメールを使っています。

今までは POP でローカルにメールを取ってきて処理していたのですが、最近、さすがに不便になってきたので、 IMAP で処理しようと思い立ちました。 幸い、さくらのメールは、 Webメール としてもアクセスできるので、問題なさそうです。

と思ったのですが、試し始めると大きな問題が。
というのも、さくらインターネットの Webメールでは、メールのフォルダへの振り分けができないのです。 いろんなメールが来るので、それをいちいち手作業で振り分けているのも、さすがにつらいものがあります。

いろいろと調べてみると、さくらインターネットの場合、 IMAP サーバ として Courier IMAP を使っており、 MDA (Mail Delivery Agent) として maildrop というがメールの受信と振り分けをやってくれているようです(maildropに関するさくら側の情報はないので、推測です)。 で、その設定ファイル .mailfilter を書いてやれば、一応振り分けはできるとのことです(こちらのさくらインターネットのヘルプでmailfilterについて触れてます)。

それなら、簡単だと思いつつ、Webメールのインターフェースから適当にフォルダを作って、

f:id:junichim:20190817104104p:plain

SSHでログインしてフォルダ名を確認すると、

[myuser@xxxxxxx ~/MailBox/account/maildir]$ ls -laF
total 84
drwx------  17 myuser  users  1024 Aug 17 10:37 ./
drwx------   5 myuser  users   512 Aug 16 15:57 .&MEIwRDBGMEgwSg-/
drwx------   6 myuser  users   512 Jul 11 16:04 .&Yy8wilIGMFEwxjC5MMg-/
drwx------   6 myuser  users   512 Jul 11 16:07 .&Yy8wilIGMFEwxjC5MMg-.&Txp5Pv8S-/
drwx------   6 myuser  users   512 Aug 10 18:23 .&Yy8wilIGMFEwxjC5MMg-.company1/
drwx------   5 myuser  users   512 Aug 10 19:33 ../
drwx------   6 myuser  users   512 Jul 11 15:37 .Archive/
drwx------   6 myuser  users   512 Jul 11 15:41 .Draft/
drwx------   6 myuser  users   512 Jul 11 15:37 .Junk E-mail/
drwx------   6 myuser  users   512 Aug  1 22:49 .Sent/
drwx------   6 myuser  users   512 Jul 11 15:41 .Trash/
drwx------   6 myuser  users   512 Jul 13 00:02 .spam/

のように、一瞬文字化けか?と思うようなわけわからん記号のフォルダが存在しています。

調べてみると、これは、日本語などのマルチバイト文字をエンコードしたフォルダ名とのこと。 このエンコード方法が IMAP で決められていて、それが『修正UTF-7』という方法になるんだそうです。

まだまだ知らないことだらけですね。

.mailfilter を書くにあたり、どれがどのフォルダに該当するのかわからないのは、はなはだ不便です。 が、ちょっとネットを見てみても、入力文字列を 修正UTF-7 にエンコードしてくれるサービスが見つかりません。
多くの方、困ってないのかな?

ということで、仕方ないので、今年のお盆休みの課題として、 修正UTF-7 にエンコード/デコードしてくれるツールを作りましたので、メモ残しておきます。

修正UTF-7

まずは、 修正UTF-7 の規格について調べます。

ゆっくり読むと、それほど難しくはないようです。

まとめると、

  • & は &- にエンコードする
  • & 以外のASCII印字可能文字はそのままとする
  • それ以外の文字は、UTF-16BE(ビッグエンディアン)でエンコード後、修正Base64でエンコードして、前に & 後ろに - を付加する

修正Base64は、

  • Base64で変換する
  • / (スラッシュ)を , (カンマ)で置き換える
  • 4文字に満たない場合も = (等号)でパディングしない

とのことです。

では、実装してみましょう

実装

今回は WSL 上の node.js (v10.16.0) で作業しました。

変換処理のメイン部分は下記の記事を参考にしました。

JavaScript で Modified UTF-7 にエンコード&デコード - Qiita

ただ、自分で、Base64 や UTF-16BE へのエンコーディングは避ける方針とし、

  • UTF-16BEへのエンコーディングは、 iconv-lite
  • base64 へのエンコーディングは、 Buffer

を使いました。

エンコード処理

エンコード処理の主な部分について触れておきます。

function encode(str) {
        var encoded = str
            .replace(/&/g, "&-")
            .replace(/[\u0000-\u0019\u007f-\uffff]+/g, modifiedBase64Encode);

        //console.log(encoded)
        return encoded;
}

最初に & を &- に変換しています。この変換を行っても、いわゆるASCII印字可能文字が増えるだけなので、修正Base64でのエンコード対象外になり、後段の処理に影響は及ぼしません。
次に、正規表現でASCII印字可能文字範囲以外が連続して出てくる箇所を見つけて、修正base64でエンコードするという処理になります。ASCII 印字可能文字の範囲が 0x20 ~ 0x7e までなので、そこを外した範囲指定になります。

ちなみにこれって、node.js(JavaScript)の文字列の内部のエンコーディングが、UTF-16だから成立しているのだと思います。 たとえば、

mor@DESKTOP-H6IEJF9:/tmp/mutf7$ node
> "あ".charCodeAt(0).toString(16)
'3042'

とすれば、『あ』に対応する UTF-16のコード U+3042 が表示されるのがわかります。

修正base64の処理はこんな感じになります。

function modifiedBase64Encode(str) {
        const buf = iconv.encode(str, "utf16-be");
        //console.log(str);
        //console.log(buf);
        return "&"+ buf.toString("base64").replace(/\//g, ",").replace(/=/g, "") + "-";
}

正規表現で変換対象として文字列を、UTF-16BEでエンコード後、さらにbase64で変換し、修正base64に合うように、文字を置換しておきます。

一連の処理の結果、正しい変換結果になっているかどうかは、さくらインターネットのWebメールで実際にフォルダ名を設定して確認しておきます。

デコード処理は基本的にこれと逆の処理をすればよいことになるので、省略しておきます。興味があれば、ソースをご覧ください。

ツールとして整理

基本の変換処理は実装できたので、ツールとして仕立てます。
ツールとして仕立てようとすると、引数をうまく処理する必要があります。 そのあたりの引数処理を行うために commander というライブラリを使いました。

いやー、便利なもんですね。

できたもの

最終的には、こんな感じになりました。

#!/usr/bin/env node
/**
 * 修正UTF-7 エンコード・デコード関数
 *
 * https://qiita.com/tkooler_lufar/items/66b01f1a88c9e018f76e
 * https://smdn.jp/programming/netfx/tips/modified_utf7/
 */

'use strict';

const iconv = require('iconv-lite');
const program = require('commander');

// コマンドライン引数処理
program.version('0.0.1')
       .usage('文字列')
       .description("与えられた文字列について、修正UTF7によるエンコード/デコードを行います")
       .option("-d, --decode","修正UTF7文字列をデコードします");

program.parse(process.argv);
//console.log("optons: " + program.opts());

var args = program.args
if (!args || args.length == 0) {
    console.log("no target string");
    process.exit(1);
    return;
}
//console.log("args: " + program.args);

if (program.decode) {
        var decoded = decode(args[0]);
        console.log(decoded);
        return;
}
var encoded = encode(args[0])
console.log(encoded)
return;

/////////////////////////////////////
// 以下、関数

function encode(str) {
        var encoded = str
            .replace(/&/g, "&-")
            .replace(/[\u0000-\u0019\u007f-\uffff]+/g, modifiedBase64Encode);

        //console.log(encoded)
        return encoded;
}
function decode(str) {
        var decoded = str
            .replace(/&([A-Za-z0-9\+\,]+)-/g, modifiedBase64Decode)
            .replace(/&-/g, "&");

        //console.log(decoded)
        return decoded;
}

function modifiedBase64Encode(str) {
        const buf = iconv.encode(str, "utf16-be");
        //console.log(str);
        //console.log(buf);
        return "&"+ buf.toString("base64").replace(/\//g, ",").replace(/=/g, "") + "-";
}
function modifiedBase64Decode(str, substr) {
        const buf = Buffer.from(substr.replace(/,/g, "/"), "base64")
        //console.log(str);
        //console.log(substr);
        //console.log(buf);
        const decoded = iconv.decode(buf, "utf16-be");
        //console.log(decoded);
        return decoded;
}

動作確認

動かしてみます。

オプションを指定しないときは、エンコードします。

mor@DESKTOP-H6IEJF9:/tmp/mutf7$ node index.js あいうえお
&MEIwRDBGMEgwSg-
mor@DESKTOP-H6IEJF9:/tmp/mutf7$ node index.js 日本語
&ZeVnLIqe-

サロゲートペアの文字(下記の例だと、𩸽(ほっけ)、𠮷)が入っていても大丈夫です。

mor@DESKTOP-H6IEJF9:/tmp/mutf7$ node index.js 𩸽定食𠮷野家
&2GfePVuamN,YQt+3kc5btg-

デコードもできます。

mor@DESKTOP-H6IEJF9:/tmp/mutf7$ node index.js -d "&MEIwRDBGMEgwSg-"
あいうえお

一応、 Github にもあげておきます。

github.com

余談

以下余談です。

その1:紆余曲折

すんなりと上記の実装が書けたわけではなく、いろいろと紆余曲折がありました。

最初、 node.js (javascript) の場合、base64に変換するのが、 Buffer を使えばできるとのことだったので、

var buf = Buffer.from("対象文字列")
var res = buf.toString("base64");

としてました。 変換結果を確認すると、違ってます。

何だろう?と思い調べてみると、 Buffer#from は文字コードを指定しないと、UTF-8でエンコードするそうです。文字列の内部表現がUTF-16なので、てっきりUTF-16だと思い込んでしまいました。

じゃあ、UTF-16BEを指定すればいいやと思いきや、Bufferは UTF-16BE には対応していないそうです(UTF-16LEはあるんですけどね)。

はじめてのNode.js:Node.js内でバイナリデータを扱うための「Buffer」クラス | OSDN Magazine

困ったなと思ってあれこれ見てたとき、ふと、ツールを作る前に iconv で修正UTF-7に変換すればいいやん、と考えていたことを思い出しました。 ただ、iconv の場合、下記に示すように、修正UTF-7には対応してなかったんですが、UTF-16はいけます。

mor@DESKTOP-H6IEJF9:/tmp/mutf7$ iconv --list | grep -i utf
ISO-10646/UTF-8/
ISO-10646/UTF8/
UTF-7//
UTF-8//
UTF-16//
UTF-16BE//
UTF-16LE//
UTF-32//
UTF-32BE//
UTF-32LE//
UTF7//
UTF8//
UTF16//
UTF16BE//
UTF16LE//
UTF32//
UTF32BE//
UTF32LE//
mor@DESKTOP-H6IEJF9:/tmp/mutf7$

ということで、 node.js から iconv を使うためのライブラリを探してみると

mor@DESKTOP-H6IEJF9:/tmp/mutf7$ npm search iconv
NAME                      | DESCRIPTION          | AUTHOR          | DATE       | VERSION  | KEYWORDS
iconv                     | Text recoding in…    | =bnoordhuis     | 2019-03-31 | 2.3.4    |
iconv-lite                | Convert character…   | =ashtuchkin     | 2019-06-26 | 0.5.0    | iconv convert charset icu
codepage                  | pure-JS library to…  | =sheetjs        | 2018-07-08 | 1.14.0   | codepage iconv convert strings
・・・

いろいろとありました。
この中の、 iconv-lite がよさそうだったので、今回はこれを使うことにしました。

その2:さくらのWebメールとサロゲートペア

さくらインターネットのwebメールでは、サロゲートペアにあたる文字が含まれるフォルダは正しく処理されませんでした。

例えば、『𩸽定食』というフォルダを作成すると

f:id:junichim:20190817113734p:plain

フォルダは作られるんだけど、画面上は文字化けしています。

f:id:junichim:20190817113949p:plain

ちなみに、直接該当アカウントのmaildir を見ると

[myuser@xxxxxxx ~/MailBox/account/maildir]$ ls -laF
total 88
drwx------  18 myuser  users  512 Aug 17 11:37 ./
drwx------   5 myuser  users  512 Aug 17 11:37 .&2GfePVuamN8-/
drwx------   5 myuser  users  512 Aug 16 15:57 .&MEIwRDBGMEgwSg-/
drwx------   6 myuser  users  512 Jul 11 16:04 .&Yy8wilIGMFEwxjC5MMg-/
drwx------   6 myuser  users  512 Jul 11 16:07 .&Yy8wilIGMFEwxjC5MMg-.&Txp5Pv8S-/
drwx------   6 myuser  users  512 Aug 10 18:23 .&Yy8wilIGMFEwxjC5MMg-.company1/
drwx------   5 myuser  users  512 Aug 10 19:33 ../

のように、正しく作られています(.&2GfePVuamN8- が𩸽定食のフォルダに該当しています)。

また、中身を見ようとしても、『読み込み中』が表示されて、そこで処理が止まってしまいます。このフォルダ名の変更、削除もできません。

いくつかのサロゲートペアの文字で試しても同様の結果になりましたが、サロゲートペアの文字一般についても同じ問題が起きるのかまでは調査していません。
もしくは、サロゲートペアの問題なのか、それとも別の問題があるのかまで特定したわけでもありません。

ですが、もし、Webメールのフォルダを操作していて不思議な挙動があれば、サロゲートペアを疑ってみるのもいいかもしれません。

ちなみに、この状態でフォルダを削除するには、SSHでログインして、 ~/Mailbox/メールアドレス名/maildir 以下にある、該当フォルダを直接削除すれば可能です。 ただ、フォルダ名は修正UTF7でエンコードされているので、間違って他のフォルダを消さないように注意してください。

(参考) JavaScript における文字コードと「文字数」の数え方 | blog.jxck.io

2019年度のUDC三重のキックオフイベントに参加してきました

少し前になりますが、去る 2019 年 7 月 27 日(土)に四日市で開催された、2019年度のアーバンデータチャレンジ(UDC)三重のキックオフイベントに参加してきました。 もっとも、参加と書いてますが、主催のUDC三重実行委員会のメンバーでもあるので、主催側の一員としての立場なんですがね。

f:id:junichim:20190804234539j:plain

せっかくなので、イベントの様子のご紹介と個人的に感じたことをつれづれと書いておきます。 ちなみに、イベントサイトはこちらになります。

udcmie.connpass.com

アーバンデータチャレンジについて

さて、いきなり、UDC三重のうんぬんかんぬん、と書かれてもなんのこっちゃ?となると思いますので、アーバンデータチャレンジ(Urban Data Challenge, UDC)というイベントについて、私なりにご紹介しておきます。

公式サイトはこちらですね。

urbandata-challenge.jp

さて、私なりの理解では、UDCというイベントは、

『(オープン)データを利用して、地域の課題を解決しよう』

ということを目的にした活動で、そのための手段として、

  • コミュニティを作りましょう
  • コンテストを開催します

という2つがあるようです。

前者は、各地域(基本的には都道府県)に『地域拠点』というのを作って、そこがあれこれ啓蒙活動をするようなイメージです。 三重の場合は、私も参加している、『UDC三重実行委員会』という任意の団体があり、そこが県や市と連携して活動しているイメージです。他の地域拠点さんの活動を見ていると、 Code for ○○ とかが主体となって動いているところが多いように見受けられます(もちろんそうじゃないところも多数ありますよ)。
ちなみに、UDC三重実行委員会は活動の趣旨のご賛同いただける方であれば、ご参加いただけますので、興味があるという方は是非ご連絡ください。

後者のコンテストは、毎年行っている地域課題の解決を目的としたコンテストで、アプリケーション・データ・アイデア・アクティビティの4部門に分かれているというものです。昨年の受賞作品などはこちらから見ることができます。コンテストの応募はどなたでも可能(詳細は毎年の応募要項をご覧ください)です。

まあ、オープンなデータを使って、身近な問題について考えましょう、という活動といったところでしょうか。

個人的には、この一連のイベントに参加することで、オープンデータそのものやオープンデータを使うための技術、オープンデータを使った事例などをいろいろ知ったり理解できたりsるきっかけにしたいと思って参加しています。

一応、当日私が発表したアーバンデータチャレンジについての説明資料もあるので、リンク張っておきますね。

www.slideshare.net

間違い等あれば、ご指摘ください。

キックオフイベントのタイムスケジュール

イベントのタイムスケジュールは、こんな感じでした。

時刻 内容
13:00 開会
13:00~14:20 参加各団体などのご紹介とご挨拶
14:20~14:35 アーバンデータチャレンジの紹介(2018結果報告ならびに2019のテーマ発表など)
14:35~14:50 休憩
14:50~16:00 講演
・今年度の活動予定
・三重大学「北勢サテライト」「健康福祉システム開発研究会」の紹介
・三重県の少子化対策
など(詳細未定)
16:00 閉会

UDC三重の活動にかかわる各団体さんからのご挨拶に加えて、アーバンデータチャレンジの概要の説明、がありました。

それらに引き続いて、今年の三重拠点の活動テーマが『少子高齢化を斬る!』ということなので、これに関連して、三重大の活動と三重県の少子化対策の担当さんからお話をいただいました。

最後にアーバンデータチャレンジの今年の動きについての話がありました。
去年までで全都道府県からの地域拠点の応募があったそうで、今年から5年をセカンドステージとして位置付けて、より一層の広がりを目指していくそうです。そのための一つの方法として、コンテストの応募部門を、既存の4部門から下記の10部門に変更にするそうです(もちろん、詳細は今年度のコンテストの応募要領が発表になってからそちらをご確認ください)。

変更前 変更後
データ 道路・交通
アプリケーション 河川・港湾・上下水道
アイデア 住宅・土地・公園・公共施設
アクティビティ まちづくり・都市計画
農業・林業・漁業
産業・観光
医療・健康
生活・文化・地域アーカイブ
教育・政治
防犯・防災

雑感

個人的には、いろいろは話が聞けて面白かったです。
特に少子化関連の話では、合計特殊出生率を増やすことだけが少子化対策ではなく、少子化が進んだ時に困らないようにするにはどうすればよいのか?という視点もあるよ、という話は印象的でした。

とはいうものの、参加した方によっては受け取った印象は様々だったようで、いろいろな方とお話をしていると面白いと受け取らなかった方もいらっしゃいました。
そういう意味でも、この手の地域課題などを考えるときは、いろんなバックグラウンドを持つ方が参加することで、様々な考えに触れることができる(そのうえで、面白いアイデアが出てくる)んだろうなと改めて思ったところです。

上記とも絡むのですが、参加者の多くが関係団体の方だったことも改善したいところも一つですね。関係団体の方がいらっしゃるのはそれはそれでうれしいのですが、どうにかして、もっと裾野を広げたコミュニティにしていかないと、活動自体が形骸化したり、単調なものになってしまう恐れがあるように感じています。

イベント会場について

最後にPRも兼ねて、今回のイベント会場について書いておきます。
今回は、近鉄四日市駅の駅ビルの近鉄百貨店の7FにあるSYNTHさんをお借りしました。SYNTHさんには、会場協力の形でイベントを応援していただきました。ありがとうございました。

mie.synth.co.jp

公式サイトの写真でもわかるように、いまどきのおしゃれなスペースですね。こちらは貸会議室の他にも、コワーキングスペースやレンタルオフィスとしての利用も可能です。
近所にあれば、ぜひ使いたいところです。伊勢にも作ってくれませんかね?>近鉄さん

ご興味を持たれた皆様!ぜひ、一度足を運んでみてください!

最後に

今年もUDC三重の活動にかかわっていきますので、少しでもご興味を持たれましたら、ぜひイベント等に足を運んでいただければと思います。 よろしくお願いします。