銀の弾丸

プログラミングに関して、いろいろ書き残していければと思っております。

Chromium版EdgeのIEモードを使ってみた

f:id:takamints:20200127222426p:plain



先日Chromiumベースの新しいMicrosoft Edgeがリリースされたと話題になっていましたが、日本で自動更新されるのは4月以降になるとのこと。 なにやら新Edgeでは動作しないWebサイトが日本国内にたくさん残っている確定申告に使うアプリ?が新しいEdgeでは動かないらしくて、混乱を避けるためだそうですよ。

しかし手動でインストールするなら最新のChromiumベースのEdgeを今すぐにでも使えるらしい。

実は弊社、イントラネットでかなり古い社内情報共有ポータルサイトが稼働しておりまして、各種社内情報の閲覧と投稿はモダンブラウザで問題ありませんが、ファイルのアップロードだけは Internet Explorer でなければできない 状態なんですね。この社内ポータルはMicrosoftのShare Point Serverで構築されているのですが、なにしろバージョンが古いためか、モダンブラウザでファイルを添付しようとすると「このブラウザでアップロードはできません」てなメッセージが表示されます。

まあ、 Windows 10 の Internet Explorer 11 は2029年までサポートされるらしいので現時点では問題なしです。 でも2029年以後はどうすんの?って問題はある。まだ9年も余裕がありますけど、弊社、平気で15年ポータルを放置していたんで更新するのかどうかわかりません。

さてさて、そんな我社の状況を見透かしたかのように、新Edgeには「IEモード」というのがあるそうで、「インターネットエクスプローラで閲覧してください」なWebサイトでも正しく動作するとの噂。さて弊社の古い SharePoint Serverのポータルに、最新EdgeのIEモードで、ファイルのアップロードはできるのか?と試してみました。

結果から先に書きますと、ファイルのアップロードもできました。

ということで、このまま弊社のポータルを放置して2029年が過ぎたとしても Edge の IEモードを使えばOKですね。 メデタシメデタシ・・・なのですがー

この新EdgeのIEモード、設定するにはひと手間必要。簡単には使えませんでした(いったん設定すればその後は問題ありませんが)。ということで、 Chromiumベースの新生Microsoft Edgeで「IEモード」を使えるようにする設定手順を以下に書いておきます。

追記: Edgeのポリシー設定でIEモードが有効に設定されているなら、本記事記載の設定でIEモードを使えるようになりますが、そうでなければ別途設定が必要です。 自分の場合は会社貸与のPCではドメインで設定されておりOKだったのですが、自宅PCではローカルグループポリシーの設定が必要でした。

ローカルグループポリシーでの設定方法は以下のページで説明しています。

takamints.hatenablog.jp

目次

新Edgeをインストール

ダウンロード

https://support.microsoft.com/ja-jp/help/4501095/download-the-new-microsoft-edge-based-on-chromium

f:id:takamints:20200127211242p:plain

「今すぐ新しいMicrosoft Edgeを入手してください」ってボタンを押すと、以下の画面が表示されます。

f:id:takamints:20200127211439p:plain

さらに「DOWNLOAD for Windows 10」というボタンを押すと以下のLICENSE TERMSの受け入れ画面が表示されます。

f:id:takamints:20200127211706p:plain

全文英語ですけど、しっかり読んで「Accept and download」を押せば「Thank you!」ってメッセージが表示されて、MicrosoftEdgeSetup.exe がダウンロードされました。

f:id:takamints:20200127211902p:plain

インストーラー実行

ダウンロードされたインストーラーを実行すると、「Getting the new Microsoft Edge」と表示されてプログレスバーが動きます。インストーラーがさらにダウンロードしているのでしょう。下には「We can't wait for you to try it」なんて表示されてますが、なんだかMicrosoftらしくないですね。

f:id:takamints:20200127212003p:plain

その後、自動的にインストールが始まって、意外に早く完了します。 そして勝手にEdgeが起動して、「ようこそ」的な画面が表示されます。

f:id:takamints:20200127212836p:plain

「Get started」 ボタンを押すと、設定を Google Chromeからインポートするかどうかを選択する画面が表示されました。最初から選択されています。

f:id:takamints:20200127213040p:plain

普段はGoogle Chromeを使っているのでインポートしない理由がありません。Chromiumベースなので安心ですし、どうせ同期されるのではないかと思うし。 「Next」ボタンを押して次の画面が表示されると既にインポートが完了していました。

この後は、新しいタブの設定、データの同期をするかどうか、あと使用状況をMicrosoftに送信するかどうかなどを選択してセットアップは完了です。

余談:新Edgeの使用感

見た目は、LinuxChromiumを使っているような感じですね。 新EdgeはChromeと違ってブックマークフォルダに色がついていません。

旧Edgeに比べて描画が明らかに高速です。木のせいではないと思います。 描画内容や使い勝手に関して「Chrome と違う」ってな所は気づきませんでした。

いやしかし、上の手順でインストールしただけでは、メニューなどが日本語化されていませんね。 そういう点では、ちょっとした違和感がありました。

てなことで、総合的には「Edgeを使っている」って気分にはなりません。 ただ、これは良いことなんでしょうね。ブラウザの主役はコンテンツですからね(ちょっと良いこと言った感じ)。

余談:奥ゆかしいかも?新Edge

あと、些末なことですが、初期Edgeの「使え使え攻撃」みたいなのがなくて、それだけで好感を持ちました。少しだけですけどね。

次に起動したときに「既定のブラウザに設定してちょうだい」なんて言ってきましたが、即刻拒否w。 そもそもChromeと使い勝手などが同じなので、好感は持ちましたが、個人的には変える理由がないわけでスマン>新Edge。 ただ、その後しつこくお勧めしてくることがなくなったのには「悔い改めたかMicrosoft」という気分です。

IEモードを有効にする

さてここからが本題。IEモードを有効にするには、以下の手順が必要です。

アドレスバーに edge://flags と入力してオプション設定の画面を開き、上部の検索ボックスに IE integ ぐらいまで入力すると、「Enable IE Integration」という項目がトップに表示されます。

f:id:takamints:20200127215943p:plain

この項目の右にあるドロップダウンから「IE Mode」を選択する(他に「Need IE」というのもあるがよく知らない)。

f:id:takamints:20200127215749p:plain

すると、「Restart」と書かれたボタンが右下に表示されるので、クリックしてEdgeをリスタートします。

f:id:takamints:20200127220126p:plain

この時点で、晴れてIEモードが使えるのかと思ったのですが、まだ無理でした。

Edgeの実行時に「IEモードを試す」というオプションを追加で指定しなくてはならないとのこと。

これはタスクバーにピン止めされてるアイコンに設定すればよろしいようで。次項の手順で設定します。

IEモードのテストを有効にする

タスクバーに表示されている青緑の勾玉みたいな新しいEdgeのアイコンを右クリックするとメニューが表示されます。

f:id:takamints:20200127220516p:plain

このメニューのトップの「Microsoft Edge」を再び右クリックすると、さらにメニューが開きます(以下)。

f:id:takamints:20200127220655p:plain

開いたメニューから最下段の「プロパティ」をクリックすると「Microsoft Edgeのプロパティ」ウィンドウが表示されます。

f:id:takamints:20200127220822p:plain

「ショートカット」タブのリンク先テキストボックスの末尾に --ie-mode-test の文字を追加し、OKボタンで設定を終えれば、IEモードのテストが有効になっているはずです。

IEモードに設定したタブでWebページを表示する

これまで開いていたウィンドウをすべて閉じ、IEモードを有効にしたアイコンで再度Edgeを起動すると「IEモードが有効になっているが安全上問題があるかもしれん」みたいなメッセージが表示されます(以下)。

f:id:takamints:20200127221042p:plain

この状態で、右上の「・・・」メニューから 「More tools」を開くと「Open sites Internet Explorer mode」という項目を選択します。

f:id:takamints:20200127221214p:plain

すると、これ以降このタブではIEモードでウェブページを開くようになります。なりましたね?

なりました?あれ?

どうも様子がおかしいですよ。会社貸与のPCでは問題ありませんでしたが自宅のPCではダメなのです。 IEモードを有効にしたタブで対象のページを開こうとしてもグルグルしたままで、サイトが表示されません。

ということで、ここまでの設定でうまくいかない場合は、別の設定が必要なようですが、それはちょっとまた後で。

既にIEモードを問題なく使えている人はおめでとうございましたっ。

TypeScriptでスタティックコンストラクタ(のようなもの)を記述する

f:id:takamints:20191215081904p:plain

TypeScriptでスタティックコンストラクタを書く方法の小ネタです。

C#では普通にスタティックコンストラクタを記述できますが、TypeScriptでは書けないようです。

先日「あったらいいな」という状況がありましたので、それっぽい記述を探ってみました。ちょっと無理やりなんですけどね。

実践TypeScript ~  BFFとNext.js&Nuxt.jsの型定義~
吉井 健文
マイナビ出版 (2019-06-26)
売り上げランキング: 14,316
目次

スタティックコンストラクタ?

スタティックコンストラクタとは、主にクラスのスタティックフィールドを初期化するためのもので、最初のインスタンスが生成される前に一度だけ動いてほしいクラスメソッド(みたいなもの)です。

複数のスタティックフィールドを同時に初期化したい場合や、元情報を加工して実行時に使用する情報を作成するといった場合に有用です。

スタティックフィールドを即時実行関数で初期化する

スタティックコンストラクタがなくても、スタティックフィールドは普通に個別に初期化できます。 さらにこの時、以下のように無名関数を即時実行してその戻り値で初期化するのも可能です。

class MyClass {
    static foo:string = (()=> {
        return "foo";
    })();
}

スタティックコンストラクタみたいな記述

無名関数の即時実行を利用すれば、TypeScriptでスタティックコンストラクタ(のようなもの)を以下のように書けます。

class MyClass {

    static foo:string = "foo";

    /**
     * スタティックコンストラクタ(のようなダミーのフィールド)。
     */
    static ctor = (()=>{
        MyClass.foo = "bar";
    })();
}

static ctor というダミーのスタティックフィールドを定義して、即時実行した無名関数の戻り値で初期化しています(ここでは無名関数が何も返していないので結果的には null になります)。

ダミーの名前は ctor である必要はありませんが、本来のインスタンスのコンストラクタとかぶりますから constructor にはできません。

注意すべき点

スタティックフィールドが上から初期化されるということには少し注意が必要です。

以下のように、スタティックコンストラクタよりも下でスタティックフィールドを宣言し、かつ初期化していると意図した動作になりません。コンパイルエラーが出ないので厄介です。

class MyClass {
    /**
     * スタティックコンストラクタ(のようなダミーのフィールド)。
     */
    static ctor = (()=>{
        MyClass.foo = "bar";
    })();

    static foo:string = "foo";
}

初期化していなければ問題はありませんが、ややこしいのでスタティックフィールドはクラス宣言の上のほうで宣言しておいたほうがよさそうですね。

あと、確実にユニットテストを記述するのも有効です。

Gitkの文字化けはAnacondaのせいだった

f:id:takamints:20191203150146p:plain

Gitのコミットログをグラフィカルに見せてくれるGitkですが、いつのころからか、Arch Linux の端末で実行すると、ウィンドウが開くまで数分かかり、さらに日本語が文字化けしてるという状態になっていました。

メインマシンではなかったので、見て見ぬふりを続けてきましたが、先月メモリを16Gバイトに4倍増して、機械学習のお勉強用などとしても使う機会が増えてくると「さすがにこれ以上は放置できない看過できないナントカセネバ!」とイライラしはじめ鼻息荒く調べてみると、割とあっさり「どうやらGitよりも先にインストールしていたAnacondaのせいだったのね」と判明しました。

まあAnacondaがすべて悪いかというと、そうも言いきれないのですが・・・とにかく以下の方法でGitkの文字化けは解消しました。

目次

Gitkの文字が化け化けだ

f:id:takamints:20191203124752p:plain

Gitリポジトリのコミットログじゃなくてウィンドウ自体の日本語が化けてるんですよね。

\u… なんて表示されているのはUnicode文字コードでしょう。 フォントが見つからないのかも。

2つのWishが混在するのが原因でした

GitkはWishを使います

Gitkは wish というコマンドを使っているそうです。

wishはtkパッケージに含まれるコマンドで /usr/bin/wish に配置されるTcl/Tkのインタプリタ。 対話的に画面を作れるツールですね。

ArchLinux公式のGitの説明では、GitkやGitGuiなどのGuiツールを使うにはこの tk パッケージが必要だと書いてあります。

AnacondaもWishを使います

Anacondaもwishを使っているそうです。 しかもAnacondaは、ユーザーのホームディレクトリ以下に独自?の wish をセットアップし、かつ /usr/bin のwish よりも独自のwishが優先的に実行されるように .bashrc を自動的に書き換えてしまいます(↓)。

# added by Anaconda3 Installer
export PATH="/home/<user>/anaconda3/bin:$PATH"

/usr/bin は $PATHに含まれているので、それより先にAnacondaのbinのwishが呼ばれてしまいます(<user>はユーザー名に読み替えてください)。

ワタシはそもそもtkをインストールしていませんでしたが、それでもGitkがなんとか起動していたのは、Anacondaがセットアップしたwishが呼ばれていたからなんですね。

対策は?

tkをインストールする

tkをインストールするには、以下のようにすればOKですが、

$ sudo pacman -S tk

.bashrcで/usr/bin/wishが優先されるように設定書き換え

というとで、.bashrcを以下のように書き換えて、 /usr/bin/wish が優先されるようにします。

# added by Anaconda3 Installer
export PATH="$PATH:/<user>/anaconda3/bin"

動作確認

ターミナルを立ち上げなおして、ちゃんと設定できたか確認しましょう。

まずは、 /usr/bin/ の wish が呼ばれるかどうか。

$ which wish
/usr/bin/wish

そしてGitk。

$ gitk --all&

↓即座に起動&文字化け解消!

f:id:takamints:20191203124220p:plain

まとめると

以下の対策で Gitkが即座に起動するようになり、文字化けも解消しました。

  • tkパッケージをインストール
  • Anacondaのwishではなく /usr/bin/wish が呼ばれるように .bashrc を設定

参考サイト

ja.stackoverflow.com

JavaScriptで文字列のバイト数を得るにはどーする?

f:id:takamints:20191123221032j:plain
photo credit: wuestenigel White tape measure via photopin (license)

ブラウザのJavaScriptとNode.jsで文字列のバイト長を知る方法です。文字数ではありません。 それぞれの環境でやり方が違いますが、統一コードも紹介してます。



目次

はじめに

JavaScriptで文字列のバイトサイズを取得する方法」を検索すると「URLエンコードして文字数を数える」って方法が検索結果の上位にたくさん出てきます。 しかし「こうすればできる」って感じがちょっとアヤシイ。

たいていはNode.jsに言及していないため、

「割と古い方法なのかな?最新式のJavaScriptではもっとスッキリした方法があるのでは?」

と思いまして「ブラウザのJavaScriptとNode.jsの両方の環境で、文字列のバイト長を求める方法」を調べてみました。

結果として、納得できるスッキリした方法がありましたけど、両環境では別方法。 まあ、どちらでも同じやり方が可能なモジュールもありましたので、それも含めて以降で説明しています。

ブラウザでは Blob を使う

ブラウザのJavaScriptでは (new Blob(["文字列"])).size で文字列のバイトサイズが得られます。

少し直感的でないので、関数として書けば以下のようになりますね。

/**
 * 文字列のバイト長を得る(ブラウザ版)。
 * 文字数ではありません。
 * @param {string} s 文字列
 * @returns {number} 入力文字列のバイト長
 */
function byteLengthOf(s) {
    return (new Blob([s])).size;
}

Blobはブラウザでバイナリデータを扱うためのクラスです詳細は以下。 上で使っているのはコンストラクタとsizeプロパティだけですね。

developer.mozilla.org

Node.js では Buffer クラスを使います。

Node.jsなら、Buffer.byteLength("文字列") でOKらしい。こちらはかなり直感的です。

/**
 * 文字列のバイト長を得る(Node.js版)。
 * @param {string} s 文字列
 * @returns {number} 入力文字列のバイト長
 */
function byteLengthOf(s) {
    return Buffer.byteLength(s);
}

nodejs.org

実行時に切り替えるには?

実行時に動作環境がブラウザであるのかNode.jsであるのかを調べて切り替えるには、以下のようにすればよろしいです。

/**
 * 文字列のバイト長を得る。
 * @param {string} s 文字列
 * @returns {number} 入力文字列のバイト長
 */
const byteLengthOf =
    ("window" in (Function("return this;")()) ?
        s => (new Blob([s])).size : // ブラウザ版
        s => Buffer.byteLength(s)); // Node.js版

npm buffer で統一できる

と、ここまで書いて気になって、追加で調べてみたのですが、 Node.jsのBufferクラスをブラウザのJavaScriptで使えるようにした buffer というnpmモジュールがありました。 最初に調べるべきだったかもしれない。

www.npmjs.com

Bundlerが使える場合

WebPackやParcelなどのBundlerを使っているなら、以下のようにrequireで読み込めば(パスにちょっと注意)、 ブラウザのJavaScriptでも Node.js版のコードが使えます。そしてNode.jsでも動作しました。

const Buffer = require('buffer/').Buffer  // 注意:最後のスラッシュは重要!
/**
 * 文字列のバイト長を得る。
 * @param {string} s 文字列
 * @returns {number} 入力文字列のバイト長
 */
function byteLengthOf(s) {
    return Buffer.byteLength(s);
}

Bundlerが使えない場合

Bundlerを使えない場合は、ビルド済みスクリプト( https://bundle.run/buffer )をHTMLのSCRIPTタグで読み込めば Buffer クラスが使えるようになるらしい(こちらに関しては未検証です)。

<script src="https://bundle.run/buffer"></script>
/**
 * 文字列のバイト長を得る。
 * @param {string} s 文字列
 * @returns {number} 入力文字列のバイト長
 */
function byteLengthOf(s) {
    return Buffer.byteLength(s);
}

あとがき

検索でトップに出てくる情報が完全に正しい情報だとは限らないと思いました。 この場合は、完全な間違いとも言い切れませんが。

JavaScriptは既にかなりな歴史が積み重なっていて、徐々に仕様が整備されてきたので、どうしても古い情報が残りがちですね。 これから始めようとする人たちにとっては弊害となることがありそうな気もします。

このような点からも、最近はPythonが流行っているということもあるのかなと(知らんけど)

このような心配とはまた別に、JavaScriptではnpmとかBundlerの類はストレスなく使えるようになっておいたほうが良さそうですね。 モダンJavaScriptバンザイです。いくつになってもお勉強です。

祝!MZ-700シリーズ発売37周年っ!に合わせてMZ-700フルJavaScriptエミュレータをWebWorkerでレンダリング!

f:id:takamints:20191115205104p:plain
1986 Tiny XEVIOUS namco (拙作「MZ-700フルJavaScriptエミュレーター」で撮りました)



今年もやってきました11月15日の祝日が(えっ?) SHARP MZ-700シリーズの発売日ですよ。ちょうど37年目のお祝いです。 発売日は 1982年11月15日。 当時ワタシはおそらく中学2年生(←昔過ぎて正確な年齢が算出できない)。 そら50歳にもなるわけだ(笑)

昨年のお祝いエントリーはコチラ↓です。

takamints.hatenablog.jp

MZ-700との出会いはたまたまでした。 1982年の年末に、機械関係、メカトロ関係のエンジニアだった父が買ってきたんですね。 プロッタプリンタのついていたMZ-731というモデルでした。 仕事で使うつもりだったみたいですが。

それから数年、兄とともに濃厚濃密な年月を過ごしました。 最初にBASICを覚えてから、機械語ってのが速いらしいと小耳にはさんでZ80のハンドアセンブルにいそしみました。 市販のゲームもやるっちゃあやるんですが、プログラムを作れば作った通りに動くってこと自体が楽しくて、Oh!MZを筆頭に、I/O、マイコンベーマガ読んで、あーだこーだとやっていました。

しかしそのうちに、文字しか表示できないMZ-700に引け目を感じるようになってしまい、X-1が良かったなーなんて思いながら一念発起、MZ-700の後継機種として発売されたMZ-1500を入手しまして、徐々に気持ちがMZ-700から離れていきました。ちなみにこの時MZ-1500に同梱されてたPSG6音を鳴らせるピアノロールみたいなソフトを使って和音の面白さにめざめて、その後の音楽趣味につながります。9割9分打ち込みだけど、Jazzコード理論(初歩)は独学。

Tiny XEVIOUS for 700 の衝撃

そのころは、世間的にも「MZ-700はオワコン」的な雰囲気になっていたと思うのですが、Oh!MZに唐突に「Tiny XEVIOUS for MZ-700」 という目も耳もなんなら鼻や口すら疑うような記事が載り、ワタシのあごは落ちました。ガクー

※ Tinyという単語はTiny XEVIOUS以前にも雑誌掲載のゲームなどでよく使われていた印象がありますが、このTinyは確かにTinyなんだけどさ、まったくTinyではありませんよね(?)。

これは「MZ-700に不可能はない!」との名言が生まれるきっかけとなったであろう古旗一浩さん作(というか移植)のゲームですけど、実は自分は当時これを打ち込んでもいなくて遊んでいません。

というのも、既にXEVIOUSはゲーセンでやり倒していたし、目の前にはMZ-1500があるしという状況。 「サンダーフォースやれるからもういいよ」的な気持ちだったなあ。

しかし、このとてつもないチャレンジ精神にあふれたほぼ同世代の古旗一浩という人の存在を知ったがために、「自分は薄っぺらくてダメなやつだ情けない」てな気持ちになってしまったのも影響していたように思います。

まるくんの MZ700Win

なんだかんだで、その後、制御系のソフト会社へもぐりこみましたが、既に時代は個人ユースでもNECPC-9801の独壇場。8ビットのPCなんて既に製造されていませんし、自分の中でMZはもう過去のものとなっていました。しかし、そこから10年、世間はインターネットとWindows。2000年ごろふと知った「まるくん」こと丸山武志さん作のWindowsMZ-700エミュレータ MZ-700Win。 当時VC++で仕事していたし、すげーなるほどこういうの作れるんだへぇーーーみたいな印象で、懐かしいゲームなどを再び楽しめて感動しました。

拙作 MZ-700フルJavaScriptエミュレータ

と、ここまで長くなりましたが、さらに10年後、世の中はHTML5Ajaxでできていて、ふと「MZ-700 のエミュレーションはJavaScriptで可能ではないだろうか?」と一念発起。

MZ-700って、発売当時は当たり前だったのかもしれませんが、Owner's Manualに回路図が載っているんですよね。 なので内蔵されてるICなどのデータシートを読み取って、それぞれJavaScriptエミュレータを書いていく。 当然Z80の命令もJavaScriptでコーディング。

この当時はWebWorkerの存在もほぼ知らず、タイマー駆動でCANVASに画面を描いていました。 最初は1枚のCANVASでなく40文字×25行のPNG画像で画面を構成してました。

今ではそれなりに最新機能も取り入れて高速化。 ずいぶん前からnpmとして提供しており、本日 v1.2.9 をリリースしました(追記:最新はnpmのGlobalインストール時の不具合を解消したv1.2.10)

node.jsを使える人は、npm install --global mz700-jsでグローバルインストールできます。コンソールからmz700-js` コマンドでWebAppが起動します。

takamin.github.io

mz700-js @1.2.9

OffscreenCanvasに対応しているブラウザでは、画面の描画はサブスレッド側で行われます

従来WorkerスレッドからのVRAM書き込み要求をメインスレッドに伝えて描画していましたが、ある程度キャッシュしないと速度低下につながりましたので、100msはキャッシュをしていました。 今回サブスレッドで描画するようにしましたが、これも逐一更新するとちらつきが多くなってむしろ低速。 バッファリングを10msに短縮すればなんとか納得いく速度を実現できました。

従来Chromeが速度と安定度でおすすめでしたが、相対的に低速だったEdgeやFirefoxで、今回それなりのパフォーマンスが出るようになっていて「おいおいChromeうかうかしてられへんぞー」という気分。とはいえやっぱりChromeの挙動が一番安定していて安心できるのも事実です。

描画方式を変えると、Tiny XEVIOUSのタイトル画面がビカビカしていました。

書き換えタイミングを変えたことでかなり高速に書き換えが発生しているようで、細かい動きの再現性が高まりました。実機の動きに近づいたかも?!