kmaebashi.comをSSL化しました

先日サーバ移転した私の個人サイト「K.Maebashi's home page」(kmaebashi.com)について、前々からやりたいと思っていたSSL化を実施しました。これにより、URLが

http://kmaebashi.com

から

https://kmaebashi.com

に変更になります。

今まで通り、http://kmaebashi.com~でアクセスしても、https://kmaebashi.com~に自動的に切り替わるように設定したので、閲覧者の皆様には特に影響ないかと思います。

SSL(Secure Sockets Layer)は通信の暗号化の技術です*1。もとより世界中に制限もなく公開しているWebサイトで、別にクレジットカード番号や個人情報を入力するところもないのに*2、なんで通信の暗号化をする必要があるのか、とも思わなくもないですが、一応うちのサイトではプログラムを載せたりしているので身元保証は必要でしょう。ドメイン認証の証明書なので「kmaebashi.comを運営している人は信用できる」と思っていただける方にしか意味はありませんが、送信元がkmaebashi.comであるということは保証できます。

こういう個人サイトでは、Let's Encryptという無料の証明書を使うのが定番のようです。これは無料はいいのですが3か月で期限が切れるので、普通はcertbotというツールを使って自動更新するように設定します(最初の導入にもcertbotを使います)。で、certbotをインストールするにはEPELリポジトリとかいうのを入れなければいけなくて、EPELリポジトリを入れた状態でdnfでインストールしようとしたらdnfがkilled.と言われて常に落ちるようになってしまった(certbotに限らず、何を入れようとしても、check-updateするだけでも落ちる)。慌てて戻して調べると、どうやらメモリ不足のようで、私が見つけたページでは512MBくらいのメモリのサーバを使っている人が「最低1GBは必要」とか書いていたけど要件が上がったのかうちの1GBのサーバでも動かないようだ。それなら一時的にサーバのメモリを2GBに上げて、インストールが終わったら戻すか、と思ったら、どうも一時的にサーバのメモリを上げるだけでも1年分の料金が取られるようで、それなら有償の証明書――年間980円のJPRSの証明書を買った方がマシだな、ということでそっちにしました。certbotで入れるより手間はかかりましたけれども。

今後ともよろしくお願いいたします。

*1:SSLは古い規格で、今実際に使われているのはTLS(Transport Layer Security)という技術ですが、「SSL化しました」とか言う時には今でもSSLと言うことが多いようなので、ここでもそう書いています

*2:一応掲示板には削除用のパスワードを設定できますが、こんな掲示板に、大事なパスワードを使い回す人はいないと信じたい。

kmaebashi.comのサーバ移転を行いました

私の個人Webサイトである「K.Maebashi's home page」(kmaebashi.com)を置いていたレンタルサーバ業者が事業を撤退するとのことで、新たにさくらインターネットVPSを借りてそちらに移転しました。

昨晩20:00頃にDNSの更新を行いました。TTLはデフォルトで3600秒だったので、DNSの浸透()は最長1時間で終わるはずで、今kmaebashi.comを見たら確実に新しい方のサーバが見えている、のではないかと思います。

http://kmaebashi.com

これが想定している新しいサーバを見たときの画面、

移転後サーバの画面

もし何らかの事情で古いサーバが見えてしまったとしたら、以下の画面になります。

古いサーバの画面

もし下の方の画面が見えてしまったら、掲示板なりここのコメント欄なりで教えてください(まあ、教えていただいたとして、私にできることはないように思いますが)。

このホームページは、最初に作ったのは1998年頃、私が使っていたプロバイダ(Nifty)のホームページスペースに置いたのが始まりです。その後、ドメインkmaebashi.comを取って移転して、そのレンタルサーバ業者が破産してサーバの再販元に引き取られたりとか、ところがその後もDNSはつぶれた会社に依存していて2017年頃に一度止まってしまったりとか、実はその後もそのDNSに依存していたらしいということが今回の移行で発覚したりとか色々ありましたが、なんやかんやでNiftyから数えれば25年にわたり運営してきたページです。今は見てくれる方も減ったとは思いますが、サーバがなくなるに任せて消えてしまう、というわけにはいきませんね。著書の正誤表なんかもここにありますし。

このページには、動的コンテンツとして、掲示板とアクセスカウンタがあります。掲示板は、元のものは「レンタルサーバでそれしか使えなかった」という理由でPHP + MySQLで書きましたが(2005年頃)、今回はVPSで言語も自由に選べるので、Java + Spring boot + PostgreSQLでゼロから作り直しました。データも移行済みです。この掲示板は、パスワードを設定しておけば自分の投稿を後から削除できるのですが、その削除用パスワードも「ほぼ」移行できたと思います。元の掲示板はパスワードにランダムなSALTを付けてMD5でハッシュしたものをDBに保持していて、そのままでいいかな、と思っていたら、ちょうど作り直している最中にMD5のパスワードが抜かれたというニュースがあったりして(この例ではSALTもついてなかったようですが)、MD5でハッシュ化したものに再度bcryptをかけるようにしました。「ほぼ」移行できたというのは、元のパスワードにシングルクォート等が入っていた場合、旧掲示板ではPHPのmagic_quotes機能で変換されてしまっていたからです。だからこんな変な機能を使ってはいけなかったんだ! (参考)

掲示板のURLは以下。拡張子が.phpになっていますが、これは過去投稿へのリンクを維持するためで、上述の通り中身はPHPではありません。

http://kmaebashi.com/bbs/list.php?boardid=kmaebashibbs

あとはアクセスカウンタ。これもJava + 生Servlet + PostgreSQLで書き直しました。私は「プログラムは依存が少ないほどえらい」と思っているのでさすがにこんなのにSpring bootとか使う気にはなれず。でもTomcatのコネクションプールは使った。

いまどき、「ホームページ」に「アクセスカウンタ」を、わざわざスクラッチで作り直してまで配置する奴もめずらしいかと思いますが、「元ページにあるものは基本全部引っ越す」方針としました。アクセスカウンタとか掲示板とかの作成記事はまた別途書こうと思います。

あまり更新もしていない過疎サイトですが、今後ともよろしくお願いいたします。

Rustで親への参照を持つ木構造

前回の記事、Rustで木構造の続きです。
前回の木は、親が子への参照を持つ1方向の木でしたが、今回は、子が親への参照も持つようにします。親が子への参照を持つだけであれば、各ノードを指す参照は必ずひとつなのでBoxが使えましたが、子が親への参照も持つとなると各ノードが複数の箇所から参照されることになり、かつ、循環参照になります。こういう場合は、親から子への参照を参照カウンタ式のスマートポインタ型であるRc(reference countingの略)とし、子から親への参照を弱参照(weak reference)で保持します。
図にするとこんな感じ。

題材としては、「The Rust Programming Language」の以下のページでやっていることそのものです。
doc.rust-jp.rs
だったら丸写しするだけじゃん、と思われるでしょうが、まあ慣れない言語で自分で組んでみるとそんなことでもはまるものです。
上の図にある木構造を作って、それを行きがけ順で走査するプログラムが以下。

use std::rc::Weak;
use std::rc::Rc;
use std::cell::RefCell;

struct Node {
    value: i32,
    children: RefCell<Vec<Rc<Node>>>,
    parent: RefCell<Weak<Node>>
}

impl Node {
    fn new(value: i32) -> Node {
        Node {
            value: value,
            children: RefCell::new(Vec::new()),
            parent: RefCell::new(Weak::new())
        }
    }
}

fn main() {
    let root = Rc::new(Node::new(0));

    let node1 = Rc::new(Node::new(1));
    *node1.parent.borrow_mut() = Rc::downgrade(&root);

    let node2 = Rc::new(Node::new(2));
    *node2.parent.borrow_mut() = Rc::downgrade(&node1);
    node1.children.borrow_mut().push(node2);

    let node3 = Rc::new(Node::new(3));
    *node3.parent.borrow_mut() = Rc::downgrade(&node1);
    node1.children.borrow_mut().push(node3);
    root.children.borrow_mut().push(node1);

    let node4 = Rc::new(Node::new(4));
    *node4.parent.borrow_mut() = Rc::downgrade(&root);

    let node5 = Rc::new(Node::new(5));
    *node5.parent.borrow_mut() = Rc::downgrade(&node4);
    node4.children.borrow_mut().push(node5);

    root.children.borrow_mut().push(node4);

    dump(&root);
}

fn dump(node: &Rc<Node>) {
    print!("node({}) ", node.value);
    match node.parent.borrow().upgrade() {
        Some(parent) => {
            println!("parent..{}", parent.value);
        },
        None => {
            println!("parent..None");
        }
    }
    for child in &*node.children.borrow() {
        dump(child);
    }
}

実行結果はこんな感じ。

node(0) parent..None
node(1) parent..0
node(2) parent..1
node(3) parent..1
node(4) parent..0
node(5) parent..4

単にRcとWeakで木構造を作るだけなら、こう書けばよいのでは、と思うかもしれませんが、

use std::rc::Weak;
use std::rc::Rc;

struct Node {
    value: i32,
    children: Vec<Rc<Node>>,
    parent: Weak<Node>
}

impl Node {
    fn new(value: i32) -> Node {
        Node {
            value: value,
            children: Vec::new(),
            parent: Weak::new()
        }
    }
}

fn main() {
    let root = Rc::new(Node::new(0));

    let node1 = Rc::new(Node::new(1));
    node1.parent = Rc::downgrade(&root);
    root.children.push(node1);
}

これだと、以下のエラーが出ます。Rustでは、「共有されているものには書き込めない」ので、Rcの指す先に書き込むことはできません。

error[E0594]: cannot assign to data in an `Rc`
  --> src\main.rs:24:5
   |
24 |     node1.parent = Rc::downgrade(&root);
   |     ^^^^^^^^^^^^ cannot assign
   |
   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Node>`

error[E0596]: cannot borrow data in an `Rc` as mutable
  --> src\main.rs:25:5
   |
25 |     root.children.push(node1);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
   |
   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Node>`

Rcの指す先のものに書き込みたければ、最初に挙げたプログラムのように、RefCellで包む必要があります。

で、ここまでは、上で挙げた「The Rust Programming Language」に書いてあることそのものなんですが。
私がはまったのは、dump()関数の中の以下のループのところです。

    for child in &*node.children.borrow() {
        dump(child);
    }

たとえば、main()の中で、rootの子としてnode1を足すところにはこう書いてあって、

    root.children.borrow_mut().push(node1);

RefCellからborrow_mut()で書き換え可能な参照を借用し、それに対してpush()をいきなり呼んでいる、ということは、root.children.borrow_mut()はVecと同じように扱えるのだな、と思って、dump()関数を最初はこう書きました。

fn dump(node: Rc<Node>) { // 引数の型も違う。後述。
    print!("node({}) ", node.value);
    match node.parent.borrow().upgrade() {
        Some(parent) => {
            println!("parent..{}", parent.value);
        },
        None => {
            println!("parent..None");
        }
    }
    for child in node.children.borrow() { // ←ここ
        dump(child);
    }
}

しかしこれはコンパイルエラー。

error[E0277]: `Ref<'_, Vec<Rc<Node>>>` is not an iterator
  --> src\main.rs:58:18
   |
58 |     for child in node.children.borrow() {
   |                  ^^^^^^^^^^^^^^^^^^^^^^ `Ref<'_, Vec<Rc<Node>>>` is not an iterator
   |
   = help: the trait `Iterator` is not implemented for `Ref<'_, Vec<Rc<Node>>>`
   = note: required because of the requirements on the impl of `IntoIterator` for `Ref<'_, Vec<Rc<Node>>>`

For more information about this error, try `rustc --explain E0277`.

node.children.borrow()の型はVec>>だと言っている。つまり、node.children.borrow_mut().push()の時はピリオドがあったから自動参照外しが行われたけれど、for文のinのところにただ置いただけでは自動参照外しはしてくれないということか。
そこで、手動で参照を外すため*を付けたら、

    for child in *node.children.borrow() {
        dump(child);
    }

これもコンパイルエラー。

error[E0507]: cannot move out of dereference of `Ref<'_, Vec<Rc<Node>>>`
  --> src\main.rs:58:18
   |
58 |     for child in *node.children.borrow() {
   |                  ^^^^^^^^^^^^^^^^^^^^^^^
   |                  |
   |                  value moved due to this implicit call to `.into_iter()`
   |                  move occurs because value has type `Vec<Rc<Node>>`, which does not implement the `Copy` trait
   |
note: this function takes ownership of the receiver `self`, which moves value
help: consider iterating over a slice of the `Vec<Rc<Node>>`'s content to avoid moving into the `for` loop
   |
58 |     for child in &*node.children.borrow() {
   |                  +

For more information about this error, try `rustc --explain E0507`.

まあこのエラーは見慣れてる。Vecはコピーできないから、こういう場合は&を付けて参照を見ればよいのだ。

fn dump(node: &Rc<Node>) {
    print!("node({}) ", node.value);
    match node.parent.borrow().upgrade() {
        Some(parent) => {
            println!("parent..{}", parent.value);
        },
        None => {
            println!("parent..None");
        }
    }
    for child in &*node.children.borrow() {
        dump(child);
    }
}

というわけでこうなって、実際動いたわけですが、なんかこの「&*」のあたり、「これでいいの?」と思ってしまう。

ていうかRustの参照外し演算子の「*」ってなんで前置なの? もちろんCの*も前置ですが、これはCの作者Dennis Ritchieが、1981年に後置の方がよかったと指摘され、「but by then it was too late to change. 」(しかし、その時には、変更するにはもう遅すぎた」と言っているような仕様なのに。自動参照外しがあるからいいというものではなく、だいたい自動とか暗黙とかそういったものは混乱を招くものなのに。まさに今回私がはまったように。

なにかこう、Rust初心者の私の知らない理由があるんでしょうか。

Rustで木構造

最近Rustの勉強を始めました。手始めに以前Javaで作った簡易プログラミング言語samplanでも実装してみようかと思ったのですが、コンパイラを作るとなれば解析木が作れなければ話にならず、では木を作ろうとするとRustといえば所有権だのなんだのと参照(ポインタ)の扱いが大変なのが知られているわけで、ひとまず小さなサンプルプログラムで木構造を作ってみました。Boxを使って、こんな感じの木構造を作ります。
木構造の図

// 木構造のノードを表す構造体。
// 複数の子を指す参照をVecで保持している。
struct Node {
    value: i32,
    children: Vec<Box<Node>>
}

impl Node {
    fn new(value: i32) -> Node {
        Node {
            value: value,
            children: Vec::new()
        }
    }
}

fn main() {
    let mut root = Node::new(0);
    let mut node1 = Node::new(1);
    let node2 = Node::new(2);
    node1.children.push(Box::new(node2));
    let node3 = Node::new(3);
    node1.children.push(Box::new(node3));
    root.children.push(Box::new(node1));
    let mut node4 = Node::new(4);
    let node5 = Node::new(5);
    node4.children.push(Box::new(node5));
    root.children.push(Box::new(node4));

    dump(root);
}

// 木構造を行きがけ順(先行順)でダンプする
fn dump(node: Node) {
    println!("node({})", node.value);

    for child in node.children {
        dump(*child);
    }
}

まあ、簡単です。ヒープに領域を確保するにはBoxを使う、というのはRust独特ですが、それを除けばCやJavaに慣れた人なら読めるコードだと思います。所有権云々で気を付けなければいけないのは、main()の中で木構造を作っているところで、たとえばこんなふうに、「Nodeを作ったらとりあえず親に登録しておこう」という方針で書くと、変数が所有権を失って以後使えなくなるので、順番に気を付ける必要がある、ということぐらいです。

fn main() {
    let mut root = Node::new(0);
    let mut node1 = Node::new(1);
    root.children.push(Box::new(node1)); // node1をrootの子として登録した時点で、変数node1は所有権を失う
    let node2 = Node::new(2);
    let node3 = Node::new(3);
    node1.children.push(Box::new(node2)); // だから、ここでnode1は使えない
    node1.children.push(Box::new(node3));
    let mut node4 = Node::new(4);
    root.children.push(Box::new(node4));
    let node5 = Node::new(5);
    node4.children.push(Box::new(node5));

    dump(root);
}

上記のソースだと、こんなエラーが出ます(抜粋)。

error[E0382]: borrow of moved value: `node1`
  --> src\main.rs:23:5
   |
19 |     let mut node1 = Node::new(1);
   |         --------- move occurs because `node1` has type `Node`, which does not implement the `Copy` trait
20 |     root.children.push(Box::new(node1));
   |                                 ----- value moved here
...
23 |     node1.children.push(Box::new(node2));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move

……まあ、その程度のことで、ここまでは簡単なんです。
しかし、プログラミング言語の解析木だと、こんな単純な木構造では済まず、「子から親への参照」が必要になる部分もあります。samplanのような言語(CやJavaも同じですが)では、波括弧で囲まれたブロックがスコープを示し、各ブロックの中では、その外側のブロックで宣言された変数とかが参照できます。そうなると、子のブロックから親のブロックへの参照が保持できないと嬉しくありません。
それをやってみたらえらく大変だったのですが、その話はまた次回に。乞うご期待!

「完全初心者のためのプログラミング入門」完結しました

2021年の6月頃に初公開した「完全初心者のためのプログラミング入門」に、以下の二つのページを加えました。これにて完結となります。

ここまでは「UFOゲーム」を作ってきましたが、最終回である今回は、こんな感じのシューティングゲームを作ります。

シューティングゲーム」の画面

下にあるキャノン砲で、敵を撃墜するゲームです。敵は、UFO、エイリアン、フライングボード(くるくる回りながら落ちてくる板です。何かに似ていますが気にしないように)、それからエイリアンが落とす爆弾の4種類です。実際のゲームは、こちらで遊べます。

ここまで作ってきたUFOゲームに比べると、相当複雑なプログラムに思えるのではないでしょうか。実際それなりにプログラムは長くなっていますが、メソッドオーバーライドとかポリモルフィズムとかのオブジェクト指向の機能により、それほどごちゃごちゃにならずにプログラムが組める、ということを示せたと思います。今後、敵の種類をもっと増やすのも簡単にできるようにしています。

一昔前は、「オブジェクト指向」について、難しいとかわからないとかそんなものは役に立たないとか、そんな意見が山ほど出ていましたが*1、実際にこのような「オブジェクト指向が明確に役に立つ例」を見てみれば、そういう疑問も解消するのではないかと思います*2

JavaScriptの「オブジェクト指向」はやわかり』の方は、class構文を使わない、昔ながらのJavaScriptオブジェクト指向を実現する方法について説明しています。いまどきそんなのなんの役に立つのか、と思うかもしれませんが、JavaScriptのclass構文が単なるシンタックスシュガーにすぎない以上、知らないで済ませることはやはりできないでしょう。

これを始めたときに書いたはてなブログがこれです。

kmaebashi.hatenablog.com

この記事の最後で、『最終的には、これくらいのシューティングゲームくらいまで持っていきたいと思っていますが、さて、どうなりますことやら。』と書いていますね。どうやらそこまで持っていくことはできました。いやあ長かった。

入門記事本体の「なぜこんなのを書いたのか」にも書きましたが、この「入門」は、1982年の「マイコンBASICマガジン」(略してベーマガ)の記事「UFOゲームを作ってみよう」へのオマージュです。しかし、当時の私には、UFOゲームは作れても、このシューティングゲームくらい複雑なプログラムは書けなかったと思います。今書けるのは、もちろんプロとして30年くらいやってるので当たり前ではあるのですが、ハードウェアの進歩(1982年当時なら、このゲームは機械語が必要だったでしょう)のほか、プログラミング言語や技法の進歩もあると思っています。今の若い人はここから始められて幸運だ、ぐらいのことは言っていいかもしれません。

多くの人が、プログラミングの楽しみに触れられますように。

 

*1:最近あまり聞かない気がするのは、たぶんみんながオブジェクト指向を理解したためではなく、話題としてトレンドではなくなったため、理解している人は普通に使っているが理解できない人が無理して理解する必要がなくなったからじゃないかなあ。

*2:その上で、そういう役に立つ範囲がどれぐらい広いのかはまた別問題

Vue.jsでテトリス風ゲームを作ったよ

タイトルの通り、Vue.jsでテトリス風のゲームを作りました。

http://kmaebashi.com/programmer/vuetetris/index.html

ゲーム画面はこんな感じ。

遊び方やゲーム本体のページへのリンク、ソースプログラム一式は上記のページに記載しています。

見た目、前回のCanvasを使ったJavaScriptテトリスReact.js版テトリスと何が違うんだ、と言われそうですが、中身は結構違うのです。いやほんと。

React.js版と同様、ゲーム画面はtableで組んでいます。React.jsに比べると、Vue.jsはアプリそのものの作り方がまるっきり変わってしまう、というわけではなくてよいですね。

しかしVue.js、「splice()とかpush()を使わず、配列の要素に直接代入すると、それを検知してくれないのでDOMが更新されない」ってのは落とし穴ですな。みんなはまっているようですが私もはまりました……

 

WordleとKotobade Asobou 言葉で遊ぼうの過去の解答ページを作りました

タイトルの通りですが、Wordleと「Kotobade Asobou 言葉で遊ぼう」の過去の解答ページを作りました。2022年6月からの分を掲載しています。

 

Wordle

http://kmaebashi.com/etc/wordle.html

 

Kotobade Asobou 言葉で遊ぼう

http://kmaebashi.com/etc/kotobade_asobou.html

 

時々更新するつもりですが、カンニング用のページにするつもりはないので、世界中のどこかでまだ誰かが解いているものは載せません。後から「あんな解答あったねえ」と振り返るページです(需要があるかどうかは知りませんが)。