Shogo's Blog

Sep 10, 2023 - 1 minute read - go golang

log/slogにログを転送する logrus hook を書いた

長らく構造化ログの仕組みが標準ライブラリになかったGoですが、 Go 1.21がリリースされて晴れて log/slog が使えるようになりました。 弊社ではlogrusを使っているので、log/slogを連携するためのフックを書きました。 背景 弊社ではlogrusをメインに使っています。 特段困ったこともなく 素晴らしいライブラリだと思います!!!(大事) 強いて問題点を上げるとすれば、メンテナンスモードに入ってしまってあまり開発が活発でない、ということでしょうか。 重大なバグがあれば別ですが、新規機能の追加等は行わない方針のようです。 一方 log/slog は公式ライブラリなので、log/slogの仕様を前提としたエコシステムが、今後発展してくでしょう。 logrusを使いながらlog/slogのいいとこ取りとする方法はないか?と考えた結果作ったのが shogo82148/logrus-slog-hook です。 SYNOPSIS sloghook.New で作成したフックを差し込むだけです。 logrusに流したログがlog/slogの設定で流れてきます。 package main import ( "io" "log/slog" "os" sloghook "github.com/shogo82148/logrus-slog-hook" "github.com/sirupsen/logrus" ) func main() { h := slog.NewTextHandler(os.Stderr, nil) logrus.AddHook(sloghook.New(h)) // logrus も logrus-slog-hook もSTDERRに書き込むので、同じログが二回表示されてしまう。 // logrus側を止めて防止。 logrus.SetFormatter(sloghook.NewFormatter()) logrus.SetOutput(io.Discard) logrus.WithFields(logrus.Fields{ "name": "joe", "age": 42, }).Error("Hello world!") // Output: // time=2023-09-10T23:32:41.229+09:00 level=ERROR msg="Hello world!" age=42 name=joe } 注意点 logrusはエラーレベルが Trace, Debug, Info, Warn, Error, Panic, Fatal と7段階ありますが、 log/slogには Debug, Info, Warn, Error しかありません。 しかし実は整数をレベルを設定できるので、適当に割り当てました。

Sep 8, 2023 - 2 minute read - github github-actions

actions/checkout@v4の襲撃を受けた件

先日 actions/checkout@v4 がリリースされましたね。 actions/checkout@v4 まあ、何が言いたいかというと、「メジャーバージョンアップ多すぎじゃない???」という話。 actions/checkout@v4の襲撃 新規に作成したレポジトリには基本的にdependabotをセットアップしています。 まあそんな状況下で actions/checkout@v4 なんてリリースされたら、こうなるわけですよ。 actions/checkout のアップデートつらい pic.twitter.com/4bNeCFsE4Y — f96fd3a0-bdb9-4f10-b69f-8f765c1d341c ICHINOSEShogo (@shogo82148) September 5, 2023 よほど単純なワークフローでない限り、 actions/checkout は必須のアクションです。 GitHub Actions でCIを組んでいるレポジトリはもれなく使っています。 @shogo82148以下にあるレポジトリだけで、76個のプルリクエストが来ました。 心を無にしてマージボタンを押しまくりました。 他のorgにも参加しているので、実際に対応したプルリクエストはもっと多いです。 Node.js 16 のEOLが近い 背景には Node.js 16 が9月11日にEOLになるという話があります。 actions/checkout@v3 は Node.js 16 で動くので、当然サポート対象外になります。 そこで新しいバージョンが必要なわけです。 actions/checkout@v4 は Node.js 20 で動くようになりました。 GitHub Actions はセフルホストできるので、まだ Node.js 20 が動かない環境も残っています。 そのような環境でオプトインできるよう、メジャーバージョンアップにしたのだと思います。 Node.js 18 がスキップされた話 ちなみに Node.js 16 と Node.js 20 の間には Node.js 18 が存在するわけですが、 Node.js 18 はスキップされました。 (Node.

Sep 4, 2023 - 4 minute read - go golang

ぼくのかんがえたさいきょうの[0.0, 1.0)の乱数を得るための方法

Twitterもとい𝕏でこんなスライドが流れてきました。 $[0.0, 1.0)$ の範囲を保証しつつ、浮動小数点数が表現可能なすべての値をとるのは難しい、というお話です。 なるほど・・・確かに改めて考えてみると「浮動小数点数が表現可能なすべての値」という条件は難しいですね。 でも、スライド中で紹介されていたアルゴリズムには、もうちょっと最適化の余地があるのでは?と考えてみました。 Goの標準ライブラリでの実装 もとのスライドはC++の話っぽいけど、C++はよくわからないので、Go言語での実装を考えます。 除算法 Goの標準ライブラリはスライド中で「除算法」と呼ばれている方法で乱数を生成します。 Go 1.21.0 の実装: https://github.com/golang/go/blob/33d4a5105cf2b2d549922e909e9239a48b8cefcc/src/math/rand/rand.go#L188-L212 // Float64 returns, as a float64, a pseudo-random number in the half-open interval [0.0,1.0). func (r *Rand) Float64() float64 { // コメント略 again: f := float64(r.Int63()) / (1 << 63) if f == 1 { goto again // resample; this branch is taken O(never) } return f } 除算法は大変シンプルですが、丸め誤差の影響で誤って 1.0 を返すことがあります。 Goは乱数を再生成することで、この問題を回避しています。 過去の実装 実際 Go 1.2 までは 1.

Sep 3, 2023 - 1 minute read - memo

ウェブ魚拓の創業者のインタビュー記事のウェブ魚拓

年に一度くらいこういうことありませんか? ウェブ魚拓の創業者のインタビュー記事読みたいな、と思って探したら、メディアが終了していてもう読めない。ウェブ魚拓を取っておけば・・・https://t.co/qpC5EdFQIJhttps://t.co/9JITbnj5ZM — f96fd3a0-bdb9-4f10-b69f-8f765c1d341c ICHINOSEShogo (@shogo82148) June 12, 2023 (はっ・・・?今年2回目・・・?) https://t.co/xzuix067a0 魚拓にあるって教えて貰ったので引っ張り出してきた。 — V (@voluntas) June 13, 2023 【魚拓】炎上の歴史とともに10周年、あの「ウェブ魚拓」創業者に会ってきた | HRナビ by リクルート https://t.co/RHWwoQwfVn 【魚拓】“握力の強さ”で日本一に 「ウェブ魚拓」創業者はいかにして肉体派プログラマーになったか | HRナビ by リクルート https://t.co/63arUxyU7Y… — V (@voluntas) June 13, 2023 Twitterもとい𝕏は最近雲行きが怪しいので、ぱっと見られるようにリンクを貼っておきます。 【魚拓】炎上の歴史とともに10周年、あの「ウェブ魚拓」創業者に会ってきた | HRナビ by リクルート 【魚拓】“握力の強さ”で日本一に 「ウェブ魚拓」創業者はいかにして肉体派プログラマーになったか | HRナビ by リクルート 新沼大樹さんも伏黒パパの役イケそう。 「呪術廻戦」伏黒パパがリアルに顕現!? 漫画みたいにTシャツへ浮き出る腹筋が「フィジカルギフテッド」と話題 魚拓

Sep 3, 2023 - 2 minute read - perl

湘南.pm #1 で「趣味でPerlのビルドをしている話」をしてきた

すでに一週間が過ぎ、今更感がありますが・・・ 「ブログに書くまでがYAPC」もといPerl Mongersという言葉もあるのでやっていきましょう。 @__papix__に声をかけていただき、8/26に開催された湘南.pm #1で発表してきました。 「趣味でPerlのビルドをしている話」と題して、AWS::Lambdaとactions-setup-perlのお話をしてきました。 趣味でPerlのビルドをしている話 資料はSpeaker Deckを見てもらうとして、簡単に補足等します。 AWS::Lambda うっかりサンプルコードの末尾に 1; を付けてしまいましたが、なんと!最新のPerlでは不要になりました! use 5.38; use utf8; sub handle ($payload, $context) { return $payload; } # 1; # ↑ スライド資料では付けてしまったけど、なくてよい これは use 5.38 で module_true feature が有効化されるためです。 詳細は「Perlのmodule_trueフラグを先取り!」という記事を書いたのでそちらをどうぞ。 この記事を書いたときは開発版のPerlで試しましたが、 Perl 5.38 で正式リリースされています。 Perl Hackers Hub に掲載したサンプルコードを流用したことがバレてしまう・・・。 Perl Hackers Hub 第75回 AWS Lambda入門 サーバレスでもPerlを活用しよう!(1) Perl Hackers Hub 第75回 AWS Lambda入門 サーバレスでもPerlを活用しよう!(2) さて、このサンプルコード、他にもPerlの(比較的)新しい機能を使っているのですが、気がついたひとはいますか? 実は引数の受け取り方が変わっています! Perlには元々「サブルーチンの引数を定義する構文」がありませんでした。 @_ という記号を使うか、 shift などの配列操作関数を使います。 use utf8; # 昔からある引数の受け取り方 sub handle { my ($payload, $context) = @_; return $payload; } 1; 記号が多くて大変初心者泣かせですね。

Aug 12, 2023 - 3 minute read - go golang

Eytzinger LayoutをGoで試してみた

2021年のスライド資料だけど、たまたま𝕏に流れているを見かけました。 このスライドでEytzinger Layoutという配列をはじめて知ったのでメモ。 Eytzinger Layout 16世紀のオーストリアの貴族Michaël Eytzingerが考案したことから、この名前がついたそうです。 もともとはヨーロッパの王様の家系図に番号をつけるための方法です。 ある人物の番号が$k$のとき、父親に$2k$、母親に$2k+1$と番号をつけます。 このルールを使うと家系図に登場するすべての人物にユニークな番号をふることができます。 この番号付けのルールをバイナリツリーに応用すると、ツリー構造をポインターを使わずに表現できます。 二分ヒープを配列で表現するときの実装としてよく登場するのを目にします。 こういう名前がついているのは知らなかった。 バイナリサーチとEytzinger Layoutの関係 イマドキのCPUは非常に高速で、CPUの動作速度と比べてメモリーへの読み書きすら遅い、というレベルです。 この速度差を解消すべく、イマドキCPUはコア上にキャッシュと持っています。 読み書きの頻度の多いメモリー領域をキャッシュ上に保存することで、高速な動作を保っています。 さて、バイナリサーチはソート済みの配列から$\log n$オーダーで要素を検索する方法です。 しかし、通常のバイナリサーチはメモリーのアクセスパターンが複雑なため、CPUのキャッシュと非常に相性が悪いです。 そこでEytzinger Layoutの出番です。 Eytzinger Layoutを利用するとよくアクセスされる要素が隣接するようになります。 これによりCPUキャッシュのヒット率をあげようという作戦です。 冒頭のスライドや、以下の記事で詳しく説明されています(図があるとわかりやすいけど、面倒で力尽きた)。 Eytzinger Binary Search キャッシュフレンドリーな二分探索 ー データ構造を再考する Cache-friendly binary search 実装 Goで実装してみました。 shogo82148/go-eytzinger ソート済みの配列からEytzinger Layoutへの変換は、再帰を使うと簡単に実装できます。 (参考: Eytzinger Binary Search) // https://github.com/shogo82148/go-eytzinger/blob/cd9c2f8a9657333f29a6b645cb2587322295ef3a/eytzinger.go#L8-L34 // Eytzinger rearranges the elements of a slice into a cache friendly binary tree // as known as [Eytzinger Layout]. // The slice must be sorted in increasing order.

Aug 9, 2023 - 1 minute read - aws aws-lambda perl

AWS::LambdaがResponse Streamingに対応しました

AWS::LambdaがResponse Streamingに対応しました。 Response Streaming 2023年4月に発表されたAWS Lambdaの新機能です。 AWS Lambda レスポンスストリーミングの紹介 Introducing AWS Lambda response streaming 従来のLambda関数は処理がすべて完了したあとでないと結果を返すことができませんでした。 Response Streamingを利用すると、処理の途中であっても段階的に処理結果を返すことができます。 使い方 通常のLambda関数のなかで使う CODEリファレンスを返すことでResponse Streamingを使うことができます。 sub handle { my ($payload, $context) = @_; return sub { # とりあえずヘッダーだけ返す my $responder = shift; my $writer = $responder->('application/json'); # ...なんか長い処理... # 最終的な結果を返す $writer->write('{"foo": "bar"}'); $writer->close; }; } もちろん処理の途中で$writer->writeを複数回呼んで、途中結果を返すことも可能です。 Function URLsと一緒に使う AWS::Lambda::PSGIを使えばFunction URLsを一緒に使うこともできます。 PSGIのDelayed Response and Streaming Body方式に対応しています。 sub app { return sub { # とりあえずヘッダーだけ返す my $responder = shift; my $writer = $responder->([200, ['Content-Type' => 'application/json']]); # .

Aug 4, 2023 - 2 minute read - go golang

Contextに埋め込んだ値をログに出力してくれるログハンドラーを書いた

Go言語にいよいよ構造化ログ用パッケージlog/slogが追加される、と各所で話題になってますね。 Go 1.21連載始まります&slogをどう使うべきか しかし、どんなにドキュメントをみても、ロガーを出し入れする関数はありません。そういう使い方を議論する issue もありましたが 現状はハンドラーにそのまま渡しているだけです。 よくよく考えればトレーシングIDなどは、コンテキストに格納されているはずで、ロガーにも属性として持つと2重持ちになってしまいます。出力時だけハンドラ自身がそれを取り出して書き出せば良い、という思想に思えます。 そのためにはハンドラーを自分でつくることになります。 (強調は筆者によるもの) たしかにトレーシングIDを2重に持つのは効率が悪いかもしれない。 そうかもしれないけど・・・でもやっぱり毎回ハンドラーを書くのは面倒・・・もうちょっと汎用的にはならないものか・・・ と結局書いちゃいました。 shogo82148/ctxslog 使い方 slogではログ関数がcontext.Contextを受け取るようになりました。 ここで渡したcontext.Contextはキャンセル処理には使用されず、値の受け渡しのみに使用されます。 このことを利用してctxslog.WithAttrsでコンテキストに値を埋め込むことができます。 ここで埋め込んだ値をctxslog.Newで作成したハンドラーが受け取って、ログに表示します。 import ( "context" "log/slog" ) func main() { // ログに出力するためにロガーをカスタマイズ handler := slog.NewTextHandler(os.Stderr, nil) slog.SetDefault(slog.New(ctxslog.New(handler))) ctx := context.Background() // このコンテキスト内のログすべてに my_context=foo-bar を埋め込む ctx = ctxslog.WithAttrs(ctx, slog.String("my_context", "foo-bar")) slog.InfoContext(ctx, "hello", "count", 42) // ログ出力、ここで `ctx` を渡しているのがポイント slog.InfoContext(ctx, "world") // Output: // time=2023-08-03T18:10:20.424+09:00 level=INFO msg=hello count=42 my_context=foo-bar // time=2023-08-03T18:10:20.424+09:00 level=INFO msg=world my_context=foo-bar } 実装 slog.

Aug 1, 2023 - 1 minute read - perl aws aws-lambda

AWS::Lambda 0.1.1リリースのお知らせ

AWS::Lambda v0.1.1が利用可能になりました。 今回のリリースでは、以下の 5 つのリージョンを新たに追加しました。 欧州(チューリッヒ)(eu-central-2) 欧州(スペイン)(eu-south-2) アジアパシフィック(ハイデラバード)(ap-south-2) アジアパシフィック(メルボルン)(ap-southeast-4) イスラエル(テルアビブ)(il-central-1) 久しぶりにリージョン一覧を眺めていたら、いっぱい増えていてびっくりしました・・・ 欧州(チューリッヒ)、欧州(スペイン)、アジアパシフィック(ハイデラバード)リージョンは去年の 11 月、 アジアパシフィック(メルボルン)は今年の 1 月にオープンでした。長いこと気が付かず申し訳ない。 イスラエル(テルアビブ)リージョンに関しては、なんと!今日オープンです! Now Open – AWS Israel (Tel Aviv ) Region もちろん 7 月 2 日にリリースされた Perl 5.38 にも対応済みです。 perl5380delta レイヤー ARN は以下のとおりです。 今回追加した 5 つのリージョンと、中東(アラブ首長国連邦)リージョンに関しては ARM 未対応なので注意してください。 x86_64 architecture arn:aws:lambda:af-south-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:ap-east-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:ap-northeast-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:ap-northeast-2:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:ap-northeast-3:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:ap-south-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:ap-south-2:445285296882:layer:perl-5-38-runtime-al2-x86_64:1 arn:aws:lambda:ap-southeast-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:ap-southeast-2:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:ap-southeast-3:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:ap-southeast-4:445285296882:layer:perl-5-38-runtime-al2-x86_64:1 arn:aws:lambda:ca-central-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:eu-central-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:eu-central-2:445285296882:layer:perl-5-38-runtime-al2-x86_64:1 arn:aws:lambda:eu-north-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:eu-south-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:eu-south-2:445285296882:layer:perl-5-38-runtime-al2-x86_64:1 arn:aws:lambda:eu-west-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:eu-west-2:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:eu-west-3:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:il-central-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:1 arn:aws:lambda:me-central-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:me-south-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:sa-east-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:us-east-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:us-east-2:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:us-west-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arn:aws:lambda:us-west-2:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 arm64 architecture arn:aws:lambda:af-south-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:ap-east-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:ap-northeast-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:ap-northeast-2:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:ap-northeast-3:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:ap-south-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:ap-southeast-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:ap-southeast-2:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:ap-southeast-3:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:ca-central-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:eu-central-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:eu-north-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:eu-south-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:eu-west-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:eu-west-2:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:eu-west-3:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:me-south-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:sa-east-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:us-east-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:us-east-2:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:us-west-1:445285296882:layer:perl-5-38-runtime-al2-arm64:2 arn:aws:lambda:us-west-2:445285296882:layer:perl-5-38-runtime-al2-arm64:2 参考 スイスに新しい AWS リージョンがオープン A New AWS Region Opens in Switzerland スペインに新しい AWS リージョンがオープン Now Open–AWS Region in Spain インドに 30 番目の AWS リージョン — アジアパシフィック (ハイデラバード) リージョンをオープンしました Now Open the 30th AWS Region – Asia Pacific (Hyderabad) Region in India 新規開設 – オーストラリアの AWS アジアパシフィック (メルボルン) リージョン Now Open — AWS Asia Pacific (Melbourne) Region in Australia Now Open – AWS Israel (Tel Aviv ) Region perl5380delta

Jul 26, 2023 - 2 minute read - golang

「ふっかつのじゅもん」みたいなBase64亜種「base64dq」を書いた

ドラゴンクエストシリーズ第一作目に登場する「ふっかつのじゅもん」っぽいBase64亜種を書いてみました。 shogo82148/base64dq 使い方 簡単に使えるようコマンドラインインターフェイスも用意しました。go installでインストール可能です。 $ go install github.com/shogo82148/base64dq/cmd/base64dq@latest base64dqコマンドが使えるようになります。 Coreutilsのbase64コマンドと同様に使えます。 $ echo 'こんにちは' | base64dq づづきとづづさとづづきわづづきめづづきげうむ・・ $ echo 'づづきとづづさとづづきわづづきめづづきげうむ・・' | base64dq --decode こんにちは ふっかつのじゅもん 「ふっかつのじゅもん」はドラゴンクエストシリーズ第一作目で採用されたゲームのセーブ方式です。 ゲームを中断するときには、再開したときに同じ状態からゲームを始められるよう、ゲームの状態を保存しておく必要があります。 しかしドラクエIが発売されたのは1986年5月。 当時ドラクエIはファミコン向けに発売されたのですが、ファミコンにはフラッシュROMのような贅沢なハードウェアはついていません。 電源を落とすと簡単にデーターは失われてしまいます。 そこでゲームの状態を20文字の「ふっかつのじゅもん」にエンコードし、 再開時には「ふっかつのじゅもん」をプレイヤーに入力してもらう、というセーブ方式が編み出されました。 プレイヤーはゲームを中断するたびに「ふっかつのじゅもん」を書き写す必要がありました。 当時は液晶ディスプレイなどあるはずもなく、一般の家庭にあるのはブラウン管のアナログディスプレイです。 解像度が荒く読み取るのが大変なため、「ふっかつのじゅもん」を間違え散っていったプレイヤーも多くいたと聞いています(筆者はまだ生まれていないのでよく知らない)。 ふっかつのじゅもんとBase64の関係 今では有志による解読も進みふっかつのじゅもんのジェネレーターも開発されています。 DQ1 復活の呪文解析日記によると、「ふっかつのじゅもん」は64種類のひらがなで構成されているそうです。 64。実に切りのいい数字です。 1文字で6ビットの情報を表し、合計で120ビットのセーブデータを表現しています。 このエンコード方法はBase64とまったく同じですね! 「ふっかつのじゅもん」は、64種類のASCII文字の代わりに、64種類のひらがなを使ったBase64の亜種、と考えることができます。 ちなみにBase64がRFCに登場したのは1987年4月のRFC 989だそうです。 当時はBase64という言葉すらなく、printable encodingと呼ばれていたようです。 ドラクエIが発売されたのは1986年5月なので、Base64が一般に広まる前に「ふっかつのじゅもん」は世に公開されたわけですね。 すごい! もちろん規格化されていないだけで「64種類の文字で情報をエンコードする」というアイディア自体はもっと昔からあったのでしょう。 でも似たようなものがゲームに使われていたのはおもしろいですね。 base64dq そういうわけで「ふっかつのじゅもん」の影響を受けて作ったのが shogo82148/base64dq です。 64種類のASCII文字の代わりに、以下の64種類のひらがなを使います。 あいうえお かきくけこ さしすせそ たちつてと なにぬねの はひふへほ まみむめも やゆよ らりるれろ わ がぎぐげご ざじずぜぞ だぢづでど ばびぶべぼ ・(パディング) 「ふっかつのじゅもん」にはパディングはないので、適当に「・」を選びました。