NYAGOS 4.4.4_1~3 を公開していました。

nyagos 4.4.4_0 を公開しました(その2)の続き、連続で参ります。

4.4.4_1

  • Linux 版バイナリがビルドできなかった問題を修正

Linux のバイナリつけるの忘れてただけでなく、ビルドも出来ない状態でした。でも、まったく苦情は来ませんでした(そりゃな)

4.4.4_2

  • バックグラウンドでキャッシュを更新することで \\host-name の補完を高速化

~\AppData\Local\nyaos.org\computers.txt にキャッシュが保存されているわけなんですが、一応過去のがあるならば、とりあえずそっちを参照させてから、更新自体は裏の goroutine で進めても別にわけですよね。

一応、前回更新から2時間以上差が空いていると裏で更新させるようにしました。computers.txt が無い時はどうしようもなくて、キャッシュ更新が終わるまで待っていただきますが、さすがにそれは容赦してくださいね(1回だけだから!1回だけだから!)

4.4.4_3

  • (#371) ファイル名に.を含む実行ファイルを参照できなかった

ええと、この文では分からん。「foo.bar.exe」というファイルを実行する時に「foo.bar」で実行できないという不具合でした。実行ファイルの検索は、スクリプトの実行を拡張する都合、自前で用意する必要があったのですが、それが CMD.EXE と互換になってませんでした。

  • diskfree でネットワークドライブに割り当てられた UNC パスを表示

接続先のサーバーがリブートするとネットワークドライブが切断されてしまう件の調査のついでに実装しました。横に長くなってすみません。

以上

nyagos 4.4.4_0 を公開しました(その2)

NYAGOS 4.4.4_0 を公開しました(その1) を書いたのに、「(その2)」を書く前に、4.4.4_14.4.4_3 をリリースしてしまったー。とはいえ、一応、書いておかないと気持ち悪いので、書ける体力があるタイミングで残りを駆け足で書いておきますね。

  • Linux用の .source を実装(/bin/sh を想定)

Windows版のバッチファイルでの変更を取り込む機能の sh 版みたいなものです。実装してくれという要望はありませんが、WindowsLinux での機能の差異は最小限にしたかったので。

  • 一行入力で、ユーザが待っている時にカーソルの点滅がオフになっていなかった不具合を修正

これが ON になっていると、\host-name 補完で待たされている時のアニメーションの横のカーソル点滅が見苦しいんですよね。

  • mklink /J マウントポイント 相対パス で作るジャンクションが壊れていた(絶対パス化が抜けていた)

相対パスでジャンクションを作ると、実際、利用できないんですよね。"path/filepath".Abs絶対パス化するようにしました。

  • 起動オプション --chdir "DIR"--netuse "X:=\\host-name\share-name" を追加

これは su コマンドで、管理者権限に昇格する際に CMD.EXE の機能を利用せずに、ネットワークドライブやカレントディレクトリを復元するために作りました。 (何もしないと、セキュリティーのために引き継がれないのです)

  • suを実行する際にCMD.EXEを使わないようにした(アイコンをNYAGOSのにするため)

--chdir "DIR"--netuse "X:=\\host-name\share-name" で実現可能になりました。

  • 100個を越える補完候補がある時、確認するようにした

VMware の中とかで、OS負荷が高くなっている時、コンソール出力すごく時間がかかるんですよね。ということで、bash とかの動作を真似ました。しきい値を 100 にしたのは、だいたいその辺に bash でもしきい値がありそうな雰囲気だったからです。

  • ps: nyagos.exe 自身の行に [self] と表示するようにした

自分を間違って kill しないようにね(たまにするらしい)

  • (#272) !(ヒストリ番号)@ をそのコマンドが実行された時のディレクトリに置換するようにした

塩漬けしていた issue 消化です。でも、あんまり使いませんねぇ。cd -hcd -1cd -9 の方の cd 専用のヒストリを使ってしまうんですよ。

  • (#130) ヒアドキュメントをサポート

こちらも塩漬けしていた issue 消化です。

  • Alt-O でショートカットのパス(例:SHORTCUT.lnk) をリンク先のファイル名に置換するようにした

ショートカットファイルを解釈しないコマンドにファイル名を渡すのに便利なんですが、実装から1ヶ月以上たつと存在忘れますねぇ(おい)

  • (#368) Lua関数 io.close() が未定義だった。

実は file:close() しか知りませんでした。io.close(file)file:close() と等価だったんですね…

  • (#332)(#369) io.open() のモード r+/w+/a+ を実装した。

GopherLua のソースを見ながらパクりま実装しました!

GopherLua にも io ライブラリは当然あるんですが、Luaグローバル変数の io.stdout / io.stdin / io.stderr に任意の *os.File に差し替える API は提供されていません。それができないと、nyagos 側で標準入出力をリダイレクトをしても、Lua のコードはガン無視になってしまいます。そうならないようにするため、自前の io ライブラリを作成しています。ですが、完全とはいかず、本件もその一つでした。

とりあえず、4.4.4_0 については以上です。

Git のセットアップ for Windows & nyagos

Git は普通に Gir for Windows をダウンロードしてインストールする(ここは別に小細工はない)

.vimrc の設定

コミット時の文字コードを UTF8 にする

au! FileType gitcommit setl fenc=utf-8

.nyagos の設定

git.exe のあるフォルダーを %PATH% に追加

local function addpath(s)
    if  nyagos.stat(s) and
        not string.find(string.upper(nyagos.env.path),string.upper(s))
    then
        nyagos.env.path = string.gsub(nyagos.env.path..";"..s,";;",";")
    end
end
addpath "C:\\Program Files\\Git\\bin"
addpath "C:\\Program Files\\Git\\cmd"
addpath "C:\\Program Files (x86)\\Git\\bin"
addpath "C:\\Program Files (x86)\\Git\\cmd"

32bit/64bit のフォルダーの両方を確認するようにしてる。フォルダーがなければ追加しない。二重追加もしない。俺えらい

ページャ・エディターを指定

nyagos.env.git_pager="cure.exe"
nyagos.env.git_editor="gvim.exe"

cure.exe は自作のカラーページャ。 メッセージに UTF8 と SJIS が混ざっても、文字化けしないようになっている (行単位で文字コード判定をしている)

git diff を見やすくするためだけに作った」といっても過言ではない

git のサブコマンドの補完

nyagos.complete_for.git = function(args)
    while #args > 2 and args[2]:sub(1,1) == "-" do
        table.remove(args,2)
    end
    if #args == 2 then
        return nyagos.fields([[
          add                 fsck-objects        rebase
          add--interactive    gc                  receive-pack
          am                  get-tar-commit-id   reflog
          annotate            grep                relink
          apply               gui                 remote
          archimport          gui--askpass        remote-ext
          archive             gui--askyesno       remote-fd
          bisect              gui.tcl             remote-ftp
          bisect--helper      hash-object         remote-ftps
          blame               help                remote-http
          branch              http-backend        remote-https
          bundle              http-fetch          repack
          cat-file            http-push           replace
          check-attr          imap-send           request-pull
          check-ignore        index-pack          rerere
          check-mailmap       init                reset
          check-ref-format    init-db             rev-list
          checkout            instaweb            rev-parse
          checkout-index      interpret-trailers  revert
          cherry              log                 rm
          cherry-pick         ls-files            send-email
          citool              ls-remote           send-pack
          clean               ls-tree             sh-i18n--envsubst
          clone               mailinfo            shortlog
          column              mailsplit           show
          commit              merge               show-branch
          commit-tree         merge-base          show-index
          config              merge-file          show-ref
          count-objects       merge-index         stage
          credential          merge-octopus       stash
          credential-manager  merge-one-file      status
          credential-store    merge-ours          stripspace
          credential-wincred  merge-recursive     submodule
          cvsexportcommit     merge-resolve       submodule--helper
          cvsimport           merge-subtree       subtree
          cvsserver           merge-tree          svn
          daemon              mergetool           symbolic-ref
          describe            mktag               tag
          diff                mktree              unpack-file
          diff-files          mv                  unpack-objects
          diff-index          name-rev            update-index
          diff-tree           notes               update-ref
          difftool            p4                  update-server-info
          difftool--helper    pack-objects        upload-archive
          fast-export         pack-redundant      upload-pack
          fast-import         pack-refs           var
          fetch               patch-id            verify-commit
          fetch-pack          prune               verify-pack
          filter-branch       prune-packed        verify-tag
          fmt-merge-msg       pull                web--browse
          for-each-ref        push                whatchanged
          format-patch        quiltimport         worktree
          fsck                read-tree           write-tree]])
    end
    if args[#args]:sub(1,1) == "-" then
        if args[2] == "commit" then
            return { "--amend" , "-a" , "--cleanup","--dry-run" }
        end
    end
    return nil
end

nyagos.d/catalog にあるものと違って、サブコマンドをコード中に直接埋め込んでいるので起動が早い。

git 向けの拡張サブコマンドを用意する

下記のようなテキストファイル:git-new (拡張子無しの sh スクリプト)を %PATH% の通ったフォルダーに入れておく。git new でレポジトリの初期設定をしてくれる。 (Windows 上ではあるが、git は MSYS 上で動くので、バッチファイルだと拡張子がひっかかって逆に動かんのだ)

  • git init の後に、空コミットを一つ入れる(後から rebase しやすい)
  • 改行コードの自動変換機能をオフする .gitattributes を登録 *commit 時のユーザ名・メールアドレスを設定
  • 日本語フォルダー名を化けさせない
#!/bin/sh

if [ ! -e .git ] ; then
    git init 
    git commit -m "empty" --allow-empty
fi
if [ ! -e .gitattributes ] ; then
    echo "* -text" > .gitattributes
    git add .gitattributes 
    git commit -m "Add .gitattributes as autocrlf=false"
fi
git config --local core.quotepath false
git config --local user.email iyahaya@example.com 
git config --local user.name  zetamatta

たぶん、だいたい以上

Go言語のセットアップの覚書 for Windows & nyagos

今更だけど、PCがクラッシュしたら忘れるかもしれないので

アーカイブの展開

MSIインストーラーが意外と遅いので、アーカイブは *.zip ファイルを使う。

% cd /
% ren go go.bak
% unzip ~/go1.12.7.windows-amd64.zip

vim の設定

*.go を開いた時、デフォルトで UTF8、インデントはタブ1文字単位とする

au! BufRead,BufNewFile *.go set ts=4 sw=4 noet ai notextmode fenc=utf-8
if $GOROOT != ''
  set rtp+=$GOROOT/misc/vim
endif

.nyagos の設定

C:\go\bin を %PATH% に追加する

  • 既に追加済みの時は二重に追加しないようにする
  • フォルダーが存在しない場合も追加しない
  • セミコロン; が連続で2つ入ってしまったら、1つにする
  • 前は _nyagos の方に書いていたが、設定ファイルを増やした結果ユーザを混乱させただけなので、もう .nyagos 一本で行こうかなと
local function addpath(s)
    if  nyagos.stat(s) and
        not string.find(string.upper(nyagos.env.path),string.upper(s))
    then
        nyagos.env.path = string.gsub(nyagos.env.path..";"..s,";;",";")
    end
end
addpath "C:\\go\\bin"

go コマンドのサブコマンドを補完できるようにする。最近は、こんなにお手軽になりました。

nyagos.complete_for.go = function(args)
    if #args == 2 then
        return {
            "build", "clean", "doc", "env", "fix", "fmt", "generate",
            "get", "install", "list", "mod", "run", "test", "tool", "version",
            "vet"
        }
    end
    return nil
end

32bit ビルド用の go エイリアスもあった

nyagos.alias.go32=function(args)
    local save=nyagos.env.goarch
    nyagos.env.goarch = "386"
    nyagos.exec{"go",(table.unpack or unpack)(args)}
    nyagos.env.goarch = save
end

GOPATH とか GOROOT とか

両方ともデフォルト( %USERPROFILE%\go , c:\go ) をそのまま使うので、敢えて設定しない方向で

たぶん、以上

std::vector の emplace_back が使えない状況で、軽い push を検討する

Visual Studio 2010 では std::vector の emplace_back がバグっているという話なので、負荷の軽い方法を検討。

でも、検証プログラムのためにわざわざソリューション作るのもめんどいから、gcc で検証してみよう(おい

#include <cstdio>
#include <string>
#include <vector>

class Foo {
public:
    std::string value;

    Foo(const char *s);
    Foo();
    ~Foo();
    Foo(const Foo &);
};

Foo::Foo(const char *s) : value(s)
{
    puts("Foo:Foo(const char*)");
}

Foo::Foo()
{
    puts("Foo::Foo()");
}

Foo::Foo(const Foo &other) : value(other.value)
{
    puts("Foo::Foo(const Foo&)");
}

Foo::~Foo()
{
    puts("Foo::~Foo");
}

int main()
{
    std::vector<Foo> foos;
    foos.reserve(10);

    puts("**** push_back ****");
    foos.push_back(Foo("ahaha"));

    puts("**** resize ****");
    foos.resize( foos.size()+1 );

    Foo &one=foos.back();
    one.value = "ihihi";

    puts("**** loop ****");

    for(std::vector<Foo>::iterator p=foos.begin() ; p != foos.end() ; p++ ){
        puts( p->value.c_str() );
    }
    puts("**** end ****");

    return 0;
}
$ gcc -O2 foo.cpp -lstdc++
$ a
**** push_back ****
Foo:Foo(const char*)
Foo::Foo(const Foo&)
Foo::~Foo
**** resize ****
Foo::Foo()
Foo::Foo(const Foo&)
Foo::Foo(const Foo&)
Foo::~Foo
Foo::~Foo
**** loop ****
ahaha
ihihi
**** end ****
Foo::~Foo
Foo::~Foo

そんな馬鹿な!なぜ、resize してるだけなのに、そんなにコンストラクタが呼ばれるんだ!

だが、ここで auto &one=foos.back(); と書くと、one が整数型になってしまうことを思い出した。C++ の規格のバージョンが古いのかな?

ということで、C++11 を指定してみよう。

$ gcc -std=c++11 -O2 foo.cpp -lstdc++
<HAYAMA-PC:~/tmp>
$ a
**** push_back ****
Foo:Foo(const char*)
Foo::Foo(const Foo&)
Foo::~Foo
**** resize ****
Foo::Foo()
**** loop ****
ahaha
ihihi
**** end ****
Foo::~Foo
Foo::~Foo

よしよし

Visual Studio のコマンドラインクライアントのラッパー vf1s を作った

Visual Studioコマンドラインクライアントのラッパー vf1s を作った。

開発経緯

そもそもは

  1. 会社のルールでバイナリもsvn commitするが、Release版だけでなく、Debug版も用意しなくてはいけない
  2. VBNetには〈バッチビルド〉がなく、一括ビルドできない
  3. 手動で Release選択→ビルド実行→ Debug選択→ビルドすると、Releaseに状態を戻し忘れる
  4. どうせ、提出先ファイルサーバーへのコピーとかはバッチファイル使ってるし、バッチファイルから devenv .com を呼び出して、全部ビルドしたい
  5. devenv .comのディレクトリに場所にパスを通す Visual Studio Command Prompt は起動が重い。そんなに環境変数全部いらんよ
  6. 環境変数が設定されてなくても devenv .com のフルパスさえ分かっていればビルドはできる
  7. devenv .com の場所、VS2015 までと VS2017 以降では探し方が違う。また複数インストールしていると、どちらを呼ぶかの判断もあるので決め打ちは危険
  8. ソリューションファイルが必要としている Visual Studio のバージョンを自動で判断して、適切なバージョンの devenv .com のフルパスを調べて、ついでにわかりにくいオプションも分かりやすいしたツールがあると便利
  9. それ、Go で作ろう

使用するソリューションファイルの決定ルール

  • 引数で指定されていたら、その *.sln ファイルを読む
  • 指定されていなければ、カレントディレクトリにある *.sln を使う。複数ある時はエラー終了

実行する Visual Studio の決定ルール

  • -2010-2019 のオプションがついている時は、それを必ずそのバージョンの Visual Studio を使う。インストールされてなさそうな時はエラー終了
  • どの Visual Studio を実行するかは *.sln ファイルのコメント欄から推定する。( # Visual Studio 2010 などという行が 2,3行目に存在している)
  • *.sln ファイルで指定された Visual Studio がない場合は 2019 から順にインストールされている Visual Studio を探し、見つかった最も新しい Visual Studio を使用する。

Visual Studio クライアント devenv.com の検索ルール

Visual Studio 2010~2015

環境変数に Tools フォルダーにパスが格納されている。

  • 2015 → %VS140COMNTOOLS%
  • 2013 → %VS120COMNTOOLS%
  • 2010 → %VS100COMNTOOLS%

この環境変数に格納されているパスの Tools 部分を IDE に置換すると、devenv.com のあるフォルダー名となる。

Visual Studio 2017~2019

環境変数は廃止されている。そのかわり 2017~2019 では

C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe

というコマンドがある。これの出力から devenv.exe の場所が特定できる。

$ vswhere | findstr productPath
productPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\devenv.exe
  • devenv.exe は devenv.com と基本機能は同じだが、コンソールに何も出力されない。コンソール出力を見たいので、拡張子を .com に変えておく。
  • 32bit Windows では C:\Program Files (x86) は存在しない。また、Program Files が C: ドライブ固定とみなすべきではない。vswhere.exe は環境変数 %ProgramFiles% と %ProgramFiles(x86)% 双方の下の Microsoft Visual Studio\Installer から探すようにする。

その上で

  • 最新のみ → vswhere latest
  • 2019 → vswhere -version [16.0,17.0)
  • 2017 → vswhere -version [15.0,16.0)

とすれば Visual Studio のバージョンを指定できる

以上を元にして、我々が呼び出した適切な Visual Studio の devenv.com のフルパスを検出することがほぼ出来るようになった。

使い方

-h オプション、もしくはソリューションファイルがある場所で引数なしで起動すると、ヘルプがでる。

$ vf1s -h
WorkReport.sln: word '2010' found.
%VS100COMNTOOLS% is not set.
look for other versions of Visual Studio.
found 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\devenv.com'
  -2010
        use Visual Studio 2010
  -2013
        use Visual Studio 2013
  -2015
        use Visual Studio 2015
  -2017
        use Visual Studio 2017
  -2019
        use Visual Studio 2019
  -a    build all configurations
  -c string
        specify the configuraion to build
  -d    build configurations contains /Debug/
  -i    open ide
  -ll
        list products
  -ls
        list products
  -n    dry run
  -r    build configurations contains /Release/
  -re
        rebuild

使用例:

  • vf1s -a … すべてのコンフィギュレーションの組み合わせ ( Win32 or x64 | Debug or Release ) でビルドする
  • vf1s -d … Debug という単語が含まれているコンフィギューレーションをビルドする
  • vf1s -r … Release という単語が含まれているコンフィギューレーションをビルドする
  • vf1s.exe -2019 -c "Release|x86" -re WorkReport.slnVisual Studio 2019 指定で、 WorkReport.sln というソリューションのRelease|x86 というコンフィギュレーションをリビルドする(全部指定)
  • vf1s -i … ビルドはせず、IDE を起動する
  • vf1s -ls … ビルドはせず、ソリューションファイルから作成される予定のプロダクト(EXE/DLL)のファイル名を標準出力に二重引用符で囲んでタブ区切りで出力する
  • vf1s -ll … ビルドはせず、ソリューションファイルから作成される予定のプロダクト(EXE/DLL)のファイル名を標準出力に改行区切りで出力する

なお、そのソリューションにどういうコンフィギュレーションがあるか、どういうファイルが作成されるかについては、ソリューションファイルとプロジェクトファイル(*.vcxproj,*.csproj,*.vbproj)を真面目に読んで推定している。この解析も結構たいへんだったのだが、今回は説明を見送る(XMLencoding/xml で単純に読んで分かる範囲でがんばっているが、まだ完璧とはいえないので)

MSBuild について

Microsoft は devenv .com ではなく MSBuild を使った方がよいと言っている。だが、VBNet の DLL をビルドする時、なぜか拡張子が .dll.dll という名前で生成されてしまう現象が確認されている(Visual Studio 2013か2015くらいだったと思う)。リネームすればよいのだが、それもあまりスマートとは思えないため、自分は devenv.com を使う方が無難と判断している。

最後に

今日、バイナリもアップロードしたので、よかったら使ってみてください。気に入ったら、チャンネル登録お願いします(まぁ、★でもつけてやってください)

以上

NYAGOS 4.4.4_0 を公開しました(その1)

記念すべき「令和元年」最初のリリースになります。括目せよ!(しなくてよい)

  • (#233) \\host-name\share-name を補完できるようになった

宿願である2年越し issue の補完を実装しました。

仕事を VMWare 上の Windows で行うことが多いのですが、ソースを置いているホスト側のフォルダーを net use P: \\vmware-host\Shared[TAB] とドライブをアサインする際に補完できないのが非常に苦痛でした。最近でこそ net use P: \\vmware-host\Shared" "Folders と空白の周辺だけ二重引用符で囲むという技を身につけて楽になっていましたが、以前は \\ までカーソルを戻して二重引用符を挿入していたのです。

無論なんとかしたかったのですが、WNetEnumResourceW をはじめとする mpr.dllAPI の使い方が分からなかった。最近になってようやく解決したのは、先日、記事に書いたとおりです。最終的な実装ソースは dos/netresource.go をご覧ください

だが、\host-name の補完だけはまだひどく遅い。改善に取り組んだ結果、share-name は普通の速度になったものの、host-name だけは最初の1回だけは…。エクスプローラーでは速くはないがまだ許容範囲でした。おそらく永続化したキャッシュを使ってるのでしょうね。こっちも永続化キャッシュを使うという手もありますが、いつ破棄するかという問題がつきもので、扱いが難しい。というわけで今のところ永続化は問題先送りです。

そのかわりというわけではありませんが、待っている間ハングアップしたかのように見えるのを回避するため / (スラッシュ)が回転するアニメをコンソールで表示するようにしました。さぁ、dir \\[TAB] してみましょう!

  • (#238) copyコマンドで進捗表示をするようにした

これも2年越しの issue ですね。CopyFileExW の引数にコールバック関数を渡せばよいだけの話なんですが、実装する気力がなくて放置してました。

手こずるかなーと思っていたのですが、やってみたら、64bit版は結構あっさりできました。具体的な実装コードは nodos/copy_windows.goです。

32bit 版はしばらくしてから動かないのに気づきました。uintptr の幅が違っていて、ファイルサイズを表す uint64 を渡せなくなってたんですね。上位32bitと下位32bitを別のuintptr として渡すようにしました。

  • 環境変数名=値 コマンド名 パラメータ… をサポート

env GOOS=linux go build を結構多用するようになったんですが、env と打つのも面倒になってきました。この時の環境変数は os.Setenv で恒久的に設定するのではなく、os.ProcessStart のパラメーターで子プロセスにのみ引き渡します。

  • バッチファイル用の一時ファイル名が重複する問題を修正

バッチファイルを実行する際、バッチファイルで変更される環境変数を取り込むために、nyagos-(PID).txt という一時ファイルを CMD.EXE にはかせていたんですが、

バッチファイル名1  | バッチファイル名2

とやったら、その一時ファイルのパスが重複してエラーになってしまいました。

  • (#277) set /a 式を実装

えーと、それほど必要性も高くなかったんですが、一旦 issue を自分で立てて「やっぱりやめました」もかっこ悪いので、がんばりました。とはいえ、今 issue にある奴のいくつかは「やっぱりやめました」不可避なんですが汗

この issue 自体は1年ほど寝かしていたものですね。意外と短い

  • (#291) バックグラウンド実行のプロセスのIDを表示するようにした

本件とは別に Use ShellExecuteEx as api to run GUI application. · Issue #288 · zetamatta/nyagos という issue がありまして、これを実現した結果、ShellExecuteExW で起動するプロセスの PID が取れるようになりました。CreateProcessW の方はそう難しくないので、結果、本件が物理的にできるようになりました。もうやるしかないでしょう。

当初は考えていなかったのですが、プロセスが終わった時に「プロセスID Done」みたいな出力も出すようにしました。これ、実はプロセス監視用に goroutine を立ち上げているのですが…まぁ、無限ループ回しているわけではなくて "os".(Process)Wait を呼んでるだけなので、許してくれますよね。

  • (#361) GUIアプリの標準出力がリダイレクトできなかった問題を修正

GUI アプリは ShellExecute* で実行していたので、普通にやると標準出力を切り替えることはできません(sudo win32 みたいに、ShellExecute される側に起動するためのランチャープログラムを用意していたら話は別)。

なので、リダイレクトする時だけ、CreateProcessW(os.ProcessStart) を使うよう修正しました。


今回のリリースでは他にもいろいろ行ったのですが、長いので続きは次回の記事にて…