とりあえずsubversionで生きていく。

愚痴。

ゴールデンウィークですね。今年も引き籠りの年になりそうです。
来年はどうなるんですかね・・・

まぁ、そんなことはともかく。

ここ半年、gitのトレーニングをしようと、趣味用途のプログラムはほとんどgitを利用して管理してきました。
クラウドサービスでVPSのインスタンスを1個作ってリモートリポジトリとして使って勉強。

結局のところ、僕のような頭の硬いおっさんには、ちょっと肌に合わないな、と思い、結局のところ挫折してしました(-_-;)
根本的に git を理解できなかった。っていうか、gitとかsubversionでブランチを使用した開発の手法をよく理解していないのが根本的な理由かなぁ。

挫折したポイントとしては、ブランチの扱い方が Subversionとあまりに違い過ぎて、付いていけなくなった(理解できなかった)こと。
いや、issue毎、feature毎にブランチを切って、マージして、という、一連の流れは分かるんですよ。
それこそ、チュートリアル的な単純なプロジェクトだと普通に分かるんすよ。ある程度コツがつかめてきて、仕事で使おうとしてたんだけど・・・どういえばいいのかちょっと迷うんだけど・・・ブランチを切る粒度というか、それがイマイチ分からないんですよねぇ。。。

アプリのソースがあって・・・
1. ある不具合があって、masterから修正のためのブランチを切る。
2. そのブランチでバグ潰しているうちに、そのバグに関連して別のバグを発見!😭

この時、
A. masterブランチから別のブランチを切って、後々リベースすればいいのか???
B. そのブランチでついでにその関連したバグを修正すればいいのか???
C. 一旦コミットしたのち、またブランチを切りなおせばいいのか?
subversionだとそんなの構わず一気に修正して、コミットして、ログに修正項目を羅列してたんだけど・・・。要は作業記録して残してるだけ、みたいな。

さらに、客側から、新しい機能のリクエストがあって、それを featureブランチを切って・・・とかやってると、慣れない git のブランチの管理でパニック!

これがチームで開発してて、同じ git使いなら、「ねぇ、今、こっちの修正で時間かかってるんで、別のバグ修正しといてくれない?」って感じで頼めるんだろうけど、おひとり様開発なので、んなのメンドクサイから、ついでに直して一緒にコミットすればいいや、って風になってしまう。
こういうのが重なってくると git の良い所を自ら潰していってるようなもん。履歴なんて滅茶苦茶。

結局、git を仕事で使うのを断念して、Subversionで、バグがあるたびに、issueブランチを作って(コピーして)、修正したらtrunkにマージして・・・という風な感じで進めていった方が生産的じゃないか???と思いつつあります。。。

一人で開発してるのって、制約がないので自由にできるけど、逆に言えば、引き継ぎのハードルが異常に高くなってしまう。
んー、こんな煩わしいことに時間を割きたくないんだけどな・・・

JSONデータをExcelファイルに展開したい、ブラウザで。

2021年7月31日 修正
babelの設定を書き忘れてた!package.jsonにbabelの設定を追加。


これの続編

サーバーで処理させるよりデータだけをWeb APIで引っ張ってきてブラウザ上のJavaScriptで処理しよう、っていうのがここ最近のトレンドだと思います。そのための環境は整ってきました。

また、InternetExplorerがやっとWindowsから取り除かれることがアナウンスされていました。なくなりはしませんが、完全にオプション扱いになるみたい? 日本のWeb環境の進歩を実質止めてきた(邪魔してきた)レガシーが無くなる予定。
Internet Explorer は Microsoft Edge へ – Windows 10 の Internet Explorer 11 デスクトップアプリは 2022 年 6 月 15 日にサポート終了

ここ最近、業務系のウェブシステムでExcelをあーだこーだしろ、っていうのが急に増えてきてまして・・・たぶん昔動かしていたAccessアプリケーションを単純にWebへ・・・という流れなんでしょうかね?

で・・・Webサーバー(LAMP)でPHP-Excel(PHP-Spreadsheet)使ってエクセルファイルを処理させると滅茶苦茶メモリ食いませんか?
数年前に少し試してみたんですが、通常業務で利用するぐらいの行数(列数)でもメモリ不足でエラーでるわ、処理が遅くて使いもんにならんわ、で使っていくのを速攻で止めました。
(PHPじゃなくてJavaとかだと速いのかもしれんが、Javaは難易度が高すぎるし、そもそもLAMPを主戦場にしている仕事環境なので。)

さて、ちょっと前に Excelファイルを読み書きする SheetJS っていうのをネタに備忘録として書いたけど、SheetJSは Pro版じゃないと(有料)、スタイルなど文字の大きさとかフォントの指定だとかは扱えません。実質、既存のExcelのデータを読むだけになると思います。まぁPro版買えって話なんですけど。

で、良い感じにブラウザでカンタンにきれいなExcel帳票を作れないかなぁ・・・といろいろ githubとか漁ってたら、XLSX-Rendererっていうのを見つけました。簡単に言うと、WORDでいうところの差し込み印刷のように、テンプレートのExcelファイルにデータを差し込んでExcelファイルを作ってくれる。
XLSX-Renderer自体は ExcelJS というnodeモジュールを使用しているみたい。

XLSX-Renderer
https://github.com/Siemienik/XToolset/tree/master/packages/xlsx-renderer

まぁ、いつもの如く中身はよく分かんねーけど一度試してみました。今回もその備忘録です。
【動作デモはこちらから】

開発環境としてnodejsとnpmが使える環境が大前提です。
また、モダンなJavaScriptの知識( Promise,await/async,thenなど)と、必要であれば、BabelJSなどのカンタンな使い方を知っている人向けです。じゃないとワケワカメになると思います。ご了承のほど。

システムにbrowserify,uglify-jsをインストール

>> sudo npm install -g browserify
>> sudo npm install -g uglify-js

説明するまでもないとは思いますが、browserifyはnodejsモジュールをブラウザで利用できるようにワンパッケージにしてくれるコマンド。uglifyjsはminifyするため。詳しくは知らない。手順だけ知っておけばいい。理屈は後回し。フロントエンド周りに詳しい人は webpack とかいろいろ方法はあるとは思いますが、僕はこれしか知らないので💦

まず、下記のようなテンプレートとなるExcelファイルを作ります。(テンプレートExcelファイル

このExcelファイルに、データをぶち込みたいところへ、#から始まる命令コマンドをセルに埋め込んでいく、という感じ。自分でセルを埋め込むメソッドをチマチマコーディングするより圧倒的にラクできる感じ。
#! FOR_EACH 命令を使えば、配列をぶち込める。

要は MVCモデルの View の出力先を エクセルファイルにしている感じでしょうか。同様に、DOCX-Renderer とか PDF-Renderer ってのも作ってほしいよ(笑)

次に本題の処理する部分をコーディングします。

扱いやすいように、僕はグローバル関数を(windowオブジェクトのプロパティとして)定義してコールするようしました。このあたりはどういう処理を行わせるかによって実装方法は変わると思います。とりあえず関数として実装しました。
このままではブラウザでは動かないので、上記のコードをブラウザで利用できるようにするため、この xlsx-template.jsをbabelなどのツールを使ってビルドします。そのため、ディレクトリを一個作って以下のpackage.jsonを置き、

>> tree .
.
├── package.json
└── xlsx-template.js

そのディレクトリで以下を実行

>> npm install
>> npm run bundle

そうすると、bundle.min.jsが生成されるので、これをHTMLファイルのscriptタグからロードします。
HTMLファイルはこんな感じでしょうか。実際にはJSONデータはサーバーから取得することになりますが・・・。データ構造は簡単で、キーと値がそのままテンプレートのExcelファイルのセルに記述した “## キー名” に対応してます。このあたりは XLSX-Renderer のgithubページに記述の仕方が書かれているので参考に。比較的簡単です。

そうすると、下記のようにテンプレートとなるExcelファイルにデータを埋めてくれます。

【動作デモ】

エクセルのレイアウトが変わっても、テンプレートのExcelファイルを変更すればいいだけので、変更も簡単で、実行コードを修正する必要もない。

まだ試していませんが・・・データベースサーバーからウェブサーバー経由で1万件ぐらいのJSONデータを取ってきて、処理させてテストしてみて、処理速度が業務に耐えられるようであれば、本格的に利用していきたい、と思ってます。

・・・しかし・・・みんなExcel好きだよねぇ。。。

ブラウザで画像ファイルのリサイズ処理

2021年3月15日 修正
blobオブジェクトを返すのではなく、new File([blob]……)として Fileオブジェクトのインスタンスを返すように修正


最近のお話。あくまでフィクションです💦 進行中案件の担当さんにある日相談を受ける。


画像をウェブサーバーにアップロードしたいけど、大きいサイズはリサイズしてサーバーに保存したいんだよねー
でも、外注先の人が・・・
『サーバーで画像縮小するんで負荷が大きいし、画像処理にGD使うからPHPのmemory_limitを上げてくれないと・・・』
って言われてるんです!サーバーは共用のレンタルサーバーでmemory_limitなんて変更してくれそうもないし・・・。
『memory_limitを仮に上げてもアクセスが重なるとサーバー落ちてしまうかもしれないけど、責任持てない』
とも言われます!

何か方法ない?


んー、アップロードする前に JavaScript でリサイズすればいいんじゃね?って単純に思ったわけですけど・・・
そんなことも分かんねー外注先使ってんのか・・・っていうのが一つ目。
つーか、重くなるのが分かってんならサーバーで処理させるな! っていうのが2つ目

ってなわけで、サンプルコードを渡して「後は良きに計らえ」コース。
サンプルを作ってやれば、あとはなんとかしてくれるんじゃねーか? つか、なんでこっちがサンプル作んなきゃいけないんだよ!!!
本来外注先のシステム制作会社がやるべき仕事だろーよ!
まぁ、怒ってもしょうがない。そのレベルの外注先しかやってくれるところないんだからしょうがない。
こうやってこのブログのネタにできるんなら、怪我の功名というやつです。(ん?使い方間違ってないか?)

本題です。要は ブラウザで画像をリサイズしてBlobオブジェクトとして取得できれば、あとは FormDataを作ってappend するなり、してやれば万事解決です。

ググればJavaScriptとCanvas APIを使ったコードがゴロゴロ転がってるので参考にしてこちらの用途に合うように手を加えていく。
画像リサイズ処理自体は Canvas API を使えば簡単にできるので、後は File オブジェクトを FileReader で読み込んで、リサイズ後に canvasオブジェクトの toBlobメソッドで Blobオブジェクトを取得してやればいい。

ややこしいのが、それらすべてが非同期で処理しなければならない事。Promiseを使って一連の画像処理をしてやれば、await構文で同期処理のように待つことができる。

再利用できるように モジュールとして書いた。
簡単に説明すると、リサイズが必要な画像のFileオブジェクトと短辺の最大サイズを引数にして、コールするとリサイズされた画像がblobオブジェクトとして resolve される。

当然ブラウザのバージョンに依存してしまうが・・・ゴチャゴチャ言われたら ターゲットのブラウザ用に Babel で変換しちまえばいいし💦

これを下記コードのように input[type=file]のonChangeイベントハンドラでゴニョゴニョしてサーバーにアップロードする。
僕は jQuery が大好きなので jQuery を使う。何度も言うけど、やっぱり document.querySelector(‘p’) とかタイプするより、$(‘p’) の方がラクなんだよね。

当然ながら Internet Explorer は全バージョンエラーになる。
chrome/firefox や safari でもバージョンによっては動かない。。。これじゃダメだ!って言われたら、最終手段 Babel のご登場(⌒∇⌒)

僕は下記のような .babelrc を書いて・・・

 >> browserify ./index.js --transform babelify | uglifyjs -c -m --output ./es5/bundle.min.js 

とかやると、とりあえず IE11でもシンタックスエラーにはならないようになる。だけど、結局 FormData.appendメソッドでエラーになるけどね😫

まぁ、今更なんですが、Canvas APIではリサイズ処理だけじゃなく図形を描画したり、ピクセル単位で演算処理を行うことでいろんなことが可能なので、サーバーサイドで画像処理を行わず、余力のあるクライアント(フロントエンド)で前処理させてから・・・というのがイマドキのやり方なんだろうな、と思います。

Windows Explorerシェルで複数のファイルをプログラムに渡したい

ファイルの差分表示に WinMerge (日本語版) を使っていました。TortoiseSVNにも自動で設定してくれるし、重宝してました。

一方、ubuntuとかCentOSのbashシェル内で作業しているときは、vim のdiffモードを使うことも増えてきまして、どうせならWindowsのデスクトップで作業しているときも gVim でやろうかな、と思い立ち、Windowsのレジストリをいじって関連付けしようとしました。

具体的には↓のように・・・

まぁ、でもこれは失敗します。この方法で2つファイルを選択した状態で、右クリックして opendiff をクリックするとgvimが二つ起動してそれぞれ別のgvimで開いてしまいます。失敗。
※追記 2021年6月24日 official buildのvimだと GvimExt32/GvimExt64 というシェルエクステンションが既にバンドルされてるみたいすね・・・。僕は kaoriya vim しか使ってなかったので気づかなかった💦

で、じゃぁ、%2とか%* ってのをつけ足せばいいんじゃない? って思うのですが、やってみれば分かりますが、失敗します。上記と同じように複数のgVimウィンドウが開きます。
どうやら標準で複数選択したファイルを同一のプログラムのインスタンスに渡すことはできないようです。

じゃあ、どうすればいいのか?というと、Explorerのシェルエクステンション(インプロセス COMサーバー)を書いてレジストリに登録する必要があります。(グーグル調べ)

ってことで、現実的に C++ で実装するのはヒジョーにメンドクサイ。探せばシェルエクステンション用のフレームワークみたいなものがあるとは思うのですが、今はC#をメインに使っているので、できるなら C# でできないか、調べたところ(グーグルで)、SharpShell という、C#のシェルエクステンション用のフレームワークがあるようです。

SharpShell
SharpShell makes it easy to create Windows Shell Extensions using the .NET Framework.

ショートカットメニュー用のシェルエクステンション作成とインストールはチュートリアルがあるので、この通りに進めていけば苦も無く作成できると思います。

チュートリアル(英語)

ただ、このチュートリアルはかなり古く2014年の時のものですが、基本的にはあまり変わっていません。
注意点は、SharpShellを nugetで入れる場合は、2021年2月現在最新のもの(2.7.2)を入れる場合、Server Manager などのツールも最新のものを使う必要があります。nugetで SharpShell Tools を入れると なぜか 2.2.0のものがインストールされてしまうので上記 githubサイトで配布されている 2.7.2 のものを使う方がいいと思います。

基本的には・・・Visual Studio 2019 Community を使用します。

  1. プロジェクトを .NET Framework のライブラリ(DLL)として作成。
  2. 「プロジェクト ⇒ nugetのパッケージ管理」で SharpShell をインストール
  3. チュートリアルで説明されているように、SharpContextMenu を継承したクラスを作成
  4. ショートカットメニューに必要な抽象メソッドを実装する(Visual Studio 2019のコード補完で自動的にスケルトンが出ると思います)
  5. プロジェクト・プロパティ⇒アプリケーション⇒アセンブリ情報 で「アセンブリをCOM参照可能にする」にチェック
  6. プロジェクト・プロパティ⇒署名⇒アセンブリに署名する(チェック)⇒新規作成 適当な名前をつける
  7. ビルド
  8. ServerManagerでビルドしたDLLファイルを読み込んで、Server⇒Install Server(x64) Register Server(x64) を順番に実行
  9. インストール&登録する前にテストしたければ、Test Server In Test Shell をクリックするとテスト用のエクスプローラもどきが出てくるのでそこでテストできるようです。

まぁ、そんなこんなで、やりたいことはできました(^▽^)/

※ただ一点注意しないといけないのは、.NET Frameworkのようなマネージコードをインプロセスサーバーとしてエクスプローラのプロセス内で動作させるのは未だにいいのかどうか分からないって点です。マイクロソフトの中の人も良いと言ってる人もいれば、やらない方がいいっていう人もいるようです。 この辺りは SharpShell のドキュメントでも書かれています。2021年現在、実際のところどうなんなんでしょうかね・・・・?

ただ、ショートカットメニューをクリックしてプロセスをキックするだけならあまり問題ないのかな~と思ってます。

ずっと前にC++で書いたシェルエクステンションのソースコードが残っているのでC++で書こうと思えば書けるんですが・・・やっぱりオッサンはもう頭が硬くなってるので時間がかかるんですよねぇ。

書いたコードはこんだけ。便利なライブラリに多謝・多謝。

簡易ISOファイル作成コマンド

これの続きです。

自分用のツールの置き場、備忘録として記録しています😅

CDやDVDのメディアからISOファイルを作成するのは結構カンタンにできました。
これで殆どやりたいことはできたのですが、やっぱりディレクトリからISOファイルを作るにはどうするんだろう??? という素朴な考えがでてきまして・・・
ググるとこれもWindowsで標準機能でできるようで・・・具体的にはイメージマスタリングAPIとしてCD/DVD等のファイルシステム作成からメディアへの書き込みまでの機能がCOMサーバーとして提供されているようです。COMサーバーで実装ってことは、WSHやC#から簡単に使える・・・ってことです。

サンプルのコードはもうマイクロソフトのコミュニティーサイトに載ってましたので、これを適当にいじって、任意のディレクトリをISOファイルにビルドできるコードを書いてみました。一つ前に書いたDVDメディアからISOファイルを作るコードも統合してみました。

イメージマスタリングAPIは.NET Frameworkのクラスライブラリで提供されておらず、C#から使用するには、TLBIMPコマンドを使用してタイプライブラリからCLRアセンブリに変換し、コンパイルするときにこのアセンブリを参照しないといけません。Visual Studio のIDE環境を使用する場合はプロジェクトにIMAPI2FS.dllの参照を追加するだけでいいかもしれません。
僕みたいにコンソール画面でカチャカチャする場合は・・・

>> tlbimp c:\WINDOWS\System32\imapi2fs.dll

のようにすると、同名のアセンブリ(dllファイル)ができるので、ソースコードをコンパイルするときに、このDLLファイルを /r オプションで追加します。

殆どサンプルコードをコピペしただけなので、特に特筆するところはありません・・・githubにリポジトリ作ろうと思ったけど、ファイル1個だけなんでgistにした。

一応、タイプライブラリのインポートもあるので nmake用の makefileも書く。