Rust の構造体Vecをsort_byしやすくするマクロを書いた

なんでつくったか

例えば x, y, z がある以下のような構造体があって、

struct Sample {
    x: i64,
    y: i64,
    z: i64,
}

v: Vec<Sample>をソートしたい。ただし、並び替える順番は利用箇所によって違う。

こんなときに、いつも、 sort_by を使って、以下のように書いていた*1

// x昇順→y昇順→z昇順
v.sort_by(|l, r| {
    match l.x.cmp(&r.x) {
        std::cmp::Ordering::Equal => {
            match l.y.cmp(&r.y) {
                std::cmp::Ordering::Equal => {
                    l.z.cmp(&r.z)
                },
                other => other
            }
        },
        other => other
    }
});

これは書くの面倒だし、やりたいことの割に長くて目を引く。

ところでSQLでは order by x, y, z と書けるな、とふと思って、 そんな感じで簡単に書けるようにするマクロが欲しくなった。ので作った。

使い方

以下のように使う。

let mut v = vec![
    Sample {x: 10, y: 200, z:3000},
    Sample {x: 10, y: 100, z:1000},
    // ...
];

// x昇順→y昇順→z昇順
v.sort_by(order_by!(x, y, z));
// x昇順→y降順
v.sort_by(order_by!(x asc, y desc));
// z昇順→x昇順
v.sort_by(order_by!(z asc, x));

さらに、タプルでもいける。

let mut v2: Vec<(i64, i64, i64)> = vec![
    (20, 100, 1000),
    (10, 300, 1000),
    (10, 300, 2000),
    (30, 300, 2000),
    (30, 300, 3000),
    // ...
];

v2.sort_by(order_by!(0, 1, 2));
v2.sort_by(order_by!(0 desc, 1, 2));
v2.sort_by(order_by!(2, 0, 1));

マクロコード

macro_rules! order_by {
    ($($x:tt)*) => {
        |l, r| {
            order_by_inner!(l, r, $($x)*)
        }
    }
}
macro_rules! order_by_inner {
    () => {};
    ($l:ident) => {std::cmp::Ordering::Equal};
    ($l:ident , ) => {std::cmp::Ordering::Equal};
    ($l:ident , $r:ident) => {std::cmp::Ordering::Equal};
    ($l:ident , $r:ident , ) => {std::cmp::Ordering::Equal};

    // last
    ($l:ident , $r:ident , $x:tt asc) => {
        $l.$x.cmp(&$r.$x)
    };
    ($l:ident , $r:ident , $x:tt desc) => {
        $l.$x.cmp(&$r.$x).reverse()
    };
    ($l:ident , $r:ident , $x:tt) => {
        order_by_inner!($l, $r, $x asc)
    };

    // mid
    ($l:ident , $r:ident , $x:tt asc , $($p:tt)+) => {
        match $l.$x.cmp(&$r.$x) {
            std::cmp::Ordering::Equal => {
                order_by_inner!($l, $r, $($p)+)
            },
            other => other
        }
    };
    ($l:ident , $r:ident , $x:tt desc , $($p:tt)+) => {
        match $l.$x.cmp(&$r.$x).reverse() {
            std::cmp::Ordering::Equal => {
                order_by_inner!($l, $r, $($p)+)
            },
            other => other
        }
    };
    ($l:ident , $r:ident , $x:tt , $($p:tt)+) => {
        order_by_inner!($l, $r, $x asc, $($p)+)
    };
}

*1:もっといいやり方があったら教えてほしい

Rust Rocket v0.4.0 の入門

この記事はRustその2 Advent Calendar 2018の23日目の記事です。

Rust の Web フレームワークである Rocket に入門していきます。

この記事では、公式のサンプルを参照しながら、それを解説していきます。

執筆環境

$ rustc --version
rustc 1.33.0-nightly (2d3e909e4 2018-12-22)

インストール

Rust のインストール

公式のインストール手順に従って下さい。

執筆環境と同等の環境を用意するには、以下のようにします。

$ rustup toolchain install nightly-2018-12-23
$ rustup default nightly-2018-12-23

リポジトリのダウンロード

公式のサンプルは、リポジトリに含まれています。 clone してきましょう。

$ git clone -b v0.4.0 https://github.com/SergioBenitez/Rocket.git
$ cd Rocket/examples

準備ができました。以下でサンプルを見ていきます。 以下では、各章開始時点では examples ディレクトリ直下に居る前提で話を進めます。

hello_world

概要

何はともあれhello worldからやっていきましょう。

$ cd hello_world
$ cargo run

難なく起動してくれるはずです。 この状態で、 localhost:8000 にアクセスすれば、 Hello, world! とだけ表示されたページが出てきます。

ソース

src/main.rs を見て下さい。 書いてある重要な内容は、大きく2つです。

ハンドラ

1つは、ハンドラの定義です。

hello_world では、ルートパスにアクセスした際に、 "Hello, world" が返されました。 この処理を定義する記述が以下になります。

#[get("/")]
fn hello() -> &'static str {
    "Hello, world!"
}

Rocketでは、カスタム属性(Custom Attribute) を使います。 #[get("/")] で、この関数が パス / へのGETリクエストに対するハンドラであると示しています。 get 以外にも、 put, post, delete, head, patch, options が利用でき、それぞれ HTTP のリクエストメソッドと対応しています。

ハンドラ自体は、引数なし、文字列を返すだけの関数となっています。 この戻り値がそのままレンダリングされていたわけです。 ハンドラの引数が何の役目を果たすのか、戻り値の型は単純な文字列以外には何が指定できるのか、などは、別のサンプルで解説されています。

マウント、起動

さて、やっていることのもうひとつは、マウントとアプリケーションの起動です。

fn main() {
    rocket::ignite().mount("/", routes![hello]).launch();
}

rocket::ignite() で、アプリケーションを作成します。 ここに、なんやかんや設定をして、最後に launch() すると、アプリケーションが開始され、アクセスできるようになります。

hello_world で設定しているのは、ルーティングがひとつだけです。 mount("/", routes![hello]) が、hello関数をルート直下にマウントしています。

hello_person

概要

この例では、パスから動的にパラメータを取得します。

$ cd hello_person
$ cargo run

以下のページにアクセスできます。

  • localhost:8000/hello/foo
    • foo とだけ描画されます
    • foo を別の文字に変えると、描画される内容も変わります
    • foo に何も入れないと Not Found になります
  • localhost:8000/hello/foo/100
    • Hello, 100 year old named foo! と描画されます
    • 100 を別の数字に変えると、描画される内容の 100 の部分が変化します
    • 100 に数字以外(abc, 1+1 など)を入れると Not Found になります
  • それ以外は Not Found です

ソース

src/main.rs に全て書かれています。

hello_world からは、以下の点が変更されています。

  • ハンドラが2つになり、それぞれの内容が変更されています
  • ルーティングにハンドラが2つ指定されています

ルーティング

まずは、ルーティングに関して確認していきます。

    rocket::ignite().mount("/", routes![hello, hi]).launch();

routes! マクロの中にハンドラを与えていますが、これは複数並べることができます。

また、 "/" を "/yo"に変更し、起動してみましょう。

localhost:8000/hello/foo/100 へはアクセスできなくなり、 localhost:8000/yo/hello/foo/100 へアクセスできるようになりました。 同時に、 localhost:8000/hello/foo へはアクセスできなくなり、 localhost:8000/yo/hello/foo へアクセスできるようになっています。

このように、 mount() の第一引数でルーティングをディレクトリ的単位でまとめて制御することができます。

ハンドラの引数とパラメータ

ハンドラが2つありますが、 hello() だけ確認します。

#[get("/hello/<name>/<age>")]
fn hello(name: String, age: u8) -> String {
    format!("Hello, {} year old named {}!", age, name)
}

カスタム属性のパスに、 <name><age> が現れました。 対応するように、 hello() の引数に、 nameage が現れました。 これらが、パスからパラメータを受け取るための記述になります。

<name> の位置に対応したものが、引数 name に与えられ、 <age> の位置に対応したものが、引数 age に与えられ、関数が呼ばれます。

特に、 age は自動的に数値型にパースされます。 では、数値として読み込めなかった時はどうなるかというと、概要で示したように Not Found になります。

パースのできる/できないはどのようにして決定するのでしょうか?そもそも、パースできる型はどのように決まっているのでしょうか? 鍵は、 FromParam トレイトにあります。

FromParamトレイトは、プリミティブの数値型、 String&RawStrOption<T>Result<T, T::Error> などに実装されています。 パス文字列から各型への変換は、 from_param() によって行われます。

この変換が成功した場合、ハンドラが実行されます。

補足としては、以下のとおりです。

  • &RawStr : 生のパス文字列そのものを表す型で、変換等しないのでマッチは必ず成功します
  • String : 生のパス文字列から文字列に変換します。失敗する場合があります
  • Option<T> : 変換が成功した時は Some(T) 、失敗したときは None を返します。マッチは必ず成功します
  • Result<T, T::Error> : 変換が成功した時は Ok(T) 、失敗した時は Err(T::Error) が返ります。マッチは必ず成功します

tera_templates

概要

hello_world、hello_personでは、レスポンスは全て単純な文字列で返してきましたが、 Rocket ではテンプレートエンジンを利用してレスポンスを作成できます。

Rocketで利用できるのは、 TeraHandlebars です。ここでは Tera を紹介します。

$ cd tera_templates
$ cargo run

起動して、 localhost:8000/hello/foo にアクセスしてみましょう。HTML文章が表示されると思います。

ソース

src/main.rs からみていきます。

        .attach(Template::fairing())

テンプレートを利用するには、 Template::fairing() をアタッチしておく必要があります。

#[get("/hello/<name>")]
fn get(name: String) -> Template {
    let context = TemplateContext { name, items: vec!["One", "Two", "Three"] };
    Template::render("index", &context)
}

ハンドラの戻り値が Template となっています。 Template::render() を返すと、テンプレートの内容をレンダリングしてくれます。

render() の引数には、テンプレートの名前と、テンプレートに渡すコンテキストを指定します。 テンプレートの名前は、 "index" を指定しているので、 templates/index.tera が解釈されます。

コンテキストには、Serde でシリアライズ可能なものを指定できます。 この例では、自前で以下のように定義しています。

#[derive(Serialize)]
struct TemplateContext {
    name: String,
    items: Vec<&'static str>
}

さて、 templates/index.tera の内容を確認していきます。

    <h1>Hi {{name}}</h1>

コンテキストとして渡した、 name が使用されています。

        {% for s in items %}
            <li>{{ s }}</li>
        {% endfor %}

ここでは items の内容をループで表示しています。


さいごに

今回は、公式のexamplesの中から基礎の基礎である hello_world 、 動的パスを扱った hello_person 、 レスポンスをリッチにする tera_template の3つを紹介しました。

計画的に執筆していなかったため、あまり紹介できませんでした。 examples は30個位上あるので、余裕のある際に追加していければと思います。

LuaJIT Libraries on LuaJITTeX de 画像処理したりする話

この記事はTeX & LaTeX Advent Calendar 2016の10日目の記事です。
昨日はyuracoさん、明日はkaizen_nagoyaさんです。

発端

まずはこちらのつぶやきをご覧ください。

以前、このツイートを拝見した際に思っていました。
画像処理で似たことが出来ないかなと。

TeX 出来ないかなと。

そこで、「TeX で画像処理するなら今こそ LuaTeX の出番!」と思いたち*1、LuaTeX でトランプ風アートを出力する私の旅は始まったのでした……

コンテンツ

この記事で掲載する内容は以下になります。

  • Torch7: Lua ライブラリの話
  • texluajit で Lua ライブラリを使う話
  • luajittex から Lua ライブラリを使う話(ホンキのLuaTeX)
    • require の動作を修正する話
  • 画像処理を行う話

Torch7: Lua ライブラリの話

とりあえず画像処理ができないことには目標が達成できません。
処理自体は、単純に範囲ごとに平均を取る方法を利用しようと思っていたので、画像から各ピクセルのRGBが取得できれば問題ありませんでした。

探してみて思ったのですが、あまりLuaの画像処理できるライブラリがないのですね。
最初に見つけたのがTorch7という機械学習などができる*2ライブラリでした。

torchの中にimageというそのままの名前のライブラリがあり、こちらを使うこととしました。

本題とは関係がないですが、このライブラリがあれば更に面白いことができそうですね。

texluajit で Lua ライブラリを使う話

Torch7 が luajit のライブラリ*3なので、まずはluajittexエンジンでluaプログラムを動かす、texluajitコマンドで動作確認です。

require('image')
image.test()

テスト出力がされれば成功です。

luajittex から Lua ライブラリを使う話

texluajitからは動作したので、今度はlatex文章に埋め込んで試しますが動きませんでした。

\documentclass{ltjsarticle}

\directlua{
	require('image')

	image.test()
}

\begin{document}
imageモジュールのテストをパス%しません
\end{document}

これの原因は次のリンク先を参照してください。要約すると、

  • requireはpackage.loaders( or serchers)を利用して探索する
  • lua(jit)texではパスの探索はkpseの探索範囲で行う
  • ただし、texlua(jit)コマンドで起動した場合は、普通のluaと同じ探索を行う

という感じです。

require の動作を修正する話

前述の通りなので、requireで読み込むときの動作を修正するモジュールを作成します。

次のページの回答で出ているコードを利用しますが、LuaTeXのLuaがこれとは少し違うようで、修正を加えています。*4

tex.stackexchange.com

以下のコードを、luaモジュールを使いたいtexファイルと同じディレクトリにというlualoader.lua名前で配置しました。

local make_loader = function(path, pos, loadfunc)
  local target = package.searchers or package.loaders
	local default_loader = target[pos]
	local loader = function(name)
		local file, _ = package.searchpath(name,path)
		if not file then
			local msg = "\n\t[lualoader] Search failed"
			local ret = default_loader(name)
			if type(ret) == "string" then
				return msg ..ret
			elseif type(ret) == "nil" then
				return msg
			else
			  return ret
			end
		end
		print("[lualoader][info]found file: " .. file .. "; (with name: " .. name ..")")
		local loader,err = loadfunc(file, name)
		if not loader then
			return "\n\t[lualoader] Loading error:\n\t"..err
		end
		return loader
	end
	target[pos] = loader
end

local binary_loader = function(file, name)
	local symbol = name:gsub("%.","_")
	return package.loadlib(file, "luaopen_"..symbol)
end

make_loader(package.path,2, function(file, name)
	return loadfile(file)
end)
make_loader(package.cpath,3, binary_loader)

これが動くことを確認するため、以下のtexファイルを実行します。

\documentclass{ltjsarticle}

\directlua{
	require('lualoader')
	require('image')

	image.test()
}

\begin{document}
imageモジュールのテストをパス
\end{document}

pdfが出力すれば成功です。これでようやく画像処理ができますね。

画像処理を行う話

画像処理内容は単純で、100x100マスごとにRGBの値を平均したものを計算します。
その色をtikzで塗っていきます。tikzのfillオプションにRGB指定するのがよくわからなかったので、xcolorで毎回色を作っています。

\documentclass{ltjsarticle}

\usepackage{xcolor,tikz,pgf}

\begin{document}
\begin{tikzpicture}[x=5mm,y=5mm]

	\directlua{
		print()
		print(package)
		for k,v in pairs(package) do
			print(k,v)
		end
		print()
		for k,v in pairs(package.loaders) do
			print(k,v)
		end
		print()

		print(package.path)
		print(package.cpath)
		require "lualoader"
		require('image')

		img = image.load("./lenna.png", 3, 'byte')

		size = 100
		rgb = torch.Tensor(
				4, %-- r,g,b, count
				math.ceil(img:size(2) / size), %-- y
				math.ceil(img:size(3) / size)  %-- x
			):fill(0)

		%-- sum color value
		for y = 1,img:size(2) do
			for x = 1,img:size(3) do
				local vy = math.ceil(y / size)
				local vx = math.ceil(x / size)
				for n = 1, 3 do
					rgb[n][vy][vx] = rgb[n][vy][vx] + img[n][y][x]
				end
				rgb[4][vy][vx] = rgb[4][vy][vx] + 1
			end
			print(y)
		end

		%-- avl color value
		for y = 1, rgb:size(2) do
			for x = 1, rgb:size(3) do
				local px = torch.Tensor(3)
				for n = 1, 3 do
					%-- rgb[n][y][x] = math.floor(rgb[n][y][x] / rgb[4][y][x])
					px[n] = math.floor(rgb[n][y][x] / rgb[4][y][x])
				end
				tex.print("\string\\definecolor{mycolor}{RGB}{" .. px[1] .. "," .. px[2] .. "," .. px[3] .. "}")
				tex.print("\string\\draw[draw=mycolor,fill=mycolor] (" .. (x - 1) .. ",-" .. (y - 1) .. ") rectangle (" .. (x-0.2) .. ",-" .. (y-0.2) .. ");")
			end
		end
	}

\end{tikzpicture}
\end{document}

これを、Lennaの画像*5で利用すると、こんな感じのが出力されます。

f:id:vraisamis:20161210194007p:plain


この画像だと512幅しかないので、このサイズで平均化すると中身がわかりませんね。
サイズを変更するといい感じになるかもしれません。

*1:PyTeX などがあるというツッコミはご容赦ください

*2:らしい

*3:JITではないインストールもできるようですが今回はしていないです

*4:Lua5.2でloadersがserchersに変更されたのが原因のようです。Lua 5.2 リファレンスマニュアル: 8.2節を参照。LuaTeXで5.2が使われた場面ってありましたかね?

*5:File:Lenna.png - Wikipedia

続きを読む

LuaLaTeXでフォントサンプル集を作りたい!

経緯

最近スライドを作成する時にフォントを探して回ったりした。自分がフォントに詳しくないのもあり、デフォルトで入っているフォントに関しては、全く知識がなかった。 フォントビューアーを利用すればいいという話もあるが、現環境がUbuntuで、使い勝手が悪かった。

ついでに、好みの問題で大文字の「W」の中央が交差しているフォントがほしかった。

それなので、とりあえずいろいろなフォントで出力するLuaLaTeXスクリプトを書けないかと試行錯誤した。

インストールされているフォント探し: luaotfload-tool

とりあえずどうやらLuaTeX系で使う、フォントDBツールが存在することがわかった。それがluaotfload-toolである。

こんな感じで使う。

# DBの更新
$ luaotfload-tool --update
# インストールされているフォントの一覧を出す
$ luaotfload-tool --list=*
# インストールされているフォントの一覧を、表示項目を指定して出す
$ luaotfload-tool --list=* --fields=plainname

このコマンド、ドキュメントが不完全に感じられる部分があって、例えば--fieldsオプションに指定できる項目がリストアップされていない。

DBを作ると、kpsewhich --var-value=TEXMFVARで出るディレクトリの、luatex/generic/names/luaotfload-names.lua.gzが作成されると思う。 巨大なファイルなので、見ることはあまりおすすめしないが、途中のmappingsの項目に羅列されているものがそれだと思う。コロン以降は簡単な解説。*1

  • basename : パスなしのファイル名。
  • familyname : フォントファミリー名
  • fontname : フォント名
  • format : ファイルのフォーマット(拡張子)
  • fullname : たぶんフォントファミリー名+サブファミリー名
  • fullpath : 絶対パス付きのフォントファイル名
  • index : 内部のインデックス
  • italicangle
  • location
  • pfmweight
  • plainname : フォントの識別名?
  • psname
  • size
  • subfamily : レギュラーとかボールドとかイタリックとか
  • subfont
  • version : フォントバージョン
  • weight
  • width

後にfontspecを利用してフォント変更を行うけど、この時におそらく使えるのはbasenameとplainnameあたり(結論から言って成功はしていない)。その他は未検証。

さて前述のコマンドでフォント一覧が取得できることがわかったので、これを\directluaブロックで取得して適当にループ回せばできるのではって感じで見通しを立てた。

# インストールされているフォントのplainname一覧を出す
$ luaotfload-tool --list=* --fields=plainname

\directluaブロックからの外部コマンド実行

参考に、luaのコードから外部コマンド(例ではls -al)を実行し、出力を得る場合は、次のようにする。

local handle = io.popen("ls -al")
for line in handle.lines() do
    -- ここでなにか色々する。lineには1行分が入っている。
    print(line)
end
handle::close()

上記を参考に\directluaブロックにluaotfload-tool呼び出しを記述しコンパイルすると、エラーが出る。具体的にはpopen()できない。なので、lualatex実行時に、オプション--shell-escapeを付加する必要がある*2

コンパイルの全容を以下に示す。

# main.texをコンパイルする。
$ lualatex --shell-escape main

これで、全ての利用可能(?)なフォントが画面に出力されるはずである。 このときのtexファイルの全容は以下の通り。

% filename: main.tex
\documentclass{ltjsarticle}

\usepackage{luatexja-fontspec}

\begin{document}
test

\directlua{
    local h = io.popen("luaotfload-tool --list=* --fields=plainname")
    print("###################")
    for line in h:lines() do
        print(line)
    end
    print("###################")
    h:close()
}

\end{document}

ここまでは上々。うまく動く。

このままとりあえずフォント名をPDF出力……できない!

なにかよくない文字が含まれているらしい? 本文中で以下のようにするとエラーが出る(再チェック前)。

\directlua{
    fontlist = {}
    local h = io.popen("luaotfload-tool --list=* --fields=plainname | grep -e Han")
    for line in h:lines() do
        tex.print(line)
        tex.print("")
    end
    h:close()
}

\verb||で囲もう。

     %tex.print(line) %%下のように変更
        tex.print("font: \string\\verb|" .. line .. "|")

できた。フォント名がすごいいっぱい並ぶ。 Ubuntuだと1500ぐらい並ぶんじゃないかな?

目的であるフォントを変更して出力

というわけで、このフォント名で\fontspec{}していけばOKなはず!

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
%% !!!!!!! 注意: これを動かすべきではない
%% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass{ltjsarticle}

\usepackage{luatexja-fontspec}

\newcommand{\sampletext}{ABCDEFGHIJKLMNOPQRSTUVWXYZ

abcdefghijklmnopqrstuvwxyz
}

\begin{document}

\directlua{
    fontlist = {}
    local h = io.popen("luaotfload-tool --list=* --fields=plainname")
    print("###################")
    for line in h:lines() do
        table.insert(fontlist, line)
        tex.print("font: \string\\verb|" .. line .. "|")
        tex.print("")
        tex.print("{\string\\fontspec{" .. line .. "}\string\\jfontspec{" .. line .. "} \string\\sampletext }")
        tex.print("")
    end
    print("###################")
    h:close()
}
\end{document}

これが、うまくいかなかった。利用できないフォントのエラーを無視していったが、その他にもエラーが出て止まった。

エラーの解析

コンパイル時にシステムモニタ(タスクマネージャ)等で確認した限り、メモリをかなり消費している。 具体的には、4GBのメインメモリと4GBのスワップがあったが、(コンパイル以外で1GB前後使っているとはいえ)これらを全て食いつぶしていた。まずい。

というわけで、手元にSource Han Sans一式(7つ)があったので、これらだけでどの程度メモリを食うのか検証した。 そのために、以下のような変更を施した。 厳密さは必要ないので、システムモニタを目視することによる検証をした。

 %local h = io.popen("luaotfload-tool --list=* --fields=plainname")
    local h = io.popen("luaotfload-tool --list=* --fields=plainname | grep Han")

結果、2GB程度のメモリを消費していた。このフォントのサイズが大きいとはいえ、さすがに食い過ぎであるように思うが現実は受け止めなければならない。 この結果を見る限り、1ファイルで全てを出力することは現実的ではないと判断した。

どうするか?→フォント毎にファイルを作ってとり込もう!

とりあえず、メインのファイルから各フォントサンプルのPDFを作成して、それを取り込めば表示できるよね!っていう考えに至った。

そこでこちらがmain.texとなる。

\documentclass{ltjsarticle}

\usepackage{graphicx}

\begin{document}
\directlua{
    fontlist = {}
    local h = io.popen("luaotfload-tool --list=* --fields=plainname")
    print("###################")
    for line in h:lines() do
        if line \string~= "" then
            table.insert(fontlist, line)
        end
    end
    h:close()
}
\begin{itemize}
\directlua{
    for k,v in ipairs(fontlist) do
        local fontname = v
        local filename = v:gsub(" ", "_"):gsub("+", "PLUS")
        local ret = os.execute("lualatex --interaction=nonstopmode --output-directory=outd --jobname=\string\"" .. filename .. "\string\" sample fontname=\string\"" .. fontname .. "\string\"")
        print("##########################", fontname, "::::", filename, "==>>", ret, "#########################")
        tex.print("\string\\item \string\\verb|fontspec{" .. fontname .. "}**|", "\string\\\string\\")
        if ret == 0 then
            tex.print("\string\\includegraphics{outd/" .. filename .. ".pdf}")
        else
            tex.print("!! Error: This compile returns", ret, "!!")
            %tex.print("")
        end
    end
}
\end{itemize}
\end{document}

とりあえず出力が出るか出ないかは気にせず、コンパイルエラーならそれを報告するようにした(エラーコードだけ)が、あまり役に立たなかった。 ファイル名にするための無害化とかTeX出力する上での無害化とかをgsub()で行ったけど、不十分だと思う。+以外の記号が含まれる不フォントもあるんじゃないかな?

また、事前に格納先のフォルダoutdが必要になる。同じフォルダに展開すると視覚的に死ぬので注意。

そして、sample.tex。数式関連は表示していない。

\RequirePackage{luatex85}
\documentclass{standalone}
\usepackage{luatexja}
\usepackage{luatexja-fontspec}
\pagestyle{empty}
\directlua{
    fname = "IPAexMincho"
    for i,v in ipairs(arg) do
        a,b,c = string.find(v, "fontname=(.+)")
        print("###########", a, ":::::", b, ":::::", c, "########")
        if c then
            fname = c
        end
    end
    tex.print("\string\\setmainfont{" .. fname .. "}")
    tex.print("\string\\setmainjfont{" .. fname .. "}")
}
\begin{document}
\begin{tabular}{l}
    abcdefghijklmnopqrstuvwxyz
    ABCDEFGHIJKLMNOPQRSTUVWXYZ
    \\
    これは日本語の文書です。
\end{tabular}
\end{document}

standaloneを使うのでluatex85を利用している。フォント指定をコマンドライン引数のインデックスではなく、マッチで行っている。 あまり考えていないので、もしフォント名が渡されなかったらIPAex明朝で表示することにした。

これで動く。ただしコンパイルにすごく時間がかかる。

それと、コンパイルに成功したフォントの数によってはファイルディスクリプタが不足してエラーになることがある。 適当に変更しておこう:うちの環境ではulimit -n 2048でふやせた。

おわりに:今後の更新

気になる部分は指摘していただければと思っています。

  • コメントをつけないとならない。
  • 組み立てを精査しないと少し読みにくい。
  • 環境等を記していない。

以上です、お疲れ様でした。

*1:間違いや追加などのコメントをいただければ幸いです

*2:おそらく、以前pngなどの画像をTeXに取り込む際にはxbbの自動生成の設定が必要だった時のshell escape commandsあたりを弄ればオプションは要らなくなると思うが、私自身はこれ以外の利用ケースを見いだせていないので、コマンドラインオプションとした

NetbeansでJava Servlet環境を整え、index.htmlを表示するまで

環境

Oracle Java8を入れ、デフォルトに設定

$ sudo add-apt-repository ppa:webupd8team/java
$ sudo apt-get update
$ sudo apt-get install oracle-java8-installer
$ sudo apt-get install oracle-java8-set-default

NetBeansをダウンロード

公式サイトからダウンロード。「Java EE」か「すべて」をえらぶ。以降は「すべて」を選んだ場合で説明する。
f:id:vraisamis:20160428142532p:plain

ダウンロードされたファイルの確認とインストーラの起動

ダウンロードが完了すると、シェルスクリプトファイルが得られる。今回はこのディレクトリ内に
何か展開されるわけではないが、説明のためnetbeansというディレクトリを作っている。
f:id:vraisamis:20160428142542p:plain


端末から同ディレクトリに移動し、シェルを起動する。
もしシェルに実行権限がなければ、次のコマンドで実行権限を付加する。

$ chmod u+x netbeans-8.1-linux.sh 

シェルを起動した様子。
f:id:vraisamis:20160428142556p:plain

NetBeansおよびTomcatのインストール設定

きちんと起動すれば次のような画面になる。この画面で、「カスタマイズ」を押す。
f:id:vraisamis:20160428142602p:plain


カスタマイズ画面では、Tomcatが選択されていないので、選択する。以上で「OK」を押す。更に「次へ」。
f:id:vraisamis:20160428142651p:plain


ライセンスの確認。同意すると次へ進むことができる。
f:id:vraisamis:20160428142702p:plain


注意する場所その1JDKのパスはこちらを選択する。デフォルトのものでは動かない。
f:id:vraisamis:20160428142711p:plain


GlassFishJDKも同様(既になっているはず)。
f:id:vraisamis:20160428142727p:plain


Tomcatの設定項目に変更はない。
f:id:vraisamis:20160428142822p:plain


設定の最終確認。チェックボックスは必要に応じて入れる。問題なければ「インストール」を押す。
f:id:vraisamis:20160428142831p:plain


ちなみに、root権限のあるユーザで実行すると、デフォルトのインストールパスなどがこのようになる。
f:id:vraisamis:20160428142841p:plain


インストールの完了までしばらく待機。ダウンロードするものもあるようなので、非課金接続でやるとよい。
f:id:vraisamis:20160428142852p:plain


インストールが完了。チェックボックスはどちらでも良い。
f:id:vraisamis:20160428142902p:plain


デスクトップアイコンで起動。アイコンはこれ。
f:id:vraisamis:20160428142911p:plain


スプラッシュ。
f:id:vraisamis:20160428142922p:plain


起動後のスタートページ。ここまででインストールは完了。
f:id:vraisamis:20160428142935p:plain

プロジェクトの作成と組み込みブラウザでの確認

実際にプロジェクトを作成する。メニューから、「ファイル」→「新規プロジェクト」を選ぶ。
f:id:vraisamis:20160428142950p:plain


プロジェクトタイプの選択。「Java Web」から「Webアプリケーション」を選択。
f:id:vraisamis:20160428143002p:plain


初回のみ機能のアクティベートが行われる。プラグインのインストール等だと思われる。
f:id:vraisamis:20160428143019p:plain


プロジェクトの設定。名前を決め、プロジェクトディレクトリを決める。

下のチェックは、おそらく複数のマシンでの開発が想定される場合には入れたほうが良い。
f:id:vraisamis:20160428143034p:plain


サーバの設定。Tomcatを選択する。「次へ」を押すとフレームワークを選択する画面が出るが、今回は選択しない(説明しない)。
f:id:vraisamis:20160428143042p:plain


以上でプロジェクトの作成は完了。左ペインの「プロジェクト」から、いま作成したアプリケーションのツリーを開いてみると、いくつかファイルがあることが確認できる。

組み込みブラウザで実行を確認する

プロジェクトを選択している状態だと、上部のツールバーのブラウザアイコンが押せるようになっているので、押して実行するブラウザを決定する。

Android云々が表示されているのは、私がAndroidStudioをインストールし、いろいろ設定してあるためだと思われる。好きなブラウザを選べば良い。
f:id:vraisamis:20160428143050p:plain


組み込みブラウザを選んで実行すると、画面中央あたりにindex.htmlの内容が表示される。右ペインにCSS等が表示されるが、中央のブラウザ表示を消すと消える。
f:id:vraisamis:20160428143101p:plain