TESMEN TM-510

古いテスターがめっからないのでデジタルのやっすいやつをポチ。

https://tesmen.com/products/digital-multimeter-4000-counts-ncv-test-ac-dc-voltage-resistance-continuity

ちゃちいカバーが着いた全オートで家の中で使う分には導通/直流電圧/交流電圧が測れれば良いので十分なもの。

単4電池ってのもまぁポイント高く。(006Pのやつが多いんだよねぇ)

ケースも着いて目立たずコンパクトで、しばらく持ってくれればいいな。

(今更)double braceでのCollection初期化

以前より取り沙汰されてはいる、Java-Collectionのdouble-braceによる初期化について。

Map<String, String> mp = new HashMap<String, String>() {{
    put("abc", "ABC");
    put("def", "DEF");
   put("ghi", "GHI");
}};

のようにインスタンス生成と初期化を行うコードはJava8以前にはちょいちょい見られ。
今もまぁちょいちょい使うのだけれど。
このdouble-braceによる初期化当初よりメモリリークが指摘され、注意が必要とされている。
匿名内部クラス(annonymous inner class)が生成され”強い外部参照”が作成されるためガーベージコレクションされることなく残り続けるというもので、繰り返し処理されるロジックでは避けるべきとされている。
(https://blog.p-y.wtf/avoid-java-double-brace-initialization で詳しく解説されている)

でもって、じゃぁ、というのはJava9以降なら簡単で、

Map<String, String> mp = Map.of("abc", "ABC", "def", "DEF", "ghi", "GHI"};

とするだけ。もちろんMap.ofの場合はImmutable Collection(不変コレクション)を返すので、putなどの編集・追加・削除操作はできないが、ごそっと初期化したい時ってぇのはImmutableで構わないケースがほとんどなので問題はないだろう。

ただ”ガーベージコレクションされない”が致命的でない場合は、double-braceも便利な書き方ではあるので、例えば単発Java Applicationのループ外での初期設定とかでは十分有効だといえる。

つーか、コレクションの初期化は面倒なのはわかるのだけれど他の言語では割と簡単にできるものであるし、ささっと初期化できないってのはなんだかなーとは思うわけだがまぁそういうものだししょうがない。

Teamsのフォント

必要があってUbuntuに青柳衡山毛筆フォントをインストール。
ところがteams-for-linuxの日本語が全部毛筆になってしもうた。

いろいろ調べるがteamsのフォントは変更ができない模様。なんじゃこりゃ。

fontconfigの登録順序とかデバッガで調べてとかやればなんとかなりそうな気もするが、
諸々面倒なので、さっくり再インストール。

$>sudo snap remove teams-for-linux

ややしばらくで完了。

$>sudo snap install teams-for-linux

なんか以前のフォント(noto-serif-cjk)とは違う気がするが、まぁ毛筆フォントからは開放されたので良し。

Javaの非同期処理

Javaの非同期も随分簡単になって、Thread管理クラスを作ってThreadを起こして終了を拾って〜などとやっていた頃が夢のように。

基本的にはコレクションのstreamをparallelで処理、という具合だが業務系では大抵の処理は
・多重度の設定
・全終了の待機
が必要になる。

で、そんな場合のために、ForkJoinPoolクラスが存在していて、だいたい次のように。

private void foo() throws Exception
{
        Map<String, String> mp = new HashMap<String, String>(){
            {{ put("a", "A"); }}
            {{ put("b", "B"); }}
            {{ put("c", "C"); }}
            {{ put("d", "D"); }}
            {{ put("e", "E"); }}
        };

        var pool = new ForkJoinPool(20);    //多重度をセット
        pool.submit(()->mp.entrySet().parallelStream().forEach((x)->{
            System.out.println(x.getKey() + " : " + x.getValue());
        })).get();    //全終了を待機

        System.out.println("parallel-end");
}

非同期処理が込み入ったものであれば、ラムダ内から処理用の関数を呼ぶようにすれば良く、更に同期処理が必要なのであれば呼ばれる関数にsynchronized修飾子をつけておけば良い。

ま、常駐型のスレッドが必要な場合はやっぱりそれなりに管理用クラスを用意して上げたほうがいぢり易くはあるんだが。

ssl_client.php

httpsで某サイトの情報を取得する必要があり、phpで単純なssl_clientを作成。

Githubのどこかを参考にしたのだが忘れてしまった。(誰か気がついたら教えて)

で、PHPがOpenSSLサポートが有効なようにコンパイルされていることが前提で、fsockopenでstreamを開き、stream_get_meta_dataで読み込む。

<?php
/**
 * ssl_client.php
 */

class ssl_client
{
    protected $options = [];
    public function __construct()
    {
        ini_set("allow_url_fopen", 1);
        $this->options = [
            'http' => [
                'method' => 'GET',
                'timeout' => 10, //タイムアウト秒
                'ignore_errors' => true, //ステータスコードが4xxや5xxなど失敗の場合でもコンテンツを取得
            ],
        ];
    }
    public function wget($url, $param = array())
    {
        $timeout = 30;
        $method = count($param) ? 'POST' : 'GET'; // $param要素あればPOST
        if (!$purl = parse_url($url)) {
            return array('', '');
        }
        //print_r($purl);
        // URL分解
        if (empty($purl['port'])) {
            $purl['port'] = 80;
        }

        $ssl = '';
        if ($purl['scheme'] == 'https') {
            $ssl = 'ssl://';
            if ($purl['port'] == 80) {
                $purl['port'] = 443;
            }
        }
        // HTTPリクエスト
        $fp = fsockopen($ssl . $purl['host'], $purl['port'], $errno, $errstr, $timeout);
        if (!$fp) {
            die("$errstr ($errno)<br />\n");
        }
        if (!empty($purl['query'])) {
            $purl['path'] .= "?{$purl['query']}";
        }

        if (substr($purl['path'], 0, 1) !== '/') {
            $purl['path'] = '/' . $purl['path'];
        }

        $data = $method === 'POST' ? http_build_query($param, '', '&') : '';
        $cl = empty($data) ? '' : "Content-Length: " . strlen($data) . "\r\n";
        $out = "$method {$purl['path']} HTTP/1.1\r\n"
            . "Host: {$purl['host']}\r\n"
            . "User-Agent: PHP-Script/1.0\r\n"
            . "Content-Type: application/x-www-form-urlencoded\r\n"
            . $cl
            . "Connection: Close\r\n\r\n"
            . $data;
        fwrite($fp, $out);

        // HTTPレスポンス取得
        stream_set_timeout($fp, $timeout);
        $header = $html = '';
        $html_arr = [];
        while (!feof($fp)) {
            $info = stream_get_meta_data($fp);
            if ($info['timed_out']) {
                die("timeout!");
            }

            if (empty($html)
                && substr($header, -4) !== "\x0d\x0a\x0d\x0a"
                && $header .= fgets($fp)) {
                continue;
            }
            $line = fgets($fp);
            if (preg_match("/^0000[0-9A-F]{4}[\r\n]*$/", $line)) {
                continue;
            }
            $html .= $line;
            $html_arr[] = $line;
        }
        fclose($fp);

        return array($header, $html, $html_arr);
    }
}

ちょいちょい 0000ABCDのような行が紛れ込むのでそいつを削除してる、ってのと、HTML全文とは別に行ごとの配列も返してるあたりがいぢってあるところ。

別にたいしたことをしているわけでもなく、元があったのをいぢっただけなのだが、時々忘れてまた探すのが面倒なので書いておく。

 

Ubuntu22.04LTSでUSB-FAXモデムを使う(1)

ポチったUSB-FAXモデムはこれ、StarTech USB56KEMH2

スペック的には
https://www.startech.com/ja-jp/networking-io/usb56kemh2

というところで、USB2.0接続の普通の56KV92のFAXモデム。

これをUbuntu22.04のノートPCにサクっと挿して、lsusbで見てみる。(まだFAX関連は何も入れていない状態)

おぉ、なんかそれっぽく出てくる。
で、ドライバを・・とStarTechのサイト見てもWindows用ドライバのみ。まぁそうだよね。

んでもFAXアプリケーション入れたらそのまま認識したりしないだろうか、ってことで何を使おうかと。まぁeFaxなのかな。

$>sudo apt install efax-gtk

さて、efax-gtkを起動してもInvalidになってるので、modprobeでもせなあかんのかな。