-
+
command! -bar -range=%
\ Reverse
@@ -137,7 +137,7 @@ command! -bar -range=%
なお、:g/^/m0 は全ての行を入れ替えるが、:N,Mg/^/mN-1 とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。
- command! -bar -range=%
+ command! -bar -range=%
\ Reverse
\ <line1>,<line2>g/^/m<line1>-1
@@ -172,7 +172,7 @@ command! -bar -range=%
前述した :Reverse コマンドの定義を少し変えて、次のようにする:
- function! s:reverse_lines(from, to) abort
+ function! s:reverse_lines(from, to) abort
execute printf("%d,%dg/^/m%d", a:from, a:to, a:from - 1)
endfunction
@@ -198,7 +198,7 @@ command! -bar -range=%
- Autocommands do not change the current search patterns. Vim saves the current search patterns before executing autocommands then restores them after the autocommands finish. This means that autocommands do not affect the strings highlighted with the `hlsearch' option.
+ Autocommands do not change the current search patterns. Vim saves the current search patterns before executing autocommands then restores them after the autocommands finish. This means that autocommands do not affect the strings highlighted with the `hlsearch' option.
@@ -212,7 +212,7 @@ command! -bar -range=%
- (略) This command doesn’t work in an autocommand, because the highlighting state is saved and restored when executing autocommands |autocmd-searchpat|. Same thing for when invoking a user function.
+ (略) This command doesn’t work in an autocommand, because the highlighting state is saved and restored when executing autocommands |autocmd-searchpat|. Same thing for when invoking a user function.
@@ -229,7 +229,7 @@ command! -bar -range=%
- command! -bar -range=%
+ command! -bar -range=%
\ Reverse
\ keeppatterns <line1>,<line2>g/^/m<line1>-1
diff --git a/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html b/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html
index b19f038d..6db138d5 100644
--- a/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html
+++ b/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html
@@ -79,7 +79,7 @@
ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。
- <?php
+ <?php
declare(strict_types=0O1);
@@ -176,7 +176,7 @@ $🐘([
なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。
- + + + + + + + + + +
+ + + + + + + + + + +
[
> + + +
> + + + + +
@@ -266,7 +266,7 @@ $🐘([
ソースコードのライセンスを示したこの部分だが、
- https:
+ https:
完全に合法な PHP のコードである。 https: 部分はラベル、// 以降は行コメントになっている。
@@ -279,7 +279,7 @@ $🐘([
ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 PHP では、型変換を利用することで任意の整数を作り出すことができる。
- assert(0 === +!![]);
+ assert(0 === +!![]);
assert(1 === +![]);
assert(2 === ![]+![]);
assert(3 === ![]+![]+![]);
@@ -324,7 +324,7 @@ $🐘([
ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。
- <?php
+ <?php
まずは普通に書くとしよう。
- <?php
+ <?php
for ($i = 1; $i < 100; $i++) {
echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n";
@@ -284,7 +284,7 @@ a'
for は、3文字もある長いキーワードである。 こんなものは使えない。array_ 系の関数を使って、適当に置き換えるとしよう。
- <?php
+ <?php
$s = range(1, 100);
array_walk(
@@ -304,7 +304,7 @@ fn($i) =>
range、array_walk、printf は長すぎるのでどうにかせねばならない。 ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。
- <?php
+ <?php
$r = 'range';
$w = 'array_walk';
@@ -340,7 +340,7 @@ fn($i) =>
というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。 例えば、 Fizz という文字列が欲しければ、次のようにする。
- $f
+ $f
=F
.i
.z
@@ -351,7 +351,7 @@ fn($i) =>
こうして簡単に文字列を作れる。 なお、この仕様は 7.x 時点でも警告を受けるので、@ 演算子を使って抑制してやるとよい。
- $f
+ $f
=@
F.
@i
@@ -376,7 +376,7 @@ F.
ずばり、文字列同士のビット演算を使う。 PHP では、文字列同士でビット演算 (&、|、^) をした場合、 文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。
- $a = "12345";
+ $a = "12345";
$b = "world";
@@ -392,7 +392,7 @@ F.
これを踏まえ、次のコードを見てみよう。
- $x = "x\nOm\n";
+ $x = "x\nOm\n";
$y = "\nk!\no";
$r = $x ^ $y;
echo "$r\n";
@@ -401,7 +401,7 @@ F.
実行すると、range が表示される。 さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。 書きかえてみよう。
- $x
+ $x
='x
Om
';
@@ -418,7 +418,7 @@ o'
さらに # を使って適当に調整すると、次のようになる。
- $x
+ $x
=
'x
Om
@@ -453,7 +453,7 @@ o'
完成したものがこちら。
- <?php
+ <?php
$x
=
@@ -621,7 +621,7 @@ _!
PHP では、バッククォートを使ってシェルを呼び出せる。 これは shell_exec 関数と等価である。 さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。
- <?php
+ <?php
printf(`
e\
@@ -658,7 +658,7 @@ o\
もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。
- <?php
+ <?php
$c = 'chr';
@@ -692,7 +692,7 @@ ${
先程と同じく、chr や printf を生成する部分は長くなるので省いた。
- ${
+ ${
'_
'}
@@ -700,7 +700,7 @@ ${
は変数で、中にはスペースとエスケープが入っている (chr(32) . chr(92))。 シェルに渡されている文字列は次のようになる。
- e\
+ e\
c\
h\
o\
@@ -721,7 +721,7 @@ o\
ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。
- ${
+ ${
'_
'}
diff --git a/vhosts/blog/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html b/vhosts/blog/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html
index eaa210c5..1c661438 100644
--- a/vhosts/blog/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html
+++ b/vhosts/blog/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html
@@ -81,7 +81,7 @@
注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。
- <?php
+ <?php
$π = $argv[1] ?? null;
if ($π === null) {
@@ -110,14 +110,14 @@ $π = trim($π);
ソースを見るとわかるとおり、$argv[1] を参照している。 それを $π なる変数に代入しているので、円周率を渡してみる。
- $ php Q.php 3.14
+ $ php Q.php 3.14
Failed.
失敗してしまった。精度を上げてみる。
- $ php Q.php 3.1415
+ $ php Q.php 3.1415
Failed.
@@ -128,7 +128,7 @@ Failed.
最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。
- $ php Q.php 3.1415926535897932
+ $ php Q.php 3.1415926535897932
Token: #YO
@@ -142,7 +142,7 @@ Token: #YO
短いので頭から追っていく。
- $π = $argv[1] ?? null;
+ $π = $argv[1] ?? null;
if ($π === null) {
exit('No input.');
}
@@ -155,7 +155,7 @@ $π = trim($π);
入力のバリデーション部分。数値のみ受け付ける。
- $s = implode(array_map(chr(...), str_split($π, 2)));
+ $s = implode(array_map(chr(...), str_split($π, 2)));
$π を 2 文字ごとに区切り (str_split)、 数値を ASCII コードと見做して文字に変換 (chr) して結合 (implode) している。
@@ -165,12 +165,12 @@ $π = trim($π);
例えば、$π が '656667' だったとすると、 65、66、67 に対応した 'A'、'B'、'C' へと変換され、'ABC' になる。
- $π = '656667';
+ $π = '656667';
$s = implode(array_map(chr(...), str_split($π, 2)));
echo $s;
- preg_match('/(\x23.+?) /', $s, $m);
+ preg_match('/(\x23.+?) /', $s, $m);
$t = $m[1] ?? '';
@@ -181,7 +181,7 @@ $π = trim($π);
なお、# を直接書いていないのは、/#.+?) / と書くと、 #.+?) という意図せぬトークンが登録されてしまうからである。
- if (md5($t) === '056e831a4146bf123e8ea16613303d2e') {
+ if (md5($t) === '056e831a4146bf123e8ea16613303d2e') {
echo "Token: {$t}\n";
} else {
echo "Failed.\n";
diff --git a/vhosts/blog/public/posts/2022-10-28/setup-server-for-this-site/index.html b/vhosts/blog/public/posts/2022-10-28/setup-server-for-this-site/index.html
index 20297c1b..c0da51a0 100644
--- a/vhosts/blog/public/posts/2022-10-28/setup-server-for-this-site/index.html
+++ b/vhosts/blog/public/posts/2022-10-28/setup-server-for-this-site/index.html
@@ -89,7 +89,7 @@
ローカルマシンで鍵を生成する。
- $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key
+ $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key
$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key
@@ -103,7 +103,7 @@ $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key
.ssh/config に設定しておく。
- Host teika
+ Host teika
HostName **********
User **********
Port **********
@@ -127,7 +127,7 @@ $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key
管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。 sudo グループに追加して sudo できるようにし、su で切り替え。
- $ sudo adduser **********
+ $ sudo adduser **********
$ sudo adduser ********** sudo
$ su **********
$ cd
@@ -135,12 +135,12 @@ $ cd
- $ sudo hostname teika
+ $ sudo hostname teika
- $ mkdir ~/.ssh
+ $ mkdir ~/.ssh
$ chmod 700 ~/.ssh
$ vi ~/.ssh/authorized_keys
@@ -155,7 +155,7 @@ $ vi ~/.ssh/authorized_keys
SSH の設定を変更し、少しでも安全にしておく。
- $ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
+ $ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
$ sudo vi /etc/ssh/sshd_config
@@ -176,7 +176,7 @@ $ sudo vi /etc/ssh/sshd_config
そして設定を反映。
- $ sudo systemctl restart sshd
+ $ sudo systemctl restart sshd
$ sudo systemctl status sshd
@@ -186,7 +186,7 @@ $ sudo systemctl status sshd
今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。 セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。
- $ ssh teika
+ $ ssh teika
- $ sudo apt update
+ $ sudo apt update
$ sudo apt upgrade
$ sudo apt update
$ sudo apt upgrade
@@ -260,12 +260,12 @@ $ sudo apt autoremove
- $ sudo apt install docker docker-compose git make
+ $ sudo apt install docker docker-compose git make
- $ sudo adduser ********** docker
+ $ sudo adduser ********** docker
@@ -274,7 +274,7 @@ $ sudo apt autoremove
80 番と 443 番を空ける。
- $ sudo ufw allow 80/tcp
+ $ sudo ufw allow 80/tcp
$ sudo ufw allow 443/tcp
$ sudo ufw reload
$ sudo ufw status
@@ -282,7 +282,7 @@ $ sudo ufw status
- $ cd
+ $ cd
$ git clone git@github.com:nsfisis/nsfisis.dev.git
$ cd nsfisis.dev
$ git submodule update --init
@@ -290,13 +290,13 @@ $ git submodule update --init
- $ docker-compose up -d acme-challenge
+ $ docker-compose up -d acme-challenge
$ make setup
- $ make serve
+ $ make serve
diff --git a/vhosts/blog/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html b/vhosts/blog/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html
index a870f0d4..5071e1ce 100644
--- a/vhosts/blog/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html
+++ b/vhosts/blog/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html
@@ -85,7 +85,7 @@
注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
@@ -107,7 +107,7 @@
実行してみると、次のような出力が得られる。
-
+
<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
@@ -122,7 +122,7 @@
1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。
-
+
W
<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
@@ -137,7 +137,7 @@ W
今度は 2 行目が書き換えられた。すべての行が変化するまで繰り返すと次のようになる。
-
+
W
E
L
@@ -163,7 +163,7 @@ P
Vim で開くと次のようになる (1 行目を抜粋)。
- <?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
<200b> と表示されているのは、Unicode の U+200b で、ゼロ幅スペースである。
@@ -188,13 +188,13 @@ P
続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて <200b> と記載する。
- fn($s)=>chr(strlen($s)/3)
+ fn($s)=>chr(strlen($s)/3)
PHP の strlen() は文字列のバイト数を返す。1 行目の $s は以下の内容となっており、
- $s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'
+ $s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'
このソースコードは UTF-8 で書かれているので、105 バイトになる。それを 3 で割ると 35 となり、これは # の ASCII コードと一致する。他の行も、同様にしてゼロ幅スペースを詰めることで文字列長を調整し、トークンをエンコードしている。
diff --git a/vhosts/blog/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html b/vhosts/blog/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html
index 397f6ceb..038cae52 100644
--- a/vhosts/blog/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html
+++ b/vhosts/blog/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html
@@ -91,7 +91,7 @@
注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。
- <?php
+ <?php
try {
f(g() / __LINE__);
} catch (Throwable $e) {
@@ -242,7 +242,7 @@
このうち 1つ目のケースは、 finally 節の中でエラーを投げると PHP 処理系が勝手に $previous を設定してくれる。
- <?php
+ <?php
try {
try {
@@ -268,7 +268,7 @@
出力部をコメントや改行を追加して再掲する:
- <?php
+ <?php
try {
f(g() / __LINE__);
} catch (Throwable $e) {
@@ -286,7 +286,7 @@
フォーマット指定子 %c は、整数を ASCII コード と見做して印字する。トークン #base64_decode('SGVsbG8sIFdvcmxkIQ==') の b であれば、ASCII コード 98 なので、75 行目で発生したエラー、
- 1, 20 => 0 / 0,
+ 1, 20 => 0 / 0,
によって表現されている。エラーを起こす方法はいろいろと考えられるが、今回はゼロ除算を使った。
@@ -303,7 +303,7 @@
f() の定義を再掲する (エラーオブジェクトの行数を利用しているので、一部分だけ抜き出すと値が変わることに注意):
- function f(int $i) {
+ function f(int $i) {
if ($i < 0) f();
try {
match ($i) {
@@ -328,11 +328,11 @@
前述のように、 finally 節でエラーを投げると PHP 処理系が $previous を設定する。ここでは、エラーを繋げるために f() を再帰呼び出ししている。最初に f() を呼び出している箇所を確認すると、
- <?php
+ <?php
try {
f(g() / __LINE__);
- function g() {
+ function g() {
return __LINE__;
}
diff --git a/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html b/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html
index 547191b9..91020aaf 100644
--- a/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html
+++ b/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html
@@ -93,7 +93,7 @@
以下のソースコードをベースにする。 今回 PNG のデコーダは扱わないので、読み込みには Go の標準ライブラリ image/png を用いる。
- package main
+ package main
import (
"image"
@@ -184,7 +184,7 @@
writeSignature の実装はこちら:
- import "encoding/binary"
+ import "encoding/binary"
func writeSignature(w io.Writer) {
sig := [8]uint8{
@@ -233,7 +233,7 @@
CRC (Cyclic Redundancy Check) は誤り検出符号の一種。Go 言語では hash/crc32 パッケージにあるが、今回はこれも自前で実装する。PNG の仕様書に C 言語のサンプルコードが載っている (D. Sample CRC implementation) ので、これを Go に移植する。
- var (
+ var (
crcTable [256]uint32
crcTableComputed bool
)
@@ -273,7 +273,7 @@
できた crc 関数を使って、chunk 一般を書き込む関数も用意しておこう。
- func writeChunk(w io.Writer, chunkType string, data []byte) {
+ func writeChunk(w io.Writer, chunkType string, data []byte) {
typeAndData := make([]byte, 0, len(chunkType)+len(data))
typeAndData = append(typeAndData, []byte(chunkType)...)
typeAndData = append(typeAndData, data...)
@@ -367,7 +367,7 @@
今回ほとんどのデータは決め打ちするので、データに応じて変わるのは width と height だけになる。コードは次のようになる。
- import "bytes"
+ import "bytes"
func writeChunkIhdr(w io.Writer, width, height uint32) {
var buf bytes.Buffer
@@ -421,7 +421,7 @@
Adler-32 も CRC と同じく誤り検出符号である。こちらも zlib の仕様書に C 言語でサンプルコードが記載されている (9. Appendix: Sample code) ので、Go に移植する。
- const adler32Base = 65521
+ const adler32Base = 65521
func updateAdler32(adler uint32, buf []byte) uint32 {
s1 := adler & 0xFFFF
@@ -468,7 +468,7 @@
実際にこの手抜き zlib を実装したものがこちら:
- func encodeZlib(data []byte) []byte {
+ func encodeZlib(data []byte) []byte {
var buf bytes.Buffer
binary.Write(&buf, binary.BigEndian, uint8(0x78))
@@ -508,7 +508,7 @@
先ほどの encodeZlib も使って実際に実装したものがこちら:
- func writeChunkIdat(w io.Writer, width, height uint32, img image.Image) {
+ func writeChunkIdat(w io.Writer, width, height uint32, img image.Image) {
var pixels bytes.Buffer
for y := uint32(0); y < height; y++ {
binary.Write(&pixels, binary.BigEndian, uint8(0))
@@ -535,7 +535,7 @@
特に追加のデータはなく、必要なのは chunk type の IEND くらいなので実装は簡単:
- func writeChunkIend(w io.Writer) {
+ func writeChunkIend(w io.Writer) {
writeChunk(w, "IEND", nil)
}
@@ -547,7 +547,7 @@
最後に全ソースコードを再掲しておく。
-
+ 多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。 + 是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。 +
++ 予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント +
+ ++ PHPのエラーを理解して適切なエラーハンドリングを学ぼう +
+ ++ エラー監視とテスト体制への改善作戦 +
+ ++ ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか +
+ ++ チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた +
+ ++ 今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。 + こちらについては別途記事にしているので、そちらを参照されたい。 +
++ 1位になった。
++ また、賞品として Echo Show 15 をいただいた。 +
+ 去年の参加レポ では、こんなことを書いた。 +
+ ++ この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。
++ これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、 + 質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。 +
+ なお、アンカンファレンスについては、1日目の終わりにトークン問題の解説放送もおこなった。 +
++ また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。 + 今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。 +
+