2017年11月11日土曜日

Arch Linuxを定期的にアップデートさせる

Arch Linuxを定期的にアップデートさせたい。


pacmanコマンドに"--noconfirm"オプションを付けることで、確認無しでアップデートしてくれる。
# pacman -Syu --noconfirm

さらに、アップデート正常終了後に再起動させる。
# pacman -Syu --noconfirm && systemctl reboot


cronにこれをやらせる。


まず、上記のコマンドを実行するシェルスクリプトを作成する。FHSに従うと自作のシェルスクリプトは/usr/local/bin/っぽいのでそこに作成する。
# vim /usr/local/bin/update_system_and_reboot.sh

#!/bin/bash
pacman -Syu --noconfirm && systemctl reboot


cronに登録する。
# EDITOR=vim crontab -e

* 7 * * 0 /usr/local/bin/update_system_and_reboot.sh

2017年11月9日木曜日

普通のSynapticsタッチパッドを高感度タッチパッドにしてみる

Macのタッチパッドはズームもジェスチャもヌルヌル動いて気持ちが良いです。

それに比べて今までのWindowsのタッチパッドはガッタガタでした。その理由はSynapticsのアプリケーションが ジェスチャ等を感知してマウス入力やキーボードショートカットに変換していたためです。

いつからか分かりませんが、Windowsでは高精度タッチパッド(Precision Touchpad)というものに対応しており、タッチパッドの入力をそのままWindowsに送ることができるようになりました。

高精度タッチパッドに対応している場合、設定→デバイス→タッチパッド を開くと、「お使いのPCには高精度タッチパッドが用意されています。」と表示されます。

常用しているThinkPad X240はもちろん対応していませんでした。

調べていくうちに、こんなサイトを見つけました。


このサイトによると、高精度タッチパッドに対応しているThinkPad X1のタッチパッドドライバを無理やり入れることで高精度タッチパッドに対応するらしいです。

早速ThinkPad X240でやってみました。


 できました。

ジェスチャーもズームもヌルヌル動いてくれます。

普通のPCならこれで万々歳ですが、ThinkPadにはトラックパッド というものがあります。

このドライバを入れることでThinkPad X240のトラックパッドの右クリックが効かなくなってしまいました。

Synapticsの設定画面もフリーズして開けなくなってしまったので泣く泣く元のドライバに戻してあげました。

5ボタントラックパッドではなく、普通の3ボタントラックパッドなら使えるかもしれません。

2017年10月21日土曜日

iptables 設定メモ

-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT

-A INPUT -i br0 -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i ppp0 -m state --state RELATED,ESTABLISHED -j ACCEPT

-A FORWARD -d 192.168.1.0/24 -j ACCEPT
-A FORWARD -i br0 -j ACCEPT
-A FORWARD -i lo -j ACCEPT
-A FORWARD -i ppp0 -m state --state RELATED,ESTABLISHED -j ACCEPT

-t nat -A POSTROUTING -s 192.168.1.0/24 -o ppp0 -j MASQUERADE

2017年10月17日火曜日

Lenovo SettingsがLenovo Companionに統合された

Lenovo SettingsがLenovo Companionに統合されました。

また、今までLenovoアカウントにログインするためにはLenovoアカウントポータルというアプリも必要でしたが、これも不要になりました。

今後はLenovo Companion 1つだけあれば良さそうです。

2017年10月2日月曜日

Windowsのスタートメニューショートカットの場所

ユーザーごと
%APPDATA%\Microsoft\Windows\Start Menu\Programs

全ユーザー
%ALLUSERSPROFILE%\Microsoft\Windows\Start Menu\Programs

PMMPサーバの構築 (Linux)

1. 適当なPMMPサーバ用のディレクトリを作成
    ~$ mkdir pmmp

2. pharファイルのダウンロード
    https://jenkins.pmmp.io/job/PocketMine-MP/
    PocketMine-MP_*_*_API-*.pharをダウンロード。
    PocketMine-MP.pharにリネームしてPMMPサーバディレクトリにコピー。

    $ cd /tmp
    /tmp$ wget https://jenkins.pmmp.io/job/PocketMine-MP/132/artifact/PocketMine-MP_1.7dev-132_b54f256f_API-3.0.0-ALPHA9.phar
    /tmp$ cp PocketMine-MP_1.7dev-132_b54f256f_API-3.0.0-ALPHA9.phar ~/pmmp/PocketMine-MP.phar

3. PHPバイナリのダウンロード
    https://jenkins.pmmp.io/
    pharファイルの要求するPHPのバージョンを選択。
    PHP_Linux-x86_64.tar.gzをダウンロード。
    解凍して、binフォルダをPMMPサーバディレクトリにコピー。

    $ cd /tmp
    /tmp$ wget https://jenkins.pmmp.io/job/PHP-7.2-Linux-x86_64/lastSuccessfulBuild/artifact/PHP_Linux-x86_64.tar.gz
    /tmp$ tar xf PHP_Linux-x86_64.tar.gz
    /tmp$ cp -R bin ~/pmmp/

4. 起動用スクリプトの作成
    $ cd ~/pmmp
    ~/pmmp$ wget https://raw.githubusercontent.com/pmmp/PocketMine-MP/master/start.sh

5. 起動用スクリプトを実行
    初期設定をして完了。

    ~/pmmp$ ./start.sh

フォルダ構成
pmmp\
 ├ bin\
 ├ PocketMine-MP.phar
 └ start.cmd or start.ps1

PMMPサーバの構築 (Windows)

1. 適当なPMMPサーバ用のフォルダを作成

2. pharファイルのダウンロード
    https://jenkins.pmmp.io/job/PocketMine-MP/
    PocketMine-MP_*_*_API-*.pharをダウンロード。
    PocketMine-MP.pharにリネームしてPMMPサーバフォルダにコピー。

3. PHPバイナリのダウンロード
    https://ci.appveyor.com/project/pmmp/php-build-scripts/history
    pharファイルの要求するPHPのバージョンを選択。
    ARTIFACTSからphp-*-vc*-x64.zipをダウンロード。
    解凍して、binフォルダをPMMPサーバフォルダにコピー。

4. VC++ランタイムをインストール
    https://support.microsoft.com/en-gb/help/2977003/the-latest-supported-visual-c-downloads
    PHPバイナリの要求するバージョンのVC++ランタイムをインストールする。
    php-7.2.0RC3-vc15-x64.zipならvc15の部分がバージョン。

5. 起動用スクリプトの作成
    https://github.com/pmmp/PocketMine-MP/blob/master/start.cmd
    Rawをクリックしてstart.cmdをダウンロードし、PMMPサーバフォルダにコピー。

    PowerShellがいいならこっち
    https://github.com/pmmp/PocketMine-MP/blob/master/start.ps1

6. 起動用スクリプトを実行
    初期設定をして完了。

フォルダ構成
pmmp\
 ├ bin\
 ├ PocketMine-MP.phar
 └ start.cmd or start.ps1

2017年9月13日水曜日

C++ 継承の使い方

一部だけ処理が異なるような複数のクラスを用意する際、継承を利用することで楽になる。

// Base.h
class Base {
public:
    int a_, b_;
    int ans_;
    Base(int a, int b) {
        a_ = a;
        b_ = b;
    }
    virtual void Calc() = 0;
    int Ans() {
        return ans_;
    }
}

// Add.h
#include "Base.h"
class Add : public Base {
public:
    Add(int a, int b) : Base(a, b) {
    }
    virtual void Calc() {
        ans_ = a_ + b_;
    }
}

// Sub.h
#include "Base.h"
class Sub : public Base {
public:
    Sub(int a, int b) : Base(a, b) {
    }
    virtual void Calc() {
        ans_ = a_ - b_;
    }
}

上記のように、基底クラスを作成し、変更したい関数を仮想関数にする。そのクラスを継承した派生クラスを作成、仮想関数を上書きすることで新しいクラスを作成することができる。

以下のように普通のクラスと同様にインスタンス生成が可能。
Add * add = new Add(2, 1);
Sub * sub = new Sub(2, 1);
add->Calc();
sub->Calc();
std::cout << add->Ans() << std::endl;
std::cout << sub->Ans() << std::endl;

派生クラスは基底クラスの型でもOK。
Base * add = new Add(2, 1);
Base * sub = new Sub(2, 1);

配列にすることもできる。
std::array<Base *, 2> calcs{new Add(2, 1), new Sub(2, 1)};
for(Base * calc : calcs) {
    calc->Calc();
    std::cout << calc->Ans() << std::endl;
}

配列にすることで順次処理が簡単になる。

2017年8月29日火曜日

C++ int型の範囲

int8_t : -128 ~ 127
uint8_t : 0 ~ 255

int16_t : -32768 ~ 32767
uint16_t : 0 ~ 65535

int32_t : -2147483648 ~ 2147483647
uint32_t : 0 ~ 4294967295

int63_t : –9223372036854775808 ~ 9223372036854775807
uint64_t : 0 ~ 18446744073709551615

2017年8月3日木曜日

MGO2R OFW版が公開された

MGO2RのOFW版が公開されました。MGO2Rは、MGO2の非公式サーバ(エミュ鯖)のことで、これまでCFWでしかできなかったものがOFWでもできるようになりました。

MGO2をMGO2Rのサーバに接続するためには、追加データをPS3に入れる必要になりますが、OFWではそのままではインストールできませんでした。

今回、追加データが入ったバックアップデータが公開されたため、このデータからリストアすることでOFWでもMGO2Rへの接続が可能になりました。

リストアする際には本体データが初期化されるため、あらかじめセーブデータ等のバックアップを取っておく必要があります。

手順

まずSaveMGOのアカウントを作成しておきます。MGO2Rへはこのアカウントで接続することになります。


以下のリンクからリストアデータをダウンロードします。

https://savemgo.com/forums/viewtopic.php?f=22&p=4423#p4423


MGS4ディスクならMGS4 Japanから、MGOディスクならMGO Japanからダウンロード、解凍してPS3ディレクトリをUSBメモリにコピーします。

PS3を起動し、USBメモリにコピーしたデータからリストアすると完了です。


MGO2を起動し、SaveMGOのID/パスワードを入力するとプレイが可能になります。

2017年5月2日火曜日

ちょうどいいLinuxデスクトップ環境がない

以前までLinuxのデスクトップ環境といえばGNOME一択という状況でしたが、GNOME 3で大幅に仕様変更され、ディストリビューションによってデスクトップ環境がばらばらになっています。

ディストリビューションごとのデフォルトのデスクトップ環境を利用すれば悩みなどないのですが、Arch Linuxにはそんなものはありません。

様々なデスクトップ環境を試してみたのですが、しっくりくるものが無かったので記しておきます。


GNOME 3
良い:Waylandに移行している。凄まじく安定している。
悪い:拡張機能入れなきゃほぼ使えない。Systemd環境でしか動作しないため、Linux以外のOSでは動作しない。設定項目が少なすぎる。

Plasma
良い:綺麗、かっこいい。Wayland版が開発中。
悪い: アプリケーション一覧が独自で見づらい。標準のデスクトップマネージャがしょぼい。

LXDE
良い:軽い。
悪い:GTK+2(GTK+3版は開発中)。統一されたテーマがない。LXDE自体の機能がほぼ無いため、GNOMEなどのアプリケーションを利用しなければならない。

LXQt
良い:LXDEのQt版。
悪い:動かない。

Xfce
良い:軽い。
悪い:GTK+2ベース。

Unity
Ubuntu標準のデスクトップ環境。開発終了。
悪い:Ubuntu専用。使いづらい。広告だらけ。ほぼGnome。

MATE
GNOME 2のフォーク。
悪い:GTK+2。

Cinnamon
GNOME 3のフォーク。
悪い:GNOMEを使いたくないからCinnamonを使おうとしているのにGNOMEのアプリケーションを使わなきゃいけない。


2017年5月1日月曜日

GNOME 3でFcitxが動かない

Arch Linuxに久しぶりにGNOME 3をインストールしてみたのですが、Fcitxが正常に動作しませんでした。

その原因はGNOME 3のデフォルトウインドウシステムがXorgからWaylandに移行したためでした。



WaylandにはXWaylandというXorg互換環境があり、FirefoxなどのXorgアプリケーションはそれで動いています。

GNOME 3標準のアプリケーションはほとんどWaylandに移行しているのですが、ほとんどのGUIアプリケーションは未だにXorgで動作している状況です。

FcitxもXWayland上で動作しているため、XorgアプリケーションではFcitxが使えるのですが、WaylandアプリケーションではFcitxが利用できません。

Todo-List Fcitxによると、add wayland supportはIn Progressになっています。


対応策としては、デスクトップセッションをGNOME 3 on Xorgとして起動するか、Fcitxの代わりにIbusを利用するしかないようです。

2017年3月10日金曜日

Bash on Windowsに関して

Bashの起動(カレントディレクトリを引き継ぐ)
C:\Users\foo> bash
/mnt/c/Users/foo$

Bashの起動(WSLのデフォルトユーザのホームディレクトリで起動)
C:\Users\foo> bash ~
/home/foo$

Bashを起動せずにLinuxコマンドを実行
> bash -c "コマンド"

Windows側のドライブはBoW上では /mnt/ドライブレター としてマウントされています。
C:\ -> /mnt/c/

逆に、Windows側から見たBoWの/ディレクトリは、
%USERPROFILE%\AppData\Local\lxss\rootfs です。

このフォルダを直接いじるとパーミッションやシンボリックリンクが壊れそうなのでやめておいたほうがよさそうです。

https://blogs.msdn.microsoft.com/commandline/2016/11/17/do-not-change-linux-files-using-windows-apps-and-tools/


C:\tesy.pyをBoWのPythonで実行するには
> bash -c "python /mnt/c/test.py"
とすることができます。


BoWのインストール
> lxrun /install
    引数に /y で許可を求めません
    既にインストールされている場合は再インストールされます。


BoWのアンインストール
> lxrun /uninstall
    引数に /full でユーザディレクトリも含めて完全に削除、 /y で許可を求めません


デフォルトユーザの設定・作成
> lxrun /setdefaultuser ユーザ名


アップデート
>lxrun /update
    $ sudo apt update と一緒です


LinuxのシステムコールをWinNTのシステムコールに変換して実行しているので、LinuxカーネルはWindowsの自前、その他はUbuntuそのもののようです。

$ cat /proc/version
Linux version 4.4.0-43-Microsoft (Microsoft@Microsoft.com) (gcc version 5.4.0 (GCC) ) #1-Microsoft Wed Dec 31 14:42:53 PST 2014

2017年3月5日日曜日

Ubuntu 16.04で指紋認証ログインしようとした

Ubuntuで指紋認証を利用する場合、PPAを追加してFingerPrint GUIを利用するという情報がほとんどです。

ですが、できるだけクリーンな状態を維持したいのであまりPPAは追加したくなく、外部のフロントエンドも利用したくありません。

Arch Linux + Gnome 3の場合にはfprintdをインストールするだけでGnomeと統合してくれましたが、Ubuntuの標準レポジトリにもfprintdがありました。

ぽぬぽぬ: Arch Linuxで指紋認証:


試しにインストールしてみると、設定内の"ユーザアカウント"に「指紋認証ログイン」が追加され、指紋の追加もできました。



これで使えるかと思ったのですがだめでした。

2017年2月22日水曜日

Arch Linux上にSoftEther VPNサーバを簡単に構築

今までxl2tpとOpenSwanでL2TP/IPsec VPNサーバを構築していましたが、SoftEther VPNで簡単に構築することができました。

L2TP/IPsecだけでなく、SSTP、OpenVPNでの接続にも対応しています。

現在の環境は、LAN用NICとhostapdまとめてbr0にブリッジ接続しています。
このbr0にSoftEther VPNサーバをブリッジさせます。

まずSoftEther VPNをインストール
$ yaourt -S softethervpn-git

SoftEther VPNの起動
$ sudo systemctl start softethervpn-server


ここからはWindows等GUIが使えるPCからリモートで設定します。

まずSoftEther VPN Server Managerを公式サイトからダウンロード
http://www.softether-download.com/ja.aspx?product=softether

起動し、 新しい接続設定の作成 からホスト名を入力保存。

接続しようとするとSoftEther VPNサーバのパスワードを訊かれるので設定します。


まず仮想HUBを作成します。

"仮想HUBの管理"→"ユーザーの管理"→"新規作成"

ユーザー名とパスワードを設定して保存。


IPsec/L2TPの有効化

"IPsec / L2TP 設定"→ "L2TP サーバー昨日を有効にする (L2TP over IPsec)"にチェック


ブリッジ設定

今回はVPN通信用のtapデバイスを作成し、これをbr0に追加させます。

"ローカルブリッジ設定"を開き、

"仮想HUB"にさっき作成した仮想HUBを選択。
"新しい tap デバイスとのブリッジ接続"を選択。
"新しい tap デバイス名"に分かりやすいように名前を付ける。今回はvpn0としました。

tapデバイス名で設定した名前は"tap_デバイス名"としてネットワークに追加されます。


br0にtapデバイスを追加する

$ sudo brctl addif br0 tap_vpn0


500、4500、1701ポートを開放する
$ sudo iptables -A INPUT -p udp --dport 500 -j ACCEPT
$ sudo iptables -A INPUT -p udp --dport 4500 -j ACCEPT
$ sudo iptables -A INPUT -p udp --dport 1701 -j ACCEPT


これでVPN接続が可能になります。


接続できたら設定の永続化

ブリッジの設定(systemd-networkdの場合)

$ sudo vim /etc/systemd/network/tap_vpn0.netdev
[NetDev]
Name=tap_vpn0
Kind=tap

$ sudo vim /etc/systemd/network/tap_vpn0.network
[Match]
Name=tap_vpn0

[Network]
Bridge=br0

$ sudo iptables-save > /etc/iptables/iptables.rules
$ sudo systemctl enable softethervpn-server.service

ブリッジ周りの設定はそのままSystemdに任せてしまうと、VPNサーバ起動前にブリッジの設定が始まってしまうので先にtapデバイスを作成しています。


WindowsからSSTP接続する場合、証明書のインストールが必要になります。
mmc → 証明書(ローカルコンピュータ) → 信頼されたルート証明機関 → 証明書 にインストールすることで認証が可能になります。

2017年2月20日月曜日

LineageOSでNow on Tapを有効化する

1, 設定→ボタン→ホームボタン長押しの動作

"検索アシスタント"を選択

2, Googleアプリ→設定→画面の検索

"ホームボタンを押し続け…に指示します。"をオンにする

3, 設定→アプリ→歯車アイコン→アシストと音声入力→アシストアプリ

"Google アプリ"を選択

2017年2月19日日曜日

Android Canvasに時計を描画する


public static String timeZoneId = "Asia/Tokyo";  //タイムゾーンを変更できるようにする
private void draw() {
        Canvas canvas = holder.lockCanvas();
        canvas.drawColor(Color.GRAY);
        Paint paint = new Paint();

        // 中心座標からCANVAS_SIZE_MINの85%に黒色の円を描画
        paint.setColor(Color.BLACK);
        canvas.drawCircle(CENTER_POS[0], CENTER_POS[1],
                (float) CANVAS_SIZE_MIN / 2f * 0.85f, paint);

        // 中心座標からCANVAS_SIZE_MINの80%に白色の円を描画
        paint.setColor(Color.WHITE);
        canvas.drawCircle(CENTER_POS[0], CENTER_POS[1],
                (float) CANVAS_SIZE_MIN / 2f * 0.8f, paint);

        // 中心座標からCANVAS_SIZE_MINの70%に文字盤を描画
        paint.setColor(Color.BLACK);
        paint.setTextSize(CANVAS_SIZE_MIN / 15); // 文字サイズ
        float fontPos = CANVAS_SIZE_MIN / 2f * 0.7f;  // フォント描画位置
        float dialWidth;  // 文字の横幅
        float dialHeight = paint.descent() + paint.ascent();  // 文字の縦幅
        for (int _i = 0; _i < 12; _i++) {
            dialWidth = paint.measureText(String.valueOf(_i == 0 ? 12 : _i));  //文字の横幅
            canvas.drawText(String.valueOf(_i == 0 ? 12 : _i),
                    (float) ((Math.sin(Math.toRadians(_i * 30)) * fontPos)
                            + CENTER_POS[0]) - (dialWidth / 2),
                    (float) ((-Math.cos(Math.toRadians(_i * 30)) * fontPos)
                            + CENTER_POS[1]) - (dialHeight / 2),
                    paint);
        }

        // 針の長さを設定
        float HOUR_HAND_LENGTH = (float) CANVAS_SIZE_MIN / 2f * 0.5f;  // 短針
        float MINUTE_HAND_LENGTH = (float) CANVAS_SIZE_MIN / 2f * 0.6f;  // 長針
        float SECOND_HAND_LENGTH = (float) CANVAS_SIZE_MIN / 2f * 0.7f;  // 秒針
        float END_HAND_LENGTH = (float) CANVAS_SIZE_MIN / 2f * 0.1f;  //針の尻尾部分

        //針の太さを設定
        float HOUR_HAND_WIDTH = (float) CANVAS_SIZE_MIN / 30f;
        float MINUTE_HAND_WIDTH = (float) CANVAS_SIZE_MIN / 40f;
        float SECOND_HAND_WIDTH = (float) CANVAS_SIZE_MIN / 50f;

        Date now = new Date(System.currentTimeMillis());  //現在時刻の取得

        // 時を取得
        DateFormat formatter = new SimpleDateFormat("HH");  // 形式を時間に設定
        formatter.setTimeZone(TimeZone.getTimeZone(timeZoneId));  // 選択したタイムゾーンを適用
        float hour = Float.parseFloat(formatter.format(now));  // 現在時刻に設定

        // 分を取得
        formatter = new SimpleDateFormat("mm");  // 形式を分に設定
        formatter.setTimeZone(TimeZone.getTimeZone(timeZoneId));  // 設定したタイムゾーンを適用
        float minute = Float.parseFloat(formatter.format(now));  // 現在時刻に設定

        // 秒を取得
        formatter = new SimpleDateFormat("ss");  // 形式を秒に設定
        formatter.setTimeZone(TimeZone.getTimeZone(timeZoneId));  // 設定したタイムゾーンを適用
        float second = Float.parseFloat(formatter.format(now));  // 現在時刻に設定

        // アナログ時計用に短針と長針を修正
        // アナログ時計では短針・長針がスムーズに動くため、その修正を加える
        // 60秒を100%として、1%=0.6秒、秒 / 0.6で現在の秒針が何%かが分かる
        // 1分を100%とし、1%=0.01分、秒針の% * 0.01で+何分したら良いのかが分かる
        // 時間も同様に1時間を100%とし、1%=0.01時間、長針の% * 0.01で+何時間したら良いのかが分かる
        hour += (minute / 0.6f) * 0.01f;
        minute += (second / 0.6f) * 0.01f;

        // 針の位置を計算
        // 短針の角度 = 時間 * 30, 長針の角度 = 分 * 6, 秒針の角度 = 秒 * 6
        // θ = 角度 * π / 180
        // x = Sinθ * 針の長さ, y = -Cosθ * 針の長さ で原点からの座標が分かる
        float[] hourPos = {(float) Math.sin(Math.toRadians(hour * 30)),
                (float) -Math.cos(Math.toRadians(hour * 30))};
        float[] minutePos = {(float) Math.sin(Math.toRadians(minute * 6)),
                (float) -Math.cos(Math.toRadians(minute * 6))};
        float[] secondPos = {(float) Math.sin(Math.toRadians(second * 6)),
                (float) -Math.cos(Math.toRadians(second * 6))};

        // 短針の描画
        paint.setStrokeWidth(HOUR_HAND_WIDTH);
        canvas.drawLine(CENTER_POS[0], CENTER_POS[1],
                hourPos[0] * HOUR_HAND_LENGTH + CENTER_POS[0],
                hourPos[1] * HOUR_HAND_LENGTH + CENTER_POS[1], paint);
        canvas.drawLine(CENTER_POS[0], CENTER_POS[1],
                -hourPos[0] * END_HAND_LENGTH + CENTER_POS[0],
                -hourPos[1] * END_HAND_LENGTH + CENTER_POS[1], paint);

        // 長針の描画
        paint.setStrokeWidth(MINUTE_HAND_WIDTH);
        canvas.drawLine(CENTER_POS[0], CENTER_POS[1],
                minutePos[0] * MINUTE_HAND_LENGTH + CENTER_POS[0],
                minutePos[1] * MINUTE_HAND_LENGTH + CENTER_POS[1], paint);
        canvas.drawLine(CENTER_POS[0], CENTER_POS[1],
                -minutePos[0] * END_HAND_LENGTH + CENTER_POS[0],
                -minutePos[1] * END_HAND_LENGTH + CENTER_POS[1], paint);

        // 秒針の描画
        paint.setStrokeWidth(SECOND_HAND_WIDTH);
        canvas.drawLine(CENTER_POS[0], CENTER_POS[1],
                secondPos[0] * SECOND_HAND_LENGTH + CENTER_POS[0],
                secondPos[1] * SECOND_HAND_LENGTH + CENTER_POS[1], paint);
        canvas.drawLine(CENTER_POS[0], CENTER_POS[1],
                -secondPos[0] * END_HAND_LENGTH + CENTER_POS[0],
                -secondPos[1] * END_HAND_LENGTH + CENTER_POS[1], paint);

        holder.unlockCanvasAndPost(canvas);
}

// 時計更新用のサブクラス
class ClockUpdate extends Thread {
    public void run() {
        try {
            draw();
            Thread.sleep(100);  // 100/1000秒ごとに更新
        } catch (Exception e) {
            break;
        }
    }
}

// 時計更新用のサブクラスをスレッド化
private ClockUpdate clockUpdate = new ClockUpdate();

2017年1月26日木曜日

Windows 10上のFirefoxのタイトルバーに色が反映されない

デフォルトではタイトルバーがグレーになっている




これだと統一性がないのでシステム色に合わせる


[Tip] Get Colored Titlebar Back in Mozilla Firefox in Windows 10 - AskVG

about.support → プロファイルフォルダ: フォルダを開く → chrome\userChrome.css を作成


#main-window[windowtype="navigator:browser"] {
    background-color: transparent !important;
}
.titlebar-button {
    background-color: transparent !important;
    transition: background-color 0.2s ease;
}
.titlebar-button > .toolbarbutton-icon {
    list-style-image: none;
}
.titlebar-button:hover {
    background-color: rgba(0, 0, 0, 0.15) !important;
}
#titlebar-close:hover {
    background-color: #E81123 !important;
}
#titlebar-close:hover > .toolbarbutton-icon {
    list-style-image: url("chrome://browser/skin/caption-buttons.svg#close-white") !important;
}

Firefoxを再起動すると適用される

2017年1月12日木曜日

LZ77による数列の符号化

メモ書き

3134313134を2進数に


3134313134
1567156567 0
783578283  1
391789141  1
195894570  1
97947285   0
48973642   1
24486821   0
12243410   1
6121705    0
3060852    1
1530426    0
765213     0
382606     1
191303     0
95651      1
47825      1
23912      1
11956      0
5978       0
2989       0
1494       1
747        0
373        1
186        1
93         0
46         1
23         0
11         1
5          1
2          1
1          0

(3134313134)_10 = (10111010110100011101001010101110)_2


LZ77符号化


スライド窓 k=16, 符号化部 m=8, 参照部 k-m=8


i                            10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32                     
0 0 0 0 0 0 0 0 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 1 1 1 0 1 0 0 1 0 1 0 1 0 1 1 1 0
i=1(0,0,1)
i=2(0,1,1)
i=4(5,1,1)
i=6(2,4,1)
i=11(3,3,0)
i=15(1,3,1)
i=19(0,4,1)
i=24(3,3,1)
i=28(2,2,1)
i=31(0,2,#)

1行目は番号

2行目は先頭に0を参照部分並べ、その後に符号化したい数列を並べていく

3行目から計算スタート。左端に参照部の長さ分枠をつける。その右に符号化部の長さ分枠をつける。
符号化部の左端から参照を開始する。まずこの行の符号化部の右端の値は"1"。"1"を参照部の左端から見ていく。この場合は存在しないため、"i=1(0,0,1)"とする。
この文字列の意味は、"i=1"が、符号化部の右端のiの値。
(0,0,1)については後述する。

4行目、スライド窓を右に1個ずらす。符号化部の左端から1つ目の値は"0"。"0"を参照部の右端から見ていく。この場合一番右端から1つ目に"0"が存在する。
見つかった場合は桁数を増やしてみる。符号化部の値を右に1桁増やすと"01"。参照部に"01"はないため、これは放棄する。
i=2とし、(0,1,1)とする。
(0,1,1)について、1つ目は参照部で見つかった値の前に空きがあればその個数を入れる。今回は先頭に見つかったため0。2つ目の数字は見つかった桁数。1桁見つかったため1。最後は符号化部から参照した数字の右の数字。今回は"0"が見つかったため、その右の"1"を入れる。

5行目、スライド窓を"見つかった桁数 + 1"ずらし、同じようにすすめる。

最後まで参照したら最後は#にする。