sun java 9 はやっぱり sun java 9 だった

ちょっと古い話題 ( sun 純正のライブラリ ) があるので sun java 9 ということで。
sun java は日本語だと語呂が良い(「さんじゃば」)けれど、ora java とか cle java とかに略さずに oracle java という表記しかないなあ。

〇 オチ
oracle java 9 は依然として add-apt-repository ppa:webupd8team/java を使用します。

〇 前提
linux 系 OS で使用できる java の実装として OpenJDK 系統と Oracle JDK 系統があります。現時点 ( 2018/03/01 ) では両方ともに oracle が開発しています。違いはいろいろありますが、JavaOne 2017 では「有償版が Oracle JDK、無償版が OpenJDK。2018 年後半を目途に両者のバイナリは互換性を持つ。」という話が出ています。
cf. gihyo.jp での JavaOne 2017 レポート 2 回目
cf. スラドの「LTS版JDKの入手にはOracleサポート契約が必須になる?」という記事

〇 本題
qiita で以下のような記事を発見
もうJava9にadd-apt-repositoryは要らない
まあ、OpenJDK しかいらないのであれば上記の記事で合っていますが、拾ってきたコードで com.sun.compile.reflection.* みたいなのを使用していると OpenJDK では手に負えなくなります。
解決策としては「Oracle JDK を使え」になるのですが、その場合は add-apt-repository する方法が必要になります。具体的には以下のようなコマンドを叩きます。


sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java9-installer

cf. Install Oracle Java 9 (JDK9) in Ubuntu, Linux Mint or Debian via PPA
やっていることは oracle 本家からダウンロードして環境変数等をそろえているだけらしいので、普通に oracle 本家から java の tar.gz を落とす -> 環境変数 JAVA_HOME を設定する -> PATH に ${JAVA_HOME}/bin を通す、のが良さそうです。
まあ rpm も用意されていますが、Ubuntu ( apt ) 使っていて更に rpm も使うのはちょっとした悪夢 ( 絶対 rpm 使っていたことを忘れる ) に思えます。

ちなみに、上記 qiita の記事の引用元は↓
Can not install ‘openjdk-9-jdk’ because it tries to overwrite file aready included in ‘openjdk-9-jdk-headless’ [duplicate]
これ、openjdk-9-jdk と openjdk-9-jdk-headless パッケージを両方入れようとすると /usr/lib/jvm/java-9-openjdk-amd64/include/linux/jawt_md.h でバッティングしてしまってインストールできない、という話です。
解決策としては
・headless 版だけ入れる
・qiita の記事のようにする ( sudo dpkg -i –force-overwrite を指定して .deb パッケージを入れる )
となりました。

〇 余談
何故 oracle Java が必要かというと、java 8 で書いたソースからの移行に –add-exports や –add-opens といった引数を指定したいと思ったからです ( 結局不要だったのですが)。
oracle java の方で “java -X” とかとやると使用方法が出てきます。
cf. Oracle JDK 9 Migration Guide の Migrating to JDK 9
↓を見ると java の modular system ( Project Jigsaw ) で使えるようなのですが、
JEP 261: Module System
jupyter-jvm-basekernel のコンパイル ( ./gradlew build ) で OpenJDK を使うと以下のようなエラーが出ます。


java.lang.IllegalAccessException: class org.gradle.api.internal.tasks.compile.reflect.SourcepathIgnoringInvocationHandler cannot access class com.sun.tools.javac.file.BaseFileManager (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.file to unnamed module @XXXXXXXX

XXXXXXXX は任意の小文字 or 数字
sun java では特にコマンドオプションを付けることなく無事 build できました。
cf. jupyter-jvm-basekernel

media contains valid xfsdump but does not support append

redhat の xfsdump を使用していて発生したエラー。
原因は別のシステムのバックアップファイルを指定していたため。スクリプトは↓

/sbin/xfsdump -L var -M mybackuphdd -l 0 -f /mnt/backup/myserver01-var.YYYYMMDD.dump /dev/rhel/var

既に myserver01-var.YYYYMMDD.dump を myserver01 で取得済みの状態で、同じ記憶媒体を利用して他のサーバでバックアップを取ろうとする ( 既に myserver01-var.YYYYMMDD.dump ファイルがある ) とエラーになります。
「バックアップファイルに指定したファイルは有効な xfsdump ファイルだが、対象のファイルは追加書きがサポートされていない」という意味らしいです。
別のサーバのシェルスクリプトを転用していたため、バックアップファイル名が他のサーバとかぶっていたことを見つけるのに時間がかかりました。
なお、-L ( バックアップ名称 ) と -M ( バックアップ媒体名称 ) を同時に指定しないと prompt で訊かれます。

MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance.

matplotlib のサンプルコードを実行している際にタイトルのようなエラーに遭遇。
実証コードは↓


import matplotlib.pyplot as plt
import numpy as np

np.random.seed(20171217)

fig = plt.figure()

for i in range(1,8):
    subplot = fig.add_subplot(4, 4, i)
    subplot.set_xticks([])
    subplot.set_yticks([])
    subplot.imshow(np.random.random((100, 100)), cmap=plt.cm.gray_r, interpolation='nearest')
    
for i in range(1,8):
    subplot = fig.add_subplot(4, 4, i+1)
    subplot.set_xticks([])
    subplot.set_yticks([])
    subplot.imshow(np.random.random((100, 100)), cmap=plt.cm.BuPu_r, interpolation='nearest')

Warning 全文は↓

/usr/local/share/anaconda3/lib/python3.6/site-packages/matplotlib/cbook/deprecation.py:106: MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance. In a future version, a new instance will always be created and returned. Meanwhile, this warning can be suppressed, and the future behavior ensured, by passing a unique label to each axes instance.
warnings.warn(message, mplDeprecation, stacklevel=1)

問題点は add_axes() 関数を使っていないのにどこでエラーになるか、ということ。
なお、add_axes() 関数のリファレンスは以下を参照
add_axes(*args, **kwargs)

サンプルコードで検証したところ、add_subplot() 関数で同じパラメータを渡すとこのエラーが出るらしいと判明。add_subplot() 関数のリファレンスは以下を参照。
add_subplot(*args, **kwargs)

上記の拙いコードでは、2 回目の subplot(4, 4, i+1) とやっている箇所で 1 回目の subplot(4, 4, i) の呼び出しと同じ引数を呼び出しているから生じるらしい。
正しく動作する ( Warning が出ない ) バージョンは↓


import matplotlib.pyplot as plt
import numpy as np

np.random.seed(20171217)

fig = plt.figure()
counter = 0

for i in range(1,8):
    subplot = fig.add_subplot(4, 4, i)
    subplot.set_xticks([])
    subplot.set_yticks([])
    subplot.imshow(np.random.random((100, 100)), cmap=plt.cm.gray_r, interpolation='nearest')

for i in range(1,8):
    subplot = fig.add_subplot(4, 4, i+8)
    subplot.set_xticks([])
    subplot.set_yticks([])
    subplot.imshow(np.random.random((100, 100)), cmap=plt.cm.BuPu_r, interpolation='nearest')

ただ単に 2 回目の for ループの add_subplot() 関数の 3 番目の引数を i+1 から i+8 に変更しただけ。

〇 対策
「ソースコード写し間違っていませんか」という話になると思います。
色々調べましたが、add_subplot() 関数には、stacklebel といったターゲット引数は指定できません。

〇 実行環境
・jupyter
・jupyterhub
・anaconda

jupyter notebook で作成した notebook 上でプロキシを有効化する

jupyter notebook で作成した notebook 上で、tensorflow の tutorial である mnist のコードを実行したところ、プロキシ環境を認識してくれませんでした。そこで notebook 上でプロキシを有効化する方法を説明します。

〇 結論
/usr/local/share/jupyter/kernels 以下にある kernel.json 内に環境変数を設定する。
設定例は以下の通り。


{
 "argv": [
  "/usr/local/share/anaconda3/bin/python",
  "-m",
  "ipykernel_launcher",
  "-f",
  "{connection_file}"
 ],
 "env": {
    "HTTP_PROXY": "http://example.jp:8123",
    "HTTPS_PROXY": "http://example.jp:8123",
    "FTP_PROXY": "http://example.jp:8123"
  },
 "display_name": "Python 3",
 "language": "python"
}

肝は “env” という箇所。ここに python の dictionary 型で環境変数を列挙します。
上記の例ではプロキシサーバが example.jp、待ち受けポートが 8123 としています。
システム統一の設定箇所というのはなく、各 kernel の kernel.json に一つずつ追加する必要があるようです。

〇参照情報

〇 環境
・Ubuntu Linux 16.04 ( たぶん )
・anaconda 8.25
・Jupyter notebook 4.4.0
・jupyterhub 0.8.0

Windows Installer Cleaner と Windows 7

コントロールパネルの「プログラムの追加と削除」でうまくアンインストールできない場合にぐぐると出てくるのが Windows Installer Cleaner ( utility )。
MS Office 2007 にバンドルされたツールだったらしいですが、Office 2007 のサポートが終了しているので MS からはダウンロードできなくなっています。
過去の情報
technet の情報によると、使い方を間違えると OS に重大なダメージを与えるから、だそうで。

今 ( 2017/09/28 時点 ) 使用するなら無理にダウンロードサイトを探すのではなく、プログラムのインストールまたは削除をブロックしている問題を解決するで公開されているツールを使用する方が良いと思います。

今回は Windows 7 ( 64bit ) にインストールされた office ime 2010 ( 32bit ) の削除の際に使用し無事解決しました。

Windows 10 でユーザープロファイルを修復する

Windows 7 あたりまでは、ユーザープロファイルの破損が原因のトラブルは

  1. ユーザープロファイルを格納したフォルダを rename
  2. 大体 C:\Users 以下にあるログオン名と同じフォルダの名前を変える

  3. 問題が生じたユーザープロファイルのアカウントでログオン

という感じでデフォルトプロファイル ( 大抵は C:\Users\Default という名前の隠しフォルダ ) からユーザープロファイルを再作成することで解決できました。
ところが、Windows 10 では同様の作業を行うと「一時プロファイルを使用しています」という表示がサインイン ( ログオン ) 後に表示され、自動でプロファイルの再作成ができません。
ということで、Windows 10 でのユーザープロファイルの修復はレジストリをいじって修正することになります。
詳細は↓
How to Fix A Corrupt User Profile In Windows 10
作業の要点は以下の通り。

  1. レジストリエディタで以下のレジストリキーをいじる
    • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList
    • の中に S-1-x-xx ( x は数字 ) というフォルダがあるので、その中の ProfileImagePath キーを見て問題のあるユーザープロファイルを特定する。

    • 対象のユーザープロファイルの State を 0 に修正する
    • 対象のユーザープロファイルの RefCount を 0 に修正する
    • RefCount キーが存在しない場合は DWORD ( 32bit ) のキーを作成する

上記サイトに画像入りで説明がありますので、それを参照すると幸せになれます。

今回遭遇した問題は「スタートボタンのタイルアイコンをクリックしてもアプリが起動しない」「Windows Explorer で複数のファイルを一括して開こうとしてもアプリが起動しない」でしたが、上記解決法にて無事解決しました。

上記サイトでは管理者アカウントが存在しない場合に built in Administrator アカウントを有効にする方法もあります。但し、built in Administrator ( というか、プロファイル名に Administrator とあるアカウント ) では Microsoft Edge が起動できない、という問題がありますので、可能であれば非常用の管理者アカウントは作っておくと良いと思います。あと chrome や firefox を予め入れましょう。

KB3185278 がインストールできない場合

Windows 7 更新プログラムで KB3186278 がインストールできない症状に出会いました。
対処法としては C:\Users 以下にあるプロファイルを移動して数個程度にする、でした。
この不具合は修正プログラムをインストールするタイミングによるらしく、300 個ほどプロファイルがあっても問題が出なかった PC もあれば、200 個程度で発生する場合もあるようです。
特に数カ月に一度 Windows Update を適用するスタイルの場合はご注意を。

apt更新後にredmineが起動しない場合の対処

apt-get update && apt-get upgrade をした後で redmine が起動しないという現象が 11 月初頭に出ました。
原因は Ruby on Rails の仕様が変更されたので、secret_token の設定が Rails アプリで必須になったからです。
一応↓にひっそりと書いてあります。
http://www.redmine.org/projects/redmine/wiki/RedmineUpgrade
本家は↓
http://guides.rubyonrails.org/upgrading_ruby_on_rails.html#config-secrets-yml

・要約
1. {REDMINE_ROOT}/config/initializers/secret_token.rb を作成

$ cd /path/to/redmine
$ bundle exec rake generate_secret_token

で作成できる。ファイルのオーナーに注意。
マニュアル的には {REDMINE_ROOT}/config/initializers/secret_token.rb が既にある場合には一度削除してから
bundle exec rake generate_secret_token するように、とある。

作成された secret_token.rb の内容は

RedmineApp::Application.config.secret_key_base = ‘fugafuga’

という感じになる。
マニュアルでは「代わりに、このシークレットを config/secrets.ymlに保存することもできます」とあるので、secret_token.rb もしくは secrets.yml のどちらかがあればよさそうに読めますが、secret_token.rb と secrets.yml の両方が必要っぽい。但し

warning: key “inodot” is duplicated and overwritten

という警告が出る。

2. bundle exec rake secret を実行し、出力された文字列を {REDMINE_ROOT}/config/secrets.yml を手で作成して設定。
フォーマットは

production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

という感じ。ENV[“SECRET_KEY_BASE”] の箇所は環境変数で渡します。例えば以下のような感じ。

$ export SECRET_KEY_BASE=”hogehoge”

とやってから Rails アプリを起動 ( Redmine を起動 ) となってます。
ただ、この場合自動起動しないので、apache の httpd.conf に

<directory "/path/to/redmine/public">
  SetEnv SECRET_KEY_BASE hogehoge
</directory>

と書いて sudo service apache2 restart とやると動作します。

・環境
Ubuntu 16.04.01
apache 2.4.18(apt経由でインストール)
redmine 3.3.1(ソースでインストール)
ruby 2.3.1p112
Bundler version 1.13.6

エラーではないけれど python

以下のような python スクリプトを書いてすこしはまりました。


#! /usr/bin/env python
# test.py
import sys
with open(sys.argv[0], "r") as f:
  for line in f:
    print line
  f.close()

これを、例えば下記のように実行するとソースファイルが二重に改行されて表示されます。

./test.py
# もしくは
python test.py

上のスクリプトは何をやっているかというと、ソースコード ( sys.argv[0] で指定されたスクリプト自身 ) を出力しているだけの話。コマンドライン引数は sys.argv[1] 以降に格納されています。
ある程度書いてからデバッグを行うと、エラーもなしにスクリプト自身が表示されて、頭を抱えることになります。
コマンドライン引数の取り扱いは注意しましょう、という話でした。