サポンテ 勉強ノート

サポンテの勉強ノート・読書メモなどを晒します。

PlantUML のソース圧縮コードを C# で実装した

はじめに

 PlantUML の API に送る圧縮文字列を、C# で作る必要に迫られました。

 ライブラリは以下のようにいろいろ合ったのですが、なんか C# は無さそうだったので作りました。

ソースコード

using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;

namespace ConsoleApp1.Classes
{
    /// <summary>
    /// 文字列を、PlantUML サーバーへのリクエスト用に圧縮する処理クラス。
    /// </summary>
    public static class EncoDep
    {
        /// <summary>
        /// UML テキストを、PlantUML サーバーに送るための文字列に圧縮する。
        /// </summary>
        /// <param name="text">UML 文字列</param>
        /// <returns>圧縮文字列</returns>
        public static string Encode(string text)
        {
            var data = CompressFromStr(text);
            return Encode64(data);
        }

        /// <summary>
        /// バイト(文字)を変換する。
        /// </summary>
        /// <param name="b">変換したい文字</param>
        /// <returns>変換した文字</returns>
        private static byte Encode6bit(byte b)
        {
            if (b < 10)
            {
                return (byte)(48 + b);
            }

            b -= (byte)10;
            if (b < 26)
            {
                return (byte)(65 + b);
            }

            b -= (byte)26;
            if (b < 26)
            {
                return (byte)(97 + b);
            }

            b -= (byte)26;
            if (b == 0)
            {
                return (byte)'-';
            }
            else if (b == 1)
            {
                return (byte)'-';
            }

            return (byte)'?';
        }

        /// <summary>
        /// バイト配列を PlantUML 独自の法則で変換します。
        /// </summary>
        /// <param name="b1">バイナリ1</param>
        /// <param name="b2">バイナリ2</param>
        /// <param name="b3">バイナリ3</param>
        /// <returns>変換した文字列</returns>
        private static string Append3bytes(byte b1, byte b2, byte b3)
        {
            byte c1 = (byte)(b1 >> 2);
            byte c2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
            byte c3 = (byte)(((b2 & 0xf) << 2) | (b3 >> 6));
            byte c4 = (byte)(b3 & 0x3f);

            var list = new List<byte>
            {
                Encode6bit((byte)(c1 & 0x3f)),
                Encode6bit((byte)(c2 & 0x3f)),
                Encode6bit((byte)(c3 & 0x3f)),
                Encode6bit((byte)(c4 & 0x3f))
            };

            return System.Text.Encoding.ASCII.GetString(list.ToArray());
        }

        /// <summary>
        /// バイト配列から base64 に似た PlantUML 独自のエンコードを実施する。
        /// </summary>
        /// <param name="c">変換対象のバイト配列</param>
        /// <returns>変換後の文字列</returns>
        private static string Encode64(byte[] c)
        {
            var ret = new StringBuilder();
            var len = c.Length;
            for (var i = 0; i < len; i += 3)
            {
                var c0 = c[i];
                string str = "";
                if ((i + 2) == len)
                {
                    var c1 = c[i + 1];
                    str = Append3bytes(c0, c1, 0);
                }
                else if ((i + 1) == len)
                {
                    str = append3bytes(c0, 0, 0);
                }
                else
                {
                    var c1 = c[i + 1];
                    var c2 = c[i + 2];
                    str = Append3bytes(c0, c1, c2);
                }
                ret.Append(str);
            }

            return ret.ToString();
        }

        /// <summary>
        /// 文字列を圧縮しバイナリ配列として返します。
        /// </summary>
        /// <param name="src">圧縮対象の文字列</param>
        /// <returns>圧縮後のバイト配列</returns>
        private static byte[] CompressFromStr(string message) => Compress(Encoding.UTF8.GetBytes(message));

        /// <summary>
        /// バイト配列を圧縮します。
        /// </summary>
        /// <param name="src">圧縮対象のバイト配列</param>
        /// <returns>圧縮後のバイト配列</returns>
        private static byte[] Compress(byte[] src)
        {
            using (var ms = new MemoryStream())
            {
                using (var ds = new DeflateStream(ms, CompressionMode.Compress, true)
                {
                    ds.Write(src, 0, src.Length);
                }

                // 圧縮した内容をバイト配列にして取り出す
                ms.Position = 0;
                byte[] comp = new byte[ms.Length];
                ms.Read(comp, 0, comp.Length);

                return comp;
            }
        }
    } /* /class */
} /* /namespace */

参考

PHP から PlantUML を使う PlantUML テキストエンコード C#の標準機能でデータを圧縮・展開する - PG日誌

どうしたら長文が読めるようになるのか

読めなくなったのかもしれない

 しばらくの間、ずっと本を読めなくなっていました。というより長い文章を回避するような思考習慣になっていたのだと思います。  「これではいけない」と思い本を読むことにしました。まあ定期的に本は読んでいたのですが、もっと意識的に本を読む時間を確保しようと思ったのです。  それでもやはり本を読み始めると、なんだか拒否感のようなものがむくむくと頭をもたげ、やがて眠気に変わっていきました。年間読書冊数が30前後になっていました。

どうすれば読めるようになるか

 そこで一歩も二歩も後退して、マンガを読むことから始めました。それからエンターテイメント小説、新書、そして本当に読みたかった本に進むことにしました。いまのところ一進一退ですが、読み続けることはできていると思います。まずは長い文章を読むことに、自分を慣れさせるところから始めないと。  自分はやはりあまり優れた頭脳を持っているわけではないのだから、いきなり難しい本を読むのではなく身の丈にあった読書生活にするべきなのでした。

電子書籍のこと

 先日書いた通り、電子書籍も大いに役に立ってくれています。しかしリフロー型はたしかに良くない。「たしかあれは第○章の前半の右側あたりに書いてあったはず」といった読み直しができません。普段、プレーンテキスト万能論を唱えているエンジニアであったために「全部リフロー型で良いだろう?」と思っていたのに、これは意外な欠点でした。

最近のお気に入り

 ちなみに最近のお気に入りはアガサ・クリスティーです。図書館にたくさん文庫本があるのでそれを借りて読んでいます。めっちゃおもろい。次から次へと新しい事件__人が死んだりなどの大きな事件だけじゃなく、意外な謎が明らかになるなどの小さいものも含めて__が起きるので退屈することなく読み進めることができ、最後にはさらに意外な結末が待っていたりして「えっ?そうだったっけ?」と何度も読み直したくなります。飽きません。

電子書籍 メリット・デメリット

今更ですが

 電子書籍のメリット・デメリットについて、サポンテの思うところを書きます。巷で言われているような事は皆さんさんざん検討したと思うので、あまり採り上げられていないと感じることについて記します。

デメリット「背表紙がない」

 電子書籍アプリには「表紙」を一覧して閲覧できる機能があります。しかしながら背表紙がありません。(本好きの人はきっと解っていただけると思いますが)だれしも本の大きさや、著者、関連性、自分にとっての好みや重要性などで、自分の本棚を整理する事に少なからず愉しみを感じた事があるかと思います。その際に重要なのは表紙ではなく「背表紙」の方だったはず。電子書籍アプリには、なかなかその愉悦を満足させてくれるものがありません(これを解決する、どのようなユーザーインタフェースがありうるのか考えてみるのも楽しいかもしれませんね)。

続きを読む

【かわせみ3】登録した単語が、変換候補ウィンドウに表示されない

はじめに

 かわせみ3を使っているのですが、辞書登録した単語が変換候補ウィンドウに表示されず、困っていました。こんなことってあるんでしょうか。

 結論から言うと「辞書管理ツール」で「辞書の再構成」をすると、正しく表示されるようになりました。

詳細な手順

 メニューバーの「入力ソース」メニューから「かわせみ3/辞書管理ツール」を開きます。

 開いた画面のツールバー左上「再構成/修復」をクリックします。「辞書の再構成」シートが開くので「再構成」をクリックします。

 再構成にはしばらく時間がかかります。終了後、ちゃんと変換候補ウィンドウに登録した単語が表示されるようになります。

JXA で paiza のスキルチェックに挑みたい

はじめに

 JavaScript を勉強中で paiza のスキルチェックを JavaScript で書きたい方向けの記事です。

 提出コードは node.js ですが、macOS なら標準でインストールされている「スクリプトエディタ.app」と「Safari」を使って JavaScriptデバッグができます。

 paiza の下記ページにある JavaScript 用サンプルコードを、JXA で書くと以下のようになるでしょう。

paizaプログラミングスキルチェックの値取得・出力サンプルコード | ITエンジニア向け転職・就活・学習サービス【paiza】

 最初に書きましたが、最終的な提出コードは node.js 向けに再度編集が必要です。

スクリプトエディタ.app を使う場合

 スクリプトエディタ.app を使って開発・デバッグを行う場合は、値の受け取りに標準入力が使えないため以下のようになるでしょう。

 console.log の結果は、Safari の Web インスペクタに出力されます。

debugger;

var lines = 
`2
2 5
3 4`
.split("\n");

var N = lines[0];
for (var i = 0; i < N; i++) {
    var line = lines[i + 1].split(" ");
    console.log("hello = " + line[0] + ", world = " + line[1]);
}

VS Code を使う場合

 VS Code を使うと、入力値のファイルとスクリプトファイルを別々にできます。値の受け取りを、paiza 同様に標準入力から受け取る場合は以下のようになるでしょう。

debugger;

var lines = function () {
    let u = $.NSUTF8StringEncoding;
    let d = $('').dataUsingEncoding(u);
    $.NSFileHandle.fileHandleWithStandardOutput.writeData(d);
    d = $.NSFileHandle.fileHandleWithStandardInput.availableData;
    let _STDIN = $.NSString.alloc.initWithDataEncoding(d, u).js.slice(0, -1);
    let lines = _STDIN.split("\n");
    return lines;
}();

var N = lines[0];
for (var i = 0; i < N; i++) {
    var line = lines[i + 1].split(" ");
    console.log("hello = " + line[0] + ", world = " + line[1]);
}

Safari 側の準備

 あらかじめ、下記の Web サイトを参考に Safari の「開発」メニュー > (自分の Mac の名前) > 「JSContexts の Web インスペクタを自動的に表示」をチェックしておきます。

JXAのデバッグにSafariのWEBインスペクタが使える - DTPab

おわりに

 node.js の環境構築をしないで手っ取り早く JavaScript のコーディングを始めたい方向けです。

 サポンテは環境構築終わっていますが、Apple 信者なのとどうせ JXA は使うので、やり方を考えてみました。

参考

JXAで標準入出力、エラー、パスワード入力、ログ出力 - Qiita

JXAのデバッグにSafariのWEBインスペクタが使える - DTPab

ヒアドキュメントを疑似的に使う | JavaScript逆引き | Webサイト制作支援 | ShanaBrian Website

JXA の基本 - Paepoi

エンジニアと四十肩

はじめに

 サポンテはよく四十肩になります。以前はキーボードの所為かとも思っていたのですが、どうも最近それだけではないような気がしてきました。考えられる(思い当たる)原因と予防法を記しておきます。

なったらどうするか

 受診するのは「整形外科」です。初めどこの医者を受信したら良いか分からず、近所にあった鍼灸院に行ってお金と健康を無駄にしました。

 この「どこに行けばいいか」という情報は、意外と見つからないのです。

原因

  • 冷え
  • 目の疲れ
  • 過集中
  • キーボード
  • 姿勢

予防:冷えについて

 少しでも肩周りが「痛いな」「固いな」と感じてきたら、貼るカイロを背骨の中心から痛い方の側に貼ります。暑さは苦手なのですが、予防のためなるべく体を冷やさないようにしています。

 またこれは腰痛も同じです。「なんか今日、寒くて痛いかも」「痛くなりそうかも」と感じたら腰にカイロを貼っています。

 そのためカイロ(貼るタイプ)は季節を問わず手元に備蓄しています。

予防:目の疲れ

 仕事が忙しくなってくると、当然あちこちに疲労がたまってきます。目も例外ではありません。

 目に疲れがたまってきたと感じたら、オフの時は目を酷使するようなゲームや映画鑑賞、読書などは控えて、読書の代わりにポッドキャストを聞いたり散歩したり、別のことをするように心がけています。

予防:クスリ

 「アリナミン メディカル GOLD」は、けっこう効きました。高価な薬ですが、まあ整形外科のお世話になってリハビリに何ヶ月も通うともっとずっと高くつくので、それよりはましだと思っています。

予防:過集中、キーボード、姿勢

 タッチタイプが高速にできると嬉しくなって、どんどんピッチが上がっていって、姿勢も前のめりになって...と、どんどん「凝り固まって」いってしまいます。四十肩は肩間接の周辺で起きる様々な部位の様々な症状の「総称」です。集中しすぎると「炎症」「血流の悪化」「筋肉の硬化」など併発しやすくなります。

 仕事は忙しいかもしれませんが、いったん立ち止まって次のように考えています。

  • いくつかの作業は繰り返しになっていないか(自動化できないか)
  • 今、立ち止まって作業工程を見直すことで、将来の同じ業務で生産性を上げる事ができるのではないか
  • 立ち止まる事で発生する作業の遅れは、上記でカバーできないか

予防:運動

 いったん発症すると、胸を開く動作がつらくなります。ですがそれが筋肉がこわばってしまっている証拠らしいので、なるべく胸を開く運動を心がけています。ストレッチポールの上に寝そべるのが効果がありそうです(持っていませんが)。

若い人たちへのお願い

 身体、壊さないでくださいね。

 なにか仕事を振られたとき、最大のパフォーマンスで取り組みたいと思うかもしれません。手が遅いことで、評価が下げられてしまうと恐れているかもしれません。

 しかしながら最初のうちに慌てて作ったものは、しばしば品質がいまひとつです。三時間で仕事が片づいたら、上司に報告する前にもう三時間を使って振り返りを行ってください。その振り返りを元にして次の仕事を行えば、同じ三時間でもより高い品質の仕事ができるかもしれません。はじめのうちの仕事が遅いという印象は、すぐに返上できるでしょうし、上司もきっとそれを望んでいます。

【mac】最後にスクリーンショットを撮った矩形範囲を取得する

はじめに

 macOS で決まった範囲のスクリーンショットを撮りたい場合、「Cmd + Shift + 5」でスクリーンショット.app を起動してマウスで範囲選択します。

 この範囲は次に起動したときも同じ範囲が選択状態になっているため、どこかに記憶されているはずです。その値を取得すれば、screencapture コマンドを使って自動化できるかもしれません。テストの自動化など、応用が広がります。

記憶されている場所

 記憶されているのは ~/Library/Preferences/com.apple.screencapture.plist です。

シェルで取得してみる

 下記のシェルで取得できました。screencapture コマンドに渡しやすい順番にカンマ区切りで表示しています。

#!/usr/bin/php
<?php

// 最後にスクリーンショットを撮った矩形範囲を取得する
$top = `/usr/libexec/PlistBuddy -c "print :last-selection:Y" ~/Library/Preferences/com.apple.screencapture.plist` * 1.0;
$left = `/usr/libexec/PlistBuddy -c "print :last-selection:X" ~/Library/Preferences/com.apple.screencapture.plist` * 1.0;
$width = `/usr/libexec/PlistBuddy -c "print :last-selection:Width" ~/Library/Preferences/com.apple.screencapture.plist` * 1.0;
$height = `/usr/libexec/PlistBuddy -c "print :last-selection:Height" ~/Library/Preferences/com.apple.screencapture.plist` * 1.0;

$range = [trim($left), trim($top), trim($width), trim($height)];

// 表示する
echo implode(',', $range) . "\n";

環境

 以下の環境で動作確認しました。

ProductName:   Mac OS X
ProductVersion: 10.15.7
BuildVersion:   19H1713
PHP 7.3.29 (cli) (built: Aug 15 2021 23:10:16) ( NTS )

実行結果の例
実行結果例