大手会社システムの不味さ

鉄道・銀行・電力・ガスの大手企業。その基幹システムのソースコードは、なんと10年以上昔のものを流用しているケースにばかり遭遇してました。僕がそういうシステムに携わった30年弱の間ですが・・・まずは新しいプロジェクトに参加して、なんと今頃そんなもの使ってるんだ!と驚愕します。そして20才代であろう若手が苦労しているのが気の毒でした。

退職前に携わったシステムなんて20年も昔のソースコードフレームワークを使っていました。

コンピューターに関わる開発環境及びハードウェアの進化スピードは、めちゃくちゃ早いのに、肝心のプログラムコードは全く進化していないのを実感しています。

もっともひどい目にあったのは、古いフレームワークを使ったコードを、最新フレームワークに、コンバートプログラムを使って流用することをした開発プロジェクトでした。

小規模なものなら、そのまま動くケースもあるでしょうが、大企業の基幹システムクラスのものなんで、そのまま動くわけありません。コンバートプログラムが吐き出す大量のエラー・警告。それを全て吟味してコードの書き換えと、警告レベルのものなんて、コードを書き換えずに、警告事体を出ないように設定するといったことをしていました。

で、そのプロジェクト・・・不具合でまくりで納期に間に合わず・・・プロジェクトリーダー曰く、「会社の問題プロジェクトに指定された。お前ら何やっとるん」って、僕から言わせれば、「お前がそれ言うな。そんなバカみたいなやり方決めたのおめぇだろ」であります。

きっと、「既存稼働の信頼あるシステムを流用しますから、コストはかからずお安くできますぅ」等どエンドユーザーを説得したのでしょうね。

結果は、不整合バグの修正コストがめちゃくちゃかかって大損こいたわけです。

システムの仕様は変わらないのです。一から作り直す決断をすればいいのに、リスクを恐れて、それをするプロジェクトリーダーは稀だと思います。理由は、偉くなったら途端に胡坐をかいて現在主流となっているテクノロジーを勉強しなくなるからだと思ってます。給料上がって、現行システムが問題なく稼働してるんですからねぇ・・・それで満足しちゃうんだろうな。

どうせバグを直すなら、新しいアーキテクチャを学ぶチャンスとして直したい。そう思うのであります。

この業界を引退した今、その機会が訪れることはもうないんですがね。ああ、幸せwwww

 

Ubuntuのapache2設定

Ububtuでapacheの設定をいじってみようと、apacheのオフィシャルサイトの入門をみたところ、なんか違う!って思いました。

例えば、通常はhttpd.confというファイルがあって・・・とかapacheのドキュメントに書いてあるのが、Ubuntuには無い。

Webの検索に引っかかるやつはどれも似た内容だけど、Ububtuの設定と、なんか違う。

最終的にこれって記事を見つけました。7年前に書かれている内容だけど、今でも通用します。ありがたや。

linuxserver.hatenadiary.jp

リンク先の内容を見て、僕が行ったのは、1行のコマンドを打つことだけでした。

sudo a2enmod cgid

今回は、C#で作った実行ファイルをCGIで使えるのか?ってのが命題でした。片付いた!終わり!

Chart.jsのlegend: generateLabelsの規定処理

Chart.jsの凡例はクリックするだけで、紐づいているdatasetのグラフ表示をOn/Offできる。このデフォルト機能のおかげで、複数のdatasetを一つのグラフに表示する場合に、とあるdatasetの最大値が大きすぎて、他のdatasetのフラフが軸線に埋もれて見えなくなる場合に、見えなくなったグラフのみをOnにすることができる。

一つのグラフに何でもかんでも詰め込んで表示することは良くないだろうが、この凡例の機能を使えば、見たいデータに絞って表示することを、ユーザー操作によって可能となるメリットはあると思う。

さて、複数のdatasetがあるグラフは、表示直後は全てのデータを表示するため、みてもらいたいデータが最初から埋もれて見づらくなってしまった場合に、凡例のクリック機能をうまく使えないだろうかと考えてみた。

Chart.jsのドキュメントによると、凡例クリックによるデフォルド処理のコードと、応用例が書いてある。ただこれはクリックをした場合であって、グラフ表示直後にできる話ではない。(javascriptの精通者なら、onClickイベントを表示時に発行させて目的を達成できるだろう…でも僕にそのスキルは無いようだorz)

そこで着目したのが、generateLabelsプロパティだ。これはfunctionで定義し、戻り値は規定のインターフェースを設定しなければならない。

やりたいことは、表示時にとあるdatasetの項目をあたかもクリックしたかのように非表示にしたい…というものだ。そのためには、表示・非表示の項目のみを操作したいのだが、ドキュメントのgenerateLabelsは、onClickの説明と違って、デフォルト動作も応用例も載っていない。

僕はどうしたかというと、

  • ブラウザでグラフを表示する
  • F12キーを押してデバッグモードにし、グラフオブジェクト生成後の場所にブレークポイントを設定する
  • 再読み込みをして、ブレークポイントにヒットさせる
  • 生成されたグラフオブジェクトの中身から、generateLabelsのコードを見つけて、コピーする(これは、Chart.js内にある)
  • コピーしたコードを自分のページに張り付ける

これで、デフォルトのgenerateLabels処理を取得した。

後で気づいたけど、Chart.jsのソースコードからgenerateLabelsを検索してもよかった。ただ、これだと複数ヒットするので、どのgenerateLabelsが使われるのかを調べておく必要がある。このとき、なぜドキュメントにgenerateLabelsのデフォルト処理が書いていないのかが分かった。グラフによって違うからだ。

抜き出したコードを改修して目的の動作をするコードを最後に乗せておく。これは3個めのdatasetのグラフを初期表示したときのみ非表示にするというものだ。

var isFirstload = true;
・・・・
var chartX = new Chart(ctx, {
    ・・・
     options: {
        legend: {
            labels: {
                generateLabels: function (chart) { // このプロパティは、グラフ描画毎に使用される
                    var data = chart.data;
                    return Array.isArray(data.datasets) ? data.datasets.map(function (dataset, i) {
                       // 付け加えたコード ここから
                        var meta = chart.getDatasetMeta(i);
                        if (isFirstLoad) {
                            if (i == 2) {
                                isFirstLoad = false;
                                meta.hidden = meta.hidden == null ? !data.datasets[i].hidden : null;
                           }
                       }
                       // 付け加えたコード ここまで
                      return {
                         text: dataset.label,
                         fillStyle: (!Array.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
                         hidden: !chart.isDatasetVisible(i),
                         lineCap: dataset.borderCapStyle,
                         lineDash: dataset.borderDash,
                         lineDashOffset: dataset.borderDashOffset,
                         lineJoin: dataset.borderJoinStyle,
                         lineWidth: dataset.borderWidth,
                         strokeStyle: dataset.borderColor,
                         pointStyle: dataset.pointStyle,

                         // Below is extra data used for toggling the datasets
                        datasetIndex: i
                      };
                  }, this) : [];
             },
  ・・・
},

デフォルト処理は、mapメソッドを使った実にうまいコードだと思う。Chart.jsのスタッフさん、素晴らしいコードをみせてくれてありがとう

PCからファイルが消えた??

もし、この記事を読んだりして僕と同じ目にあった人は、OneDriveの設定を予備知識無しにあれこれ変えずに、サイトをググってPCとOneDriveの紐づけを安全に切る方法を実施しましょう。

Visual Stdioで、開発中のプロジェクトを「最近」ウイジェットで開いたら、ファイルがないのでリストから削除する?ってメッセージが表示された(-_-;)

ウィルスにやられたかと思った(´;ω;`) (最近怪しいサイトみたんで…)

プロジェクトは「ドキュメント」フォルダに置いていた。で、ドキュメントフォルダをみたら、プロジェクトがあるではないっすか…

で、そこからソリューションを開いたら、Webサイト関連のプロジェクトで、ファイルが無いとかでエラーとなって、メンテできなくなった…

開いたソリューションのフルパスをみたら、ドキュメントのパスが、"OneDrive"の配下にあるじゃん。

あれれ…なんじゃこりゃ…

慌ててOneDriveの設定をあれこれ弄ってドキュメントやデスクトップと、OneDriveの関係を断ち切る操作をしたんだけど、今度は、ドキュメントフォルダの中身が消えてしまった。ハタとみると、デスクトップのアイコンにいつも表示されているはずのものが無い( ;∀;)

やられた・・・

率直に言いたい。マイクロソフトさん、説明なさすぎ、わかりにくスギです。

最近Windows10のバージョンを1903に上げてから、デスクトップのアイコンに見たことのない印が付いていたが気にしてなかった。

この印の意味がこれでわかった。アップデートすると、OneDriveがデスクトップやドキュメントに紐づいて、同期処理が行われるようになるのね。見たことのない印は、同期されたか否かを示すものだったようですorz

アップデート後、表示されるウィザードをポンポン「次へ」って内容を見ずにやった結果でしょうな(# ゚Д゚)

でもさ、面倒じゃん。わけわからん説明だし、次へ進まないと先にいけないし。

一度切った紐づけを戻すことは僕のスキルでは無理だった。仕方ないので、空になったドキュメントやデスクトップのファイル達をOneDriveのサーバーから逆にダウンロードしました。ドキュメントなんて3G程あるんで、結構な時間かかったよ( ;∀;)

とりあえず、元に戻ったようなのでこれで良しとしたんだけど、PC1台しかないし、モバイルに同期する必要ないんで、OneDriveを起動しないようにしたぁぁぁぁ。

僕のモバイルはandroidです。PCとの同期はGoogleアプリで十分。マイクロソフトランチャーより使い慣れたランチャーのほうがいいしね。

OneDriveで恩恵を受けている人は多いんだろうけど、僕はいらない。

いらないんですよぉぉぉぉ!

WS2K12R2で、Azure VPN Gatewayを使ったP2S接続

Windows Server 2012 R2からAzureにP2S(ポイント対サイト)接続を構成して、ドロ沼にハマったので、ちょっと覚書。

まずは、Windows SDK V7.1を無理矢理インストール

Win10や、Server2016のようにPowerShellで証明書が作れないので、MakeCertを使うことになるのです。で、MakeCertは、普通に2012R2にありませんorz。 なんで、SDKをぶち込んでMakeCertが使えるようにしないと・・・なのです。 でも、ダウンロードして普通にインストールしても、エラーが出てインストールが異常終了します。 解決策は、下のリンク。Win10の話ですが、WS2012R2でも全く同じ症状でしたので、やってみましたよ。

qiita.com

更新プログラムの適用

ググりまくって、たくさんの更新プログラムをインストールしてみたんですが、既に適用済みってのばっかでした。何を適用すればいいのかわからないですが、次のリンクにあるものが開始点でした。

docs.microsoft.com

レジストリの内容を編集

上のリンクに、サラッとコマンドが書いてありますが、レジストリを弄るのは、とても危険なので、以下2つのリンクを勉強しました。

マイクロソフト セキュリティ アドバイザリ: TLS の使用を可能にする Microsoft EAP 実装の更新プログラム (2014 年 10 月 14 日)

WinHTTP が Windows での既定のセキュリティで保護されたプロトコルとして TLS 1.1 および TLS 1.2 を有効にする更新プログラム

で、設定したのは以下。真似する人は自己責任でお願いします。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\RasMan\PPP\EAP\13 に、Key: TlsVersion, Value(DWORD): 0xfc0 を追加
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp に、Key: DefaultSecureProtocols, Value(DWORD): 0xaa0 を追加
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp に、Key: DefaultSecureProtocols, Value(DWORD): 0xaa0 を追加 

これで、エラーで動作しなかった Azure VPNアイコンクリックで接続ががうまくいきました。

f:id:megusuritan:20190610011750j:plain
接続に成功したAzure VPN
さて、寝るか。

Android SMSメッセージの受信

ぃやぁ、やっとうまくSMS受信メッセージに反応するBroadcastReceiverを作成できました。

ググりまくって、サンプル試しまくってもBroadcastReceiverがSMS_RECIVEDに反応しなかった諸兄は、以下を試すと幸せになれるかもしれません。

テストアプリにSMSの権限を付けましょう

ということで、デバッグしたのであれば、Visual StudioなどのIDEが、デバイス(エミュレータ―)にテストするアプリを配置してくれてるはずです。

設定>アプリ>テスト対象のアプリの順にタップしていくと、次の画面にたどり着きます

f:id:megusuritan:20190525180222j:plain
Test対象のアプリ情報

赤枠の権限をタップします。と、次の画面になるでしょう・・・

f:id:megusuritan:20190525180403j:plain
SMS権限の設定

そこにあるSMSのチェックを入れましょう。これでいけるとおもいます。デバッグ中でもおkですよ。

なぜにそうするのか?

それは、Android6以降の仕様によります。Android6以降のアクセス許可は、安全なアクセス許可と危険なアクセス許可の2種類に分けられ、SMSのアクセス許可が危険なアクセス許可になったからです。

危険なアクセス許可は、マニフェストに実行許可を付けただけでダメで、アプリを実行するユーザーが直々に設定する必要があるのです。それが上図の手順というわけです。

ググりまくった成功例のサンプルには、その話が載っていませんでした。多分、その記事を書いた時期がAndroid6より前だったのでしょう。

テストアプリを世にだそうとする場合は、上図手順ではなく、下記リンクをしっかり読んで、アクセス許可について理解し、APIを駆使して作る必要がありますね。

docs.microsoft.com

んじゃ、僕のほうはやりたいことの5割ができたので、さらなる改良を加えていくことにしますよ。BroadcastReceiverが反応してくれたんで、色々をごにょごにょしちゃいますーーー

Selenium WebDriverのまとめ

ようやく、操作を自動化したいサイトのアプリ作成が終わったので、手間がかかったことをまとめておきます。

Click, SendKeys, Submitメソッド

Seleniumは、手動操作を自動化するものなので、これらのメソッドでほとんどのinputタグの値を設定できます。できないものは、type="hidden"くらいでしょうか。

inputタグの中で、ダイアログがでるものがあります。type="file"しかやってませんが、type="text"と同様にSendKeysメソッドでファイルパスを設定すればOKです。

SendKeysはキーボード入力のエミュレートですが、漢字もOKでした。

MoveToFrame, ModeToWindowメソッド

iframeタグで、他のページを見せている場合は、画面に表示されているのにFindElementメソッドで見つけられません。ソースを見てもフレーム内の内容はありませんから、当然ですね。

こんな時に、MoveToFrameメソッドを使ってそのフレームに移動すると、FindElementメソッドで見つけることができるようになります。

そもそも、ソースに無いものをどうやって見つけるかというと、Chromeブラウザの場合は、F12キーを押して開発者ビューから、フレーム内の内容をたどることができます。そして操作したいターゲットを特定します。

もとに戻る場合、MoveToWindowメソッドを使います。このとき、引数であるwindowHandleが必要なので、フレームに移動する前にWebDriver.CurrentWindowHandleプロパティの値を保持しておきます。

ExecuteScriptメソッド

javascriptを使いたいときに使用します。ドライバーのインスタンスをIJavaScriptExecutorインターフェースにキャストして使います。

javascriptを使えるなら何でもできちゃいそうですが、使う場面は限られるように思いました。

僕の場合は、input type="text"にonclickイベントで、javascriptで表示させたダイアログの操作結果を設定するという部分に使いました。手動操作では、値を入力するためにそのフィールドをクリックするだけでダイアログが表示されるので、直接入力したい内容はそのダイアログでしかできません。

Seleniumを駆使してそのダイアログの操作をするのはとても面倒という判断をして、ダイアログでやっているであろう処理を操作プログラム内でやらせて、その結果を設定するのに、javascriptを使いました。

((IJavaScriptExecutor)driver).ExecuteScript(string.Format("$('#<操作したいID>').val('{0}');", "<処理結果>"));

driverは、WebDriverのインスタンスです。

こんなところでしょうかね。後は、タイムアウトの問題ですが、これは前回の記事で書きました。ふぅ。おつかれ