Java 11

あんまり分かってないけど、とりあえずJRE付きでエクスポートまではできた。

Java 9以降のこと

これまでの実行可能Jar

  • Javaランタイム(JRE)を同梱しなくても、システムにインストールされたPublic JREで実行できた

これから

  • システムにJREがない
  • 同様に実行できるようにするには、JREをアプリケーションに同梱する必要がある(?)
    • これまでもrt.jarJREの同梱された形としてあったはず

Jigsawモジュールシステム

Java 9以降導入されたJavaの依存関係システム。

依存関係はmodule-info.javaファイルに記述する。

module sample.module {
    requires java.base; // 不要(省略可)
}

実行可能Jarのエクスポート(MavenJREなし)

Java 8まで、こんな感じだった。

Maven pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.sample</groupId>
    <artifactId>Sample</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>8</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.1.1</version>

                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>com.example.sample.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

JREの生成(手動、module-info使用)

コンパイルしたクラスファイルのディレクトリを指定

jlink --module-path './classes;JDK_DIRECTORY/jmods' --add-modules sample.module --output jre

Jarを指定

jlink --module-path './sample.jar;JDK_DIRECTORY/jmods' --add-modules sample.module --output jre

圧縮

-c 2

起動用スクリプトも生成してくれる。

--launcher mycmd=sample.module/com.example.sample.Main

OpenJDK 11.0.1 (Windows)で実行すると、dll, exe, ランチャーシェルスクリプト, bat他が生成された。OpenJDKの中身を絞って移してきてる? 複数OS想定する場合、JREはOS別に作る必要があるのか? それとも別の方法があるのか。

実行可能Jarのエクスポート(MavenJREあり、ランチャー)

上の処理を自動化してくれるプラグインを使う。

ant-runの部分はjlinkツールが出力ディレクトリを上書きしてくれないので、packageを実行するごとに削除させるため。手動で消すかcleanすれば不要。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.sample</groupId>
    <artifactId>Sample</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>11</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
    </properties>

    <build>
        <plugins>
            <!-- https://mvnrepository.com/artifact/org.moditect/moditect-maven-plugin -->
            <plugin>
                <groupId>org.moditect</groupId>
                <artifactId>moditect-maven-plugin</artifactId>
                <version>1.0.0.Beta2</version>
                <executions>
                    <execution>
                        <id>create-runtime-image</id>
                        <phase>package</phase>
                        <goals>
                            <goal>create-runtime-image</goal>
                        </goals>
                        <configuration>
                            <compression>2</compression>
                            <modulePath>
                                <path>${project.build.outputDirectory}</path>
                            </modulePath>
                            <modules>
                                <module>sample.module</module>
                            </modules>
                            <launcher>
                                <name>Sample</name>
                                <module>sample.module/com.example.sample.Main</module>
                            </launcher>
                            <outputDirectory>
                                ${project.build.directory}/jlink
                            </outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-antrun-plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.8</version>
                <executions>
                    <execution>
                        <phase>initialize</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <target>
                                <delete dir="${project.build.directory}/jlink" quiet="true" />
                            </target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

ただ、この方法だとjarファイルが見当たらない。たぶんruntimeも自分のプログラムも混ざってどこかに入ってる。外部jarを混ぜずに読み込む方法もわからない。

JREの生成(手動、Jar使用)

module-infoを使わない方法(使わないでいいのかは分からないけど)。

jdeps --list-deps JARファイルmodule-infoのないJARの依存するモジュールリストが出力される。

このリストをもとに下のコマンドでJREを生成すれば混ざることはないはず。

jlink -c 2 -p 'JDK_DIRECTORY/jmods' -m モジュールカンマ区切りリスト --output jre

生成されたjava実行ファイルに対してjava -jar JARファイルするスクリプトを書けば外にjarを置ける。

外部Jarライブラリをlibsディレクトリに置く、というのを次はやりたい。今まで通りクラスパスに追加して、JREだけ上の方法で生成する、実行はスクリプトから、は正解じゃない気がするので、どうすればいいのか。それから、Launch4j使いたい場合?

json, bson, sqlite3 IOの実験メモ

import json
import random
import time

file = 'test.tmp'
N = 500

# Generate
start = time.time()
entries = []
for i in range(N):
    title = ''.join([ chr(random.randint(ord('あ'), ord('ん')+1)) for i in range(32) ])
    body = ''.join([ chr(random.randint(ord('あ'), ord('ん')+1)) for i in range(30000) ])
    entries.append({
        'id': i,
        'title': title,
        'body': body,
    })

data = {
    'entries': entries,
}

end = time.time()
print('Generate: %.1fs' % (end - start, ))
Generate: 38.6s
import os

# Write
start = time.time()
with open(file, 'w', encoding='utf-8') as fp:
    json.dump(data, fp, ensure_ascii=False)

end = time.time()
print('Write: %.3fs' % (end - start, ))

print('%.2fMB' % (os.path.getsize(file)/(1024**2), ))

# Read
start = time.time()
with open(file, 'r', encoding='utf-8') as fp:
    data = json.load(fp)

end = time.time()
print('Read: %.3fs' % (end - start, ))
Write: 0.252s
42.98MB
Read: 0.214s

pip install bson

import bson

# Write
start = time.time()
s = bson.dumps(data)
print('%.2fMB' % (len(s)/(1024**2), ))

dumpEnd = time.time()

with open(file, 'wb') as fp:
    fp.write(s)

end = time.time()

print('Write: %.3fs (Dump: %.3fs)' % (end - start, dumpEnd - start))


# Read
start = time.time()

with open(file, 'rb') as fp:
    s = fp.read()

loadStart = time.time()

data = bson.loads(s)
end = time.time()

print('Read: %.3fs (Load: %.3fs)' % (end - start, end - loadStart))
42.98MB
Write: 0.830s (Dump: 0.638s)
Read: 0.156s (Load: 0.095s)
import sqlite3

if os.path.exists(file):
    os.unlink(file)

start = time.time()
with sqlite3.connect(file) as db:
    cur = db.cursor()

    cur.execute('CREATE TABLE entries(id INTEGER AUTO INCREMENT, title TEXT, body TEXT)')
    for entry in data['entries']:
        cur.execute('INSERT INTO entries VALUES(?,?,?)', (entry['id'], entry['title'], entry['body'], ))
    
end = time.time()

print('Write: %.3fs' % (end - start, ))

start = time.time()
with sqlite3.connect(file) as db:
    cur = db.cursor()

    results = []
    for row in cur.execute('SELECT * FROM entries'):
        results.append(row)

end = time.time()

print('Read: %.3fs' % (end - start, ))


print('%.2fMB' % (os.path.getsize(file)/(1024**2), ))

db.close()
Write: 1.093s
Read: 0.243s
43.22MB

HOG特徴量の計算(Scikit-image)

pip install scikit-image

from skimage.feature import hog
import numpy as np

size = 32
channel = 1
image = np.random.randn(size, size, channel)
feature = hog(image)

print(feature.shape)
print(feature)

デフォルト(勾配方向数9, セルサイズ8, ブロックサイズ3)では32x32の画像に対して324次元のHOG特徴量が出力される。

出力例

(324,)
[0.01877925 0.00125122 0.00899619 0.00630656 0.01330613 0.0150924
...
0.00763393 0.01668535 0.01852621 0.01204107 0.00433798 0.01147866]

ドキュメント: http://scikit-image.org/docs/dev/api/skimage.feature.html#skimage.feature.hog

PythonからPaSoRiを使って交通系ICカードのIDmを読む

環境

セットアップ

まずPaSoRiを接続する。PaSoRiをUSBポートに挿して、VirtualBox仮想マシンの設定からUSB、USB デバイスフィルターにSONY RC-S380/Pを追加。

$ lsusb
Bus 001 Device 004: ID 054c:06c3 Sony Corp.
...

これでOK。

次にnfcpyのインストール(※Python2に導入すること、virtualenvを使うといいのでは)。

pip install nfcpy

いくらか準備が必要なので、python -m nfcを実行する。

$ python -m nfc
No handlers could be found for logger "nfc.llcp.sec"
This is the 0.13.5 version of nfcpy run in Python 2.7.15rc1
on Linux-4.15.0-33-generic-x86_64-with-Ubuntu-18.04-bionic
I'm now searching your system for contactless devices
** found usb:054c:06c3 at usb:001:004 but access is denied
-- the device is owned by 'root' but you are 'USERNAME'
-- also members of the 'root' group would be permitted
-- you could use 'sudo' but this is not recommended
-- better assign the device to the 'plugdev' group
   sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'
   sudo udevadm control -R # then re-attach device
I'm not trying serial devices because you haven't told me
-- add the option '--search-tty' to have me looking
-- but beware that this may break other serial devs
Sorry, but I couldn't find any contactless device

一般ユーザーの場合こんなメッセージが出るので、指示通りデバイスplugdevグループに割り当てる。

sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'

/etc/udev/rules.d/nfcdev.rulesはこうなる。

SUBSYSTEM=="usb", ACTION=="add", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="06c3", GROUP="plugdev"
...

下のコマンドはリロード、のはずだが、うまく動かないのでPaSoRiを抜き差しする(VirtualBoxのメニューからでも、ホストからでも)。

sudo udevadm control -R

もう一度チェックするとメッセージが変わる。

$ python -m nfc
No handlers could be found for logger "nfc.llcp.sec"
This is the 0.13.5 version of nfcpy run in Python 2.7.15rc1
on Linux-4.15.0-33-generic-x86_64-with-Ubuntu-18.04-bionic
I'm now searching your system for contactless devices
** found usb:054c:06c3 at usb:001:005 but it's already used
-- scan sysfs entry at '/sys/bus/usb/devices/1-2:1.0/'
-- the device is used by the 'port100' kernel driver
-- this kernel driver belongs to the linux nfc subsystem
-- you can remove it to free the device for this session
   sudo modprobe -r port100
-- and blacklist the driver to prevent loading next time
   sudo sh -c 'echo blacklist port100 >> /etc/modprobe.d/blacklist-nfc.conf'
I'm not trying serial devices because you haven't told me
-- add the option '--search-tty' to have me looking
-- but beware that this may break other serial devs
Sorry, but I couldn't find any contactless device
sudo modprobe -r port100

でport100なるドライバが止まり、動くようになる。

sudo sh -c 'echo blacklist port100 >> /etc/modprobe.d/blacklist-nfc.conf'

これで次回起動以降、port100が起動しなくなるのかな。

port100を止めたらもう一度チェック。

$ python -m nfc
No handlers could be found for logger "nfc.llcp.sec"
This is the 0.13.5 version of nfcpy run in Python 2.7.15rc1
on Linux-4.15.0-33-generic-x86_64-with-Ubuntu-18.04-bionic
I'm now searching your system for contactless devices
** found SONY RC-S380/P NFC Port-100 v1.11 at usb:001:005
I'm not trying serial devices because you haven't told me
-- add the option '--search-tty' to have me looking
-- but beware that this may break other serial devs

ちゃんと見つかったらOK。

IDmを読む

短いサンプルコード。

nf.py

import nfc
from nfc.clf import RemoteTarget

clf = nfc.ContactlessFrontend('usb')
print(clf)

tag = clf.connect(rdwr={
    'on-connect': lambda tag: False
})

print(tag)

ICカードがない場合、以下の出力の後(clf.connectで)ブロックされる。

$ python nf.py
No handlers could be found for logger "nfc.llcp.sec"
SONY RC-S380/P on usb:001:005

ここでICカードを近づけると、タグが出力(print(tag))される。

$ python nf.py
No handlers could be found for logger "nfc.llcp.sec"
SONY RC-S380/P on usb:001:005
Type3Tag ID=$$$$$$$$$$$$$$$$ PMM=$$$$$$$$$$$$$$$$ SYS=0003
>>> print(type(tag))
<class 'nfc.tag.tt3.Type3Tag'>
>>> 
>>> print(vars(tag)).keys())
['_clf', '_target', 'sys', 'idm', '_ndef', 'pmm', '_nfcid', '_authenticated']

tag.idmを使えばIDmが取れそうなのでOK。

参考




SSD換装時のOS移動(スケールダウン)

容量の小さなSSDに換装する(HDD 500GBからSSD 250GB)。

  1. 対象のHDD, SSD以外でUbuntuを起動(USBブートなど)
  2. GPartedで必要なパーティションをHDDからSSDにコピー(Boot, OSとか)
  3. コピー先でパーティションを右クリック、Manage Flagsからコピー元のパーティションとFlagsを一致させる
  4. Ubuntuとのデュアルブートにしていたため、EFIをマウントして"ubuntu"を削除

プライベートリポジトリに対してgit cloneがNot Found吐くとき(複数アカウント運用)

環境

Windows 10

原因

Windows 資格情報に対象のリポジトリのあるアカウント以外の認証情報が記録されてた

解決

資格情報マネージャー(Credential Manager)を開いてWindows 資格情報、汎用資格情報からgitを削除。

これでclone時にログイン用のブラウザが表示される(GitHub)。

参考

Windows10でCortanaの検索結果から"Recent"を消去する

17/11/05追記:この記事でやっているのは履歴の消去のみ。記録を無効にするものではない。

Winキー、アプリケーション名入力、Enterでアプリケーションを開くのが便利だが、Cortanaは"最近開いたファイル" = "Recent"を記録する。

この"Recent"、右クリック、"この一覧から消去"では消えなかった。Cortana(検索)を開き直すと復活する。アプリケーションを右クリックして出るジャンプリストも同じだ。

https://account.microsoft.com/privacy/cortana

ここから"Cortana データを消去する"で消せた。