MJHD

エモさ駆動開発

WSLをXenialにアップデートしてみた

mjhd.hatenablog.com 過去記事で紹介したBashOnWindows(WSL)環境において、UbuntuのバージョンをTrustyからXenialへアップデートしたメモ。

アップデート方法

以下のコマンドを実行するだけ。

sudo do-release-upgrade

その後、いくつかのアプリケーションに問題が起こった。

dbusがらみのエラーが起こる

DBusを使用するアプリケーションが、「Exhausted Authentication Mechanisms」的なエラーを吐いて起動しない。
“/etc/dbus-1/session.conf"を以下のように編集することで対応可能。

<auth>EXTERNAL</auth>

<!--<auth>EXTERNAL</auth>-->

とする。

GnomeTerminalがすぐ終了する

なんでか知らんけど、GnomeTerminalが子プロセス作って自分は勝手に終了しちゃう。
以下のように–disable-factoryを追加することで対応可能。

gnome-terminal --disable-factory

そんなぐらい。

オブジェクト指向とは

新人プログラマに知っておいてもらいたい人類がオブジェクト指向を手に入れるまでの軌跡 - Qiitaなどを参考にまとめたメモ。

オブジェクト指向プログラミングとは,オブジェクト同士の相互作用として,システムの振る舞いを捉える考え方である.所謂手続き型の言語しかなかった時代,コンピュータの性能向上につれて,データ構造,処理の複雑化し,正しく動く可読性の高いプログラムの記述が困難になった.1960年代にはこうした状況に「ソフトウェア危機」[1]という名前が付けられ,新たなプログラミングの手法が模索された.こうして考案されたのが「構造化プログラミング」[2]などのデザインパターンである.構造化プログラミングでは,言語特有のステートメントを直接使うのではなく,抽象化したステートメントを持つ仮想機械を想定し,その仮想機械上でプログラミングを行う.こうすることで, プログラムの正当性や可読性を向上することができるようになる.またこれとともに,「モジュラプログラミング」[3]と呼ばれる,同じ機能を持つ処理同士をモジュールという単位でまとめ,分割する手法が広まっていき,また良い分割を行うために,「状態」と「副作用」[4]を如何に扱うかが問題になっていった.その一つの解決策として現れたのが,オブジェクト指向プログラミングと,関数型プログラミングである.関数型プログラミングでは,基本的に副作用を持たず引数と返り値のみでプログラムを構成することで,参照透過性を保っているが,オブジェクト指向プログラミングでは,状態と副作用を「オブジェクト」に閉じ込めることで,抽象化を行った.このオブジェクト指向言語として初めて現れたのが,Simula[5]である.Simulaには,オブジェクト,クラス,動的ディスパッチ,継承,ガベージコレクションなどの現在のオブジェクト指向言語が持つ機能が実装されていて,後にC言語にこの機能が取り入れられ,C++言語ができた.また, Smalltalk[6]もSimulaに影響を受けた言語として制作され,C言語Smalltalkの機能を取り入れた言語として,Objective-C[7]言語などが作られた. オブジェクト指向プログラミングでは,プログラムはオブジェクトの集合として定義され,特徴として「カプセル化」[8]や「ポリモーフィズム」[9],「継承」[10]などの概念が挙げられる.初めに,カプセル化とは,Simulaで考案されたもので,データと処理を1つのオブジェクトとしてまとめることで,オブジェクト外部への副作用を減らすことができ,プログラムの正当性を高めることができるものである.例えば,グローバル変数を使い状態を共有しているモジュールがあった場合,片方の仕様を変更したとき,もう一方も修正しなくてはならなくなる.このような時,カプセル化を行うことでこのモジュール間の結合をなくすことができる.次に,ポリモーフィズムとは,現在の言語ではオーバーロードや仮想関数,インターフェースと呼ばれる機能などで実現されていて,異なるクラスであっても同一のコードで扱えるよう,クラスが複数のクラスに属すことのできる性質のことを言う.例えば,以下のリスト7の様な処理があった時,printNumber, printDate関数は,以下のリスト8の様に一つの関数としてまとめることができるようになる.最後に,継承とは,あるクラスを基に,機能を追加したり変更したりした別のクラスを定義することのできる機能である.これにより,副作用を基のクラスに隠蔽したまま,新たな機能を追加することができるため,プログラムの正当性,可読性に役立つ.

リスト7. ポリモーフィズムの例1 (疑似コード)


1:  class Number {
2:      public string ToString() {
3:          retutn 文字列へ変換する処理;
4:      }
5:  }
6:  
7:  class Date {
8:      public string ToString() {
9:          return 文字列へ変換する処理;
10:     }
11: }
12: 
13: public void printNumber(Number value) {
14:     print(value.ToString());
15: }
16: public void printDate(Date value) {
17:     print(value.ToString());
18: }
19: // プログラムの開始地点
20: public void main() {
21:     var number = new Number();
22:     var date   = new Date();
23: 
24:     // それぞれ別の関数に渡さなければいけない
25:     printNumber(number);
26:     printDate(date);
27: }

リスト8. ポリモーフィズムの例2 (疑似コード)


1:  interface IConvertible {
2:      public string ToString();
3:  }
4:  
5:  class Number : IConvertible {
6:      public string ToString() {
7:          retutn 文字列へ変換する処理;
8:      }
9:  }
10: 
11: class Date   : IConvertible {
12:     public string ToString() {
13:         return 文字列へ変換する処理;
14:     }
15: }
16: 
17: public void print(IConvertible value) {
18:     print(value.ToString());
19: }
20: // プログラムの開始地点
21: public void main() {
22:     var number = new Number();
23:     var date   = new Date();
24: 
25:     // 同じ関数に異なる型を渡すことができる
26:     print(number);
27:     print(date);
28: }

参考:

[1] ソフトウェア危機Wikipedia, http://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E5%8D%B1%E6%A9%9F [2] 構造化プログラミング Wikipedia, http://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E5%8D%B1%E6%A9%9F [3] モジュール Wikipedia, http://ja.wikipedia.org/wiki/%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB [4] 副作用(プログラム) Wikipedia, http://ja.wikipedia.org/wiki/%E5%89%AF%E4%BD%9C%E7%94%A8%28%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%29 [5] Simula Wikipedia, http://ja.wikipedia.org/wiki/Simula [6] Smalltalk Wikipedia, http://ja.wikipedia.org/wiki/Smalltalk [7] Objective-C Wikipedia, http://ja.wikipedia.org/wiki/Objective-C [8] カプセル化 Wikipedia, http://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%97%E3%82%BB%E3%83%AB%E5%8C%96 [9] ポリモーフィズム Wikipedia, http://ja.wikipedia.org/wiki/%E3%83%9D%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%95%E3%82%A3%E3%82%BA%E3%83%A0 [10] 継承 Wikipedia, http://ja.wikipedia.org/wiki/%E7%B6%99%E6%89%BF%28%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%29

FuelPHPのemailで日本語メールを送る際に気を付けること

マルチバイト環境でFuelPHPのemailを使う際、いくつか気を付けなければいけない問題がある。

今回想定している環境は、以下。

  • FuelPHP 1.8
  • UTF8でメールを送りたい
  • HTMLメールを送りたい

 

自動改行処理を止める(あるいは、改善する)

FuelPHPのemailパッケージには、自動改行処理を行う部分がある。

デフォルトでは76文字で改行を行ってくれるのだが、この際に使用している関数がPHP標準のwordwrap関数。この関数はマルチバイト文字に対応していないため、改行付近で文字化けするという痛い問題が発生する。

自動改行処理を止めるには、/fuel/core/config/email.phpを/fuel/app/config/email.phpとしてコピーをし、


 'wordwrap' = 76,

となっている部分を、


 'wordwrap' = false,

と書き換える。

もし、自動改行処理は有効にしたいけど、文字化けを解消したいという方は、emailクラスを編集して、マルチバイトに対応させる必要がある。

具体的には、/fuel/packages/email/classes/email/driver.phpのwordwrapを呼び出している箇所(おそらく二か所)を、[PHP]マルチバイト対応のwordwrapが無いから作った - Qiitaこういったものに置き換える必要がある。

 

 代替テキストの生成を止める

HTMLメールを送る際、emailパッケージは親切にプレーンテキスト版を自動生成し、一緒に送信してくれる。

受信したクライアントは、HTML版、プレーンテキスト版の二つから好きな方を表示することができる便利な機能である。

しかし、メールの見た目を統一したいなどの理由で、代替テキストが表示されてほしくない場面もある。

この場合、/fuel/app/config/email.phpを編集し、'generate_alt'の欄をfalseに設定すればよいのだが、

日本語を送る関係で'encoding'に"quoted-printable"や"base64"を指定している場合、正常に表示ができなくなる。

これは、何故かemailパッケージが"Content-Transfer-Encoding"のヘッダーを出力しないためであり、

/fuel/packages/email/classes/email/driver.phpの以下の箇所を編集することで対応が可能。


protected function build_message($no_bbc = false)
{<
    ...中略...
    $parts = array('Date', 'Return-Path', ...中略..., 'Content-Type');

となっている部分を、以下のように変更する。


    protected function build_message($no_bbc = false)
    {
    ...中略...
    $parts = array('Date', 'Return-Path', ...中略..., 'Content-Type', 'Content-Transfer-Encoding'); // 追加した

これで、正常に表示ができるようになる。

最高のXiaomi Notebook Air 13.3を購入した

もともとはMacBookAir13を4年間使っていたのだが、macOS sierraにアップデートしてから様々な問題にぶち当たり、Macが少しだけ嫌いになったのと、もともとメモリ4GBしかなかったため流石にしんどくなってきたので、新しいPCを買うことに。

中国メーカーXiaomiが出しているMacBookAirもろリスペクトのノートPC、「Xiomi Notebook Air」を購入した。

安い

gearbestで購入したのだが、記事執筆時の値段は$809.99=「9.17万円」

スペックは後述するが、この性能でこの値段はなかなかない。

www.gearbest.com

スペック

CPU: Intel Core i5 2.3GHz(最大2.8GHz) 物理2コア

GPUGeForce GT 940MX 1GB

SSD: サムスン製 256GB

RAM: 8GB(アップグレード不可、はんだ付け)

バッテリー: 5400mAh (USB Type-Cポートを使用して充電、30分ほどで充電完了、5時間ほど持つ)

外部ポート: HDMI、イヤホン/マイク共用ジャック、USB Type-C、USB3 x 2

WiFiIntel(R) Dual Band Wireless-AC 8260、802.11n

Bluetooth: 4.1

ディスプレイ: 1920x1080 IPS 13.3inch

スピーカー: AKG speaker with Dolby Audio Premium Surround Sound(かなり良い)

OS:

Windows10 Homeの中国語版がプリインストールされている。日本語版をクリーンインストールすることでアクティベーション可能。

開封の儀

f:id:wait0000:20161111113154j:plain

f:id:wait0000:20161111113344j:plain

f:id:wait0000:20161111113426j:plain

これまたMacBookAirっぽい箱の中に、フィルムにくるまった状態で入っていた。

付属品は簡単な説明書と充電用アダプタだけだった。

充電用アダプタは前述したとおり、USB Type-Cの形状をしており、幅広い機器に使えるもののようだ。

手に持った感じ、MacBookAirと重さは変わらなかった。大きさは若干Xiaomi NotebookAirの方が小さかった。

 

ちゃんと最後まで開封してみた。

f:id:wait0000:20161111121341j:plain

ファンはCPU用とGPU用の二つ。

SSDスロットは拡張用含めて二つ。

スピーカーも二つ確認できた。

 

以下、使ってみての感想。

スピーカーが良い

一番感動しているのがココ。AKG製のスピーカーが背面に2つ入っているのだが、Dolbyのサラウンド対応ということで音がヤバイ。語彙力がないのでヤバイしか言えないのだが、映画などを観るとその凄さがよくわかる。

目の前のパソコンから音が出ているとは思えない…。

このPCを購入してから、イヤホンをほとんど使わなくなってしまった。

 

キーボード

MacBookAirのキーボードがグッグッなら、Xiaomi Notebook Airはパタパタという感じ。

打鍵音は大きめ、またキーの打鍵感も大きいので少し指がつかれるかも。

それでも打鍵感がかなり良く、打っていて楽しい。

 

デザインはほぼほぼMacBookAir

背面にリンゴがいない以外、ほぼほぼMacBookAir。

アルミ感満載なところ、キーにLEDがついてるところ、トラックパッドに関してはまったく同じ見た目。

 

f:id:wait0000:20161111113657j:plain

 

f:id:wait0000:20161111113724j:plain

f:id:wait0000:20161111114144j:plain

 

軽いしバッテリーのもちもいいし性能もいいし安いし、大満足。

最高のBoW(Bash on Ubuntu on Windows)環境のために

最近、Macを捨ててWindowsに乗り換えた。その際に、Macで使用していたCUIにより開発環境をできるだけWindowsに移植できないかと考えた。

BoW(Bash on Ubuntu on Windows)

BoWは、Windows10よりベータ版として提供された、Windows上でLinuxバイナリを実行することができる仕組み。

仮想環境よりもっとミニマルで、内部的にはWindows上で動作するUbuntu互換のAPIを実装している模様。

つまり、Linuxマシン語をネイティブに実行することができるということ。(しっかりとWindowsのプロセスとして立ち上がる)

このBoW環境が思ったよりもしっかりとしていたため、開発環境を整えてみた。

どんな見た目?

デスクトップにおいたリンクから端末を起動することができる。

 

X11に対応しているので、GUIも使える。

 

インストールすべきもの

まず、BoWのインストールが済んでいることが前提。

 

qiita.com

こちらを参考に。

 

次に、VcXsrvをインストールする。これは、X11互換のサーバであり、GUIを表示するために必要。(Xmingをおススメしているサイトが多いが、こちらのほうが安定している)

sourceforge.net

 インストールが終わったら、スタートアップとして登録しておこう。

BoWにて

まず、Win+Rボタンを押し「cmd」と入力しエンターを押す。

コマンドプロンプトが立ち上がるので、ここに「bash」と入力する。これでBoW環境に入ることができる。

ここで、以下のコマンドを実行しよう。

 

sudo apt-get install aptitude
sudo aptitude install gnome-terminal

 これで、gnome-terminalというターミナルエミュレータが入った。

bash上で、「gnome-terminal」と入力することで、新しい端末が立ち上がる。

 

また、日本語入力ができるよう、以下のコマンドも実行しよう。

sudo aptitude install uim-fep uim-anthy

そして~/.uimを作成し、以下の内容を記述しよう。キーバインドなどは自由でおk。

(define default-im-name 'anthy)
(define-key generic-on-key? '(" "))
(define-key generic-off-key? '(" "))

 

次に、zshを入れよう。

sudo aptitude install zsh

 

あとは好みに応じて、各自のdotfilesを入れるといいと思う。

使いやすく

この時点で、~/.bashrcを編集し、以下のように書き足そう。


export DISPLAY=localhost:0.0
export XMODIFIERS=@im=uim

if [ -t 1 ]; then
	 exec gnome-terminal -x uim-fep -e zsh
fi

 

 

これにより、bashコマンドを叩くとすぐにgnome-terminal上でuim-fepzshを起動することができるようになる。

また、以下のようなファイルを作成することで、cmdを非表示にしたまま、gnome-terminalだけを起動することができる。

terminal.vbs

Set ws = CreateObject("Wscript.Shell")
ws.run "bash", vbhide

 

あとは煮るなり焼くなり、好きなように環境設定をしよう。

 

mysqlapacheなどの個人的に必要なソフトウェアも、serviceコマンドから実行できるようなので、逆に他に何がほしいの?というレベル。

MacからWindowsに乗り換えるタイミングとしては最適だったように思える。

 

AirPrintをXamarin Androidに載っけてみた

 

mjhd.hatenablog.com

 

の記事にて、BMPからUNIRASTへの変換が完了した。

あとは、BonjourとIPPを実装すれば理論上はXamarin AndroidからAirPrintができるはず。

ということで実装してみた。

 

Bonjour

Bonjourは、ネットワーク上のデバイスを探すためのプロトコルのよう。

NuGetにPCLでも使えるBonjourライブラリがあったため、今回はこれを使用する。

www.nuget.org

例えば、ネットワーク上にあるプリンタを列挙したい場合、以下のようなコードを書くことで可能になる。

 

 


    var printer_search = ZeroconfResolver.ResolveAsync("_printer._tcp.local.");
    printer_search.Wait();
    var printers = printer_search.Result;
    foreach(var printer in printers)
      Console.WriteLine(printer);

IPP

AirPrintは実際はIPPを使用して印刷している。

IPPはHTTP上に実装された印刷を制御するためのプロトコル。HTTP上でやりとりが行われているため、プロクシやらSSLやら何やら、HTTPで使用できる技術の恩恵が受けられる点が強みらしい。

遠隔地からの印刷なども、HTTPさえ繋がれば可能になる。

 

今回は、以下のプロジェクトを参考に、IPPをある程度実装した。

github.com

IPPは以下のような書式になっている。(全てビッグエンディアン)

 

Major Version                                 1byte

Minor Version                                 1byte

Operation ID または Status Code  2byte (送信はOperationID、受信はStatusCode)

Request ID                                     4byte (1以上、リクエスト毎の連番)

-- Group

Group ID                                        1byte

-- Attribute

Tag ID                                             1byte

Name Length                                  2byte

Name                                              (Name Length)byte

Value Length                                   2byte

Value                                              (Value Length)byte

Tag ID

-- Attributeの繰り返し

-- Groupの繰り返し

0x03(EndOfAttribute Group ID)      1byte

Groupは、Attributeの集合。操作に関するIDや、ジョブに関するIDなど、Attributeの種類に応じてグループが存在する。

 

Attributeは、実際の値の集合となっている。この辺からかなり複雑になってくるので、割愛。

 

実際のやりとりは、プリンタに対して行いたい操作をOperation IDとしてセットし、詳しい設定をAttributeとしてセット、そして送信する。

その後、帰ってきたIPPデータを読み取り、Status CodeがSuccessなどだったら、Attributeを読み込み、結果を取得する。

という流れになる。

 

今回は、プリンタの情報を取得するGet-Printer-Attributes操作と、ジョブの有効性を判定するValidate-Job操作、実際に印刷をするPrint-Job操作、印刷の状況を取得するGet-Job-Attribute操作を実装した。

 

## ソースコード

https://github.com/mj-hd/AirPrint.NET

 

結果

以上、すべてのソースコードがPCL上で完結しているため、Xamarin上で使用することができる。

そして、無事、Xamarin AndroidからAirPrint対応プリンタを通して印刷が行えた。

 

これにより何が嬉しいかというと、Android標準の印刷ダイアログを表示せずに印刷を行うことができる。

Android標準の印刷機能を使うと、どうしてもユーザに印刷ボタンを押す操作をしてもらう必要が出てしまうため、回避するためにはこう言った工夫が必要なのだと思う。

 

今後の課題

今現在は多くの印刷に関する設定を、プリンタのデフォルト値にしているため、プリンタによって印刷結果が変わってしまうことがある。

この辺どうにかしたい。けど、テストできるプリンタがない…。

 

追記:

実は、AirPrintはBonjourを使うとも限らないようで、自分が探した中にも、Bonjour以外の方法でしか探すことのできないプリンタがあった。どういった方法で探索しているかは、ベンダしか知らないようなので、今回の方法ではすべてのプリンタを探索できるわけではないということが分かった。

探索できない場合は、手動でIPアドレスを指定するようにした。

UNIRASTをC#で実装してみる

UNIRASTという画像形式がある。

AirPrintなどで使われている形式のようで、Appleが独自開発をしたもののようだ。公式なドキュメントは見当たらないが、リバースエンジニアリングしたものがGitHub上にたくさん転がっていたので、それをC#で書き直してみた。

 

目標は、BMP形式から、URF(UNIRAST)形式へ相互変換できること。

UNIRAST

UNIRASTは、以下のようなフォーマットになっている。

 

github.com

 

TIFFに結構近い模様。

ファイルは、

"UNIRAST\0" 12byte (\0は0x00)

Page Count    4byte   (ページ数)

から始まる。

この後、各ページが格納される。

各ページは以下のヘッダから始まる。

Bit Per Pixel   1byte   (深度)

Color Space   1byte   (なんだろ?)

Duplex Mode  1byte   (両面印刷)

Quality            1byte   (印刷クオリティ)

-                      4byte

-                      4byte 

Width              4byte  (横幅)

Height             4byte  (縦幅)

DPI                  4byte

-                      4byte

-                      4byte 

それぞれのページ毎に形式の違うデータを格納できるよう。

 

そしてその後各ページのピクセルデータが続く。

ピクセルデータは、以下のような書式になっている。

Line Repeat Count   1byte (一行のピクセルデータを、何回繰り返すか)

PackBit                     1byte (後述)

Pixel Data                 Bit Per Pixel分 (RGBが入る)

...

PackBit                     1byte

...(PackBitとPixelDataが、右端まで続く)

Line Repeat Count    1byte

...(Line Repeat Countが、下端まで続く)

Line Repeat Countは、一行のピクセルデータを何回繰り返すかを表しており、たとえば3だった場合は、次から始まる一行のデータを4行繰り返す。

 

PickBitは、TIFFで使われているアルゴリズムのようで、この値により後に現れるピクセルデータの扱いが変わる。

0x00-0x7Fの場合、後に現れるピクセルデータを、PackBit+1回だけ繰り返す。

0x80の場合、その時点から右端までデータは空白になる。真っ白。

0x81-0xFFの場合、後に現れるピクセルデータを、PackBit - 0x80個そのまま取り出す。

 

以上でUNIRAST形式のファイルを生成することができる。

## ソースコード

https://github.com/mj-hd/AirPrint.NET