diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-01 00:49:15 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-01 00:49:19 +0900 |
| commit | 6dedddc545e2f1930bdc2256784eb1551bd4231d (patch) | |
| tree | 75fcb5a6043dc0f2c31b098bf3cfd17a2b938599 | |
| parent | d08e3edb65b215152aa26e3518fb2f2cd7071c4b (diff) | |
| download | nsfisis.dev-6dedddc545e2f1930bdc2256784eb1551bd4231d.tar.gz nsfisis.dev-6dedddc545e2f1930bdc2256784eb1551bd4231d.tar.zst nsfisis.dev-6dedddc545e2f1930bdc2256784eb1551bd4231d.zip | |
feat(nuldoc): rewrite nuldoc in Ruby
152 files changed, 6484 insertions, 7922 deletions
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c3e068a3..014d2f2c 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,13 +10,15 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 - - name: Set up Deno - uses: denoland/setup-deno@v2 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 with: - deno-version: v2.x + ruby-version: '3.4' + bundler-cache: true + working-directory: services/nuldoc - - name: Run deno task check - run: cd services/nuldoc; deno task check + - name: Run rubocop + run: cd services/nuldoc; bundle exec rake rubocop deploy: needs: test diff --git a/services/nuldoc/.rubocop.yml b/services/nuldoc/.rubocop.yml new file mode 100644 index 00000000..730d0009 --- /dev/null +++ b/services/nuldoc/.rubocop.yml @@ -0,0 +1,20 @@ +plugins: + - rubocop-performance + - rubocop-rake + +AllCops: + TargetRubyVersion: 3.4 + Enabled: true + NewCops: enable + +Metrics: + Enabled: false + +Naming/MethodParameterName: + MinNameLength: 1 + +Style/FrozenStringLiteralComment: + EnforcedStyle: never + +Style/Documentation: + Enabled: false diff --git a/services/nuldoc/Gemfile b/services/nuldoc/Gemfile new file mode 100644 index 00000000..52ca7a1c --- /dev/null +++ b/services/nuldoc/Gemfile @@ -0,0 +1,13 @@ +source 'https://rubygems.org' + +gem 'dry-cli' +gem 'rouge' +gem 'toml-rb' +gem 'webrick' + +group :development do + gem 'rake' + gem 'rubocop' + gem 'rubocop-performance' + gem 'rubocop-rake' +end diff --git a/services/nuldoc/Gemfile.lock b/services/nuldoc/Gemfile.lock new file mode 100644 index 00000000..6ed6b94d --- /dev/null +++ b/services/nuldoc/Gemfile.lock @@ -0,0 +1,65 @@ +GEM + remote: https://rubygems.org/ + specs: + ast (2.4.3) + citrus (3.0.2) + dry-cli (1.4.1) + json (2.18.0) + language_server-protocol (3.17.0.5) + lint_roller (1.1.0) + parallel (1.27.0) + parser (3.3.10.1) + ast (~> 2.4.1) + racc + prism (1.9.0) + racc (1.8.1) + rainbow (3.1.1) + rake (13.3.1) + regexp_parser (2.11.3) + rouge (4.7.0) + rubocop (1.84.0) + json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.49.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.49.0) + parser (>= 3.3.7.2) + prism (~> 1.7) + rubocop-performance (1.26.1) + lint_roller (~> 1.1) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.47.1, < 2.0) + rubocop-rake (0.7.1) + lint_roller (~> 1.1) + rubocop (>= 1.72.1) + ruby-progressbar (1.13.0) + toml-rb (4.1.0) + citrus (~> 3.0, > 3.0) + racc (~> 1.7) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.2.0) + webrick (1.9.2) + +PLATFORMS + ruby + x86_64-linux + +DEPENDENCIES + dry-cli + rake + rouge + rubocop + rubocop-performance + rubocop-rake + toml-rb + webrick + +BUNDLED WITH + 2.6.9 diff --git a/services/nuldoc/NOTE.md b/services/nuldoc/NOTE.md index 6345ff86..d632513f 100644 --- a/services/nuldoc/NOTE.md +++ b/services/nuldoc/NOTE.md @@ -5,19 +5,19 @@ Generate the site. ``` -$ ./nuldoc build +$ rake build ``` Create a new post. ``` -$ ./nuldoc new post +$ rake new post ``` Create a new slide. ``` -$ ./nuldoc new slide +$ rake new slide ``` Update PDF.js. diff --git a/services/nuldoc/Rakefile b/services/nuldoc/Rakefile new file mode 100644 index 00000000..811398f4 --- /dev/null +++ b/services/nuldoc/Rakefile @@ -0,0 +1,22 @@ +require 'rubocop/rake_task' +require_relative 'lib/nuldoc' + +RuboCop::RakeTask.new + +desc 'Build the site' +task :build do + config = Nuldoc::ConfigLoader.load_config(Nuldoc::ConfigLoader.default_config_path) + Nuldoc::Commands::Build.run(config) +end + +desc 'Start development server' +task :serve, [:site] do |_t, args| + config = Nuldoc::ConfigLoader.load_config(Nuldoc::ConfigLoader.default_config_path) + Nuldoc::Commands::Serve.run(config, site_name: args[:site], no_rebuild: false) +end + +desc 'Create new content' +task :new, [:type] do |_t, args| + config = Nuldoc::ConfigLoader.load_config(Nuldoc::ConfigLoader.default_config_path) + Nuldoc::Commands::New.run(config, type: args[:type], date: nil) +end diff --git a/services/nuldoc/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.md b/services/nuldoc/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.md index 70068754..fb8c8798 100644 --- a/services/nuldoc/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.md +++ b/services/nuldoc/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.md @@ -60,8 +60,7 @@ $ clang –std=c++17 hoge.cpp 別件で [cppreference.com の identifier のページ](https://en.cppreference.com/w/cpp/language/identifiers)を読んでいた時、次の文が目に止まった。 > * the identifiers that are keywords cannot be used for other purposes; -> -> * The only place they can be used as non-keywords is in an attribute-token. (e.g. [[private]] is a valid attribute) (since C++11) +> * The only place they can be used as non-keywords is in an attribute-token. (e.g. [[private]] is a valid attribute) (since C++11) キーワードでも属性として指定する場合は非キーワードとして使えるらしい。 実際にやってみる。 diff --git a/services/nuldoc/content/posts/2023-04-01/implementation-of-minimal-png-image-encoder.md b/services/nuldoc/content/posts/2023-04-01/implementation-of-minimal-png-image-encoder.md index 6f4fb3c8..2fd69590 100644 --- a/services/nuldoc/content/posts/2023-04-01/implementation-of-minimal-png-image-encoder.md +++ b/services/nuldoc/content/posts/2023-04-01/implementation-of-minimal-png-image-encoder.md @@ -189,19 +189,19 @@ IHDR chunk は最初に配置される chunk である。次のようなデー 1. 画像の幅 (符号なし 4 バイト整数) 1. 画像の高さ (符号なし 4 バイト整数) 1. ビット深度 (符号なし 1 バイト整数) - * 1 色に使うビット数。1 ピクセルに 24 bit 使う truecolor 画像では 8 になる + * 1 色に使うビット数。1 ピクセルに 24 bit 使う truecolor 画像では 8 になる 1. 色タイプ (符号なし 1 バイト整数) - * 0: グレースケール - * 2: Truecolor (今回はこれに決め打ち) - * 3: パレットのインデックス - * 4: グレースケール + アルファ - * 6: Truecolor + アルファ + * 0: グレースケール + * 2: Truecolor (今回はこれに決め打ち) + * 3: パレットのインデックス + * 4: グレースケール + アルファ + * 6: Truecolor + アルファ 1. 圧縮方式 (符号なし 1 バイト整数) - * PNG の仕様書に 0 しか定義されていないので 0 で固定 + * PNG の仕様書に 0 しか定義されていないので 0 で固定 1. フィルタ方式 (符号なし 1 バイト整数) - * PNG の仕様書に 0 しか定義されていないので 0 で固定 + * PNG の仕様書に 0 しか定義されていないので 0 で固定 1. インターレース方式 (符号なし 1 バイト整数) - * 今回はインターレースしないので 0 + * 今回はインターレースしないので 0 今回ほとんどのデータは決め打ちするので、データに応じて変わるのは width と height だけになる。コードは次のようになる。 diff --git a/services/nuldoc/deno.jsonc b/services/nuldoc/deno.jsonc deleted file mode 100644 index 3174e5c5..00000000 --- a/services/nuldoc/deno.jsonc +++ /dev/null @@ -1,34 +0,0 @@ -{ - "imports": { - "@std/assert": "jsr:@std/assert@^1.0.13", - "@std/cli": "jsr:@std/cli@^1.0.20", - "@std/fs": "jsr:@std/fs@^1.0.19", - "@std/http": "jsr:@std/http@^1.0.19", - "@std/path": "jsr:@std/path@^1.1.1", - "@std/toml": "jsr:@std/toml@^1.0.8", - "checksum/": "https://deno.land/x/checksum@1.4.0/", - "shiki": "npm:shiki@^3.7.0", - "unified": "npm:unified@^11.0.0", - "remark-parse": "npm:remark-parse@^11.0.0", - "remark-gfm": "npm:remark-gfm@^4.0.0", - "remark-directive": "npm:remark-directive@^3.0.0", - "remark-smartypants": "npm:remark-smartypants@^3.0.0", - "mdast": "npm:@types/mdast@^4.0.0", - "mdast-util-directive": "npm:mdast-util-directive@^3.0.0", - "zod/": "https://deno.land/x/zod@v3.24.2/" - }, - "permissions": { - "default": { - "read": ["."], - "write": ["."], - "net": ["127.0.0.1:8000"], - "env": [ - "VSCODE_TEXTMATE_DEBUG", // VSCODE_TEXTMATE_DEBUG is read by shiki. - ], - }, - } - "tasks": { - "check": "deno check nuldoc-src/main.ts && deno lint -- nuldoc-src/ && deno fmt --check -- nuldoc-src/", - "fmt": "deno fmt -- nuldoc-src", - }, -} diff --git a/services/nuldoc/deno.lock b/services/nuldoc/deno.lock deleted file mode 100644 index 225fcf2c..00000000 --- a/services/nuldoc/deno.lock +++ /dev/null @@ -1,1137 +0,0 @@ -{ - "version": "5", - "specifiers": { - "jsr:@std/assert@^1.0.13": "1.0.13", - "jsr:@std/cli@^1.0.20": "1.0.20", - "jsr:@std/collections@^1.1.1": "1.1.2", - "jsr:@std/encoding@^1.0.10": "1.0.10", - "jsr:@std/fmt@^1.0.8": "1.0.8", - "jsr:@std/fs@^1.0.19": "1.0.19", - "jsr:@std/html@^1.0.4": "1.0.4", - "jsr:@std/http@^1.0.19": "1.0.19", - "jsr:@std/internal@^1.0.6": "1.0.9", - "jsr:@std/internal@^1.0.9": "1.0.9", - "jsr:@std/media-types@^1.1.0": "1.1.0", - "jsr:@std/net@^1.0.4": "1.0.4", - "jsr:@std/path@^1.1.1": "1.1.1", - "jsr:@std/streams@^1.0.10": "1.0.10", - "jsr:@std/toml@^1.0.8": "1.0.8", - "npm:@types/mdast@4": "4.0.4", - "npm:mdast-util-directive@3": "3.1.0", - "npm:remark-directive@3": "3.0.1", - "npm:remark-gfm@4": "4.0.1", - "npm:remark-parse@11": "11.0.0", - "npm:remark-smartypants@3": "3.0.2", - "npm:shiki@^3.7.0": "3.7.0", - "npm:unified@11": "11.0.5" - }, - "jsr": { - "@std/assert@1.0.13": { - "integrity": "ae0d31e41919b12c656c742b22522c32fb26ed0cba32975cb0de2a273cb68b29", - "dependencies": [ - "jsr:@std/internal@^1.0.6" - ] - }, - "@std/cli@1.0.13": { - "integrity": "5db2d95ab2dca3bca9fb6ad3c19908c314e93d6391c8b026725e4892d4615a69" - }, - "@std/cli@1.0.20": { - "integrity": "a8c384a2c98cec6ec6a2055c273a916e2772485eb784af0db004c5ab8ba52333" - }, - "@std/collections@1.1.2": { - "integrity": "f1685dd45c3ec27c39d0e8a642ccf810f391ec8a6cb5e7355926e6dacc64c43e" - }, - "@std/encoding@1.0.10": { - "integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1" - }, - "@std/fmt@1.0.8": { - "integrity": "71e1fc498787e4434d213647a6e43e794af4fd393ef8f52062246e06f7e372b7" - }, - "@std/fs@1.0.19": { - "integrity": "051968c2b1eae4d2ea9f79a08a3845740ef6af10356aff43d3e2ef11ed09fb06", - "dependencies": [ - "jsr:@std/internal@^1.0.9", - "jsr:@std/path" - ] - }, - "@std/html@1.0.4": { - "integrity": "eff3497c08164e6ada49b7f81a28b5108087033823153d065e3f89467dd3d50e" - }, - "@std/http@1.0.19": { - "integrity": "52128c8d00a1f0b20019f8b72376e7ef5f3133375b6f805b5bc89b9de2ad4686", - "dependencies": [ - "jsr:@std/cli", - "jsr:@std/encoding", - "jsr:@std/fmt", - "jsr:@std/fs", - "jsr:@std/html", - "jsr:@std/media-types", - "jsr:@std/net", - "jsr:@std/path", - "jsr:@std/streams" - ] - }, - "@std/internal@1.0.9": { - "integrity": "bdfb97f83e4db7a13e8faab26fb1958d1b80cc64366501af78a0aee151696eb8" - }, - "@std/media-types@1.1.0": { - "integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4" - }, - "@std/net@1.0.4": { - "integrity": "2f403b455ebbccf83d8a027d29c5a9e3a2452fea39bb2da7f2c04af09c8bc852" - }, - "@std/path@1.1.1": { - "integrity": "fe00026bd3a7e6a27f73709b83c607798be40e20c81dde655ce34052fd82ec76", - "dependencies": [ - "jsr:@std/internal@^1.0.9" - ] - }, - "@std/streams@1.0.10": { - "integrity": "75c0b1431873cd0d8b3d679015220204d36d3c7420d93b60acfc379eb0dc30af" - }, - "@std/toml@1.0.8": { - "integrity": "eb8ae76b4cc1c6c13f2a91123675823adbec2380de75cd3748c628960d952164", - "dependencies": [ - "jsr:@std/collections" - ] - } - }, - "npm": { - "@shikijs/core@3.7.0": { - "integrity": "sha512-yilc0S9HvTPyahHpcum8eonYrQtmGTU0lbtwxhA6jHv4Bm1cAdlPFRCJX4AHebkCm75aKTjjRAW+DezqD1b/cg==", - "dependencies": [ - "@shikijs/types", - "@shikijs/vscode-textmate", - "@types/hast", - "hast-util-to-html" - ] - }, - "@shikijs/engine-javascript@3.7.0": { - "integrity": "sha512-0t17s03Cbv+ZcUvv+y33GtX75WBLQELgNdVghnsdhTgU3hVcWcMsoP6Lb0nDTl95ZJfbP1mVMO0p3byVh3uuzA==", - "dependencies": [ - "@shikijs/types", - "@shikijs/vscode-textmate", - "oniguruma-to-es" - ] - }, - "@shikijs/engine-oniguruma@3.7.0": { - "integrity": "sha512-5BxcD6LjVWsGu4xyaBC5bu8LdNgPCVBnAkWTtOCs/CZxcB22L8rcoWfv7Hh/3WooVjBZmFtyxhgvkQFedPGnFw==", - "dependencies": [ - "@shikijs/types", - "@shikijs/vscode-textmate" - ] - }, - "@shikijs/langs@3.7.0": { - "integrity": "sha512-1zYtdfXLr9xDKLTGy5kb7O0zDQsxXiIsw1iIBcNOO8Yi5/Y1qDbJ+0VsFoqTlzdmneO8Ij35g7QKF8kcLyznCQ==", - "dependencies": [ - "@shikijs/types" - ] - }, - "@shikijs/themes@3.7.0": { - "integrity": "sha512-VJx8497iZPy5zLiiCTSIaOChIcKQwR0FebwE9S3rcN0+J/GTWwQ1v/bqhTbpbY3zybPKeO8wdammqkpXc4NVjQ==", - "dependencies": [ - "@shikijs/types" - ] - }, - "@shikijs/types@3.7.0": { - "integrity": "sha512-MGaLeaRlSWpnP0XSAum3kP3a8vtcTsITqoEPYdt3lQG3YCdQH4DnEhodkYcNMcU0uW0RffhoD1O3e0vG5eSBBg==", - "dependencies": [ - "@shikijs/vscode-textmate", - "@types/hast" - ] - }, - "@shikijs/vscode-textmate@10.0.2": { - "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==" - }, - "@types/debug@4.1.12": { - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "dependencies": [ - "@types/ms" - ] - }, - "@types/hast@3.0.4": { - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": [ - "@types/unist@3.0.3" - ] - }, - "@types/mdast@4.0.4": { - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": [ - "@types/unist@3.0.3" - ] - }, - "@types/ms@2.1.0": { - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" - }, - "@types/nlcst@2.0.3": { - "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", - "dependencies": [ - "@types/unist@3.0.3" - ] - }, - "@types/unist@2.0.11": { - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" - }, - "@types/unist@3.0.3": { - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "@ungap/structured-clone@1.3.0": { - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==" - }, - "array-iterate@2.0.1": { - "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==" - }, - "bail@2.0.2": { - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" - }, - "ccount@2.0.1": { - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==" - }, - "character-entities-html4@2.1.0": { - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==" - }, - "character-entities-legacy@3.0.0": { - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==" - }, - "character-entities@2.0.2": { - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==" - }, - "character-reference-invalid@2.0.1": { - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==" - }, - "comma-separated-tokens@2.0.3": { - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" - }, - "debug@4.4.0": { - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dependencies": [ - "ms" - ] - }, - "decode-named-character-reference@1.2.0": { - "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", - "dependencies": [ - "character-entities" - ] - }, - "dequal@2.0.3": { - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" - }, - "devlop@1.1.0": { - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "dependencies": [ - "dequal" - ] - }, - "escape-string-regexp@5.0.0": { - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==" - }, - "extend@3.0.2": { - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "hast-util-to-html@9.0.5": { - "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", - "dependencies": [ - "@types/hast", - "@types/unist@3.0.3", - "ccount", - "comma-separated-tokens", - "hast-util-whitespace", - "html-void-elements", - "mdast-util-to-hast", - "property-information", - "space-separated-tokens", - "stringify-entities", - "zwitch" - ] - }, - "hast-util-whitespace@3.0.0": { - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", - "dependencies": [ - "@types/hast" - ] - }, - "html-void-elements@3.0.0": { - "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==" - }, - "is-alphabetical@2.0.1": { - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==" - }, - "is-alphanumerical@2.0.1": { - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", - "dependencies": [ - "is-alphabetical", - "is-decimal" - ] - }, - "is-decimal@2.0.1": { - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==" - }, - "is-hexadecimal@2.0.1": { - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==" - }, - "is-plain-obj@4.1.0": { - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" - }, - "longest-streak@3.1.0": { - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==" - }, - "markdown-table@3.0.4": { - "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==" - }, - "mdast-util-directive@3.1.0": { - "integrity": "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==", - "dependencies": [ - "@types/mdast", - "@types/unist@3.0.3", - "ccount", - "devlop", - "mdast-util-from-markdown", - "mdast-util-to-markdown", - "parse-entities", - "stringify-entities", - "unist-util-visit-parents" - ] - }, - "mdast-util-find-and-replace@3.0.2": { - "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", - "dependencies": [ - "@types/mdast", - "escape-string-regexp", - "unist-util-is", - "unist-util-visit-parents" - ] - }, - "mdast-util-from-markdown@2.0.2": { - "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", - "dependencies": [ - "@types/mdast", - "@types/unist@3.0.3", - "decode-named-character-reference", - "devlop", - "mdast-util-to-string", - "micromark", - "micromark-util-decode-numeric-character-reference", - "micromark-util-decode-string", - "micromark-util-normalize-identifier", - "micromark-util-symbol", - "micromark-util-types", - "unist-util-stringify-position" - ] - }, - "mdast-util-gfm-autolink-literal@2.0.1": { - "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", - "dependencies": [ - "@types/mdast", - "ccount", - "devlop", - "mdast-util-find-and-replace", - "micromark-util-character" - ] - }, - "mdast-util-gfm-footnote@2.1.0": { - "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", - "dependencies": [ - "@types/mdast", - "devlop", - "mdast-util-from-markdown", - "mdast-util-to-markdown", - "micromark-util-normalize-identifier" - ] - }, - "mdast-util-gfm-strikethrough@2.0.0": { - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", - "dependencies": [ - "@types/mdast", - "mdast-util-from-markdown", - "mdast-util-to-markdown" - ] - }, - "mdast-util-gfm-table@2.0.0": { - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", - "dependencies": [ - "@types/mdast", - "devlop", - "markdown-table", - "mdast-util-from-markdown", - "mdast-util-to-markdown" - ] - }, - "mdast-util-gfm-task-list-item@2.0.0": { - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", - "dependencies": [ - "@types/mdast", - "devlop", - "mdast-util-from-markdown", - "mdast-util-to-markdown" - ] - }, - "mdast-util-gfm@3.1.0": { - "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", - "dependencies": [ - "mdast-util-from-markdown", - "mdast-util-gfm-autolink-literal", - "mdast-util-gfm-footnote", - "mdast-util-gfm-strikethrough", - "mdast-util-gfm-table", - "mdast-util-gfm-task-list-item", - "mdast-util-to-markdown" - ] - }, - "mdast-util-phrasing@4.1.0": { - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", - "dependencies": [ - "@types/mdast", - "unist-util-is" - ] - }, - "mdast-util-to-hast@13.2.0": { - "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", - "dependencies": [ - "@types/hast", - "@types/mdast", - "@ungap/structured-clone", - "devlop", - "micromark-util-sanitize-uri", - "trim-lines", - "unist-util-position", - "unist-util-visit", - "vfile" - ] - }, - "mdast-util-to-markdown@2.1.2": { - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", - "dependencies": [ - "@types/mdast", - "@types/unist@3.0.3", - "longest-streak", - "mdast-util-phrasing", - "mdast-util-to-string", - "micromark-util-classify-character", - "micromark-util-decode-string", - "unist-util-visit", - "zwitch" - ] - }, - "mdast-util-to-string@4.0.0": { - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": [ - "@types/mdast" - ] - }, - "micromark-core-commonmark@2.0.3": { - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", - "dependencies": [ - "decode-named-character-reference", - "devlop", - "micromark-factory-destination", - "micromark-factory-label", - "micromark-factory-space", - "micromark-factory-title", - "micromark-factory-whitespace", - "micromark-util-character", - "micromark-util-chunked", - "micromark-util-classify-character", - "micromark-util-html-tag-name", - "micromark-util-normalize-identifier", - "micromark-util-resolve-all", - "micromark-util-subtokenize", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-extension-directive@3.0.2": { - "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", - "dependencies": [ - "devlop", - "micromark-factory-space", - "micromark-factory-whitespace", - "micromark-util-character", - "micromark-util-symbol", - "micromark-util-types", - "parse-entities" - ] - }, - "micromark-extension-gfm-autolink-literal@2.1.0": { - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", - "dependencies": [ - "micromark-util-character", - "micromark-util-sanitize-uri", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-extension-gfm-footnote@2.1.0": { - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", - "dependencies": [ - "devlop", - "micromark-core-commonmark", - "micromark-factory-space", - "micromark-util-character", - "micromark-util-normalize-identifier", - "micromark-util-sanitize-uri", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-extension-gfm-strikethrough@2.1.0": { - "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", - "dependencies": [ - "devlop", - "micromark-util-chunked", - "micromark-util-classify-character", - "micromark-util-resolve-all", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-extension-gfm-table@2.1.1": { - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", - "dependencies": [ - "devlop", - "micromark-factory-space", - "micromark-util-character", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-extension-gfm-tagfilter@2.0.0": { - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", - "dependencies": [ - "micromark-util-types" - ] - }, - "micromark-extension-gfm-task-list-item@2.1.0": { - "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", - "dependencies": [ - "devlop", - "micromark-factory-space", - "micromark-util-character", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-extension-gfm@3.0.0": { - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", - "dependencies": [ - "micromark-extension-gfm-autolink-literal", - "micromark-extension-gfm-footnote", - "micromark-extension-gfm-strikethrough", - "micromark-extension-gfm-table", - "micromark-extension-gfm-tagfilter", - "micromark-extension-gfm-task-list-item", - "micromark-util-combine-extensions", - "micromark-util-types" - ] - }, - "micromark-factory-destination@2.0.1": { - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", - "dependencies": [ - "micromark-util-character", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-factory-label@2.0.1": { - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", - "dependencies": [ - "devlop", - "micromark-util-character", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-factory-space@2.0.1": { - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "dependencies": [ - "micromark-util-character", - "micromark-util-types" - ] - }, - "micromark-factory-title@2.0.1": { - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", - "dependencies": [ - "micromark-factory-space", - "micromark-util-character", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-factory-whitespace@2.0.1": { - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", - "dependencies": [ - "micromark-factory-space", - "micromark-util-character", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-util-character@2.1.1": { - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "dependencies": [ - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-util-chunked@2.0.1": { - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", - "dependencies": [ - "micromark-util-symbol" - ] - }, - "micromark-util-classify-character@2.0.1": { - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", - "dependencies": [ - "micromark-util-character", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-util-combine-extensions@2.0.1": { - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", - "dependencies": [ - "micromark-util-chunked", - "micromark-util-types" - ] - }, - "micromark-util-decode-numeric-character-reference@2.0.2": { - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", - "dependencies": [ - "micromark-util-symbol" - ] - }, - "micromark-util-decode-string@2.0.1": { - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", - "dependencies": [ - "decode-named-character-reference", - "micromark-util-character", - "micromark-util-decode-numeric-character-reference", - "micromark-util-symbol" - ] - }, - "micromark-util-encode@2.0.1": { - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==" - }, - "micromark-util-html-tag-name@2.0.1": { - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==" - }, - "micromark-util-normalize-identifier@2.0.1": { - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", - "dependencies": [ - "micromark-util-symbol" - ] - }, - "micromark-util-resolve-all@2.0.1": { - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", - "dependencies": [ - "micromark-util-types" - ] - }, - "micromark-util-sanitize-uri@2.0.1": { - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", - "dependencies": [ - "micromark-util-character", - "micromark-util-encode", - "micromark-util-symbol" - ] - }, - "micromark-util-subtokenize@2.1.0": { - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", - "dependencies": [ - "devlop", - "micromark-util-chunked", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "micromark-util-symbol@2.0.1": { - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==" - }, - "micromark-util-types@2.0.2": { - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==" - }, - "micromark@4.0.2": { - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", - "dependencies": [ - "@types/debug", - "debug", - "decode-named-character-reference", - "devlop", - "micromark-core-commonmark", - "micromark-factory-space", - "micromark-util-character", - "micromark-util-chunked", - "micromark-util-combine-extensions", - "micromark-util-decode-numeric-character-reference", - "micromark-util-encode", - "micromark-util-normalize-identifier", - "micromark-util-resolve-all", - "micromark-util-sanitize-uri", - "micromark-util-subtokenize", - "micromark-util-symbol", - "micromark-util-types" - ] - }, - "ms@2.1.3": { - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "nlcst-to-string@4.0.0": { - "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", - "dependencies": [ - "@types/nlcst" - ] - }, - "oniguruma-parser@0.12.1": { - "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==" - }, - "oniguruma-to-es@4.3.3": { - "integrity": "sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==", - "dependencies": [ - "oniguruma-parser", - "regex", - "regex-recursion" - ] - }, - "parse-entities@4.0.2": { - "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", - "dependencies": [ - "@types/unist@2.0.11", - "character-entities-legacy", - "character-reference-invalid", - "decode-named-character-reference", - "is-alphanumerical", - "is-decimal", - "is-hexadecimal" - ] - }, - "parse-latin@7.0.0": { - "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", - "dependencies": [ - "@types/nlcst", - "@types/unist@3.0.3", - "nlcst-to-string", - "unist-util-modify-children", - "unist-util-visit-children", - "vfile" - ] - }, - "property-information@7.1.0": { - "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==" - }, - "regex-recursion@6.0.2": { - "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", - "dependencies": [ - "regex-utilities" - ] - }, - "regex-utilities@2.3.0": { - "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==" - }, - "regex@6.0.1": { - "integrity": "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==", - "dependencies": [ - "regex-utilities" - ] - }, - "remark-directive@3.0.1": { - "integrity": "sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==", - "dependencies": [ - "@types/mdast", - "mdast-util-directive", - "micromark-extension-directive", - "unified" - ] - }, - "remark-gfm@4.0.1": { - "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", - "dependencies": [ - "@types/mdast", - "mdast-util-gfm", - "micromark-extension-gfm", - "remark-parse", - "remark-stringify", - "unified" - ] - }, - "remark-parse@11.0.0": { - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", - "dependencies": [ - "@types/mdast", - "mdast-util-from-markdown", - "micromark-util-types", - "unified" - ] - }, - "remark-smartypants@3.0.2": { - "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==", - "dependencies": [ - "retext", - "retext-smartypants", - "unified", - "unist-util-visit" - ] - }, - "remark-stringify@11.0.0": { - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", - "dependencies": [ - "@types/mdast", - "mdast-util-to-markdown", - "unified" - ] - }, - "retext-latin@4.0.0": { - "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", - "dependencies": [ - "@types/nlcst", - "parse-latin", - "unified" - ] - }, - "retext-smartypants@6.2.0": { - "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", - "dependencies": [ - "@types/nlcst", - "nlcst-to-string", - "unist-util-visit" - ] - }, - "retext-stringify@4.0.0": { - "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", - "dependencies": [ - "@types/nlcst", - "nlcst-to-string", - "unified" - ] - }, - "retext@9.0.0": { - "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", - "dependencies": [ - "@types/nlcst", - "retext-latin", - "retext-stringify", - "unified" - ] - }, - "shiki@3.7.0": { - "integrity": "sha512-ZcI4UT9n6N2pDuM2n3Jbk0sR4Swzq43nLPgS/4h0E3B/NrFn2HKElrDtceSf8Zx/OWYOo7G1SAtBLypCp+YXqg==", - "dependencies": [ - "@shikijs/core", - "@shikijs/engine-javascript", - "@shikijs/engine-oniguruma", - "@shikijs/langs", - "@shikijs/themes", - "@shikijs/types", - "@shikijs/vscode-textmate", - "@types/hast" - ] - }, - "space-separated-tokens@2.0.2": { - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==" - }, - "stringify-entities@4.0.4": { - "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", - "dependencies": [ - "character-entities-html4", - "character-entities-legacy" - ] - }, - "trim-lines@3.0.1": { - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==" - }, - "trough@2.2.0": { - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==" - }, - "unified@11.0.5": { - "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", - "dependencies": [ - "@types/unist@3.0.3", - "bail", - "devlop", - "extend", - "is-plain-obj", - "trough", - "vfile" - ] - }, - "unist-util-is@6.0.0": { - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", - "dependencies": [ - "@types/unist@3.0.3" - ] - }, - "unist-util-modify-children@4.0.0": { - "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", - "dependencies": [ - "@types/unist@3.0.3", - "array-iterate" - ] - }, - "unist-util-position@5.0.0": { - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", - "dependencies": [ - "@types/unist@3.0.3" - ] - }, - "unist-util-stringify-position@4.0.0": { - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": [ - "@types/unist@3.0.3" - ] - }, - "unist-util-visit-children@3.0.0": { - "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", - "dependencies": [ - "@types/unist@3.0.3" - ] - }, - "unist-util-visit-parents@6.0.1": { - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", - "dependencies": [ - "@types/unist@3.0.3", - "unist-util-is" - ] - }, - "unist-util-visit@5.0.0": { - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", - "dependencies": [ - "@types/unist@3.0.3", - "unist-util-is", - "unist-util-visit-parents" - ] - }, - "vfile-message@4.0.2": { - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", - "dependencies": [ - "@types/unist@3.0.3", - "unist-util-stringify-position" - ] - }, - "vfile@6.0.3": { - "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", - "dependencies": [ - "@types/unist@3.0.3", - "vfile-message" - ] - }, - "zwitch@2.0.4": { - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==" - } - }, - "remote": { - "https://deno.land/std@0.224.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", - "https://deno.land/std@0.224.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834", - "https://deno.land/std@0.224.0/assert/assert_almost_equals.ts": "9e416114322012c9a21fa68e187637ce2d7df25bcbdbfd957cd639e65d3cf293", - "https://deno.land/std@0.224.0/assert/assert_array_includes.ts": "14c5094471bc8e4a7895fc6aa5a184300d8a1879606574cb1cd715ef36a4a3c7", - "https://deno.land/std@0.224.0/assert/assert_equals.ts": "3bbca947d85b9d374a108687b1a8ba3785a7850436b5a8930d81f34a32cb8c74", - "https://deno.land/std@0.224.0/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd", - "https://deno.land/std@0.224.0/assert/assert_false.ts": "3e9be8e33275db00d952e9acb0cd29481a44fa0a4af6d37239ff58d79e8edeff", - "https://deno.land/std@0.224.0/assert/assert_greater.ts": "5e57b201fd51b64ced36c828e3dfd773412c1a6120c1a5a99066c9b261974e46", - "https://deno.land/std@0.224.0/assert/assert_greater_or_equal.ts": "9870030f997a08361b6f63400273c2fb1856f5db86c0c3852aab2a002e425c5b", - "https://deno.land/std@0.224.0/assert/assert_instance_of.ts": "e22343c1fdcacfaea8f37784ad782683ec1cf599ae9b1b618954e9c22f376f2c", - "https://deno.land/std@0.224.0/assert/assert_is_error.ts": "f856b3bc978a7aa6a601f3fec6603491ab6255118afa6baa84b04426dd3cc491", - "https://deno.land/std@0.224.0/assert/assert_less.ts": "60b61e13a1982865a72726a5fa86c24fad7eb27c3c08b13883fb68882b307f68", - "https://deno.land/std@0.224.0/assert/assert_less_or_equal.ts": "d2c84e17faba4afe085e6c9123a63395accf4f9e00150db899c46e67420e0ec3", - "https://deno.land/std@0.224.0/assert/assert_match.ts": "ace1710dd3b2811c391946954234b5da910c5665aed817943d086d4d4871a8b7", - "https://deno.land/std@0.224.0/assert/assert_not_equals.ts": "78d45dd46133d76ce624b2c6c09392f6110f0df9b73f911d20208a68dee2ef29", - "https://deno.land/std@0.224.0/assert/assert_not_instance_of.ts": "3434a669b4d20cdcc5359779301a0588f941ffdc2ad68803c31eabdb4890cf7a", - "https://deno.land/std@0.224.0/assert/assert_not_match.ts": "df30417240aa2d35b1ea44df7e541991348a063d9ee823430e0b58079a72242a", - "https://deno.land/std@0.224.0/assert/assert_not_strict_equals.ts": "37f73880bd672709373d6dc2c5f148691119bed161f3020fff3548a0496f71b8", - "https://deno.land/std@0.224.0/assert/assert_object_match.ts": "411450fd194fdaabc0089ae68f916b545a49d7b7e6d0026e84a54c9e7eed2693", - "https://deno.land/std@0.224.0/assert/assert_rejects.ts": "4bee1d6d565a5b623146a14668da8f9eb1f026a4f338bbf92b37e43e0aa53c31", - "https://deno.land/std@0.224.0/assert/assert_strict_equals.ts": "b4f45f0fd2e54d9029171876bd0b42dd9ed0efd8f853ab92a3f50127acfa54f5", - "https://deno.land/std@0.224.0/assert/assert_string_includes.ts": "496b9ecad84deab72c8718735373feb6cdaa071eb91a98206f6f3cb4285e71b8", - "https://deno.land/std@0.224.0/assert/assert_throws.ts": "c6508b2879d465898dab2798009299867e67c570d7d34c90a2d235e4553906eb", - "https://deno.land/std@0.224.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917", - "https://deno.land/std@0.224.0/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47", - "https://deno.land/std@0.224.0/assert/fail.ts": "0eba674ffb47dff083f02ced76d5130460bff1a9a68c6514ebe0cdea4abadb68", - "https://deno.land/std@0.224.0/assert/mod.ts": "48b8cb8a619ea0b7958ad7ee9376500fe902284bb36f0e32c598c3dc34cbd6f3", - "https://deno.land/std@0.224.0/assert/unimplemented.ts": "8c55a5793e9147b4f1ef68cd66496b7d5ba7a9e7ca30c6da070c1a58da723d73", - "https://deno.land/std@0.224.0/assert/unreachable.ts": "5ae3dbf63ef988615b93eb08d395dda771c96546565f9e521ed86f6510c29e19", - "https://deno.land/std@0.224.0/async/delay.ts": "f90dd685b97c2f142b8069082993e437b1602b8e2561134827eeb7c12b95c499", - "https://deno.land/std@0.224.0/cli/parse_args.ts": "5250832fb7c544d9111e8a41ad272c016f5a53f975ef84d5a9fe5fcb70566ece", - "https://deno.land/std@0.224.0/collections/_utils.ts": "b2ec8ada31b5a72ebb1d99774b849b4c09fe4b3a38d07794bd010bd218a16e0b", - "https://deno.land/std@0.224.0/collections/deep_merge.ts": "04f8d2a6cfa15c7580e788689bcb5e162512b9ccb18bab1241824b432a78551e", - "https://deno.land/std@0.224.0/encoding/_util.ts": "beacef316c1255da9bc8e95afb1fa56ed69baef919c88dc06ae6cb7a6103d376", - "https://deno.land/std@0.224.0/encoding/base64.ts": "dd59695391584c8ffc5a296ba82bcdba6dd8a84d41a6a539fbee8e5075286eaf", - "https://deno.land/std@0.224.0/encoding/hex.ts": "6270f25e5d85f99fcf315278670ba012b04b7c94b67715b53f30d03249687c07", - "https://deno.land/std@0.224.0/flags/mod.ts": "88553267f34519c8982212185339efdb2d2e62c159ec558f47eb50c8952a6be3", - "https://deno.land/std@0.224.0/fmt/bytes.ts": "7b294a4b9cf0297efa55acb55d50610f3e116a0ac772d1df0ae00f0b833ccd4a", - "https://deno.land/std@0.224.0/fmt/colors.ts": "508563c0659dd7198ba4bbf87e97f654af3c34eb56ba790260f252ad8012e1c5", - "https://deno.land/std@0.224.0/fs/_create_walk_entry.ts": "5d9d2aaec05bcf09a06748b1684224d33eba7a4de24cf4cf5599991ca6b5b412", - "https://deno.land/std@0.224.0/fs/_get_file_info_type.ts": "da7bec18a7661dba360a1db475b826b18977582ce6fc9b25f3d4ee0403fe8cbd", - "https://deno.land/std@0.224.0/fs/_is_same_path.ts": "709c95868345fea051c58b9e96af95cff94e6ae98dfcff2b66dee0c212c4221f", - "https://deno.land/std@0.224.0/fs/_is_subdir.ts": "c68b309d46cc8568ed83c000f608a61bbdba0943b7524e7a30f9e450cf67eecd", - "https://deno.land/std@0.224.0/fs/_to_path_string.ts": "29bfc9c6c112254961d75cbf6ba814d6de5349767818eb93090cecfa9665591e", - "https://deno.land/std@0.224.0/fs/copy.ts": "7ab12a16adb65d155d4943c88081ca16ce3b0b5acada64c1ce93800653678039", - "https://deno.land/std@0.224.0/fs/empty_dir.ts": "e400e96e1d2c8c558a5a1712063bd43939e00619c1d1cc29959babc6f1639418", - "https://deno.land/std@0.224.0/fs/ensure_dir.ts": "51a6279016c65d2985f8803c848e2888e206d1b510686a509fa7cc34ce59d29f", - "https://deno.land/std@0.224.0/fs/ensure_file.ts": "67608cf550529f3d4aa1f8b6b36bf817bdc40b14487bf8f60e61cbf68f507cf3", - "https://deno.land/std@0.224.0/fs/ensure_link.ts": "5c98503ebfa9cc05e2f2efaa30e91e60b4dd5b43ebbda82f435c0a5c6e3ffa01", - "https://deno.land/std@0.224.0/fs/ensure_symlink.ts": "cafe904cebacb9a761977d6dbf5e3af938be946a723bb394080b9a52714fafe4", - "https://deno.land/std@0.224.0/fs/eol.ts": "18c4ac009d0318504c285879eb7f47942643f13619e0ff070a0edc59353306bd", - "https://deno.land/std@0.224.0/fs/exists.ts": "3d38cb7dcbca3cf313be343a7b8af18a87bddb4b5ca1bd2314be12d06533b50f", - "https://deno.land/std@0.224.0/fs/expand_glob.ts": "2e428d90acc6676b2aa7b5c78ef48f30641b13f1fe658e7976c9064fb4b05309", - "https://deno.land/std@0.224.0/fs/mod.ts": "c25e6802cbf27f3050f60b26b00c2d8dba1cb7fcdafe34c66006a7473b7b34d4", - "https://deno.land/std@0.224.0/fs/move.ts": "ca205d848908d7f217353bc5c623627b1333490b8b5d3ef4cab600a700c9bd8f", - "https://deno.land/std@0.224.0/fs/walk.ts": "cddf87d2705c0163bff5d7767291f05b0f46ba10b8b28f227c3849cace08d303", - "https://deno.land/std@0.224.0/http/_negotiation/common.ts": "051a9f6edd1ed69507df89bbc16fc1b13b7654b9b8fd38072ec33ae4c185fc13", - "https://deno.land/std@0.224.0/http/_negotiation/encoding.ts": "fdedea1145c1dea3b3de2d5217e8eb927e764083eebc8c52d09a1ed3d9bb7a93", - "https://deno.land/std@0.224.0/http/_negotiation/language.ts": "300a5c586f844c97f246ab72c948e9fde9a8f45e92ec08e1cc9a9df80259e2a3", - "https://deno.land/std@0.224.0/http/_negotiation/media_type.ts": "87a1ecb22c1b268d0fa23d798e1ea238343505268cb1ff82bd038638de29ce31", - "https://deno.land/std@0.224.0/http/cookie.ts": "a377fa60175ba5f61dd4b8a70b34f2bbfbc70782dfd5faf36d314c42e4306006", - "https://deno.land/std@0.224.0/http/etag.ts": "9ca56531be682f202e4239971931060b688ee5c362688e239eeaca39db9e72cb", - "https://deno.land/std@0.224.0/http/file_server.ts": "2a5392195b8e7713288f274d071711b705bb5b3220294d76cce495d456c61a93", - "https://deno.land/std@0.224.0/http/mod.ts": "b0e06293a8a2f71b041add53d4674d4997bd2b83a4760bddad1b5e552130bcc8", - "https://deno.land/std@0.224.0/http/negotiation.ts": "d06ef2958ca712a7dbe4538eed6a46abfa2b87f8e150b7c89d83a6055dabd7cc", - "https://deno.land/std@0.224.0/http/server.ts": "f9313804bf6467a1704f45f76cb6cd0a3396a3b31c316035e6a4c2035d1ea514", - "https://deno.land/std@0.224.0/http/server_sent_event_stream.ts": "d9c20b46f986d78f60c38dbd91e95c71d73b45f29739a8ef4216dfa5f2e71eb3", - "https://deno.land/std@0.224.0/http/status.ts": "ed61b4882af2514a81aefd3245e8df4c47b9a8e54929a903577643d2d1ebf514", - "https://deno.land/std@0.224.0/http/unstable_signed_cookie.ts": "2a5bfbdf6b4aa35ef1464300fe1ba4eb89eb79f535c9cb28401d55fbb7038479", - "https://deno.land/std@0.224.0/http/user_agent.ts": "05f8849c7e27b898793bfc70204f0c72b6be9bee7accbe98e18a1c413bd4ace3", - "https://deno.land/std@0.224.0/internal/diff.ts": "6234a4b493ebe65dc67a18a0eb97ef683626a1166a1906232ce186ae9f65f4e6", - "https://deno.land/std@0.224.0/internal/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2", - "https://deno.land/std@0.224.0/internal/mod.ts": "534125398c8e7426183e12dc255bb635d94e06d0f93c60a297723abe69d3b22e", - "https://deno.land/std@0.224.0/media_types/_db.ts": "19563a2491cd81b53b9c1c6ffd1a9145c355042d4a854c52f6e1424f73ff3923", - "https://deno.land/std@0.224.0/media_types/_util.ts": "e0b8da0c7d8ad2015cf27ac16ddf0809ac984b2f3ec79f7fa4206659d4f10deb", - "https://deno.land/std@0.224.0/media_types/content_type.ts": "ed3f2e1f243b418ad3f441edc95fd92efbadb0f9bde36219c7564c67f9639513", - "https://deno.land/std@0.224.0/media_types/format_media_type.ts": "ffef4718afa2489530cb94021bb865a466eb02037609f7e82899c017959d288a", - "https://deno.land/std@0.224.0/media_types/get_charset.ts": "277ebfceb205bd34e616fe6764ef03fb277b77f040706272bea8680806ae3f11", - "https://deno.land/std@0.224.0/media_types/parse_media_type.ts": "487f000a38c230ccbac25420a50f600862e06796d0eee19d19631b9e84ee9654", - "https://deno.land/std@0.224.0/media_types/type_by_extension.ts": "bf4e3f5d6b58b624d5daa01cbb8b1e86d9939940a77e7c26e796a075b60ec73b", - "https://deno.land/std@0.224.0/media_types/vendor/mime-db.v1.52.0.ts": "0218d2c7d900e8cd6fa4a866e0c387712af4af9a1bae55d6b2546c73d273a1e6", - "https://deno.land/std@0.224.0/path/_common/assert_path.ts": "dbdd757a465b690b2cc72fc5fb7698c51507dec6bfafce4ca500c46b76ff7bd8", - "https://deno.land/std@0.224.0/path/_common/basename.ts": "569744855bc8445f3a56087fd2aed56bdad39da971a8d92b138c9913aecc5fa2", - "https://deno.land/std@0.224.0/path/_common/common.ts": "ef73c2860694775fe8ffcbcdd387f9f97c7a656febf0daa8c73b56f4d8a7bd4c", - "https://deno.land/std@0.224.0/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c", - "https://deno.land/std@0.224.0/path/_common/dirname.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8", - "https://deno.land/std@0.224.0/path/_common/format.ts": "92500e91ea5de21c97f5fe91e178bae62af524b72d5fcd246d6d60ae4bcada8b", - "https://deno.land/std@0.224.0/path/_common/from_file_url.ts": "d672bdeebc11bf80e99bf266f886c70963107bdd31134c4e249eef51133ceccf", - "https://deno.land/std@0.224.0/path/_common/glob_to_reg_exp.ts": "6cac16d5c2dc23af7d66348a7ce430e5de4e70b0eede074bdbcf4903f4374d8d", - "https://deno.land/std@0.224.0/path/_common/normalize.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8", - "https://deno.land/std@0.224.0/path/_common/normalize_string.ts": "33edef773c2a8e242761f731adeb2bd6d683e9c69e4e3d0092985bede74f4ac3", - "https://deno.land/std@0.224.0/path/_common/relative.ts": "faa2753d9b32320ed4ada0733261e3357c186e5705678d9dd08b97527deae607", - "https://deno.land/std@0.224.0/path/_common/strip_trailing_separators.ts": "7024a93447efcdcfeaa9339a98fa63ef9d53de363f1fbe9858970f1bba02655a", - "https://deno.land/std@0.224.0/path/_common/to_file_url.ts": "7f76adbc83ece1bba173e6e98a27c647712cab773d3f8cbe0398b74afc817883", - "https://deno.land/std@0.224.0/path/_interface.ts": "8dfeb930ca4a772c458a8c7bbe1e33216fe91c253411338ad80c5b6fa93ddba0", - "https://deno.land/std@0.224.0/path/_os.ts": "8fb9b90fb6b753bd8c77cfd8a33c2ff6c5f5bc185f50de8ca4ac6a05710b2c15", - "https://deno.land/std@0.224.0/path/basename.ts": "7ee495c2d1ee516ffff48fb9a93267ba928b5a3486b550be73071bc14f8cc63e", - "https://deno.land/std@0.224.0/path/common.ts": "03e52e22882402c986fe97ca3b5bb4263c2aa811c515ce84584b23bac4cc2643", - "https://deno.land/std@0.224.0/path/constants.ts": "0c206169ca104938ede9da48ac952de288f23343304a1c3cb6ec7625e7325f36", - "https://deno.land/std@0.224.0/path/dirname.ts": "85bd955bf31d62c9aafdd7ff561c4b5fb587d11a9a5a45e2b01aedffa4238a7c", - "https://deno.land/std@0.224.0/path/extname.ts": "593303db8ae8c865cbd9ceec6e55d4b9ac5410c1e276bfd3131916591b954441", - "https://deno.land/std@0.224.0/path/format.ts": "6ce1779b0980296cf2bc20d66436b12792102b831fd281ab9eb08fa8a3e6f6ac", - "https://deno.land/std@0.224.0/path/from_file_url.ts": "911833ae4fd10a1c84f6271f36151ab785955849117dc48c6e43b929504ee069", - "https://deno.land/std@0.224.0/path/glob_to_regexp.ts": "7f30f0a21439cadfdae1be1bf370880b415e676097fda584a63ce319053b5972", - "https://deno.land/std@0.224.0/path/is_absolute.ts": "4791afc8bfd0c87f0526eaa616b0d16e7b3ab6a65b62942e50eac68de4ef67d7", - "https://deno.land/std@0.224.0/path/is_glob.ts": "a65f6195d3058c3050ab905705891b412ff942a292bcbaa1a807a74439a14141", - "https://deno.land/std@0.224.0/path/join.ts": "ae2ec5ca44c7e84a235fd532e4a0116bfb1f2368b394db1c4fb75e3c0f26a33a", - "https://deno.land/std@0.224.0/path/join_globs.ts": "5b3bf248b93247194f94fa6947b612ab9d3abd571ca8386cf7789038545e54a0", - "https://deno.land/std@0.224.0/path/mod.ts": "f6bd79cb08be0e604201bc9de41ac9248582699d1b2ee0ab6bc9190d472cf9cd", - "https://deno.land/std@0.224.0/path/normalize.ts": "4155743ccceeed319b350c1e62e931600272fad8ad00c417b91df093867a8352", - "https://deno.land/std@0.224.0/path/normalize_glob.ts": "cc89a77a7d3b1d01053b9dcd59462b75482b11e9068ae6c754b5cf5d794b374f", - "https://deno.land/std@0.224.0/path/parse.ts": "77ad91dcb235a66c6f504df83087ce2a5471e67d79c402014f6e847389108d5a", - "https://deno.land/std@0.224.0/path/posix/_util.ts": "1e3937da30f080bfc99fe45d7ed23c47dd8585c5e473b2d771380d3a6937cf9d", - "https://deno.land/std@0.224.0/path/posix/basename.ts": "d2fa5fbbb1c5a3ab8b9326458a8d4ceac77580961b3739cd5bfd1d3541a3e5f0", - "https://deno.land/std@0.224.0/path/posix/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4", - "https://deno.land/std@0.224.0/path/posix/constants.ts": "93481efb98cdffa4c719c22a0182b994e5a6aed3047e1962f6c2c75b7592bef1", - "https://deno.land/std@0.224.0/path/posix/dirname.ts": "76cd348ffe92345711409f88d4d8561d8645353ac215c8e9c80140069bf42f00", - "https://deno.land/std@0.224.0/path/posix/extname.ts": "e398c1d9d1908d3756a7ed94199fcd169e79466dd88feffd2f47ce0abf9d61d2", - "https://deno.land/std@0.224.0/path/posix/format.ts": "185e9ee2091a42dd39e2a3b8e4925370ee8407572cee1ae52838aed96310c5c1", - "https://deno.land/std@0.224.0/path/posix/from_file_url.ts": "951aee3a2c46fd0ed488899d024c6352b59154c70552e90885ed0c2ab699bc40", - "https://deno.land/std@0.224.0/path/posix/glob_to_regexp.ts": "76f012fcdb22c04b633f536c0b9644d100861bea36e9da56a94b9c589a742e8f", - "https://deno.land/std@0.224.0/path/posix/is_absolute.ts": "cebe561ad0ae294f0ce0365a1879dcfca8abd872821519b4fcc8d8967f888ede", - "https://deno.land/std@0.224.0/path/posix/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9", - "https://deno.land/std@0.224.0/path/posix/join.ts": "7fc2cb3716aa1b863e990baf30b101d768db479e70b7313b4866a088db016f63", - "https://deno.land/std@0.224.0/path/posix/join_globs.ts": "a9475b44645feddceb484ee0498e456f4add112e181cb94042cdc6d47d1cdd25", - "https://deno.land/std@0.224.0/path/posix/mod.ts": "2301fc1c54a28b349e20656f68a85f75befa0ee9b6cd75bfac3da5aca9c3f604", - "https://deno.land/std@0.224.0/path/posix/normalize.ts": "baeb49816a8299f90a0237d214cef46f00ba3e95c0d2ceb74205a6a584b58a91", - "https://deno.land/std@0.224.0/path/posix/normalize_glob.ts": "9c87a829b6c0f445d03b3ecadc14492e2864c3ebb966f4cea41e98326e4435c6", - "https://deno.land/std@0.224.0/path/posix/parse.ts": "09dfad0cae530f93627202f28c1befa78ea6e751f92f478ca2cc3b56be2cbb6a", - "https://deno.land/std@0.224.0/path/posix/relative.ts": "3907d6eda41f0ff723d336125a1ad4349112cd4d48f693859980314d5b9da31c", - "https://deno.land/std@0.224.0/path/posix/resolve.ts": "08b699cfeee10cb6857ccab38fa4b2ec703b0ea33e8e69964f29d02a2d5257cf", - "https://deno.land/std@0.224.0/path/posix/to_file_url.ts": "7aa752ba66a35049e0e4a4be5a0a31ac6b645257d2e031142abb1854de250aaf", - "https://deno.land/std@0.224.0/path/posix/to_namespaced_path.ts": "28b216b3c76f892a4dca9734ff1cc0045d135532bfd9c435ae4858bfa5a2ebf0", - "https://deno.land/std@0.224.0/path/relative.ts": "ab739d727180ed8727e34ed71d976912461d98e2b76de3d3de834c1066667add", - "https://deno.land/std@0.224.0/path/resolve.ts": "a6f977bdb4272e79d8d0ed4333e3d71367cc3926acf15ac271f1d059c8494d8d", - "https://deno.land/std@0.224.0/path/to_file_url.ts": "88f049b769bce411e2d2db5bd9e6fd9a185a5fbd6b9f5ad8f52bef517c4ece1b", - "https://deno.land/std@0.224.0/path/to_namespaced_path.ts": "b706a4103b104cfadc09600a5f838c2ba94dbcdb642344557122dda444526e40", - "https://deno.land/std@0.224.0/path/windows/_util.ts": "d5f47363e5293fced22c984550d5e70e98e266cc3f31769e1710511803d04808", - "https://deno.land/std@0.224.0/path/windows/basename.ts": "6bbc57bac9df2cec43288c8c5334919418d784243a00bc10de67d392ab36d660", - "https://deno.land/std@0.224.0/path/windows/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4", - "https://deno.land/std@0.224.0/path/windows/constants.ts": "5afaac0a1f67b68b0a380a4ef391bf59feb55856aa8c60dfc01bd3b6abb813f5", - "https://deno.land/std@0.224.0/path/windows/dirname.ts": "33e421be5a5558a1346a48e74c330b8e560be7424ed7684ea03c12c21b627bc9", - "https://deno.land/std@0.224.0/path/windows/extname.ts": "165a61b00d781257fda1e9606a48c78b06815385e7d703232548dbfc95346bef", - "https://deno.land/std@0.224.0/path/windows/format.ts": "bbb5ecf379305b472b1082cd2fdc010e44a0020030414974d6029be9ad52aeb6", - "https://deno.land/std@0.224.0/path/windows/from_file_url.ts": "ced2d587b6dff18f963f269d745c4a599cf82b0c4007356bd957cb4cb52efc01", - "https://deno.land/std@0.224.0/path/windows/glob_to_regexp.ts": "e45f1f89bf3fc36f94ab7b3b9d0026729829fabc486c77f414caebef3b7304f8", - "https://deno.land/std@0.224.0/path/windows/is_absolute.ts": "4a8f6853f8598cf91a835f41abed42112cebab09478b072e4beb00ec81f8ca8a", - "https://deno.land/std@0.224.0/path/windows/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9", - "https://deno.land/std@0.224.0/path/windows/join.ts": "8d03530ab89195185103b7da9dfc6327af13eabdcd44c7c63e42e27808f50ecf", - "https://deno.land/std@0.224.0/path/windows/join_globs.ts": "a9475b44645feddceb484ee0498e456f4add112e181cb94042cdc6d47d1cdd25", - "https://deno.land/std@0.224.0/path/windows/mod.ts": "2301fc1c54a28b349e20656f68a85f75befa0ee9b6cd75bfac3da5aca9c3f604", - "https://deno.land/std@0.224.0/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780", - "https://deno.land/std@0.224.0/path/windows/normalize_glob.ts": "9c87a829b6c0f445d03b3ecadc14492e2864c3ebb966f4cea41e98326e4435c6", - "https://deno.land/std@0.224.0/path/windows/parse.ts": "08804327b0484d18ab4d6781742bf374976de662f8642e62a67e93346e759707", - "https://deno.land/std@0.224.0/path/windows/relative.ts": "3e1abc7977ee6cc0db2730d1f9cb38be87b0ce4806759d271a70e4997fc638d7", - "https://deno.land/std@0.224.0/path/windows/resolve.ts": "8dae1dadfed9d46ff46cc337c9525c0c7d959fb400a6308f34595c45bdca1972", - "https://deno.land/std@0.224.0/path/windows/to_file_url.ts": "40e560ee4854fe5a3d4d12976cef2f4e8914125c81b11f1108e127934ced502e", - "https://deno.land/std@0.224.0/path/windows/to_namespaced_path.ts": "4ffa4fb6fae321448d5fe810b3ca741d84df4d7897e61ee29be961a6aac89a4c", - "https://deno.land/std@0.224.0/streams/byte_slice_stream.ts": "5bbdcadb118390affa9b3d0a0f73ef8e83754f59bb89df349add669dd9369713", - "https://deno.land/std@0.224.0/testing/asserts.ts": "d0cdbabadc49cc4247a50732ee0df1403fdcd0f95360294ad448ae8c240f3f5c", - "https://deno.land/std@0.224.0/toml/_parser.ts": "187560eb4465977808b18c68299e1f5a6e4631c0a181d868c8f24722cf9146d1", - "https://deno.land/std@0.224.0/toml/mod.ts": "a457ea7877a6d5e7f3d6985c43da4d2ecd7461038d5c4c7a0089737e90a7ee90", - "https://deno.land/std@0.224.0/toml/parse.ts": "2f0729a8f62c7e508af8dfada0386a4bc2c0d664ef4d26090df03cf495dcb25a", - "https://deno.land/std@0.224.0/toml/stringify.ts": "8b9ba3c1bf8fa7d58d7b62ad62b3174dbbc51050d5cc302aa8e2834089c00d73", - "https://deno.land/std@0.224.0/version.ts": "f6a28c9704d82d1c095988777e30e6172eb674a6570974a0d27a653be769bbbe", - "https://deno.land/x/checksum@1.4.0/hash.ts": "89ebbf7c57576e20462badc05bfb4a7ac01fe7668b6908cd547c79067c4221b9", - "https://deno.land/x/checksum@1.4.0/md5.ts": "1bb0889eaec838d5c1f219e0533277fe5ea10806d022920b6f0f2f8c398fec77", - "https://deno.land/x/checksum@1.4.0/mod.ts": "df8282cc1ecfd0f148535337c8bec077a1630e96a2012f2d19b2ca380f2c88c2", - "https://deno.land/x/checksum@1.4.0/sha1.ts": "a608a6493694b7d734acfc4eee83e09bd9deaa4909cdac07f3eed3db427f97ae", - "https://deno.land/x/zod@v3.23.8/ZodError.ts": "528da200fbe995157b9ae91498b103c4ef482217a5c086249507ac850bd78f52", - "https://deno.land/x/zod@v3.23.8/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef", - "https://deno.land/x/zod@v3.23.8/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe", - "https://deno.land/x/zod@v3.23.8/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c", - "https://deno.land/x/zod@v3.23.8/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7", - "https://deno.land/x/zod@v3.23.8/helpers/parseUtil.ts": "c14814d167cc286972b6e094df88d7d982572a08424b7cd50f862036b6fcaa77", - "https://deno.land/x/zod@v3.23.8/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7", - "https://deno.land/x/zod@v3.23.8/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e", - "https://deno.land/x/zod@v3.23.8/helpers/util.ts": "30c273131661ca5dc973f2cfb196fa23caf3a43e224cdde7a683b72e101a31fc", - "https://deno.land/x/zod@v3.23.8/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268", - "https://deno.land/x/zod@v3.23.8/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", - "https://deno.land/x/zod@v3.23.8/mod.ts": "ec6e2b1255c1a350b80188f97bd0a6bac45801bb46fc48f50b9763aa66046039", - "https://deno.land/x/zod@v3.23.8/types.ts": "1b172c90782b1eaa837100ebb6abd726d79d6c1ec336350c8e851e0fd706bf5c", - "https://deno.land/x/zod@v3.24.2/ZodError.ts": "27b41119736fcdc69cc72e63838bed1e9e1210c7ce721211f02256e06b443b55", - "https://deno.land/x/zod@v3.24.2/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef", - "https://deno.land/x/zod@v3.24.2/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe", - "https://deno.land/x/zod@v3.24.2/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c", - "https://deno.land/x/zod@v3.24.2/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7", - "https://deno.land/x/zod@v3.24.2/helpers/parseUtil.ts": "c14814d167cc286972b6e094df88d7d982572a08424b7cd50f862036b6fcaa77", - "https://deno.land/x/zod@v3.24.2/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7", - "https://deno.land/x/zod@v3.24.2/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e", - "https://deno.land/x/zod@v3.24.2/helpers/util.ts": "30c273131661ca5dc973f2cfb196fa23caf3a43e224cdde7a683b72e101a31fc", - "https://deno.land/x/zod@v3.24.2/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268", - "https://deno.land/x/zod@v3.24.2/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", - "https://deno.land/x/zod@v3.24.2/mod.ts": "ec6e2b1255c1a350b80188f97bd0a6bac45801bb46fc48f50b9763aa66046039", - "https://deno.land/x/zod@v3.24.2/standard-schema.ts": "4abb2e7bd784fb95d219584673971bb317e74fb4fd0c74c196b558ba46df4456", - "https://deno.land/x/zod@v3.24.2/types.ts": "91f825106bcf5b2ba08daa108283aadc32c0ac332f09c9a90db3d88b142476a3" - }, - "workspace": { - "dependencies": [ - "jsr:@std/assert@^1.0.13", - "jsr:@std/cli@^1.0.20", - "jsr:@std/fs@^1.0.19", - "jsr:@std/http@^1.0.19", - "jsr:@std/path@^1.1.1", - "jsr:@std/toml@^1.0.8", - "npm:@types/mdast@4", - "npm:mdast-util-directive@3", - "npm:remark-directive@3", - "npm:remark-gfm@4", - "npm:remark-parse@11", - "npm:remark-smartypants@3", - "npm:shiki@^3.7.0", - "npm:unified@11" - ] - } -} diff --git a/services/nuldoc/lib/nuldoc.rb b/services/nuldoc/lib/nuldoc.rb new file mode 100644 index 00000000..2cd2a032 --- /dev/null +++ b/services/nuldoc/lib/nuldoc.rb @@ -0,0 +1,62 @@ +require 'date' +require 'digest' +require 'English' +require 'fileutils' +require 'securerandom' + +require 'dry/cli' +require 'rouge' +require 'toml-rb' +require 'webrick' + +require_relative 'nuldoc/dom' +require_relative 'nuldoc/revision' +require_relative 'nuldoc/config' +require_relative 'nuldoc/page' +require_relative 'nuldoc/render' +require_relative 'nuldoc/renderers/html' +require_relative 'nuldoc/renderers/xml' +require_relative 'nuldoc/markdown/document' +require_relative 'nuldoc/markdown/parser/line_scanner' +require_relative 'nuldoc/markdown/parser/attributes' +require_relative 'nuldoc/markdown/parser/inline_parser' +require_relative 'nuldoc/markdown/parser/block_parser' +require_relative 'nuldoc/markdown/parse' +require_relative 'nuldoc/markdown/transform' +require_relative 'nuldoc/slide/slide' +require_relative 'nuldoc/slide/parse' +require_relative 'nuldoc/components/utils' +require_relative 'nuldoc/components/page_layout' +require_relative 'nuldoc/components/global_footer' +require_relative 'nuldoc/components/global_headers' +require_relative 'nuldoc/components/post_page_entry' +require_relative 'nuldoc/components/slide_page_entry' +require_relative 'nuldoc/components/pagination' +require_relative 'nuldoc/components/table_of_contents' +require_relative 'nuldoc/components/tag_list' +require_relative 'nuldoc/components/static_stylesheet' +require_relative 'nuldoc/components/static_script' +require_relative 'nuldoc/pages/home_page' +require_relative 'nuldoc/pages/about_page' +require_relative 'nuldoc/pages/post_page' +require_relative 'nuldoc/pages/post_list_page' +require_relative 'nuldoc/pages/slide_page' +require_relative 'nuldoc/pages/slide_list_page' +require_relative 'nuldoc/pages/tag_page' +require_relative 'nuldoc/pages/tag_list_page' +require_relative 'nuldoc/pages/atom_page' +require_relative 'nuldoc/pages/not_found_page' +require_relative 'nuldoc/generators/home' +require_relative 'nuldoc/generators/about' +require_relative 'nuldoc/generators/post' +require_relative 'nuldoc/generators/post_list' +require_relative 'nuldoc/generators/slide' +require_relative 'nuldoc/generators/slide_list' +require_relative 'nuldoc/generators/tag' +require_relative 'nuldoc/generators/tag_list' +require_relative 'nuldoc/generators/atom' +require_relative 'nuldoc/generators/not_found' +require_relative 'nuldoc/commands/build' +require_relative 'nuldoc/commands/serve' +require_relative 'nuldoc/commands/new' +require_relative 'nuldoc/cli' diff --git a/services/nuldoc/lib/nuldoc/cli.rb b/services/nuldoc/lib/nuldoc/cli.rb new file mode 100644 index 00000000..f3a18da9 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/cli.rb @@ -0,0 +1,46 @@ +module Nuldoc + module CLI + extend Dry::CLI::Registry + + class BuildCommand < Dry::CLI::Command + desc 'Build the site' + + def call(**) + config = ConfigLoader.load_config(ConfigLoader.default_config_path) + Commands::Build.run(config) + end + end + + class ServeCommand < Dry::CLI::Command + desc 'Start development server' + + argument :site, required: true, desc: 'Site to serve (default, about, blog, slides)' + option :no_rebuild, type: :boolean, default: false, desc: 'Skip rebuilding on each request' + + def call(site:, **options) + config = ConfigLoader.load_config(ConfigLoader.default_config_path) + Commands::Serve.run(config, site_name: site, no_rebuild: options[:no_rebuild]) + end + end + + class NewCommand < Dry::CLI::Command + desc 'Create new content' + + argument :type, required: true, desc: 'Content type (post or slide)' + option :date, desc: 'Date (YYYY-MM-DD)' + + def call(type:, **options) + config = ConfigLoader.load_config(ConfigLoader.default_config_path) + Commands::New.run(config, type: type, date: options[:date]) + end + end + + register 'build', BuildCommand + register 'serve', ServeCommand + register 'new', NewCommand + + def self.call + Dry::CLI.new(self).call + end + end +end diff --git a/services/nuldoc/lib/nuldoc/commands/build.rb b/services/nuldoc/lib/nuldoc/commands/build.rb new file mode 100644 index 00000000..868493c3 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/commands/build.rb @@ -0,0 +1,216 @@ +module Nuldoc + module Commands + class Build + def self.run(config) + new(config).run + end + + def initialize(config) + @config = config + end + + def run + posts = build_post_pages + build_post_list_page(posts) + slides = build_slide_pages + build_slide_list_page(slides) + post_tags = build_tag_pages(posts, 'blog') + build_tag_list_page(post_tags, 'blog') + slides_tags = build_tag_pages(slides, 'slides') + build_tag_list_page(slides_tags, 'slides') + build_home_page + build_about_page(slides) + %w[default about blog slides].each { |site| build_not_found_page(site) } + copy_static_files + copy_slides_files(slides) + copy_blog_asset_files + copy_slides_asset_files + copy_post_source_files(posts) + end + + private + + def build_post_pages + source_dir = File.join(Dir.pwd, @config.locations.content_dir, 'posts') + post_files = Dir.glob(File.join(source_dir, '**', '*.md')) + posts = post_files.map do |file| + doc = MarkdownParser.new(file, @config).parse + Generators::Post.new(doc, @config).generate + end + posts.each { |post| write_page(post) } + posts + end + + def build_post_list_page(posts) + sorted_posts = posts.sort do |a, b| + [GeneratorUtils.published_date(b), a.href] <=> [GeneratorUtils.published_date(a), b.href] + end + + post_list_pages = Generators::PostList.new(sorted_posts, @config).generate + post_list_pages.each { |page| write_page(page) } + + post_feed = Generators::Atom.new( + '/posts/', 'posts', + "投稿一覧|#{@config.sites.blog.site_name}", + posts, 'blog', @config + ).generate + write_page(post_feed) + end + + def build_slide_pages + source_dir = File.join(Dir.pwd, @config.locations.content_dir, 'slides') + slide_files = Dir.glob(File.join(source_dir, '**', '*.toml')) + slides = slide_files.map do |file| + slide = SlideParser.new(file).parse + Generators::Slide.new(slide, @config).generate + end + slides.each { |slide| write_page(slide) } + slides + end + + def build_slide_list_page(slides) + slide_list_page = Generators::SlideList.new(slides, @config).generate + write_page(slide_list_page) + + slide_feed = Generators::Atom.new( + slide_list_page.href, 'slides', + "スライド一覧|#{@config.sites.slides.site_name}", + slides, 'slides', @config + ).generate + write_page(slide_feed) + end + + def build_home_page + write_page(Generators::Home.new(@config).generate) + end + + def build_about_page(slides) + write_page(Generators::About.new(slides, @config).generate) + end + + def build_not_found_page(site) + write_page(Generators::NotFound.new(site, @config).generate) + end + + def build_tag_pages(pages, site) + tags_and_pages = collect_tags(pages) + tags = [] + tags_and_pages.each do |tag, tag_pages| + tag_page = Generators::Tag.new(tag, tag_pages, site, @config).generate + write_page(tag_page) + + tag_feed = Generators::Atom.new( + tag_page.href, "tag-#{tag}", + "タグ「#{@config.tag_label(tag)}」一覧|#{@config.site_entry(site).site_name}", + tag_pages, site, @config + ).generate + write_page(tag_feed) + tags.push(tag_page) + end + tags + end + + def build_tag_list_page(tags, site) + write_page(Generators::TagList.new(tags, site, @config).generate) + end + + def collect_tags(tagged_pages) + tags_and_pages = {} + tagged_pages.each do |page| + page.tags.each do |tag| + tags_and_pages[tag] ||= [] + tags_and_pages[tag].push(page) + end + end + + tags_and_pages.sort_by { |tag, _| tag }.map do |tag, pages| + sorted_pages = pages.sort do |a, b| + [GeneratorUtils.published_date(b), a.href] <=> [GeneratorUtils.published_date(a), b.href] + end + [tag, sorted_pages] + end + end + + def copy_static_files + static_dir = File.join(Dir.pwd, @config.locations.static_dir) + + %w[default about blog slides].each do |site| + dest_dir = File.join(Dir.pwd, @config.locations.dest_dir, site) + + Dir.glob(File.join(static_dir, '_all', '*')).each do |entry| + next unless File.file?(entry) + + FileUtils.cp(entry, File.join(dest_dir, File.basename(entry))) + end + + Dir.glob(File.join(static_dir, site, '*')).each do |entry| + next unless File.file?(entry) + + FileUtils.cp(entry, File.join(dest_dir, File.basename(entry))) + end + end + end + + def copy_slides_files(slides) + content_dir = File.join(Dir.pwd, @config.locations.content_dir) + dest_dir = File.join(Dir.pwd, @config.locations.dest_dir) + + slides.each do |slide| + src = File.join(content_dir, slide.slide_link) + dst = File.join(dest_dir, 'slides', slide.slide_link) + FileUtils.mkdir_p(File.dirname(dst)) + FileUtils.cp(src, dst) + end + end + + def copy_blog_asset_files + content_dir = File.join(Dir.pwd, @config.locations.content_dir, 'posts') + dest_dir = File.join(Dir.pwd, @config.locations.dest_dir, 'blog') + + Dir.glob(File.join(content_dir, '**', '*')).each do |path| + next unless File.file?(path) + next if path.end_with?('.md', '.toml', '.pdf') + + relative = path.sub("#{content_dir}/", '') + dst = File.join(dest_dir, 'posts', relative) + FileUtils.mkdir_p(File.dirname(dst)) + FileUtils.cp(path, dst) + end + end + + def copy_slides_asset_files + content_dir = File.join(Dir.pwd, @config.locations.content_dir, 'slides') + dest_dir = File.join(Dir.pwd, @config.locations.dest_dir, 'slides') + + Dir.glob(File.join(content_dir, '**', '*')).each do |path| + next unless File.file?(path) + next if path.end_with?('.md', '.toml', '.pdf') + + relative = path.sub("#{content_dir}/", '') + dst = File.join(dest_dir, 'slides', relative) + FileUtils.mkdir_p(File.dirname(dst)) + FileUtils.cp(path, dst) + end + end + + def write_page(page) + dest_file_path = File.join(Dir.pwd, @config.locations.dest_dir, page.site, page.dest_file_path) + FileUtils.mkdir_p(File.dirname(dest_file_path)) + File.write(dest_file_path, Renderer.new.render(page.root, page.renderer)) + end + + def copy_post_source_files(posts) + content_dir = File.join(Dir.pwd, @config.locations.content_dir) + dest_dir = File.join(Dir.pwd, @config.locations.dest_dir, 'blog') + + posts.each do |post| + src = post.source_file_path + relative = src.sub("#{content_dir}/", '') + dst = File.join(dest_dir, relative) + FileUtils.mkdir_p(File.dirname(dst)) + FileUtils.cp(src, dst) + end + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/commands/new.rb b/services/nuldoc/lib/nuldoc/commands/new.rb new file mode 100644 index 00000000..13919a75 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/commands/new.rb @@ -0,0 +1,81 @@ +module Nuldoc + module Commands + class New + def self.run(config, type:, date: nil) + new(config).run(type: type, date: date) + end + + def initialize(config) + @config = config + end + + def run(type:, date: nil) + unless %w[post slide].include?(type) + warn <<~USAGE + Usage: nuldoc new <type> + + <type> must be either "post" or "slide". + + OPTIONS: + --date <DATE> + USAGE + exit 1 + end + + ymd = date || Time.now.strftime('%Y-%m-%d') + + dir_path = type == 'post' ? 'posts' : 'slides' + filename = type == 'post' ? 'TODO.md' : 'TODO.toml' + + dest_file_path = File.join(Dir.pwd, @config.locations.content_dir, dir_path, ymd, filename) + FileUtils.mkdir_p(File.dirname(dest_file_path)) + File.write(dest_file_path, template(type, ymd)) + + relative = dest_file_path.sub(Dir.pwd, '') + puts "New file #{relative} was successfully created." + end + + private + + def template(type, date) + uuid = SecureRandom.uuid + if type == 'post' + <<~TEMPLATE + --- + [article] + uuid = "#{uuid}" + title = "TODO" + description = "TODO" + tags = [ + "TODO", + ] + + [[article.revisions]] + date = "#{date}" + remark = "公開" + --- + # はじめに {#intro} + + TODO + TEMPLATE + else + <<~TEMPLATE + [slide] + uuid = "#{uuid}" + title = "TODO" + event = "TODO" + talkType = "TODO" + link = "TODO" + tags = [ + "TODO", + ] + + [[slide.revisions]] + date = "#{date}" + remark = "登壇" + TEMPLATE + end + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/commands/serve.rb b/services/nuldoc/lib/nuldoc/commands/serve.rb new file mode 100644 index 00000000..060e51b8 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/commands/serve.rb @@ -0,0 +1,63 @@ +module Nuldoc + module Commands + class Serve + def self.run(config, site_name:, no_rebuild: false) + new(config).run(site_name: site_name, no_rebuild: no_rebuild) + end + + def initialize(config) + @config = config + end + + def run(site_name:, no_rebuild: false) + raise 'Usage: nuldoc serve <site>' if site_name.nil? || site_name.empty? + + root_dir = File.join(Dir.pwd, @config.locations.dest_dir, site_name) + + server = WEBrick::HTTPServer.new( + Port: 8000, + BindAddress: '127.0.0.1', + DocumentRoot: root_dir, + Logger: WEBrick::Log.new($stderr, WEBrick::Log::INFO) + ) + + server.mount_proc '/' do |req, res| + pathname = req.path + + unless resource_path?(pathname) || no_rebuild + Build.run(@config) + warn 'rebuild' + end + + file_path = File.expand_path(File.join(root_dir, pathname)) + unless file_path.start_with?(File.realpath(root_dir)) + res.status = 403 + res.body = '403 Forbidden' + next + end + file_path = File.join(file_path, 'index.html') if File.directory?(file_path) + + if File.exist?(file_path) + res.body = File.read(file_path) + res['Content-Type'] = WEBrick::HTTPUtils.mime_type(file_path, WEBrick::HTTPUtils::DefaultMimeTypes) + else + not_found_path = File.join(root_dir, '404.html') + res.status = 404 + res.body = File.exist?(not_found_path) ? File.read(not_found_path) : '404 Not Found' + res['Content-Type'] = 'text/html' + end + end + + trap('INT') { server.shutdown } + server.start + end + + private + + def resource_path?(pathname) + extensions = %w[.css .gif .ico .jpeg .jpg .js .mjs .png .svg] + extensions.any? { |ext| pathname.end_with?(ext) } + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/components/global_footer.rb b/services/nuldoc/lib/nuldoc/components/global_footer.rb new file mode 100644 index 00000000..8d4143fb --- /dev/null +++ b/services/nuldoc/lib/nuldoc/components/global_footer.rb @@ -0,0 +1,11 @@ +module Nuldoc + module Components + class GlobalFooter + extend Dom + + def self.render(config:) + footer({ 'class' => 'footer' }, "© #{config.site.copyright_year} #{config.site.author}") + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/components/global_headers.rb b/services/nuldoc/lib/nuldoc/components/global_headers.rb new file mode 100644 index 00000000..b06c6173 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/components/global_headers.rb @@ -0,0 +1,54 @@ +module Nuldoc + module Components + class DefaultGlobalHeader + extend Dom + + def self.render(config:) + header({ 'class' => 'header' }, + div({ 'class' => 'site-logo' }, + a({ 'href' => "https://#{config.sites.default.fqdn}/" }, 'nsfisis.dev'))) + end + end + + class AboutGlobalHeader + extend Dom + + def self.render(config:) + header({ 'class' => 'header' }, + div({ 'class' => 'site-logo' }, + a({ 'href' => "https://#{config.sites.default.fqdn}/" }, 'nsfisis.dev'))) + end + end + + class BlogGlobalHeader + extend Dom + + def self.render(config:) + header({ 'class' => 'header' }, + div({ 'class' => 'site-logo' }, + a({ 'href' => "https://#{config.sites.default.fqdn}/" }, 'nsfisis.dev')), + div({ 'class' => 'site-name' }, config.sites.blog.site_name), + nav({ 'class' => 'nav' }, + ul({}, + li({}, a({ 'href' => "https://#{config.sites.about.fqdn}/" }, 'About')), + li({}, a({ 'href' => '/posts/' }, 'Posts')), + li({}, a({ 'href' => '/tags/' }, 'Tags'))))) + end + end + + class SlidesGlobalHeader + extend Dom + + def self.render(config:) + header({ 'class' => 'header' }, + div({ 'class' => 'site-logo' }, + a({ 'href' => "https://#{config.sites.default.fqdn}/" }, 'nsfisis.dev')), + nav({ 'class' => 'nav' }, + ul({}, + li({}, a({ 'href' => "https://#{config.sites.about.fqdn}/" }, 'About')), + li({}, a({ 'href' => '/slides/' }, 'Slides')), + li({}, a({ 'href' => '/tags/' }, 'Tags'))))) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/components/page_layout.rb b/services/nuldoc/lib/nuldoc/components/page_layout.rb new file mode 100644 index 00000000..5d14ec0d --- /dev/null +++ b/services/nuldoc/lib/nuldoc/components/page_layout.rb @@ -0,0 +1,35 @@ +module Nuldoc + module Components + class PageLayout + extend Dom + + def self.render(meta_copyright_year:, meta_description:, meta_title:, site:, config:, children:, + meta_keywords: nil, meta_atom_feed_href: nil) + site_entry = config.site_entry(site) + + elem('html', { 'lang' => 'ja-JP' }, + elem('head', {}, + meta({ 'charset' => 'UTF-8' }), + meta({ 'name' => 'viewport', 'content' => 'width=device-width, initial-scale=1.0' }), + meta({ 'name' => 'author', 'content' => config.site.author }), + meta({ 'name' => 'copyright', + 'content' => "© #{meta_copyright_year} #{config.site.author}" }), + meta({ 'name' => 'description', 'content' => meta_description }), + meta_keywords && !meta_keywords.empty? ? meta({ 'name' => 'keywords', + 'content' => meta_keywords.join(',') }) : nil, + meta({ 'property' => 'og:type', 'content' => 'article' }), + meta({ 'property' => 'og:title', 'content' => meta_title }), + meta({ 'property' => 'og:description', 'content' => meta_description }), + meta({ 'property' => 'og:site_name', 'content' => site_entry.site_name }), + meta({ 'property' => 'og:locale', 'content' => 'ja_JP' }), + meta({ 'name' => 'Hatena::Bookmark', 'content' => 'nocomment' }), + meta_atom_feed_href ? link({ 'rel' => 'alternate', 'href' => meta_atom_feed_href, + 'type' => 'application/atom+xml' }) : nil, + link({ 'rel' => 'icon', 'href' => '/favicon.svg', 'type' => 'image/svg+xml' }), + elem('title', {}, meta_title), + StaticStylesheet.render(file_name: '/style.css', config: config)), + children) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/components/pagination.rb b/services/nuldoc/lib/nuldoc/components/pagination.rb new file mode 100644 index 00000000..500b81f9 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/components/pagination.rb @@ -0,0 +1,62 @@ +module Nuldoc + module Components + class Pagination + extend Dom + + def self.render(current_page:, total_pages:, base_path:) + return div({}) if total_pages <= 1 + + pages = generate_page_numbers(current_page, total_pages) + + nav({ 'class' => 'pagination' }, + div({ 'class' => 'pagination-prev' }, + current_page > 1 ? a({ 'href' => page_url_at(base_path, current_page - 1) }, '前へ') : nil), + *pages.map do |page| + if page == '...' + div({ 'class' => 'pagination-elipsis' }, "\u2026") + elsif page == current_page + div({ 'class' => 'pagination-page pagination-page-current' }, + span({}, page.to_s)) + else + div({ 'class' => 'pagination-page' }, + a({ 'href' => page_url_at(base_path, page) }, page.to_s)) + end + end, + div({ 'class' => 'pagination-next' }, + current_page < total_pages ? a({ 'href' => page_url_at(base_path, current_page + 1) }, '次へ') : nil)) + end + + def self.generate_page_numbers(current_page, total_pages) + pages = Set.new + pages.add(1) + pages.add([1, current_page - 1].max) + pages.add(current_page) + pages.add([total_pages, current_page + 1].min) + pages.add(total_pages) + + sorted = pages.sort + + result = [] + sorted.each_with_index do |page, i| + if i.positive? + gap = page - sorted[i - 1] + if gap == 2 + result.push(sorted[i - 1] + 1) + elsif gap > 2 + result.push('...') + end + end + result.push(page) + end + + result + end + + def self.page_url_at(base_path, page) + page == 1 ? base_path : "#{base_path}#{page}/" + end + + private_class_method :generate_page_numbers, :page_url_at + end + end +end diff --git a/services/nuldoc/lib/nuldoc/components/post_page_entry.rb b/services/nuldoc/lib/nuldoc/components/post_page_entry.rb new file mode 100644 index 00000000..5232bc6b --- /dev/null +++ b/services/nuldoc/lib/nuldoc/components/post_page_entry.rb @@ -0,0 +1,25 @@ +module Nuldoc + module Components + class PostPageEntry + extend Dom + + def self.render(post:, config:) + published = Revision.date_to_string(GeneratorUtils.published_date(post)) + updated = Revision.date_to_string(GeneratorUtils.updated_date(post)) + has_updates = GeneratorUtils.any_updates?(post) + + article({ 'class' => 'post-entry' }, + a({ 'href' => post.href }, + header({ 'class' => 'entry-header' }, h2({}, post.title)), + section({ 'class' => 'entry-content' }, p({}, post.description)), + footer({ 'class' => 'entry-footer' }, + elem('time', { 'datetime' => published }, published), + ' 投稿', + has_updates ? '、' : nil, + has_updates ? elem('time', { 'datetime' => updated }, updated) : nil, + has_updates ? ' 更新' : nil, + post.tags.length.positive? ? TagList.render(tags: post.tags, config: config) : nil))) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/components/slide_page_entry.rb b/services/nuldoc/lib/nuldoc/components/slide_page_entry.rb new file mode 100644 index 00000000..b80f52c8 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/components/slide_page_entry.rb @@ -0,0 +1,25 @@ +module Nuldoc + module Components + class SlidePageEntry + extend Dom + + def self.render(slide:, config:) + published = Revision.date_to_string(GeneratorUtils.published_date(slide)) + updated = Revision.date_to_string(GeneratorUtils.updated_date(slide)) + has_updates = GeneratorUtils.any_updates?(slide) + + article({ 'class' => 'post-entry' }, + a({ 'href' => slide.href }, + header({ 'class' => 'entry-header' }, h2({}, slide.title)), + section({ 'class' => 'entry-content' }, p({}, slide.description)), + footer({ 'class' => 'entry-footer' }, + elem('time', { 'datetime' => published }, published), + ' 登壇', + has_updates ? '、' : nil, + has_updates ? elem('time', { 'datetime' => updated }, updated) : nil, + has_updates ? ' 更新' : nil, + slide.tags.length.positive? ? TagList.render(tags: slide.tags, config: config) : nil))) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/components/static_script.rb b/services/nuldoc/lib/nuldoc/components/static_script.rb new file mode 100644 index 00000000..755dc3fc --- /dev/null +++ b/services/nuldoc/lib/nuldoc/components/static_script.rb @@ -0,0 +1,16 @@ +module Nuldoc + module Components + class StaticScript + extend Dom + + def self.render(file_name:, config:, site: nil, type: nil, defer: nil) + file_path = File.join(Dir.pwd, config.locations.static_dir, site || '_all', file_name) + hash = ComponentUtils.calculate_file_hash(file_path) + attrs = { 'src' => "#{file_name}?h=#{hash}" } + attrs['type'] = type if type + attrs['defer'] = defer if defer + script(attrs) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/components/static_stylesheet.rb b/services/nuldoc/lib/nuldoc/components/static_stylesheet.rb new file mode 100644 index 00000000..3127286d --- /dev/null +++ b/services/nuldoc/lib/nuldoc/components/static_stylesheet.rb @@ -0,0 +1,13 @@ +module Nuldoc + module Components + class StaticStylesheet + extend Dom + + def self.render(file_name:, config:, site: nil) + file_path = File.join(Dir.pwd, config.locations.static_dir, site || '_all', file_name) + hash = ComponentUtils.calculate_file_hash(file_path) + link({ 'rel' => 'stylesheet', 'href' => "#{file_name}?h=#{hash}" }) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/components/table_of_contents.rb b/services/nuldoc/lib/nuldoc/components/table_of_contents.rb new file mode 100644 index 00000000..b3a5b531 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/components/table_of_contents.rb @@ -0,0 +1,21 @@ +module Nuldoc + module Components + class TableOfContents + extend Dom + + def self.render(toc:) + nav({ 'class' => 'toc' }, + h2({}, '目次'), + ul({}, *toc.items.map { |entry| toc_entry_component(entry) })) + end + + def self.toc_entry_component(entry) + li({}, + a({ 'href' => "##{entry.id}" }, entry.text), + entry.children.length.positive? ? ul({}, *entry.children.map { |child| toc_entry_component(child) }) : nil) + end + + private_class_method :toc_entry_component + end + end +end diff --git a/services/nuldoc/lib/nuldoc/components/tag_list.rb b/services/nuldoc/lib/nuldoc/components/tag_list.rb new file mode 100644 index 00000000..0c566f32 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/components/tag_list.rb @@ -0,0 +1,15 @@ +module Nuldoc + module Components + class TagList + extend Dom + + def self.render(tags:, config:) + ul({ 'class' => 'entry-tags' }, + *tags.map do |slug| + li({ 'class' => 'tag' }, + span({ 'class' => 'tag-inner' }, text(config.tag_label(slug)))) + end) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/components/utils.rb b/services/nuldoc/lib/nuldoc/components/utils.rb new file mode 100644 index 00000000..18337c86 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/components/utils.rb @@ -0,0 +1,8 @@ +module Nuldoc + class ComponentUtils + def self.calculate_file_hash(file_path) + content = File.binread(file_path) + Digest::MD5.hexdigest(content) + end + end +end diff --git a/services/nuldoc/lib/nuldoc/config.rb b/services/nuldoc/lib/nuldoc/config.rb new file mode 100644 index 00000000..b4334bcd --- /dev/null +++ b/services/nuldoc/lib/nuldoc/config.rb @@ -0,0 +1,67 @@ +module Nuldoc + Config = Data.define(:locations, :site, :sites, :tag_labels) do + def tag_label(slug) + label = tag_labels[slug] + raise "Unknown tag: #{slug}" if label.nil? + + label + end + + def site_entry(site_key) + sites.public_send(site_key) + end + end + + LocationsConfig = Data.define(:content_dir, :dest_dir, :static_dir) + + SiteConfig = Data.define(:author, :copyright_year) + + SiteEntry = Data.define(:fqdn, :site_name, :posts_per_page) + + SitesConfig = Data.define(:default, :about, :blog, :slides) + + class ConfigLoader + def self.default_config_path + File.join(Dir.pwd, 'nuldoc.toml') + end + + def self.load_config(file_path) + raw = TomlRB.load_file(file_path) + + locations = LocationsConfig.new( + content_dir: raw.dig('locations', 'contentDir'), + dest_dir: raw.dig('locations', 'destDir'), + static_dir: raw.dig('locations', 'staticDir') + ) + + site = SiteConfig.new( + author: raw.dig('site', 'author'), + copyright_year: raw.dig('site', 'copyrightYear') + ) + + sites = SitesConfig.new( + default: build_site_entry(raw.dig('sites', 'default')), + about: build_site_entry(raw.dig('sites', 'about')), + blog: build_site_entry(raw.dig('sites', 'blog')), + slides: build_site_entry(raw.dig('sites', 'slides')) + ) + + Config.new( + locations: locations, + site: site, + sites: sites, + tag_labels: raw['tagLabels'] || {} + ) + end + + def self.build_site_entry(hash) + SiteEntry.new( + fqdn: hash['fqdn'], + site_name: hash['siteName'], + posts_per_page: hash['postsPerPage'] + ) + end + + private_class_method :build_site_entry + end +end diff --git a/services/nuldoc/lib/nuldoc/dom.rb b/services/nuldoc/lib/nuldoc/dom.rb new file mode 100644 index 00000000..7e28ac06 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/dom.rb @@ -0,0 +1,136 @@ +module Nuldoc + Text = Struct.new(:content, keyword_init: true) do + def kind = :text + end + + RawHTML = Struct.new(:html, keyword_init: true) do + def kind = :raw + end + + Element = Struct.new(:name, :attributes, :children, keyword_init: true) do + def kind = :element + end + + module Dom + module_function + + def text(content) + Text.new(content: content) + end + + def raw_html(html) + RawHTML.new(html: html) + end + + def elem(name, attributes = {}, *children) + Element.new( + name: name, + attributes: attributes || {}, + children: flatten_children(children) + ) + end + + def a(attributes = {}, *children) = elem('a', attributes, *children) + def article(attributes = {}, *children) = elem('article', attributes, *children) + def button(attributes = {}, *children) = elem('button', attributes, *children) + def div(attributes = {}, *children) = elem('div', attributes, *children) + def footer(attributes = {}, *children) = elem('footer', attributes, *children) + def h1(attributes = {}, *children) = elem('h1', attributes, *children) + def h2(attributes = {}, *children) = elem('h2', attributes, *children) + def h3(attributes = {}, *children) = elem('h3', attributes, *children) + def h4(attributes = {}, *children) = elem('h4', attributes, *children) + def h5(attributes = {}, *children) = elem('h5', attributes, *children) + def h6(attributes = {}, *children) = elem('h6', attributes, *children) + def header(attributes = {}, *children) = elem('header', attributes, *children) + def img(attributes = {}) = elem('img', attributes) + def li(attributes = {}, *children) = elem('li', attributes, *children) + def link(attributes = {}) = elem('link', attributes) + def meta(attributes = {}) = elem('meta', attributes) + def nav(attributes = {}, *children) = elem('nav', attributes, *children) + def ol(attributes = {}, *children) = elem('ol', attributes, *children) + def p(attributes = {}, *children) = elem('p', attributes, *children) + def script(attributes = {}, *children) = elem('script', attributes, *children) + def section(attributes = {}, *children) = elem('section', attributes, *children) + def span(attributes = {}, *children) = elem('span', attributes, *children) + def ul(attributes = {}, *children) = elem('ul', attributes, *children) + + def add_class(element, klass) + classes = element.attributes['class'] + if classes.nil? + element.attributes['class'] = klass + else + class_list = classes.split + class_list.push(klass) + class_list.sort! + element.attributes['class'] = class_list.join(' ') + end + end + + def find_first_child_element(element, name) + element.children.find { |c| c.kind == :element && c.name == name } + end + + def find_child_elements(element, name) + element.children.select { |c| c.kind == :element && c.name == name } + end + + def inner_text(element) + t = +'' + for_each_child(element) do |c| + t << c.content if c.kind == :text + end + t + end + + def for_each_child(element, &) + element.children.each(&) + end + + def for_each_child_recursively(element) + g = proc do |c| + yield(c) + for_each_child(c, &g) if c.kind == :element + end + for_each_child(element, &g) + end + + def for_each_element_of_type(root, element_name) + for_each_child_recursively(root) do |n| + yield(n) if n.kind == :element && n.name == element_name + end + end + + def process_text_nodes_in_element(element) + new_children = [] + element.children.each do |child| + if child.kind == :text + new_children.concat(yield(child.content)) + else + new_children.push(child) + end + end + element.children.replace(new_children) + end + + private + + def flatten_children(children) + result = [] + children.each do |child| + case child + when nil, false + next + when String + result.push(text(child)) + when Array + result.concat(flatten_children(child)) + else + result.push(child) + end + end + result + end + + module_function :flatten_children + end +end diff --git a/services/nuldoc/lib/nuldoc/generators/about.rb b/services/nuldoc/lib/nuldoc/generators/about.rb new file mode 100644 index 00000000..e64f0d1d --- /dev/null +++ b/services/nuldoc/lib/nuldoc/generators/about.rb @@ -0,0 +1,22 @@ +module Nuldoc + module Generators + class About + def initialize(slides, config) + @slides = slides + @config = config + end + + def generate + html = Pages::AboutPage.render(slides: @slides, config: @config) + + Page.new( + root: html, + renderer: :html, + site: 'about', + dest_file_path: '/index.html', + href: '/' + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/generators/atom.rb b/services/nuldoc/lib/nuldoc/generators/atom.rb new file mode 100644 index 00000000..74750eb7 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/generators/atom.rb @@ -0,0 +1,58 @@ +module Nuldoc + Feed = Data.define(:author, :icon, :id, :link_to_self, :link_to_alternate, :title, :updated, :entries) + + FeedEntry = Data.define(:id, :link_to_alternate, :published, :summary, :title, :updated) + + module Generators + class Atom + BASE_NAME = 'atom.xml'.freeze + + def initialize(alternate_link, feed_slug, feed_title, entries, site, config) + @alternate_link = alternate_link + @feed_slug = feed_slug + @feed_title = feed_title + @entries = entries + @site = site + @config = config + end + + def generate + feed_entries = @entries.map do |entry| + fqdn = entry.respond_to?(:event) ? @config.sites.slides.fqdn : @config.sites.blog.fqdn + FeedEntry.new( + id: "urn:uuid:#{entry.uuid}", + link_to_alternate: "https://#{fqdn}#{entry.href}", + title: entry.title, + summary: entry.description, + published: Revision.date_to_rfc3339_string(entry.published), + updated: Revision.date_to_rfc3339_string(entry.updated) + ) + end + + feed_entries.sort! { |a, b| [b.published, a.link_to_alternate] <=> [a.published, b.link_to_alternate] } + + site_entry = @config.site_entry(@site) + feed_path = "#{@alternate_link}#{BASE_NAME}" + + feed = Feed.new( + author: @config.site.author, + icon: "https://#{site_entry.fqdn}/favicon.svg", + id: "tag:#{site_entry.fqdn},#{@config.site.copyright_year}:#{@feed_slug}", + link_to_self: "https://#{site_entry.fqdn}#{feed_path}", + link_to_alternate: "https://#{site_entry.fqdn}#{@alternate_link}", + title: @feed_title, + updated: feed_entries.map(&:updated).max || feed_entries.first&.updated || '', + entries: feed_entries + ) + + Page.new( + root: Pages::AtomPage.render(feed: feed), + renderer: :xml, + site: @site, + dest_file_path: feed_path, + href: feed_path + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/generators/home.rb b/services/nuldoc/lib/nuldoc/generators/home.rb new file mode 100644 index 00000000..54f8753f --- /dev/null +++ b/services/nuldoc/lib/nuldoc/generators/home.rb @@ -0,0 +1,21 @@ +module Nuldoc + module Generators + class Home + def initialize(config) + @config = config + end + + def generate + html = Pages::HomePage.render(config: @config) + + Page.new( + root: html, + renderer: :html, + site: 'default', + dest_file_path: '/index.html', + href: '/' + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/generators/not_found.rb b/services/nuldoc/lib/nuldoc/generators/not_found.rb new file mode 100644 index 00000000..cffe1df8 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/generators/not_found.rb @@ -0,0 +1,22 @@ +module Nuldoc + module Generators + class NotFound + def initialize(site, config) + @site = site + @config = config + end + + def generate + html = Pages::NotFoundPage.render(site: @site, config: @config) + + Page.new( + root: html, + renderer: :html, + site: @site, + dest_file_path: '/404.html', + href: '/404.html' + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/generators/post.rb b/services/nuldoc/lib/nuldoc/generators/post.rb new file mode 100644 index 00000000..0d5a3afc --- /dev/null +++ b/services/nuldoc/lib/nuldoc/generators/post.rb @@ -0,0 +1,57 @@ +module Nuldoc + PostPage = Data.define(:root, :renderer, :site, :dest_file_path, :href, + :title, :description, :tags, :revisions, :published, :updated, + :uuid, :source_file_path) + + class GeneratorUtils + def self.published_date(page) + page.revisions.each do |rev| + return rev.date unless rev.is_internal + end + page.revisions[0].date + end + + def self.updated_date(page) + page.revisions.last.date + end + + def self.any_updates?(page) + page.revisions.count { |rev| !rev.is_internal } >= 2 + end + end + + module Generators + class Post + def initialize(doc, config) + @doc = doc + @config = config + end + + def generate + html = Pages::PostPage.render(doc: @doc, config: @config) + + content_dir = File.join(Dir.pwd, @config.locations.content_dir) + dest_file_path = File.join( + @doc.source_file_path.sub(content_dir, '').sub('.md', ''), + 'index.html' + ) + + PostPage.new( + root: html, + renderer: :html, + site: 'blog', + dest_file_path: dest_file_path, + href: dest_file_path.sub('index.html', ''), + title: @doc.title, + description: @doc.description, + tags: @doc.tags, + revisions: @doc.revisions, + published: GeneratorUtils.published_date(@doc), + updated: GeneratorUtils.updated_date(@doc), + uuid: @doc.uuid, + source_file_path: @doc.source_file_path + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/generators/post_list.rb b/services/nuldoc/lib/nuldoc/generators/post_list.rb new file mode 100644 index 00000000..680a0c32 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/generators/post_list.rb @@ -0,0 +1,41 @@ +module Nuldoc + module Generators + class PostList + def initialize(posts, config) + @posts = posts + @config = config + end + + def generate + posts_per_page = @config.sites.blog.posts_per_page + total_pages = (@posts.length.to_f / posts_per_page).ceil + pages = [] + + (0...total_pages).each do |page_index| + page_posts = @posts[page_index * posts_per_page, posts_per_page] + current_page = page_index + 1 + + html = Pages::PostListPage.render( + posts: page_posts, + config: @config, + current_page: current_page, + total_pages: total_pages + ) + + dest_file_path = current_page == 1 ? '/posts/index.html' : "/posts/#{current_page}/index.html" + href = current_page == 1 ? '/posts/' : "/posts/#{current_page}/" + + pages.push(Page.new( + root: html, + renderer: :html, + site: 'blog', + dest_file_path: dest_file_path, + href: href + )) + end + + pages + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/generators/slide.rb b/services/nuldoc/lib/nuldoc/generators/slide.rb new file mode 100644 index 00000000..58fde56e --- /dev/null +++ b/services/nuldoc/lib/nuldoc/generators/slide.rb @@ -0,0 +1,42 @@ +module Nuldoc + SlidePageData = Data.define(:root, :renderer, :site, :dest_file_path, :href, + :title, :description, :event, :talk_type, :slide_link, + :tags, :revisions, :published, :updated, :uuid) + + module Generators + class Slide + def initialize(slide, config) + @slide = slide + @config = config + end + + def generate + html = Pages::SlidePage.render(slide: @slide, config: @config) + + content_dir = File.join(Dir.pwd, @config.locations.content_dir) + dest_file_path = File.join( + @slide.source_file_path.sub(content_dir, '').sub('.toml', ''), + 'index.html' + ) + + SlidePageData.new( + root: html, + renderer: :html, + site: 'slides', + dest_file_path: dest_file_path, + href: dest_file_path.sub('index.html', ''), + title: @slide.title, + description: "#{@slide.event} (#{@slide.talk_type})", + event: @slide.event, + talk_type: @slide.talk_type, + slide_link: @slide.slide_link, + tags: @slide.tags, + revisions: @slide.revisions, + published: GeneratorUtils.published_date(@slide), + updated: GeneratorUtils.updated_date(@slide), + uuid: @slide.uuid + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/generators/slide_list.rb b/services/nuldoc/lib/nuldoc/generators/slide_list.rb new file mode 100644 index 00000000..8d23e4b4 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/generators/slide_list.rb @@ -0,0 +1,22 @@ +module Nuldoc + module Generators + class SlideList + def initialize(slides, config) + @slides = slides + @config = config + end + + def generate + html = Pages::SlideListPage.render(slides: @slides, config: @config) + + Page.new( + root: html, + renderer: :html, + site: 'slides', + dest_file_path: '/slides/index.html', + href: '/slides/' + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/generators/tag.rb b/services/nuldoc/lib/nuldoc/generators/tag.rb new file mode 100644 index 00000000..7a5f7a7b --- /dev/null +++ b/services/nuldoc/lib/nuldoc/generators/tag.rb @@ -0,0 +1,31 @@ +module Nuldoc + TagPageData = Data.define(:root, :renderer, :site, :dest_file_path, :href, + :tag_slug, :tag_label, :num_of_posts, :num_of_slides) + + module Generators + class Tag + def initialize(tag_slug, pages, site, config) + @tag_slug = tag_slug + @pages = pages + @site = site + @config = config + end + + def generate + html = Pages::TagPage.render(tag_slug: @tag_slug, pages: @pages, site: @site, config: @config) + + TagPageData.new( + root: html, + renderer: :html, + site: @site, + dest_file_path: "/tags/#{@tag_slug}/index.html", + href: "/tags/#{@tag_slug}/", + tag_slug: @tag_slug, + tag_label: @config.tag_label(@tag_slug), + num_of_posts: @pages.count { |p| !p.respond_to?(:event) }, + num_of_slides: @pages.count { |p| p.respond_to?(:event) } + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/generators/tag_list.rb b/services/nuldoc/lib/nuldoc/generators/tag_list.rb new file mode 100644 index 00000000..089b6f0c --- /dev/null +++ b/services/nuldoc/lib/nuldoc/generators/tag_list.rb @@ -0,0 +1,23 @@ +module Nuldoc + module Generators + class TagList + def initialize(tags, site, config) + @tags = tags + @site = site + @config = config + end + + def generate + html = Pages::TagListPage.render(tags: @tags, site: @site, config: @config) + + Page.new( + root: html, + renderer: :html, + site: @site, + dest_file_path: '/tags/index.html', + href: '/tags/' + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/markdown/document.rb b/services/nuldoc/lib/nuldoc/markdown/document.rb new file mode 100644 index 00000000..1268a7f8 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/markdown/document.rb @@ -0,0 +1,19 @@ +module Nuldoc + TocEntry = Struct.new(:id, :text, :level, :children, keyword_init: true) + + TocRoot = Struct.new(:items, keyword_init: true) + + Document = Struct.new( + :root, + :source_file_path, + :uuid, + :link, + :title, + :description, + :tags, + :revisions, + :toc, + :is_toc_enabled, + keyword_init: true + ) +end diff --git a/services/nuldoc/lib/nuldoc/markdown/parse.rb b/services/nuldoc/lib/nuldoc/markdown/parse.rb new file mode 100644 index 00000000..fc96352d --- /dev/null +++ b/services/nuldoc/lib/nuldoc/markdown/parse.rb @@ -0,0 +1,51 @@ +module Nuldoc + class MarkdownParser + def initialize(file_path, config) + @file_path = file_path + @config = config + end + + def parse + file_content = File.read(@file_path) + _, frontmatter, *rest = file_content.split(/^---$/m) + meta = parse_metadata(frontmatter) + content = rest.join('---') + + dom_root = Parser::BlockParser.parse(content) + content_dir = File.join(Dir.pwd, @config.locations.content_dir) + link_path = @file_path.sub(content_dir, '').sub('.md', '/') + + revisions = meta['article']['revisions'].each_with_index.map do |r, i| + Revision.new( + number: i, + date: Revision.string_to_date(r['date']), + remark: r['remark'], + is_internal: !r['isInternal'].nil? + ) + end + + doc = Document.new( + root: dom_root, + source_file_path: @file_path, + uuid: meta['article']['uuid'], + link: link_path, + title: meta['article']['title'], + description: meta['article']['description'], + tags: meta['article']['tags'], + revisions: revisions, + toc: nil, + is_toc_enabled: meta['article']['toc'] != false + ) + + Transform.to_html(doc) + rescue StandardError => e + raise e.class, "#{e.message} in #{@file_path}" + end + + private + + def parse_metadata(s) + TomlRB.parse(s) + end + end +end diff --git a/services/nuldoc/lib/nuldoc/markdown/parser/attributes.rb b/services/nuldoc/lib/nuldoc/markdown/parser/attributes.rb new file mode 100644 index 00000000..328c2446 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/markdown/parser/attributes.rb @@ -0,0 +1,25 @@ +module Nuldoc + module Parser + class Attributes + def self.parse_trailing_attributes(text) + match = text.match(/\s*\{([^}]+)\}\s*$/) + return [text, nil, {}] unless match + + attr_string = match[1] + text_before = text[0...match.begin(0)] + + id = nil + attributes = {} + + id_match = attr_string.match(/#([\w-]+)/) + id = id_match[1] if id_match + + attr_string.scan(/([\w-]+)="([^"]*)"/) do |key, value| + attributes[key] = value + end + + [text_before, id, attributes] + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/markdown/parser/block_parser.rb b/services/nuldoc/lib/nuldoc/markdown/parser/block_parser.rb new file mode 100644 index 00000000..6a135b5b --- /dev/null +++ b/services/nuldoc/lib/nuldoc/markdown/parser/block_parser.rb @@ -0,0 +1,602 @@ +module Nuldoc + module Parser + class BlockParser + extend Dom + + HeaderBlock = Struct.new(:level, :id, :attributes, :heading_element, keyword_init: true) + FootnoteBlock = Struct.new(:id, :children, keyword_init: true) + + class << self + def parse(text) + scanner = LineScanner.new(text) + blocks = parse_blocks(scanner) + build_document(blocks) + end + + private + + # --- Block parsing --- + + def parse_blocks(scanner) + blocks = [] + until scanner.eof? + block = parse_block(scanner) + blocks << block if block + end + blocks + end + + def parse_block(scanner) + return nil if scanner.eof? + + line = scanner.peek + + # 1. Blank line + if line.strip.empty? + scanner.advance + return nil + end + + # 2. HTML comment + if (result = try_html_comment(scanner)) + return result + end + + # 3. Fenced code block + if (result = try_fenced_code(scanner)) + return result + end + + # 4. Note/Edit block + if (result = try_note_block(scanner)) + return result + end + + # 5. Heading + if (result = try_heading(scanner)) + return result + end + + # 6. Horizontal rule + if (result = try_hr(scanner)) + return result + end + + # 7. Footnote definition + if (result = try_footnote_def(scanner)) + return result + end + + # 8. Table + if (result = try_table(scanner)) + return result + end + + # 9. Blockquote + if (result = try_blockquote(scanner)) + return result + end + + # 10. Ordered list + if (result = try_ordered_list(scanner)) + return result + end + + # 11. Unordered list + if (result = try_unordered_list(scanner)) + return result + end + + # 12. HTML block + if (result = try_html_block(scanner)) + return result + end + + # 13. Paragraph + parse_paragraph(scanner) + end + + def try_html_comment(scanner) + line = scanner.peek + return nil unless line.strip.start_with?('<!--') + + content = +'' + until scanner.eof? + l = scanner.advance + content << l << "\n" + break if l.include?('-->') + end + nil # skip comments + end + + def try_fenced_code(scanner) + match = scanner.match(/^```(\S*)(.*)$/) + return nil unless match + + scanner.advance + language = match[1].empty? ? nil : match[1] + meta_string = match[2].strip + + attributes = {} + attributes['language'] = language if language + + if meta_string && !meta_string.empty? + filename_match = meta_string.match(/filename="([^"]+)"/) + attributes['filename'] = filename_match[1] if filename_match + attributes['numbered'] = 'true' if meta_string.include?('numbered') + end + + code_lines = [] + until scanner.eof? + l = scanner.peek + if l.start_with?('```') + scanner.advance + break + end + code_lines << scanner.advance + end + + code = code_lines.join("\n") + elem('codeblock', attributes, text(code)) + end + + def try_note_block(scanner) + match = scanner.match(/^:::(note|edit)(.*)$/) + return nil unless match + + scanner.advance + block_type = match[1] + attr_string = match[2].strip + + attributes = {} + if block_type == 'edit' + # Parse {editat="..." operation="..."} + editat_match = attr_string.match(/editat="([^"]+)"/) + operation_match = attr_string.match(/operation="([^"]+)"/) + attributes['editat'] = editat_match[1] if editat_match + attributes['operation'] = operation_match[1] if operation_match + end + + # Collect content until ::: + content_lines = [] + until scanner.eof? + l = scanner.peek + if l.strip == ':::' + scanner.advance + break + end + content_lines << scanner.advance + end + + inner_text = content_lines.join("\n") + inner_scanner = LineScanner.new(inner_text) + children = parse_blocks(inner_scanner) + + # Convert children - they are block elements already + child_elements = children.compact.select { |c| c.is_a?(Element) || c.is_a?(Text) || c.is_a?(RawHTML) } + elem('note', attributes, *child_elements) + end + + def try_heading(scanner) + match = scanner.match(/^(\#{1,5})\s+(.+)$/) + return nil unless match + + scanner.advance + level = match[1].length + raw_text = match[2] + + text_before, id, attributes = Attributes.parse_trailing_attributes(raw_text) + + inline_nodes = InlineParser.parse(text_before.strip) + heading_element = elem('h', {}, *inline_nodes) + + HeaderBlock.new(level: level, id: id, attributes: attributes, heading_element: heading_element) + end + + def try_hr(scanner) + match = scanner.match(/^---+\s*$/) + return nil unless match + + scanner.advance + elem('hr', {}) + end + + def try_footnote_def(scanner) + match = scanner.match(/^\[\^([^\]]+)\]:\s*(.*)$/) + return nil unless match + + scanner.advance + id = match[1] + first_line = match[2] + + content_lines = [first_line] + # Continuation lines: 4-space indent + until scanner.eof? + l = scanner.peek + break unless l.start_with?(' ') + + content_lines << scanner.advance[4..] + + end + + inner_text = content_lines.join("\n").strip + inner_scanner = LineScanner.new(inner_text) + children = parse_blocks(inner_scanner) + + child_elements = children.compact.select { |c| c.is_a?(Element) || c.is_a?(Text) || c.is_a?(RawHTML) } + FootnoteBlock.new(id: id, children: child_elements) + end + + def try_table(scanner) + # Check if this looks like a table + return nil unless scanner.peek.start_with?('|') + + # Quick lookahead: second line must be a separator + return nil if scanner.pos + 1 >= scanner.lines.length + return nil unless scanner.lines[scanner.pos + 1].match?(/^\|[\s:|-]+\|$/) + + # Collect table lines + lines = [] + while !scanner.eof? && scanner.peek.start_with?('|') + lines << scanner.peek + scanner.advance + end + + header_line = lines[0] + separator_line = lines[1] + body_lines = lines[2..] || [] + + alignment = parse_table_alignment(separator_line) + header_cells = parse_table_row_cells(header_line) + header_row = build_table_row(header_cells, true, alignment) + + body_rows = body_lines.map do |bl| + cells = parse_table_row_cells(bl) + build_table_row(cells, false, alignment) + end + + table_children = [] + table_children << elem('thead', {}, header_row) + table_children << elem('tbody', {}, *body_rows) unless body_rows.empty? + + elem('table', {}, *table_children) + end + + def parse_table_alignment(separator_line) + cells = separator_line.split('|').map(&:strip).reject(&:empty?) + cells.map do |cell| + left = cell.start_with?(':') + right = cell.end_with?(':') + if left && right + 'center' + elsif right + 'right' + elsif left + 'left' + end + end + end + + def parse_table_row_cells(line) + # Strip leading and trailing |, then split by | + stripped = line.strip + stripped = stripped[1..] if stripped.start_with?('|') + stripped = stripped[0...-1] if stripped.end_with?('|') + stripped.split('|').map(&:strip) + end + + def build_table_row(cells, is_header, alignment) + cell_elements = cells.each_with_index.map do |cell_text, i| + attributes = {} + align = alignment[i] + attributes['align'] = align if align && align != 'default' + + tag = is_header ? 'th' : 'td' + inline_nodes = InlineParser.parse(cell_text) + elem(tag, attributes, *inline_nodes) + end + elem('tr', {}, *cell_elements) + end + + def try_blockquote(scanner) + return nil unless scanner.peek.start_with?('> ') || scanner.peek == '>' + + lines = [] + while !scanner.eof? && (scanner.peek.start_with?('> ') || scanner.peek == '>') + line = scanner.advance + lines << (line == '>' ? '' : line[2..]) + end + + inner_text = lines.join("\n") + inner_scanner = LineScanner.new(inner_text) + children = parse_blocks(inner_scanner) + child_elements = children.compact.select { |c| c.is_a?(Element) || c.is_a?(Text) || c.is_a?(RawHTML) } + + elem('blockquote', {}, *child_elements) + end + + def try_ordered_list(scanner) + match = scanner.match(/^(\d+)\.\s+(.*)$/) + return nil unless match + + items = parse_list_items(scanner, :ordered) + return nil if items.empty? + + build_list(:ordered, items) + end + + def try_unordered_list(scanner) + match = scanner.match(/^\*\s+(.*)$/) + return nil unless match + + items = parse_list_items(scanner, :unordered) + return nil if items.empty? + + build_list(:unordered, items) + end + + def parse_list_items(scanner, type) + items = [] + marker_re = type == :ordered ? /^(\d+)\.\s+(.*)$/ : /^\*\s+(.*)$/ + indent_size = 4 + + while !scanner.eof? && (m = scanner.match(marker_re)) + scanner.advance + first_line = type == :ordered ? m[2] : m[1] + + content_lines = [first_line] + has_blank = false + + # Collect continuation lines and sub-items + until scanner.eof? + l = scanner.peek + + # Blank line might be part of loose list + if l.strip.empty? + # Check if next non-blank line is still part of the list + next_pos = scanner.pos + 1 + next_pos += 1 while next_pos < scanner.lines.length && scanner.lines[next_pos].strip.empty? + + if next_pos < scanner.lines.length + next_line = scanner.lines[next_pos] + if next_line.start_with?(' ' * indent_size) || next_line.match?(marker_re) + has_blank = true + content_lines << '' + scanner.advance + next + end + end + break + end + + # Indented continuation (sub-items or content) + if l.start_with?(' ' * indent_size) + content_lines << scanner.advance[indent_size..] + next + end + + # New list item at same level + break if l.match?(marker_re) + + # Non-indented, non-marker line - might be continuation of tight paragraph + break if l.strip.empty? + break if l.match?(/^[#>*\d]/) && !l.match?(/^\d+\.\s/) # another block element + + # Paragraph continuation + content_lines << scanner.advance + end + + items << { lines: content_lines, has_blank: has_blank } + end + + items + end + + def build_list(type, items) + # Determine tight/loose + is_tight = items.none? { |item| item[:has_blank] } + + attributes = {} + attributes['__tight'] = is_tight ? 'true' : 'false' + + # Check for task list items + is_task_list = false + if type == :unordered + is_task_list = items.any? { |item| item[:lines].first&.match?(/^\[[ xX]\]\s/) } + attributes['type'] = 'task' if is_task_list + end + + list_items = items.map do |item| + build_list_item(item, is_task_list) + end + + if type == :ordered + ol(attributes, *list_items) + else + ul(attributes, *list_items) + end + end + + def build_list_item(item, is_task_list) + attributes = {} + content = item[:lines].join("\n") + + if is_task_list + task_match = content.match(/^\[( |[xX])\]\s(.*)$/m) + if task_match + attributes['checked'] = task_match[1] == ' ' ? 'false' : 'true' + content = task_match[2] + end + end + + # Parse inner content as blocks + inner_scanner = LineScanner.new(content) + children = parse_blocks(inner_scanner) + + # If no block-level elements were created, wrap in paragraph + child_elements = children.compact.select { |c| c.is_a?(Element) || c.is_a?(Text) || c.is_a?(RawHTML) } + child_elements = [p({}, *InlineParser.parse(content))] if child_elements.empty? + + li(attributes, *child_elements) + end + + def try_html_block(scanner) + line = scanner.peek + match = line.match(/^<(div|details|summary)(\s[^>]*)?>/) + return nil unless match + + tag = match[1] + lines = [] + close_tag = "</#{tag}>" + + until scanner.eof? + l = scanner.advance + lines << l + break if l.include?(close_tag) + end + + html_content = lines.join("\n") + + if tag == 'div' + # Parse inner content for div blocks + inner_match = html_content.match(%r{<div([^>]*)>(.*)</div>}m) + if inner_match + attr_str = inner_match[1] + inner_content = inner_match[2].strip + + attributes = {} + attr_str.scan(/([\w-]+)="([^"]*)"/) do |key, value| + attributes[key] = value + end + + if inner_content.empty? + div(attributes) + else + inner_scanner = LineScanner.new(inner_content) + children = parse_blocks(inner_scanner) + child_elements = children.compact.select { |c| c.is_a?(Element) || c.is_a?(Text) || c.is_a?(RawHTML) } + div(attributes, *child_elements) + end + else + div({ 'class' => 'raw-html' }, raw_html(html_content)) + end + else + div({ 'class' => 'raw-html' }, raw_html(html_content)) + end + end + + def parse_paragraph(scanner) + lines = [] + until scanner.eof? + l = scanner.peek + break if l.strip.empty? + break if l.match?(/^```/) + break if l.match?(/^\#{1,5}\s/) + break if l.match?(/^---+\s*$/) + break if l.match?(/^>\s/) + break if l.match?(/^\*\s/) + break if l.match?(/^\d+\.\s/) + if l.match?(/^\|/) && + scanner.pos + 1 < scanner.lines.length && + scanner.lines[scanner.pos + 1].match?(/^\|[\s:|-]+\|$/) + break + end + break if l.match?(/^:::/) + break if l.match?(/^<!--/) + break if l.match?(/^<(div|details|summary)/) + break if l.match?(/^\[\^[^\]]+\]:/) + + lines << scanner.advance + end + + return nil if lines.empty? + + text_content = lines.join("\n") + inline_nodes = InlineParser.parse(text_content) + p({}, *inline_nodes) + end + + # --- Section hierarchy --- + + def build_document(blocks) + footnote_blocks = blocks.select { |b| b.is_a?(FootnoteBlock) } + non_footnote_blocks = blocks.reject { |b| b.is_a?(FootnoteBlock) } + + article_content = build_section_hierarchy(non_footnote_blocks) + + unless footnote_blocks.empty? + footnote_elements = footnote_blocks.map do |fb| + elem('footnote', { 'id' => fb.id }, *fb.children) + end + footnote_section = section({ 'class' => 'footnotes' }, *footnote_elements) + article_content.push(footnote_section) + end + + elem('__root__', {}, article({}, *article_content)) + end + + def build_section_hierarchy(blocks) + result = [] + section_stack = [] + + blocks.each do |block| + if block.is_a?(HeaderBlock) + level = block.level + + while !section_stack.empty? && section_stack.last[:level] >= level + closed = section_stack.pop + section_el = create_section_element(closed) + if section_stack.empty? + result.push(section_el) + else + section_stack.last[:children].push(section_el) + end + end + + section_stack.push({ + id: block.id, + attributes: block.attributes, + level: level, + heading: block.heading_element, + children: [] + }) + else + next if block.nil? + + targets = if section_stack.empty? + result + else + section_stack.last[:children] + end + + if block.is_a?(Array) + targets.concat(block) + else + targets.push(block) + end + end + end + + until section_stack.empty? + closed = section_stack.pop + section_el = create_section_element(closed) + if section_stack.empty? + result.push(section_el) + else + section_stack.last[:children].push(section_el) + end + end + + result + end + + def create_section_element(section_info) + attributes = section_info[:attributes].dup + attributes['id'] = section_info[:id] if section_info[:id] + + section(attributes, section_info[:heading], *section_info[:children]) + end + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/markdown/parser/inline_parser.rb b/services/nuldoc/lib/nuldoc/markdown/parser/inline_parser.rb new file mode 100644 index 00000000..3d6f9ac7 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/markdown/parser/inline_parser.rb @@ -0,0 +1,383 @@ +module Nuldoc + module Parser + class InlineParser + extend Dom + + class << self + INLINE_HTML_TAGS = %w[del mark sub sup ins br].freeze + SELF_CLOSING_TAGS = %w[br].freeze + + def parse(text) + parse_inline(text, 0, text.length) + end + + private + + def parse_inline(text, start, stop) + nodes = [] + pos = start + + while pos < stop + # Try each inline pattern + matched = try_escape(text, pos, stop, nodes) || + try_code_span(text, pos, stop, nodes) || + try_autolink(text, pos, stop, nodes) || + try_inline_html(text, pos, stop, nodes) || + try_image(text, pos, stop, nodes) || + try_link(text, pos, stop, nodes) || + try_footnote_ref(text, pos, stop, nodes) || + try_bold(text, pos, stop, nodes) || + try_italic(text, pos, stop, nodes) || + try_strikethrough(text, pos, stop, nodes) || + try_typographic(text, pos, stop, nodes) + + if matched + pos = matched + else + # Plain character + char_end = pos + 1 + # Collect consecutive plain characters + while char_end < stop + break if special_char?(text[char_end]) + + char_end += 1 + end + nodes << text(text[pos...char_end]) + pos = char_end + end + end + + merge_text_nodes(nodes) + end + + def special_char?(ch) + case ch + when '\\', '`', '<', '!', '[', '*', '~', '.', '-', "'", '"' + true + else + false + end + end + + def try_escape(text, pos, _stop, nodes) + return nil unless text[pos] == '\\' + return nil if pos + 1 >= text.length + + next_char = text[pos + 1] + return unless '\\`*_{}[]()#+-.!~|>:'.include?(next_char) + + nodes << text(next_char) + pos + 2 + end + + def try_autolink(text, pos, stop, nodes) + return nil unless text[pos] == '<' + + # Match <URL> where URL starts with http:// or https:// + close = text.index('>', pos + 1) + return nil unless close && close < stop + + url = text[(pos + 1)...close] + return nil unless url.match?(%r{^https?://\S+$}) + + nodes << a({ 'href' => url, 'class' => 'url' }, text(url)) + close + 1 + end + + def try_code_span(text, pos, stop, nodes) + return nil unless text[pos] == '`' + + # Count opening backticks + tick_count = 0 + i = pos + while i < stop && text[i] == '`' + tick_count += 1 + i += 1 + end + + # Find matching closing backticks + close_pos = text.index('`' * tick_count, i) + return nil unless close_pos && close_pos < stop + + content = text[i...close_pos] + # Strip one leading and one trailing space if both present + content = content[1...-1] if content.length >= 2 && content[0] == ' ' && content[-1] == ' ' + + nodes << elem('code', {}, text(content)) + close_pos + tick_count + end + + def try_inline_html(text, pos, stop, nodes) + return nil unless text[pos] == '<' + + # Self-closing tags + SELF_CLOSING_TAGS.each do |tag| + pattern = "<#{tag}>" + len = pattern.length + if pos + len <= stop && text[pos, len].downcase == pattern + nodes << elem(tag) + return pos + len + end + pattern_sc = "<#{tag} />" + len_sc = pattern_sc.length + if pos + len_sc <= stop && text[pos, len_sc].downcase == pattern_sc + nodes << elem(tag) + return pos + len_sc + end + pattern_sc2 = "<#{tag}/>" + len_sc2 = pattern_sc2.length + if pos + len_sc2 <= stop && text[pos, len_sc2].downcase == pattern_sc2 + nodes << elem(tag) + return pos + len_sc2 + end + end + + # Opening tags with content + (INLINE_HTML_TAGS - SELF_CLOSING_TAGS).each do |tag| + open_tag = "<#{tag}>" + close_tag = "</#{tag}>" + next unless pos + open_tag.length <= stop && text[pos, open_tag.length].downcase == open_tag + + close_pos = text.index(close_tag, pos + open_tag.length) + next unless close_pos && close_pos + close_tag.length <= stop + + inner = text[(pos + open_tag.length)...close_pos] + children = parse_inline(inner, 0, inner.length) + nodes << elem(tag, {}, *children) + return close_pos + close_tag.length + end + + nil + end + + def try_image(text, pos, stop, nodes) + return nil unless text[pos] == '!' && pos + 1 < stop && text[pos + 1] == '[' + + # Find ] + bracket_close = find_matching_bracket(text, pos + 1, stop) + return nil unless bracket_close + + alt = text[(pos + 2)...bracket_close] + + # Expect ( + return nil unless bracket_close + 1 < stop && text[bracket_close + 1] == '(' + + paren_close = find_matching_paren(text, bracket_close + 1, stop) + return nil unless paren_close + + inner = text[(bracket_close + 2)...paren_close].strip + url, title = parse_url_title(inner) + + attributes = {} + attributes['src'] = url if url + attributes['alt'] = alt unless alt.empty? + attributes['title'] = title if title + + nodes << img(attributes) + paren_close + 1 + end + + def try_link(text, pos, stop, nodes) + return nil unless text[pos] == '[' + + bracket_close = find_matching_bracket(text, pos, stop) + return nil unless bracket_close + + link_text = text[(pos + 1)...bracket_close] + + # Expect ( + return nil unless bracket_close + 1 < stop && text[bracket_close + 1] == '(' + + paren_close = find_matching_paren(text, bracket_close + 1, stop) + return nil unless paren_close + + inner = text[(bracket_close + 2)...paren_close].strip + url, title = parse_url_title(inner) + + attributes = {} + attributes['href'] = url if url + attributes['title'] = title if title + + children = parse_inline(link_text, 0, link_text.length) + + # Check if autolink + is_autolink = children.length == 1 && + children[0].kind == :text && + children[0].content == url + attributes['class'] = 'url' if is_autolink + + nodes << a(attributes, *children) + paren_close + 1 + end + + def try_footnote_ref(text, pos, stop, nodes) + return nil unless text[pos] == '[' && pos + 1 < stop && text[pos + 1] == '^' + + close = text.index(']', pos + 2) + return nil unless close && close < stop + + # Make sure there's no nested [ or ( between + inner = text[(pos + 2)...close] + return nil if inner.include?('[') || inner.include?(']') + return nil if inner.empty? + + nodes << elem('footnoteref', { 'reference' => inner }) + close + 1 + end + + def try_bold(text, pos, stop, nodes) + return nil unless text[pos] == '*' && pos + 1 < stop && text[pos + 1] == '*' + + close = text.index('**', pos + 2) + return nil unless close && close + 2 <= stop + + inner = text[(pos + 2)...close] + children = parse_inline(inner, 0, inner.length) + nodes << elem('strong', {}, *children) + close + 2 + end + + def try_italic(text, pos, stop, nodes) + return nil unless text[pos] == '*' + return nil if pos + 1 < stop && text[pos + 1] == '*' + + # Find closing * that is not ** + i = pos + 1 + while i < stop + if text[i] == '*' + # Make sure it's not ** + if i + 1 < stop && text[i + 1] == '*' + i += 2 + else + inner = text[(pos + 1)...i] + return nil if inner.empty? + + children = parse_inline(inner, 0, inner.length) + nodes << elem('em', {}, *children) + return i + 1 + end + else + i += 1 + end + end + nil + end + + def try_strikethrough(text, pos, stop, nodes) + return nil unless text[pos] == '~' && pos + 1 < stop && text[pos + 1] == '~' + + close = text.index('~~', pos + 2) + return nil unless close && close + 2 <= stop + + inner = text[(pos + 2)...close] + children = parse_inline(inner, 0, inner.length) + nodes << elem('del', {}, *children) + close + 2 + end + + def try_typographic(text, pos, stop, nodes) + # Ellipsis + if text[pos] == '.' && pos + 2 < stop && text[pos + 1] == '.' && text[pos + 2] == '.' + nodes << text("\u2026") + return pos + 3 + end + + # Em dash (must check before en dash) + if text[pos] == '-' && pos + 2 < stop && text[pos + 1] == '-' && text[pos + 2] == '-' + nodes << text("\u2014") + return pos + 3 + end + + # En dash + # Make sure it's not --- + if text[pos] == '-' && pos + 1 < stop && text[pos + 1] == '-' && (pos + 2 >= stop || text[pos + 2] != '-') + nodes << text("\u2013") + return pos + 2 + end + + # Smart quotes + try_smart_quotes(text, pos, stop, nodes) + end + + def try_smart_quotes(text, pos, _stop, nodes) + ch = text[pos] + return nil unless ["'", '"'].include?(ch) + + prev_char = pos.positive? ? text[pos - 1] : nil + is_opening = prev_char.nil? || prev_char == ' ' || prev_char == "\n" || prev_char == '(' || prev_char == '[' + + nodes << if ch == "'" + text(is_opening ? "\u2018" : "\u2019") + else + text(is_opening ? "\u201C" : "\u201D") + end + pos + 1 + end + + def find_matching_bracket(text, pos, stop) + return nil unless text[pos] == '[' + + depth = 0 + i = pos + while i < stop + case text[i] + when '\\' + i += 2 + next + when '[' + depth += 1 + when ']' + depth -= 1 + return i if depth.zero? + end + i += 1 + end + nil + end + + def find_matching_paren(text, pos, stop) + return nil unless text[pos] == '(' + + depth = 0 + i = pos + while i < stop + case text[i] + when '\\' + i += 2 + next + when '(' + depth += 1 + when ')' + depth -= 1 + return i if depth.zero? + end + i += 1 + end + nil + end + + def parse_url_title(inner) + # URL might be followed by "title" + match = inner.match(/^(\S+)\s+"([^"]*)"$/) + if match + [match[1], match[2]] + else + [inner, nil] + end + end + + def merge_text_nodes(nodes) + result = [] + nodes.each do |node| + if node.kind == :text && !result.empty? && result.last.kind == :text + result[-1] = text(result.last.content + node.content) + else + result << node + end + end + result + end + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/markdown/parser/line_scanner.rb b/services/nuldoc/lib/nuldoc/markdown/parser/line_scanner.rb new file mode 100644 index 00000000..18a66158 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/markdown/parser/line_scanner.rb @@ -0,0 +1,38 @@ +module Nuldoc + module Parser + class LineScanner + attr_reader :lines, :pos + + def initialize(text) + @lines = text.lines(chomp: true) + @pos = 0 + end + + def eof? + @pos >= @lines.length + end + + def peek + return nil if eof? + + @lines[@pos] + end + + def advance + line = peek + @pos += 1 + line + end + + def match(pattern) + return false if eof? + + peek.match(pattern) + end + + def skip_blank_lines + advance while !eof? && peek.strip.empty? + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/markdown/transform.rb b/services/nuldoc/lib/nuldoc/markdown/transform.rb new file mode 100644 index 00000000..45be7ddd --- /dev/null +++ b/services/nuldoc/lib/nuldoc/markdown/transform.rb @@ -0,0 +1,418 @@ +module Nuldoc + class Transform + include Dom + + def self.to_html(doc) + new(doc).to_html + end + + def initialize(doc) + @doc = doc + end + + def to_html + merge_consecutive_text_nodes + remove_unnecessary_text_node + transform_link_like_to_anchor_element + transform_section_id_attribute + assign_section_title_anchor + transform_section_title_element + transform_note_element + add_attributes_to_external_link_element + traverse_footnotes + remove_unnecessary_paragraph_node + transform_and_highlight_code_block_element + merge_consecutive_text_nodes + generate_table_of_contents + remove_toc_attributes + @doc + end + + private + + def merge_consecutive_text_nodes + for_each_child_recursively(@doc.root) do |n| + next unless n.kind == :element + + new_children = [] + current_text = +'' + + n.children.each do |child| + if child.kind == :text + current_text << child.content + else + unless current_text.empty? + new_children.push(text(current_text)) + current_text = +'' + end + new_children.push(child) + end + end + + new_children.push(text(current_text)) unless current_text.empty? + + n.children.replace(new_children) + end + end + + def remove_unnecessary_text_node + for_each_child_recursively(@doc.root) do |n| + next unless n.kind == :element + + loop do + changed = false + if !n.children.empty? && n.children.first.kind == :text && n.children.first.content.strip.empty? + n.children.shift + changed = true + end + if !n.children.empty? && n.children.last.kind == :text && n.children.last.content.strip.empty? + n.children.pop + changed = true + end + break unless changed + end + end + end + + def transform_link_like_to_anchor_element + for_each_child_recursively(@doc.root) do |n| + next unless n.kind == :element + next if %w[a code codeblock].include?(n.name) + + process_text_nodes_in_element(n) do |content| + nodes = [] + rest = content + until rest.empty? + match = %r{^(.*?)(https?://[^ \n]+)(.*)$}m.match(rest) + unless match + nodes.push(text(rest)) + break + end + nodes.push(text(match[1])) unless match[1].empty? + nodes.push(a({ 'href' => match[2], 'class' => 'url' }, text(match[2]))) + rest = match[3] + end + nodes + end + end + end + + def transform_section_id_attribute + section_stack = [] + used_ids = Set.new + + process_node = proc do |n| + next unless n.kind == :element + + if n.name == 'section' + id_attr = n.attributes['id'] + if id_attr + new_id = if section_stack.empty? + "section--#{id_attr}" + else + "section--#{section_stack.join('--')}--#{id_attr}" + end + + raise "[nuldoc.tohtml] Duplicate section ID: #{new_id}" if used_ids.include?(new_id) + + used_ids.add(new_id) + n.attributes['id'] = new_id + section_stack.push(id_attr) + + for_each_child(n, &process_node) + + section_stack.pop + else + for_each_child(n, &process_node) + end + else + for_each_child(n, &process_node) + end + end + + for_each_child(@doc.root, &process_node) + end + + def assign_section_title_anchor + section_stack = [] + + g = proc do |c| + next unless c.kind == :element + + section_stack.push(c) if c.name == 'section' + for_each_child(c, &g) + section_stack.pop if c.name == 'section' + + if c.name == 'h' + current_section = section_stack.last + raise '[nuldoc.tohtml] <h> element must be inside <section>' unless current_section + + section_id = current_section.attributes['id'] + a_element = a({}, *c.children) + a_element.attributes['href'] = "##{section_id}" + c.children.replace([a_element]) + end + end + + for_each_child(@doc.root, &g) + end + + def transform_section_title_element + section_level = 1 + + g = proc do |c| + next unless c.kind == :element + + if c.name == 'section' + section_level += 1 + c.attributes['__sectionLevel'] = section_level.to_s + end + for_each_child(c, &g) + section_level -= 1 if c.name == 'section' + c.name = "h#{section_level}" if c.name == 'h' + end + + for_each_child(@doc.root, &g) + end + + def transform_note_element + for_each_element_of_type(@doc.root, 'note') do |n| + editat_attr = n.attributes['editat'] + operation_attr = n.attributes['operation'] + is_edit_block = editat_attr && operation_attr + + label_element = div({ 'class' => 'admonition-label' }, + text(is_edit_block ? "#{editat_attr} #{operation_attr}" : 'NOTE')) + content_element = div({ 'class' => 'admonition-content' }, *n.children.dup) + n.name = 'div' + add_class(n, 'admonition') + n.children.replace([label_element, content_element]) + end + end + + def add_attributes_to_external_link_element + for_each_element_of_type(@doc.root, 'a') do |n| + href = n.attributes['href'] || '' + next unless href.start_with?('http') + + n.attributes['target'] = '_blank' + n.attributes['rel'] = 'noreferrer' + end + end + + def traverse_footnotes + footnote_counter = 0 + footnote_map = {} + + for_each_element_of_type(@doc.root, 'footnoteref') do |n| + reference = n.attributes['reference'] + next unless reference + + unless footnote_map.key?(reference) + footnote_counter += 1 + footnote_map[reference] = footnote_counter + end + footnote_number = footnote_map[reference] + + n.name = 'sup' + n.attributes.delete('reference') + n.attributes['class'] = 'footnote' + n.children.replace([ + a( + { + 'id' => "footnoteref--#{reference}", + 'class' => 'footnote', + 'href' => "#footnote--#{reference}" + }, + text("[#{footnote_number}]") + ) + ]) + end + + for_each_element_of_type(@doc.root, 'footnote') do |n| + id = n.attributes['id'] + unless id && footnote_map.key?(id) + n.name = 'span' + n.children.replace([]) + next + end + + footnote_number = footnote_map[id] + + n.name = 'div' + n.attributes.delete('id') + n.attributes['class'] = 'footnote' + n.attributes['id'] = "footnote--#{id}" + + old_children = n.children.dup + n.children.replace([ + a({ 'href' => "#footnoteref--#{id}" }, text("#{footnote_number}. ")), + *old_children + ]) + end + end + + def remove_unnecessary_paragraph_node + for_each_child_recursively(@doc.root) do |n| + next unless n.kind == :element + next unless %w[ul ol].include?(n.name) + + is_tight = n.attributes['__tight'] == 'true' + next unless is_tight + + n.children.each do |child| + next unless child.kind == :element && child.name == 'li' + + new_grand_children = [] + child.children.each do |grand_child| + if grand_child.kind == :element && grand_child.name == 'p' + new_grand_children.concat(grand_child.children) + else + new_grand_children.push(grand_child) + end + end + child.children.replace(new_grand_children) + end + end + end + + def transform_and_highlight_code_block_element + for_each_child_recursively(@doc.root) do |n| + next unless n.kind == :element && n.name == 'codeblock' + + language = n.attributes['language'] || 'text' + filename = n.attributes['filename'] + numbered = n.attributes['numbered'] + source_code_node = n.children[0] + source_code = if source_code_node.kind == :text + source_code_node.content.rstrip + else + source_code_node.html.rstrip + end + + highlighted = highlight_code(source_code, language) + + n.name = 'div' + n.attributes['class'] = 'codeblock' + n.attributes.delete('language') + + if numbered == 'true' + n.attributes.delete('numbered') + add_class(n, 'numbered') + end + + if filename + n.attributes.delete('filename') + n.children.replace([ + div({ 'class' => 'filename' }, text(filename)), + raw_html(highlighted) + ]) + else + n.children.replace([raw_html(highlighted)]) + end + end + end + + def highlight_code(source, language) + lexer = Rouge::Lexer.find(language) || Rouge::Lexers::PlainText.new + lexer = lexer.new if lexer.is_a?(Class) + formatter = Rouge::Formatters::HTMLInline.new('github.light') + tokens = lexer.lex(source) + inner_html = formatter.format(tokens) + "<pre class=\"highlight\" style=\"background-color:#f5f5f5\"><code>#{inner_html}\n</code></pre>" + end + + def generate_table_of_contents + return unless @doc.is_toc_enabled + + toc_entries = [] + stack = [] + excluded_levels = [] + + process_node = proc do |node| + next unless node.kind == :element + + match = node.name.match(/^h(\d+)$/) + if match + level = match[1].to_i + + parent_section = find_parent_section(@doc.root, node) + next unless parent_section + + if parent_section.attributes['toc'] == 'false' + excluded_levels.clear + excluded_levels.push(level) + next + end + + should_exclude = excluded_levels.any? { |el| level > el } + next if should_exclude + + excluded_levels.pop while !excluded_levels.empty? && excluded_levels.last >= level + + section_id = parent_section.attributes['id'] + next unless section_id + + heading_text = '' + node.children.each do |child| + heading_text = inner_text(child) if child.kind == :element && child.name == 'a' + end + + entry = { id: section_id, text: heading_text, level: level, children: [] } + + stack.pop while !stack.empty? && stack.last[:level] >= level + + if stack.empty? + toc_entries.push(entry) + else + stack.last[:children].push(entry) + end + + stack.push(entry) + end + + for_each_child(node, &process_node) + end + + for_each_child(@doc.root, &process_node) + + return if toc_entries.length == 1 && toc_entries[0][:children].empty? + + toc = TocRoot.new(items: build_toc_entries(toc_entries)) + @doc.toc = toc + end + + def build_toc_entries(raw_entries) + raw_entries.map do |e| + TocEntry.new( + id: e[:id], + text: e[:text], + level: e[:level], + children: build_toc_entries(e[:children]) + ) + end + end + + def find_parent_section(root, target) + return root if root.kind == :element && root.name == 'section' && root.children.include?(target) + + if root.kind == :element + root.children.each do |child| + next unless child.kind == :element + + return child if child.name == 'section' && child.children.include?(target) + + result = find_parent_section(child, target) + return result if result + end + end + nil + end + + def remove_toc_attributes + for_each_child_recursively(@doc.root) do |node| + node.attributes.delete('toc') if node.kind == :element && node.name == 'section' + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/page.rb b/services/nuldoc/lib/nuldoc/page.rb new file mode 100644 index 00000000..88795859 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/page.rb @@ -0,0 +1,3 @@ +module Nuldoc + Page = Data.define(:root, :renderer, :site, :dest_file_path, :href) +end diff --git a/services/nuldoc/lib/nuldoc/pages/about_page.rb b/services/nuldoc/lib/nuldoc/pages/about_page.rb new file mode 100644 index 00000000..7dfe7e6a --- /dev/null +++ b/services/nuldoc/lib/nuldoc/pages/about_page.rb @@ -0,0 +1,70 @@ +module Nuldoc + module Pages + class AboutPage + extend Dom + + def self.render(slides:, config:) + sorted_slides = slides.sort_by { |s| GeneratorUtils.published_date(s) }.reverse + + Components::PageLayout.render( + meta_copyright_year: config.site.copyright_year, + meta_description: 'このサイトの著者について', + meta_title: "About|#{config.sites.about.site_name}", + site: 'about', + config: config, + children: elem('body', { 'class' => 'single' }, + Components::AboutGlobalHeader.render(config: config), + elem('main', { 'class' => 'main' }, + article({ 'class' => 'post-single' }, + header({ 'class' => 'post-header' }, + h1({ 'class' => 'post-title' }, 'nsfisis'), + div({ 'class' => 'my-icon' }, + div({ 'id' => 'myIcon' }, + img({ 'src' => '/favicon.svg' })), + Components::StaticScript.render( + site: 'about', + file_name: '/my-icon.js', + defer: 'true', + config: config + ))), + div({ 'class' => 'post-content' }, + section({}, + h2({}, '読み方'), + p({}, '読み方は決めていません。音にする必要があるときは本名である「いまむら」をお使いください。')), + section({}, + h2({}, 'アカウント'), + ul({}, + li({}, a({ 'href' => 'https://twitter.com/nsfisis', + 'target' => '_blank', + 'rel' => 'noreferrer' }, + 'Twitter (現 𝕏): @nsfisis')), + li({}, a({ 'href' => 'https://github.com/nsfisis', + 'target' => '_blank', + 'rel' => 'noreferrer' }, + 'GitHub: @nsfisis')))), + section({}, + h2({}, '仕事'), + ul({}, + li({}, '2021-01~現在: ', + a({ 'href' => 'https://www.dgcircus.com/', + 'target' => '_blank', + 'rel' => 'noreferrer' }, + 'デジタルサーカス株式会社')))), + section({}, + h2({}, '登壇'), + ul({}, + *sorted_slides.map do |slide| + slide_url = "https://#{config.sites.slides.fqdn}#{slide.href}" + slide_date = Revision.date_to_string( + GeneratorUtils.published_date(slide) + ) + li({}, + a({ 'href' => slide_url }, + "#{slide_date}: #{slide.event} (#{slide.talk_type})")) + end))))), + Components::GlobalFooter.render(config: config)) + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/pages/atom_page.rb b/services/nuldoc/lib/nuldoc/pages/atom_page.rb new file mode 100644 index 00000000..68c21193 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/pages/atom_page.rb @@ -0,0 +1,26 @@ +module Nuldoc + module Pages + class AtomPage + extend Dom + + def self.render(feed:) + elem('feed', { 'xmlns' => 'http://www.w3.org/2005/Atom' }, + elem('id', {}, feed.id), + elem('title', {}, feed.title), + link({ 'rel' => 'alternate', 'href' => feed.link_to_alternate }), + link({ 'rel' => 'self', 'href' => feed.link_to_self }), + elem('author', {}, elem('name', {}, feed.author)), + elem('updated', {}, feed.updated), + *feed.entries.map do |entry| + elem('entry', {}, + elem('id', {}, entry.id), + link({ 'rel' => 'alternate', 'href' => entry.link_to_alternate }), + elem('title', {}, entry.title), + elem('summary', {}, entry.summary), + elem('published', {}, entry.published), + elem('updated', {}, entry.updated)) + end) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/pages/home_page.rb b/services/nuldoc/lib/nuldoc/pages/home_page.rb new file mode 100644 index 00000000..3a7df7cc --- /dev/null +++ b/services/nuldoc/lib/nuldoc/pages/home_page.rb @@ -0,0 +1,36 @@ +module Nuldoc + module Pages + class HomePage + extend Dom + + def self.render(config:) + Components::PageLayout.render( + meta_copyright_year: config.site.copyright_year, + meta_description: 'nsfisis のサイト', + meta_title: config.sites.default.site_name, + meta_atom_feed_href: "https://#{config.sites.default.fqdn}/atom.xml", + site: 'default', + config: config, + children: elem('body', { 'class' => 'single' }, + Components::DefaultGlobalHeader.render(config: config), + elem('main', { 'class' => 'main' }, + article({ 'class' => 'post-single' }, + article({ 'class' => 'post-entry' }, + a({ 'href' => "https://#{config.sites.about.fqdn}/" }, + header({ 'class' => 'entry-header' }, h2({}, 'About')))), + article({ 'class' => 'post-entry' }, + a({ 'href' => "https://#{config.sites.blog.fqdn}/posts/" }, + header({ 'class' => 'entry-header' }, h2({}, 'Blog')))), + article({ 'class' => 'post-entry' }, + a({ 'href' => "https://#{config.sites.slides.fqdn}/slides/" }, + header({ 'class' => 'entry-header' }, h2({}, 'Slides')))), + article({ 'class' => 'post-entry' }, + a({ 'href' => "https://repos.#{config.sites.default.fqdn}/" }, + header({ 'class' => 'entry-header' }, + h2({}, 'Repositories')))))), + Components::GlobalFooter.render(config: config)) + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/pages/not_found_page.rb b/services/nuldoc/lib/nuldoc/pages/not_found_page.rb new file mode 100644 index 00000000..53023e47 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/pages/not_found_page.rb @@ -0,0 +1,31 @@ +module Nuldoc + module Pages + class NotFoundPage + extend Dom + + def self.render(site:, config:) + global_header = case site + when 'about' then Components::AboutGlobalHeader + when 'blog' then Components::BlogGlobalHeader + when 'slides' then Components::SlidesGlobalHeader + else Components::DefaultGlobalHeader + end + + site_entry = config.site_entry(site) + + Components::PageLayout.render( + meta_copyright_year: config.site.copyright_year, + meta_description: 'リクエストされたページが見つかりません', + meta_title: "Page Not Found|#{site_entry.site_name}", + site: site, + config: config, + children: elem('body', { 'class' => 'single' }, + global_header.render(config: config), + elem('main', { 'class' => 'main' }, + article({}, div({ 'class' => 'not-found' }, '404'))), + Components::GlobalFooter.render(config: config)) + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/pages/post_list_page.rb b/services/nuldoc/lib/nuldoc/pages/post_list_page.rb new file mode 100644 index 00000000..c6978735 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/pages/post_list_page.rb @@ -0,0 +1,34 @@ +module Nuldoc + module Pages + class PostListPage + extend Dom + + def self.render(posts:, config:, current_page:, total_pages:) + page_title = '投稿一覧' + page_info_suffix = " (#{current_page}ページ目)" + meta_title = "#{page_title}#{page_info_suffix}|#{config.sites.blog.site_name}" + meta_description = "投稿した記事の一覧#{page_info_suffix}" + + Components::PageLayout.render( + meta_copyright_year: config.site.copyright_year, + meta_description: meta_description, + meta_title: meta_title, + meta_atom_feed_href: "https://#{config.sites.blog.fqdn}/posts/atom.xml", + site: 'blog', + config: config, + children: elem('body', { 'class' => 'list' }, + Components::BlogGlobalHeader.render(config: config), + elem('main', { 'class' => 'main' }, + header({ 'class' => 'page-header' }, + h1({}, "#{page_title}#{page_info_suffix}")), + Components::Pagination.render(current_page: current_page, total_pages: total_pages, + base_path: '/posts/'), + *posts.map { |post| Components::PostPageEntry.render(post: post, config: config) }, + Components::Pagination.render(current_page: current_page, total_pages: total_pages, + base_path: '/posts/')), + Components::GlobalFooter.render(config: config)) + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/pages/post_page.rb b/services/nuldoc/lib/nuldoc/pages/post_page.rb new file mode 100644 index 00000000..a8ccda17 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/pages/post_page.rb @@ -0,0 +1,46 @@ +module Nuldoc + module Pages + class PostPage + extend Dom + + def self.render(doc:, config:) + Components::PageLayout.render( + meta_copyright_year: GeneratorUtils.published_date(doc).year, + meta_description: doc.description, + meta_keywords: doc.tags.map { |slug| config.tag_label(slug) }, + meta_title: "#{doc.title}|#{config.sites.blog.site_name}", + site: 'blog', + config: config, + children: elem('body', { 'class' => 'single' }, + Components::BlogGlobalHeader.render(config: config), + elem('main', { 'class' => 'main' }, + article({ 'class' => 'post-single' }, + header({ 'class' => 'post-header' }, + h1({ 'class' => 'post-title' }, doc.title), + doc.tags.length.positive? ? ul({ 'class' => 'post-tags' }, + *doc.tags.map do |slug| + li({ 'class' => 'tag' }, + a({ 'class' => 'tag-inner', + 'href' => "/tags/#{slug}/" }, + config.tag_label(slug))) + end) : nil), + if doc.toc && doc.toc.items.length.positive? + Components::TableOfContents.render(toc: doc.toc) + end, + div({ 'class' => 'post-content' }, + section({ 'id' => 'changelog' }, + h2({}, a({ 'href' => '#changelog' }, '更新履歴')), + ol({}, + *doc.revisions.map do |rev| + ds = Revision.date_to_string(rev.date) + li({ 'class' => 'revision' }, + elem('time', { 'datetime' => ds }, ds), + ": #{rev.remark}") + end)), + *doc.root.children[0].children))), + Components::GlobalFooter.render(config: config)) + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/pages/slide_list_page.rb b/services/nuldoc/lib/nuldoc/pages/slide_list_page.rb new file mode 100644 index 00000000..9dc25d30 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/pages/slide_list_page.rb @@ -0,0 +1,29 @@ +module Nuldoc + module Pages + class SlideListPage + extend Dom + + def self.render(slides:, config:) + page_title = 'スライド一覧' + sorted = slides.sort_by { |s| GeneratorUtils.published_date(s) }.reverse + + Components::PageLayout.render( + meta_copyright_year: config.site.copyright_year, + meta_description: '登壇したイベントで使用したスライドの一覧', + meta_title: "#{page_title}|#{config.sites.slides.site_name}", + meta_atom_feed_href: "https://#{config.sites.slides.fqdn}/slides/atom.xml", + site: 'slides', + config: config, + children: elem('body', { 'class' => 'list' }, + Components::SlidesGlobalHeader.render(config: config), + elem('main', { 'class' => 'main' }, + header({ 'class' => 'page-header' }, h1({}, page_title)), + *sorted.map do |slide| + Components::SlidePageEntry.render(slide: slide, config: config) + end), + Components::GlobalFooter.render(config: config)) + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/pages/slide_page.rb b/services/nuldoc/lib/nuldoc/pages/slide_page.rb new file mode 100644 index 00000000..ac54bb85 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/pages/slide_page.rb @@ -0,0 +1,66 @@ +module Nuldoc + module Pages + class SlidePage + extend Dom + + def self.render(slide:, config:) + Components::PageLayout.render( + meta_copyright_year: GeneratorUtils.published_date(slide).year, + meta_description: "「#{slide.title}」(#{slide.event} で登壇)", + meta_keywords: slide.tags.map { |slug| config.tag_label(slug) }, + meta_title: "#{slide.title} (#{slide.event})|#{config.sites.slides.site_name}", + site: 'slides', + config: config, + children: elem('body', { 'class' => 'single' }, + Components::StaticStylesheet.render(site: 'slides', file_name: '/slides.css', + config: config), + Components::SlidesGlobalHeader.render(config: config), + elem('main', { 'class' => 'main' }, + article({ 'class' => 'post-single' }, + header({ 'class' => 'post-header' }, + h1({ 'class' => 'post-title' }, slide.title), + slide.tags.length.positive? ? ul({ 'class' => 'post-tags' }, + *slide.tags.map do |slug| + li({ 'class' => 'tag' }, + a({ 'class' => 'tag-inner', + 'href' => "/tags/#{slug}/" }, + config.tag_label(slug))) + end) : nil), + div({ 'class' => 'post-content' }, + section({ 'id' => 'changelog' }, + h2({}, a({ 'href' => '#changelog' }, '更新履歴')), + ol({}, + *slide.revisions.map do |rev| + ds = Revision.date_to_string(rev.date) + li({ 'class' => 'revision' }, + elem('time', { 'datetime' => ds }, ds), + ": #{rev.remark}") + end)), + elem('canvas', + { 'id' => 'slide', 'data-slide-link' => slide.slide_link }), + div({ 'class' => 'controllers' }, + div({ 'class' => 'controllers-buttons' }, + button({ 'id' => 'prev', 'type' => 'button' }, + elem('svg', { 'width' => '20', 'height' => '20', + 'viewBox' => '0 0 24 24', 'fill' => 'none', + 'stroke' => 'currentColor', + 'stroke-width' => '2' }, + elem('path', { 'd' => 'M15 18l-6-6 6-6' }))), + button({ 'id' => 'next', 'type' => 'button' }, + elem('svg', { 'width' => '20', 'height' => '20', + 'viewBox' => '0 0 24 24', 'fill' => 'none', + 'stroke' => 'currentColor', + 'stroke-width' => '2' }, + elem('path', { 'd' => 'M9 18l6-6-6-6' }))))), + Components::StaticScript.render( + site: 'slides', + file_name: '/slide.js', + type: 'module', + config: config + )))), + Components::GlobalFooter.render(config: config)) + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/pages/tag_list_page.rb b/services/nuldoc/lib/nuldoc/pages/tag_list_page.rb new file mode 100644 index 00000000..612a50b5 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/pages/tag_list_page.rb @@ -0,0 +1,39 @@ +module Nuldoc + module Pages + class TagListPage + extend Dom + + def self.render(tags:, site:, config:) + page_title = 'タグ一覧' + global_header = site == 'blog' ? Components::BlogGlobalHeader : Components::SlidesGlobalHeader + site_entry = config.site_entry(site) + + sorted_tags = tags.sort_by(&:tag_slug) + + Components::PageLayout.render( + meta_copyright_year: config.site.copyright_year, + meta_description: 'タグの一覧', + meta_title: "#{page_title}|#{site_entry.site_name}", + site: site, + config: config, + children: elem('body', { 'class' => 'list' }, + global_header.render(config: config), + elem('main', { 'class' => 'main' }, + header({ 'class' => 'page-header' }, h1({}, page_title)), + *sorted_tags.map do |tag| + posts_text = tag.num_of_posts.zero? ? '' : "#{tag.num_of_posts}件の記事" + slides_text = tag.num_of_slides.zero? ? '' : "#{tag.num_of_slides}件のスライド" + separator = !posts_text.empty? && !slides_text.empty? ? '、' : '' + footer_text = "#{posts_text}#{separator}#{slides_text}" + + article({ 'class' => 'post-entry' }, + a({ 'href' => tag.href }, + header({ 'class' => 'entry-header' }, h2({}, tag.tag_label)), + footer({ 'class' => 'entry-footer' }, footer_text))) + end), + Components::GlobalFooter.render(config: config)) + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/pages/tag_page.rb b/services/nuldoc/lib/nuldoc/pages/tag_page.rb new file mode 100644 index 00000000..38c55652 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/pages/tag_page.rb @@ -0,0 +1,37 @@ +module Nuldoc + module Pages + class TagPage + extend Dom + + def self.render(tag_slug:, pages:, site:, config:) + tag_label = config.tag_label(tag_slug) + page_title = "タグ「#{tag_label}」一覧" + + global_header = site == 'blog' ? Components::BlogGlobalHeader : Components::SlidesGlobalHeader + site_entry = config.site_entry(site) + + Components::PageLayout.render( + meta_copyright_year: GeneratorUtils.published_date(pages.last).year, + meta_description: "タグ「#{tag_label}」のついた記事またはスライドの一覧", + meta_keywords: [tag_label], + meta_title: "#{page_title}|#{site_entry.site_name}", + meta_atom_feed_href: "https://#{site_entry.fqdn}/tags/#{tag_slug}/atom.xml", + site: site, + config: config, + children: elem('body', { 'class' => 'list' }, + global_header.render(config: config), + elem('main', { 'class' => 'main' }, + header({ 'class' => 'page-header' }, h1({}, page_title)), + *pages.map do |page| + if page.respond_to?(:event) + Components::SlidePageEntry.render(slide: page, config: config) + else + Components::PostPageEntry.render(post: page, config: config) + end + end), + Components::GlobalFooter.render(config: config)) + ) + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/render.rb b/services/nuldoc/lib/nuldoc/render.rb new file mode 100644 index 00000000..facd670b --- /dev/null +++ b/services/nuldoc/lib/nuldoc/render.rb @@ -0,0 +1,14 @@ +module Nuldoc + class Renderer + def render(root, renderer_type) + case renderer_type + when :html + HtmlRenderer.new.render(root) + when :xml + XmlRenderer.new.render(root) + else + raise "Unknown renderer: #{renderer_type}" + end + end + end +end diff --git a/services/nuldoc/lib/nuldoc/renderers/html.rb b/services/nuldoc/lib/nuldoc/renderers/html.rb new file mode 100644 index 00000000..956750c5 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/renderers/html.rb @@ -0,0 +1,210 @@ +module Nuldoc + class HtmlRenderer + DTD = { + 'a' => { type: :inline }, + 'article' => { type: :block }, + 'blockquote' => { type: :block }, + 'body' => { type: :block }, + 'br' => { type: :block, self_closing: true }, + 'button' => { type: :block }, + 'canvas' => { type: :block }, + 'caption' => { type: :block }, + 'code' => { type: :inline }, + 'del' => { type: :block }, + 'div' => { type: :block }, + 'em' => { type: :inline }, + 'footer' => { type: :block }, + 'h1' => { type: :inline }, + 'h2' => { type: :inline }, + 'h3' => { type: :inline }, + 'h4' => { type: :inline }, + 'h5' => { type: :inline }, + 'h6' => { type: :inline }, + 'head' => { type: :block }, + 'header' => { type: :block }, + 'hr' => { type: :block, self_closing: true }, + 'html' => { type: :block }, + 'i' => { type: :inline }, + 'li' => { type: :block }, + 'link' => { type: :block, self_closing: true }, + 'img' => { type: :inline, self_closing: true }, + 'ins' => { type: :inline }, + 'main' => { type: :block }, + 'mark' => { type: :inline }, + 'meta' => { type: :block, self_closing: true }, + 'nav' => { type: :block }, + 'noscript' => { type: :block }, + 'ol' => { type: :block }, + 'p' => { type: :block }, + 'pre' => { type: :block }, + 'script' => { type: :block }, + 'section' => { type: :block }, + 'span' => { type: :inline }, + 'strong' => { type: :inline }, + 'sub' => { type: :inline }, + 'sup' => { type: :inline }, + 'table' => { type: :block }, + 'tbody' => { type: :block }, + 'td' => { type: :block }, + 'tfoot' => { type: :block }, + 'th' => { type: :block }, + 'thead' => { type: :block }, + 'time' => { type: :inline }, + 'title' => { type: :inline }, + 'tr' => { type: :block }, + 'ul' => { type: :block }, + 'svg' => { type: :block }, + 'path' => { type: :block } + }.freeze + + def render(root) + "<!DOCTYPE html>\n#{node_to_html(root, indent_level: 0, is_in_pre: false)}" + end + + private + + def get_dtd(name) + dtd = DTD[name] + raise "[html.write] Unknown element name: #{name}" if dtd.nil? + + dtd + end + + def inline_node?(node) + return true if %i[text raw].include?(node.kind) + + return get_dtd(node.name)[:type] == :inline if node.name != 'a' + + node.children.all? { |c| inline_node?(c) } + end + + def block_node?(node) + !inline_node?(node) + end + + def node_to_html(node, indent_level:, is_in_pre:) + case node.kind + when :text + text_node_to_html(node, _indent_level: indent_level, is_in_pre: is_in_pre) + when :raw + node.html + when :element + element_node_to_html(node, indent_level: indent_level, is_in_pre: is_in_pre) + end + end + + def text_node_to_html(node, _indent_level:, is_in_pre:) + s = encode_special_characters(node.content) + return s if is_in_pre + + s.gsub(/\n */) do |_match| + offset = $LAST_MATCH_INFO.begin(0) + last_char = offset.positive? ? s[offset - 1] : nil + if ['。', '、'].include?(last_char) + '' + else + ' ' + end + end + end + + def encode_special_characters(s) + s.gsub(/&(?!(?:\w+|#\d+|#x[\da-fA-F]+);)/, '&') + .gsub('<', '<') + .gsub('>', '>') + .gsub("'", ''') + .gsub('"', '"') + end + + def element_node_to_html(element, indent_level:, is_in_pre:) + dtd = get_dtd(element.name) + s = +'' + + s << indent(indent_level) if block_node?(element) + s << "<#{element.name}" + + attributes = get_element_attributes(element) + unless attributes.empty? + s << ' ' + attributes.each_with_index do |(name, value), i| + if name == 'defer' && value == 'true' + s << 'defer' + else + attr_name = name == 'className' ? 'class' : name + s << "#{attr_name}=\"#{encode_special_characters(value)}\"" + end + s << ' ' if i != attributes.length - 1 + end + end + s << '>' + s << "\n" if block_node?(element) && element.name != 'pre' + + child_indent = indent_level + 1 + prev_child = nil + child_is_in_pre = is_in_pre || element.name == 'pre' + + element.children.each do |child| + if block_node?(element) && !child_is_in_pre + if inline_node?(child) + s << indent(child_indent) if needs_indent?(prev_child) + elsif needs_line_break?(prev_child) + s << "\n" + end + end + s << node_to_html(child, indent_level: child_indent, is_in_pre: child_is_in_pre) + prev_child = child + end + + unless dtd[:self_closing] + if (element.name != 'pre') && block_node?(element) + s << "\n" if needs_line_break?(prev_child) + s << indent(indent_level) + end + s << "</#{element.name}>" + s << "\n" if block_node?(element) + end + + s + end + + def indent(level) + ' ' * level + end + + def get_element_attributes(element) + element.attributes + .reject { |k, _| k.start_with?('__') } + .compact + .sort { |a, b| compare_attributes(element.name, a, b) } + end + + def compare_attributes(element_name, a, b) + ak, = a + bk, = b + + if element_name == 'meta' + return 1 if ak == 'content' && bk == 'name' + return -1 if ak == 'name' && bk == 'content' + return 1 if ak == 'content' && bk == 'property' + return -1 if ak == 'property' && bk == 'content' + end + + if element_name == 'link' + return 1 if ak == 'href' && bk == 'rel' + return -1 if ak == 'rel' && bk == 'href' + return 1 if ak == 'href' && bk == 'type' + return -1 if ak == 'type' && bk == 'href' + end + + ak <=> bk + end + + def needs_indent?(prev_child) + prev_child.nil? || block_node?(prev_child) + end + + def needs_line_break?(prev_child) + !needs_indent?(prev_child) + end + end +end diff --git a/services/nuldoc/lib/nuldoc/renderers/xml.rb b/services/nuldoc/lib/nuldoc/renderers/xml.rb new file mode 100644 index 00000000..c27fe256 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/renderers/xml.rb @@ -0,0 +1,97 @@ +module Nuldoc + class XmlRenderer + BLOCK_ELEMENTS = %w[feed entry author].freeze + + def render(root) + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n#{node_to_xml(root, indent_level: 0)}" + end + + private + + def inline_node?(node) + return true if %i[text raw].include?(node.kind) + + !BLOCK_ELEMENTS.include?(node.name) + end + + def block_node?(node) + !inline_node?(node) + end + + def node_to_xml(node, indent_level:) + case node.kind + when :text + text_node_to_xml(node) + when :raw + node.html + when :element + element_node_to_xml(node, indent_level: indent_level) + end + end + + def text_node_to_xml(node) + encode_special_characters(node.content).gsub(/\n */, ' ') + end + + def encode_special_characters(s) + s.gsub(/&(?!(?:\w+|#\d+|#x[\da-fA-F]+);)/, '&') + .gsub('<', '<') + .gsub('>', '>') + .gsub("'", ''') + .gsub('"', '"') + end + + def element_node_to_xml(element, indent_level:) + s = +'' + + s << indent(indent_level) + s << "<#{element.name}" + + attributes = get_element_attributes(element) + unless attributes.empty? + s << ' ' + attributes.each_with_index do |(name, value), i| + s << "#{name}=\"#{encode_special_characters(value)}\"" + s << ' ' if i != attributes.length - 1 + end + end + s << '>' + s << "\n" if block_node?(element) + + child_indent = indent_level + 1 + element.children.each do |child| + s << node_to_xml(child, indent_level: child_indent) + end + + s << indent(indent_level) if block_node?(element) + s << "</#{element.name}>" + s << "\n" + + s + end + + def indent(level) + ' ' * level + end + + def get_element_attributes(element) + element.attributes + .reject { |k, _| k.start_with?('__') } + .sort { |a, b| compare_attributes(element.name, a, b) } + end + + def compare_attributes(element_name, a, b) + ak, = a + bk, = b + + if element_name == 'link' + return 1 if ak == 'href' && bk == 'rel' + return -1 if ak == 'rel' && bk == 'href' + return 1 if ak == 'href' && bk == 'type' + return -1 if ak == 'type' && bk == 'href' + end + + ak <=> bk + end + end +end diff --git a/services/nuldoc/lib/nuldoc/revision.rb b/services/nuldoc/lib/nuldoc/revision.rb new file mode 100644 index 00000000..f672af8e --- /dev/null +++ b/services/nuldoc/lib/nuldoc/revision.rb @@ -0,0 +1,18 @@ +module Nuldoc + Revision = Data.define(:number, :date, :remark, :is_internal) do + def self.string_to_date(s) + match = s.match(/\A(\d{4})-(\d{2})-(\d{2})\z/) + raise "Invalid date string: #{s}" if match.nil? + + Date.new(match[1].to_i, match[2].to_i, match[3].to_i) + end + + def self.date_to_string(date) + format('%<year>04d-%<month>02d-%<day>02d', year: date.year, month: date.month, day: date.day) + end + + def self.date_to_rfc3339_string(date) + format('%<year>04d-%<month>02d-%<day>02dT00:00:00+09:00', year: date.year, month: date.month, day: date.day) + end + end +end diff --git a/services/nuldoc/lib/nuldoc/slide/parse.rb b/services/nuldoc/lib/nuldoc/slide/parse.rb new file mode 100644 index 00000000..32046f73 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/slide/parse.rb @@ -0,0 +1,16 @@ +require 'toml-rb' + +module Nuldoc + class SlideParser + def initialize(file_path) + @file_path = file_path + end + + def parse + metadata = TomlRB.load_file(@file_path) + SlideFactory.new(metadata, @file_path).create + rescue StandardError => e + raise e.class, "#{e.message} in #{@file_path}" + end + end +end diff --git a/services/nuldoc/lib/nuldoc/slide/slide.rb b/services/nuldoc/lib/nuldoc/slide/slide.rb new file mode 100644 index 00000000..cb4cadf2 --- /dev/null +++ b/services/nuldoc/lib/nuldoc/slide/slide.rb @@ -0,0 +1,44 @@ +module Nuldoc + Slide = Data.define( + :source_file_path, + :uuid, + :title, + :event, + :talk_type, + :slide_link, + :tags, + :revisions + ) + + class SlideFactory + def initialize(metadata, source_file_path) + @metadata = metadata + @source_file_path = source_file_path + end + + def create + slide_data = @metadata['slide'] + revisions = slide_data['revisions'].each_with_index.map do |rev, i| + Revision.new( + number: i + 1, + date: Revision.string_to_date(rev['date']), + remark: rev['remark'], + is_internal: !rev['isInternal'].nil? + ) + end + + raise "[slide.new] 'slide.revisions' field is empty" if revisions.empty? + + Slide.new( + source_file_path: @source_file_path, + uuid: slide_data['uuid'], + title: slide_data['title'], + event: slide_data['event'], + talk_type: slide_data['talkType'], + slide_link: slide_data['link'], + tags: slide_data['tags'], + revisions: revisions + ) + end + end +end diff --git a/services/nuldoc/nuldoc b/services/nuldoc/nuldoc deleted file mode 100755 index 758ebc3f..00000000 --- a/services/nuldoc/nuldoc +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -deno run -P nuldoc-src/main.ts "$@" diff --git a/services/nuldoc/nuldoc-src/commands/build.ts b/services/nuldoc/nuldoc-src/commands/build.ts deleted file mode 100644 index 61853816..00000000 --- a/services/nuldoc/nuldoc-src/commands/build.ts +++ /dev/null @@ -1,332 +0,0 @@ -import { dirname, join, joinGlobs, relative } from "@std/path"; -import { ensureDir, expandGlob } from "@std/fs"; -import { generateFeedPageFromEntries } from "../generators/atom.ts"; -import { Config, getTagLabel } from "../config.ts"; -import { parseMarkdownFile } from "../markdown/parse.ts"; -import { Page } from "../page.ts"; -import { render } from "../render.ts"; -import { dateToString } from "../revision.ts"; -import { generateAboutPage } from "../generators/about.ts"; -import { generateHomePage } from "../generators/home.ts"; -import { generateNotFoundPage } from "../generators/not_found.ts"; -import { - generatePostPage, - getPostPublishedDate, - PostPage, -} from "../generators/post.ts"; -import { generatePostListPages } from "../generators/post_list.ts"; -import { generateSlidePage, SlidePage } from "../generators/slide.ts"; -import { generateSlideListPage } from "../generators/slide_list.ts"; -import { generateTagPage, TagPage } from "../generators/tag.ts"; -import { TaggedPage } from "../generators/tagged_page.ts"; -import { generateTagListPage } from "../generators/tag_list.ts"; -import { parseSlideFile } from "../slide/parse.ts"; - -export async function runBuildCommand(config: Config) { - const posts = await buildPostPages(config); - await buildPostListPage(posts, config); - const slides = await buildSlidePages(config); - await buildSlideListPage(slides, config); - const postTags = await buildTagPages(posts, "blog", config); - await buildTagListPage(postTags, "blog", config); - const slidesTags = await buildTagPages(slides, "slides", config); - await buildTagListPage(slidesTags, "slides", config); - await buildHomePage(config); - await buildAboutPage(slides, config); - await buildNotFoundPage("default", config); - await buildNotFoundPage("about", config); - await buildNotFoundPage("blog", config); - await buildNotFoundPage("slides", config); - await copyStaticFiles(config); - await copySlidesFiles(slides, config); - await copyBlogAssetFiles(config); - await copySlidesAssetFiles(config); - await copyPostSourceFiles(posts, config); -} - -async function buildPostPages(config: Config): Promise<PostPage[]> { - const sourceDir = join(Deno.cwd(), config.locations.contentDir, "posts"); - const postFiles = await collectPostFiles(sourceDir); - const posts = await parsePosts(postFiles, config); - for (const post of posts) { - await writePage(post, config); - } - return posts; -} - -async function collectPostFiles(sourceDir: string): Promise<string[]> { - const filePaths = []; - const globPattern = joinGlobs([sourceDir, "**", "*.md"]); - for await (const entry of expandGlob(globPattern)) { - filePaths.push(entry.path); - } - return filePaths; -} - -async function parsePosts( - postFiles: string[], - config: Config, -): Promise<PostPage[]> { - const posts = []; - for (const postFile of postFiles) { - posts.push( - await generatePostPage(await parseMarkdownFile(postFile, config), config), - ); - } - return posts; -} - -async function buildPostListPage(posts: PostPage[], config: Config) { - // Sort posts by published date (newest first) - const sortedPosts = [...posts].sort((a, b) => { - const ta = dateToString(getPostPublishedDate(a)); - const tb = dateToString(getPostPublishedDate(b)); - if (ta > tb) return -1; - if (ta < tb) return 1; - return 0; - }); - - const postListPages = await generatePostListPages(sortedPosts, config); - for (const page of postListPages) { - await writePage(page, config); - } - - const postFeedPage = generateFeedPageFromEntries( - "/posts/", - "posts", - `投稿一覧|${config.sites.blog.siteName}`, - posts, - "blog", - config, - ); - await writePage(postFeedPage, config); -} - -async function buildSlidePages(config: Config): Promise<SlidePage[]> { - const sourceDir = join(Deno.cwd(), config.locations.contentDir, "slides"); - const slideFiles = await collectSlideFiles(sourceDir); - const slides = await parseSlides(slideFiles, config); - for (const slide of slides) { - await writePage(slide, config); - } - return slides; -} - -async function collectSlideFiles(sourceDir: string): Promise<string[]> { - const filePaths = []; - const globPattern = joinGlobs([sourceDir, "**", "*.toml"]); - for await (const entry of expandGlob(globPattern)) { - filePaths.push(entry.path); - } - return filePaths; -} - -async function parseSlides( - slideFiles: string[], - config: Config, -): Promise<SlidePage[]> { - const slides = []; - for (const slideFile of slideFiles) { - slides.push( - await generateSlidePage(await parseSlideFile(slideFile), config), - ); - } - return slides; -} - -async function buildSlideListPage(slides: SlidePage[], config: Config) { - const slideListPage = await generateSlideListPage(slides, config); - await writePage(slideListPage, config); - const slideFeedPage = generateFeedPageFromEntries( - slideListPage.href, - "slides", - `スライド一覧|${config.sites.slides.siteName}`, - slides, - "slides", - config, - ); - await writePage(slideFeedPage, config); -} - -async function buildHomePage(config: Config) { - const homePage = await generateHomePage(config); - await writePage(homePage, config); -} - -async function buildAboutPage(slides: SlidePage[], config: Config) { - const aboutPage = await generateAboutPage(slides, config); - await writePage(aboutPage, config); -} - -async function buildNotFoundPage( - site: "default" | "about" | "blog" | "slides", - config: Config, -) { - const notFoundPage = await generateNotFoundPage(site, config); - await writePage(notFoundPage, config); -} - -async function buildTagPages( - pages: TaggedPage[], - site: "blog" | "slides", - config: Config, -): Promise<TagPage[]> { - const tagsAndPages = collectTags(pages); - const tags = []; - for (const [tag, pages] of tagsAndPages) { - const tagPage = await generateTagPage(tag, pages, site, config); - await writePage(tagPage, config); - const tagFeedPage = generateFeedPageFromEntries( - tagPage.href, - `tag-${tag}`, - `タグ「${getTagLabel(config, tag)}」一覧|${config.sites[site].siteName}`, - pages, - site, - config, - ); - await writePage(tagFeedPage, config); - tags.push(tagPage); - } - return tags; -} - -async function buildTagListPage( - tags: TagPage[], - site: "blog" | "slides", - config: Config, -) { - const tagListPage = await generateTagListPage(tags, site, config); - await writePage(tagListPage, config); -} - -function collectTags(taggedPages: TaggedPage[]): [string, TaggedPage[]][] { - const tagsAndPages = new Map(); - for (const page of taggedPages) { - for (const tag of page.tags) { - if (!tagsAndPages.has(tag)) { - tagsAndPages.set(tag, []); - } - tagsAndPages.get(tag).push(page); - } - } - - const result: [string, TaggedPage[]][] = []; - for (const tag of Array.from(tagsAndPages.keys()).sort()) { - result.push([ - tag, - tagsAndPages.get(tag).sort((a: TaggedPage, b: TaggedPage) => { - const ta = dateToString(getPostPublishedDate(a)); - const tb = dateToString(getPostPublishedDate(b)); - if (ta > tb) return -1; - if (ta < tb) return 1; - return 0; - }), - ]); - } - return result; -} - -async function copyStaticFiles(config: Config) { - const staticDir = join(Deno.cwd(), config.locations.staticDir); - - for (const site of Object.keys(config.sites)) { - const destDir = join(Deno.cwd(), config.locations.destDir, site); - - // Copy files from static/_all/ to all sites - for await (const entry of expandGlob(join(staticDir, "_all", "*"))) { - await Deno.copyFile(entry.path, join(destDir, entry.name)); - } - - // Copy files from static/<site>/ to the corresponding site - for await (const entry of expandGlob(join(staticDir, site, "*"))) { - await Deno.copyFile(entry.path, join(destDir, entry.name)); - } - } -} - -async function copySlidesFiles(slides: SlidePage[], config: Config) { - const cwd = Deno.cwd(); - const contentDir = join(cwd, config.locations.contentDir); - const destDir = join(cwd, config.locations.destDir); - - for (const slide of slides) { - const src = join(contentDir, slide.slideLink); - const dst = join(destDir, "slides", slide.slideLink); - await ensureDir(dirname(dst)); - await Deno.copyFile(src, dst); - } -} - -async function copyBlogAssetFiles(config: Config) { - const cwd = Deno.cwd(); - const contentDir = join(cwd, config.locations.contentDir, "posts"); - const destDir = join(cwd, config.locations.destDir, "blog"); - - const globPattern = joinGlobs([contentDir, "**", "*"]); - for await (const { isFile, path } of expandGlob(globPattern)) { - if (!isFile) continue; - - // Skip .md, .toml, .pdf files - if ( - path.endsWith(".md") || - path.endsWith(".toml") || - path.endsWith(".pdf") - ) { - continue; - } - - const src = path; - const dst = join(destDir, "posts", relative(contentDir, path)); - await ensureDir(dirname(dst)); - await Deno.copyFile(src, dst); - } -} - -async function copySlidesAssetFiles(config: Config) { - const cwd = Deno.cwd(); - const contentDir = join(cwd, config.locations.contentDir, "slides"); - const destDir = join(cwd, config.locations.destDir, "slides"); - - const globPattern = joinGlobs([contentDir, "**", "*"]); - for await (const { isFile, path } of expandGlob(globPattern)) { - if (!isFile) continue; - - // Skip .md, .toml, .pdf files - if ( - path.endsWith(".md") || - path.endsWith(".toml") || - path.endsWith(".pdf") - ) { - continue; - } - - const src = path; - const dst = join(destDir, "slides", relative(contentDir, path)); - await ensureDir(dirname(dst)); - await Deno.copyFile(src, dst); - } -} - -async function writePage(page: Page, config: Config) { - const destFilePath = join( - Deno.cwd(), - config.locations.destDir, - page.site, - page.destFilePath, - ); - await ensureDir(dirname(destFilePath)); - await Deno.writeTextFile(destFilePath, render(page.root, page.renderer)); -} - -async function copyPostSourceFiles(posts: PostPage[], config: Config) { - const cwd = Deno.cwd(); - const contentDir = join(cwd, config.locations.contentDir); - const destDir = join(cwd, config.locations.destDir, "blog"); - - for (const post of posts) { - const src = post.sourceFilePath; - const dst = join(destDir, relative(contentDir, src)); - await ensureDir(dirname(dst)); - await Deno.copyFile(src, dst); - } -} diff --git a/services/nuldoc/nuldoc-src/commands/new.ts b/services/nuldoc/nuldoc-src/commands/new.ts deleted file mode 100644 index f355376d..00000000 --- a/services/nuldoc/nuldoc-src/commands/new.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { dirname, join } from "@std/path"; -import { ensureDir } from "@std/fs"; -import { parseArgs } from "@std/cli"; -import { Config } from "../config.ts"; - -export async function runNewCommand(config: Config) { - const parsedArgs = parseArgs(Deno.args, { - string: ["date"], - }); - - const type = parsedArgs._[1]; - if (type !== "post" && type !== "slide") { - console.log(`Usage: nuldoc new <type> - -<type> must be either "post" or "slide". - -OPTIONS: - --date <DATE> -`); - Deno.exit(1); - } - - const ymd = (() => { - if (parsedArgs.date) { - return parsedArgs.date; - } - - const now = new Date(); - const y = now.getFullYear(); - const d = (now.getMonth() + 1).toString().padStart(2, "0"); - const m = now.getDate().toString().padStart(2, "0"); - return `${y}-${d}-${m}`; - })(); - - const destFilePath = join( - Deno.cwd(), - config.locations.contentDir, - getDirPath(type), - ymd, - getFilename(type), - ); - - await ensureDir(dirname(destFilePath)); - await Deno.writeTextFile(destFilePath, getTemplate(type, ymd)); - console.log( - `New file ${ - destFilePath.replace(Deno.cwd(), "") - } was successfully created.`, - ); -} - -function getFilename(type: "post" | "slide"): string { - return type === "post" ? "TODO.md" : "TODO.toml"; -} - -function getDirPath(type: "post" | "slide"): string { - return type === "post" ? "posts" : "slides"; -} - -function getTemplate(type: "post" | "slide", date: string): string { - const uuid = crypto.randomUUID(); - if (type === "post") { - return `--- -[article] -uuid = "${uuid}" -title = "TODO" -description = "TODO" -tags = [ - "TODO", -] - -[[article.revisions]] -date = "${date}" -remark = "公開" ---- -# はじめに {#intro} - -TODO -`; - } else { - return `[slide] -uuid = "${uuid}" -title = "TODO" -event = "TODO" -talkType = "TODO" -link = "TODO" -tags = [ - "TODO", -] - -[[slide.revisions]] -date = "${date}" -remark = "登壇" -`; - } -} diff --git a/services/nuldoc/nuldoc-src/commands/serve.ts b/services/nuldoc/nuldoc-src/commands/serve.ts deleted file mode 100644 index 8388d48a..00000000 --- a/services/nuldoc/nuldoc-src/commands/serve.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { parseArgs } from "@std/cli"; -import { serveDir, STATUS_CODE, STATUS_TEXT } from "@std/http"; -import { join } from "@std/path"; -import { Config } from "../config.ts"; -import { runBuildCommand } from "./build.ts"; - -function isResourcePath(pathname: string): boolean { - const EXTENSIONS = [ - ".css", - ".gif", - ".ico", - ".jpeg", - ".jpg", - ".js", - ".mjs", - ".png", - ".svg", - ]; - return EXTENSIONS.some((ext) => pathname.endsWith(ext)); -} - -export function runServeCommand(config: Config) { - const parsedArgs = parseArgs(Deno.args, { - boolean: ["no-rebuild"], - }); - - const doRebuild = !parsedArgs["no-rebuild"]; - const siteName = String(parsedArgs._[1]); - if (siteName === "") { - throw new Error("Usage: nuldoc serve <site>"); - } - - const rootDir = join(Deno.cwd(), config.locations.destDir, siteName); - Deno.serve({ hostname: "127.0.0.1" }, async (req) => { - const pathname = new URL(req.url).pathname; - if (!isResourcePath(pathname) && doRebuild) { - await runBuildCommand(config); - console.log("rebuild"); - } - const res = await serveDir(req, { - fsRoot: rootDir, - showIndex: true, - }); - if (res.status !== STATUS_CODE.NotFound) { - return res; - } - - const notFoundHtml = await Deno.readTextFile(join(rootDir, "404.html")); - return new Response(notFoundHtml, { - status: STATUS_CODE.NotFound, - statusText: STATUS_TEXT[STATUS_CODE.NotFound], - headers: { - "content-type": "text/html", - }, - }); - }); -} diff --git a/services/nuldoc/nuldoc-src/components/AboutGlobalHeader.ts b/services/nuldoc/nuldoc-src/components/AboutGlobalHeader.ts deleted file mode 100644 index df437931..00000000 --- a/services/nuldoc/nuldoc-src/components/AboutGlobalHeader.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Config } from "../config.ts"; -import { a, div, Element, header } from "../dom.ts"; - -export default function GlobalHeader({ config }: { config: Config }): Element { - return header( - { class: "header" }, - div( - { class: "site-logo" }, - a( - { href: `https://${config.sites.default.fqdn}/` }, - "nsfisis.dev", - ), - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/BlogGlobalHeader.ts b/services/nuldoc/nuldoc-src/components/BlogGlobalHeader.ts deleted file mode 100644 index ae0fc13a..00000000 --- a/services/nuldoc/nuldoc-src/components/BlogGlobalHeader.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Config } from "../config.ts"; -import { a, div, Element, header, li, nav, ul } from "../dom.ts"; - -export default function GlobalHeader({ config }: { config: Config }): Element { - return header( - { class: "header" }, - div( - { class: "site-logo" }, - a( - { href: `https://${config.sites.default.fqdn}/` }, - "nsfisis.dev", - ), - ), - div({ class: "site-name" }, config.sites.blog.siteName), - nav( - { class: "nav" }, - ul( - {}, - li( - {}, - a({ href: `https://${config.sites.about.fqdn}/` }, "About"), - ), - li({}, a({ href: "/posts/" }, "Posts")), - li({}, a({ href: "/tags/" }, "Tags")), - ), - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/DefaultGlobalHeader.ts b/services/nuldoc/nuldoc-src/components/DefaultGlobalHeader.ts deleted file mode 100644 index df437931..00000000 --- a/services/nuldoc/nuldoc-src/components/DefaultGlobalHeader.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Config } from "../config.ts"; -import { a, div, Element, header } from "../dom.ts"; - -export default function GlobalHeader({ config }: { config: Config }): Element { - return header( - { class: "header" }, - div( - { class: "site-logo" }, - a( - { href: `https://${config.sites.default.fqdn}/` }, - "nsfisis.dev", - ), - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/GlobalFooter.ts b/services/nuldoc/nuldoc-src/components/GlobalFooter.ts deleted file mode 100644 index 313a01c5..00000000 --- a/services/nuldoc/nuldoc-src/components/GlobalFooter.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Config } from "../config.ts"; -import { Element, footer } from "../dom.ts"; - -export default function GlobalFooter({ config }: { config: Config }): Element { - return footer( - { class: "footer" }, - `© ${config.site.copyrightYear} ${config.site.author}`, - ); -} diff --git a/services/nuldoc/nuldoc-src/components/PageLayout.ts b/services/nuldoc/nuldoc-src/components/PageLayout.ts deleted file mode 100644 index f970c0b6..00000000 --- a/services/nuldoc/nuldoc-src/components/PageLayout.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Config } from "../config.ts"; -import { elem, Element, link, meta, Node } from "../dom.ts"; -import StaticStylesheet from "./StaticStylesheet.ts"; - -type Props = { - metaCopyrightYear: number; - metaDescription: string; - metaKeywords?: string[]; - metaTitle: string; - metaAtomFeedHref?: string; - requiresSyntaxHighlight?: boolean; - site: "default" | "about" | "blog" | "slides"; - config: Config; - children: Node; -}; - -export default async function PageLayout( - { - metaCopyrightYear, - metaDescription, - metaKeywords, - metaTitle, - metaAtomFeedHref, - requiresSyntaxHighlight: _, - site, - config, - children, - }: Props, -): Promise<Element> { - return elem( - "html", - { lang: "ja-JP" }, - elem( - "head", - {}, - meta({ charset: "UTF-8" }), - meta({ - name: "viewport", - content: "width=device-width, initial-scale=1.0", - }), - meta({ name: "author", content: config.site.author }), - meta({ - name: "copyright", - content: `© ${metaCopyrightYear} ${config.site.author}`, - }), - meta({ name: "description", content: metaDescription }), - metaKeywords && metaKeywords.length !== 0 - ? meta({ name: "keywords", content: metaKeywords.join(",") }) - : null, - meta({ property: "og:type", content: "article" }), - meta({ property: "og:title", content: metaTitle }), - meta({ property: "og:description", content: metaDescription }), - meta({ - property: "og:site_name", - content: config.sites[site].siteName, - }), - meta({ property: "og:locale", content: "ja_JP" }), - meta({ name: "Hatena::Bookmark", content: "nocomment" }), - metaAtomFeedHref - ? link({ - rel: "alternate", - href: metaAtomFeedHref, - type: "application/atom+xml", - }) - : null, - link({ - rel: "icon", - href: "/favicon.svg", - type: "image/svg+xml", - }), - elem("title", {}, metaTitle), - await StaticStylesheet({ fileName: "/style.css", config }), - ), - children, - ); -} diff --git a/services/nuldoc/nuldoc-src/components/Pagination.ts b/services/nuldoc/nuldoc-src/components/Pagination.ts deleted file mode 100644 index d9203165..00000000 --- a/services/nuldoc/nuldoc-src/components/Pagination.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { a, div, Element, nav, span } from "../dom.ts"; - -type Props = { - currentPage: number; - totalPages: number; - basePath: string; -}; - -export default function Pagination( - { currentPage, totalPages, basePath }: Props, -): Element { - if (totalPages <= 1) { - return div({}); - } - - const pages = generatePageNumbers(currentPage, totalPages); - - return nav( - { class: "pagination" }, - div( - { class: "pagination-prev" }, - currentPage > 1 - ? a({ href: pageUrlAt(basePath, currentPage - 1) }, "前へ") - : null, - ), - ...pages.map((page) => { - if (page === "...") { - return div({ class: "pagination-elipsis" }, "…"); - } else if (page === currentPage) { - return div( - { class: "pagination-page pagination-page-current" }, - span({}, String(page)), - ); - } else { - return div( - { class: "pagination-page" }, - a({ href: pageUrlAt(basePath, page) }, String(page)), - ); - } - }), - div( - { class: "pagination-next" }, - currentPage < totalPages - ? a({ href: pageUrlAt(basePath, currentPage + 1) }, "次へ") - : null, - ), - ); -} - -type PageItem = number | "..."; - -/** - * Generates page numbers for pagination display. - * - * - Always show the first page - * - Always show the last page - * - Always show the current page - * - Always show the page before and after the current page - * - If there's only one page gap between displayed pages, fill it - * - If there are two or more pages gap between displayed pages, show ellipsis - */ -function generatePageNumbers( - currentPage: number, - totalPages: number, -): PageItem[] { - const pages = new Set<number>(); - pages.add(1); - pages.add(Math.max(1, currentPage - 1)); - pages.add(currentPage); - pages.add(Math.min(totalPages, currentPage + 1)); - pages.add(totalPages); - - const sorted = Array.from(pages).sort((a, b) => a - b); - - const result: PageItem[] = []; - for (let i = 0; i < sorted.length; i++) { - if (i > 0) { - const gap = sorted[i] - sorted[i - 1]; - if (gap === 2) { - result.push(sorted[i - 1] + 1); - } else if (gap > 2) { - result.push("..."); - } - } - result.push(sorted[i]); - } - - return result; -} - -function pageUrlAt(basePath: string, page: number): string { - return page === 1 ? basePath : `${basePath}${page}/`; -} diff --git a/services/nuldoc/nuldoc-src/components/PostPageEntry.ts b/services/nuldoc/nuldoc-src/components/PostPageEntry.ts deleted file mode 100644 index 482a3a8e..00000000 --- a/services/nuldoc/nuldoc-src/components/PostPageEntry.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - getPostPublishedDate, - getPostUpdatedDate, - postHasAnyUpdates, - PostPage, -} from "../generators/post.ts"; -import { dateToString } from "../revision.ts"; -import { Config } from "../config.ts"; -import { - a, - article, - elem, - Element, - footer, - h2, - header, - p, - section, -} from "../dom.ts"; -import TagList from "./TagList.ts"; - -type Props = { post: PostPage; config: Config }; - -export default function PostPageEntry({ post, config }: Props): Element { - return article( - { class: "post-entry" }, - a( - { href: post.href }, - header({ class: "entry-header" }, h2({}, post.title)), - section( - { class: "entry-content" }, - p({}, post.description), - ), - footer( - { class: "entry-footer" }, - elem( - "time", - { datetime: dateToString(getPostPublishedDate(post)) }, - dateToString(getPostPublishedDate(post)), - ), - " 投稿", - postHasAnyUpdates(post) ? "、" : null, - postHasAnyUpdates(post) - ? elem( - "time", - { datetime: dateToString(getPostUpdatedDate(post)) }, - dateToString(getPostUpdatedDate(post)), - ) - : null, - postHasAnyUpdates(post) ? " 更新" : null, - post.tags.length !== 0 ? TagList({ tags: post.tags, config }) : null, - ), - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/SlidePageEntry.ts b/services/nuldoc/nuldoc-src/components/SlidePageEntry.ts deleted file mode 100644 index b48ab4e5..00000000 --- a/services/nuldoc/nuldoc-src/components/SlidePageEntry.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - getPostPublishedDate, - getPostUpdatedDate, - postHasAnyUpdates, -} from "../generators/post.ts"; -import { SlidePage } from "../generators/slide.ts"; -import { dateToString } from "../revision.ts"; -import { Config } from "../config.ts"; -import { - a, - article, - elem, - Element, - footer, - h2, - header, - p, - section, -} from "../dom.ts"; -import TagList from "./TagList.ts"; - -type Props = { slide: SlidePage; config: Config }; - -export default function SlidePageEntry({ slide, config }: Props): Element { - return article( - { class: "post-entry" }, - a( - { href: slide.href }, - header( - { class: "entry-header" }, - h2({}, slide.title), - ), - section({ class: "entry-content" }, p({}, slide.description)), - footer( - { class: "entry-footer" }, - elem( - "time", - { datetime: dateToString(getPostPublishedDate(slide)) }, - dateToString(getPostPublishedDate(slide)), - ), - " 登壇", - postHasAnyUpdates(slide) ? "、" : null, - postHasAnyUpdates(slide) - ? elem( - "time", - { datetime: dateToString(getPostUpdatedDate(slide)) }, - dateToString(getPostUpdatedDate(slide)), - ) - : null, - postHasAnyUpdates(slide) ? " 更新" : null, - slide.tags.length !== 0 ? TagList({ tags: slide.tags, config }) : null, - ), - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/SlidesGlobalHeader.ts b/services/nuldoc/nuldoc-src/components/SlidesGlobalHeader.ts deleted file mode 100644 index 666ca0e3..00000000 --- a/services/nuldoc/nuldoc-src/components/SlidesGlobalHeader.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Config } from "../config.ts"; -import { a, div, Element, header, li, nav, ul } from "../dom.ts"; - -export default function GlobalHeader({ config }: { config: Config }): Element { - return header( - { class: "header" }, - div( - { class: "site-logo" }, - a( - { href: `https://${config.sites.default.fqdn}/` }, - "nsfisis.dev", - ), - ), - nav( - { class: "nav" }, - ul( - {}, - li( - {}, - a({ href: `https://${config.sites.about.fqdn}/` }, "About"), - ), - li({}, a({ href: "/slides/" }, "Slides")), - li({}, a({ href: "/tags/" }, "Tags")), - ), - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/StaticScript.ts b/services/nuldoc/nuldoc-src/components/StaticScript.ts deleted file mode 100644 index 1a3431a3..00000000 --- a/services/nuldoc/nuldoc-src/components/StaticScript.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { join } from "@std/path"; -import { Config } from "../config.ts"; -import { Element, script } from "../dom.ts"; -import { calculateFileHash } from "./utils.ts"; - -export default async function StaticScript( - { site, fileName, type, defer, config }: { - site?: string; - fileName: string; - type?: string; - defer?: "true"; - config: Config; - }, -): Promise<Element> { - const filePath = join( - Deno.cwd(), - config.locations.staticDir, - site || "_all", - fileName, - ); - const hash = await calculateFileHash(filePath); - const attrs: Record<string, string> = { src: `${fileName}?h=${hash}` }; - if (type) attrs.type = type; - if (defer) attrs.defer = defer; - return script(attrs); -} diff --git a/services/nuldoc/nuldoc-src/components/StaticStylesheet.ts b/services/nuldoc/nuldoc-src/components/StaticStylesheet.ts deleted file mode 100644 index f2adb473..00000000 --- a/services/nuldoc/nuldoc-src/components/StaticStylesheet.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { join } from "@std/path"; -import { Config } from "../config.ts"; -import { Element, link } from "../dom.ts"; -import { calculateFileHash } from "./utils.ts"; - -export default async function StaticStylesheet( - { site, fileName, config }: { - site?: string; - fileName: string; - config: Config; - }, -): Promise<Element> { - const filePath = join( - Deno.cwd(), - config.locations.staticDir, - site || "_all", - fileName, - ); - const hash = await calculateFileHash(filePath); - return link({ rel: "stylesheet", href: `${fileName}?h=${hash}` }); -} diff --git a/services/nuldoc/nuldoc-src/components/TableOfContents.ts b/services/nuldoc/nuldoc-src/components/TableOfContents.ts deleted file mode 100644 index 1eb79e98..00000000 --- a/services/nuldoc/nuldoc-src/components/TableOfContents.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { TocEntry, TocRoot } from "../markdown/document.ts"; -import { a, Element, h2, li, nav, ul } from "../dom.ts"; - -type Props = { - toc: TocRoot; -}; - -export default function TableOfContents({ toc }: Props): Element { - return nav( - { class: "toc" }, - h2({}, "目次"), - ul( - {}, - ...toc.entries.map((entry) => TocEntryComponent({ entry })), - ), - ); -} - -function TocEntryComponent({ entry }: { entry: TocEntry }): Element { - return li( - {}, - a({ href: `#${entry.id}` }, entry.text), - entry.children.length > 0 - ? ul( - {}, - ...entry.children.map((child) => TocEntryComponent({ entry: child })), - ) - : null, - ); -} diff --git a/services/nuldoc/nuldoc-src/components/TagList.ts b/services/nuldoc/nuldoc-src/components/TagList.ts deleted file mode 100644 index ed3fc1a1..00000000 --- a/services/nuldoc/nuldoc-src/components/TagList.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Config, getTagLabel } from "../config.ts"; -import { Element, li, span, text, ul } from "../dom.ts"; - -type Props = { - tags: string[]; - config: Config; -}; - -export default function TagList({ tags, config }: Props): Element { - return ul( - { class: "entry-tags" }, - ...tags.map((slug) => - li( - { class: "tag" }, - span({ class: "tag-inner" }, text(getTagLabel(config, slug))), - ) - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/components/utils.ts b/services/nuldoc/nuldoc-src/components/utils.ts deleted file mode 100644 index 14059b5b..00000000 --- a/services/nuldoc/nuldoc-src/components/utils.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Hash } from "checksum/mod.ts"; - -export async function calculateFileHash( - filePath: string, -): Promise<string> { - const content = await Deno.readFile(filePath); - return new Hash("md5").digest(content).hex(); -} diff --git a/services/nuldoc/nuldoc-src/config.ts b/services/nuldoc/nuldoc-src/config.ts deleted file mode 100644 index 267a8f99..00000000 --- a/services/nuldoc/nuldoc-src/config.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { join } from "@std/path"; -import { parse as parseToml } from "@std/toml"; -import { z } from "zod/mod.ts"; - -const ConfigSchema = z.object({ - locations: z.object({ - contentDir: z.string(), - destDir: z.string(), - staticDir: z.string(), - }), - site: z.object({ - author: z.string(), - copyrightYear: z.number(), - }), - sites: z.object({ - default: z.object({ - fqdn: z.string(), - siteName: z.string(), - }), - about: z.object({ - fqdn: z.string(), - siteName: z.string(), - }), - blog: z.object({ - fqdn: z.string(), - siteName: z.string(), - postsPerPage: z.number(), - }), - slides: z.object({ - fqdn: z.string(), - siteName: z.string(), - }), - }), - tagLabels: z.record(z.string(), z.string()), -}); - -export type Config = z.infer<typeof ConfigSchema>; - -export function getTagLabel(c: Config, slug: string): string { - if (!(slug in c.tagLabels)) { - throw new Error(`Unknown tag: ${slug}`); - } - return c.tagLabels[slug]; -} - -export function getDefaultConfigPath(): string { - return join(Deno.cwd(), "nuldoc.toml"); -} - -export async function loadConfig(filePath: string): Promise<Config> { - return ConfigSchema.parse(parseToml(await Deno.readTextFile(filePath))); -} diff --git a/services/nuldoc/nuldoc-src/dom.ts b/services/nuldoc/nuldoc-src/dom.ts deleted file mode 100644 index 5faf184a..00000000 --- a/services/nuldoc/nuldoc-src/dom.ts +++ /dev/null @@ -1,283 +0,0 @@ -export type Text = { - kind: "text"; - content: string; -}; - -export type RawHTML = { - kind: "raw"; - html: string; -}; - -export type Element = { - kind: "element"; - name: string; - attributes: Record<string, string>; - children: Node[]; -}; - -export type Node = Element | Text | RawHTML; - -export type NodeLike = Node | string | null | undefined | false | NodeLike[]; - -function flattenChildren(children: NodeLike[]): Node[] { - const result: Node[] = []; - for (const child of children) { - if (child === null || child === undefined || child === false) { - continue; - } - if (typeof child === "string") { - result.push(text(child)); - } else if (Array.isArray(child)) { - result.push(...flattenChildren(child)); - } else { - result.push(child); - } - } - return result; -} - -export function text(content: string): Text { - return { - kind: "text", - content, - }; -} - -export function rawHTML(html: string): RawHTML { - return { - kind: "raw", - html, - }; -} - -export function elem( - name: string, - attributes?: Record<string, string>, - ...children: NodeLike[] -): Element { - return { - kind: "element", - name, - attributes: attributes || {}, - children: flattenChildren(children), - }; -} - -// Helper functions for commonly used elements -export const a = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("a", attributes, ...children); - -export const article = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("article", attributes, ...children); - -export const button = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("button", attributes, ...children); - -export const div = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("div", attributes, ...children); - -export const footer = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("footer", attributes, ...children); - -export const h1 = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("h1", attributes, ...children); - -export const h2 = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("h2", attributes, ...children); - -export const h3 = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("h3", attributes, ...children); - -export const h4 = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("h4", attributes, ...children); - -export const h5 = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("h5", attributes, ...children); - -export const h6 = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("h6", attributes, ...children); - -export const header = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("header", attributes, ...children); - -export const img = (attributes?: Record<string, string>) => - elem("img", attributes); - -export const li = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("li", attributes, ...children); - -export const link = (attributes?: Record<string, string>) => - elem("link", attributes); - -export const meta = (attributes?: Record<string, string>) => - elem("meta", attributes); - -export const nav = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("nav", attributes, ...children); - -export const ol = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("ol", attributes, ...children); - -export const p = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("p", attributes, ...children); - -export const script = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("script", attributes, ...children); - -export const section = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("section", attributes, ...children); - -export const span = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("span", attributes, ...children); - -export const ul = ( - attributes?: Record<string, string>, - ...children: NodeLike[] -) => elem("ul", attributes, ...children); - -export function addClass(e: Element, klass: string) { - const classes = e.attributes.class; - if (classes === undefined) { - e.attributes.class = klass; - } else { - const classList = classes.split(" "); - classList.push(klass); - classList.sort(); - e.attributes.class = classList.join(" "); - } -} - -export function findFirstChildElement( - e: Element, - name: string, -): Element | null { - for (const c of e.children) { - if (c.kind === "element" && c.name === name) { - return c; - } - } - return null; -} - -export function findChildElements(e: Element, name: string): Element[] { - const cs = []; - for (const c of e.children) { - if (c.kind === "element" && c.name === name) { - cs.push(c); - } - } - return cs; -} - -export function innerText(e: Element): string { - let t = ""; - forEachChild(e, (c) => { - if (c.kind === "text") { - t += c.content; - } - }); - return t; -} - -export function forEachChild(e: Element, f: (n: Node) => void) { - for (const c of e.children) { - f(c); - } -} - -export async function forEachChildAsync( - e: Element, - f: (n: Node) => Promise<void>, -): Promise<void> { - for (const c of e.children) { - await f(c); - } -} - -export function forEachChildRecursively(e: Element, f: (n: Node) => void) { - const g = (c: Node) => { - f(c); - if (c.kind === "element") { - forEachChild(c, g); - } - }; - forEachChild(e, g); -} - -export async function forEachChildRecursivelyAsync( - e: Element, - f: (n: Node) => Promise<void>, -): Promise<void> { - const g = async (c: Node) => { - await f(c); - if (c.kind === "element") { - await forEachChildAsync(c, g); - } - }; - await forEachChildAsync(e, g); -} - -export function forEachElementOfType( - root: Element, - elementName: string, - f: (e: Element) => void, -) { - forEachChildRecursively(root, (n) => { - if (n.kind === "element" && n.name === elementName) { - f(n); - } - }); -} - -export function processTextNodesInElement( - e: Element, - f: (text: string) => Node[], -) { - const newChildren: Node[] = []; - for (const child of e.children) { - if (child.kind === "text") { - newChildren.push(...f(child.content)); - } else { - newChildren.push(child); - } - } - e.children = newChildren; -} diff --git a/services/nuldoc/nuldoc-src/errors.ts b/services/nuldoc/nuldoc-src/errors.ts deleted file mode 100644 index 1692a4c8..00000000 --- a/services/nuldoc/nuldoc-src/errors.ts +++ /dev/null @@ -1,17 +0,0 @@ -export class NuldocError extends Error { - static { - this.prototype.name = "NuldocError"; - } -} - -export class SlideError extends Error { - static { - this.prototype.name = "SlideError"; - } -} - -export class XmlParseError extends Error { - static { - this.prototype.name = "XmlParseError"; - } -} diff --git a/services/nuldoc/nuldoc-src/generators/about.ts b/services/nuldoc/nuldoc-src/generators/about.ts deleted file mode 100644 index 628c370e..00000000 --- a/services/nuldoc/nuldoc-src/generators/about.ts +++ /dev/null @@ -1,21 +0,0 @@ -import AboutPage from "../pages/AboutPage.ts"; -import { Config } from "../config.ts"; -import { Page } from "../page.ts"; -import { SlidePage } from "./slide.ts"; - -export type AboutPage = Page; - -export async function generateAboutPage( - slides: SlidePage[], - config: Config, -): Promise<AboutPage> { - const html = await AboutPage(slides, config); - - return { - root: html, - renderer: "html", - site: "about", - destFilePath: "/index.html", - href: "/", - }; -} diff --git a/services/nuldoc/nuldoc-src/generators/atom.ts b/services/nuldoc/nuldoc-src/generators/atom.ts deleted file mode 100644 index f501d834..00000000 --- a/services/nuldoc/nuldoc-src/generators/atom.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { Config } from "../config.ts"; -import { Page } from "../page.ts"; -import { PostPage } from "../generators/post.ts"; -import { SlidePage } from "../generators/slide.ts"; -import { dateToRfc3339String } from "../revision.ts"; -import AtomPage from "../pages/AtomPage.ts"; - -export type Feed = { - author: string; - icon: string; - id: string; - linkToSelf: string; - linkToAlternate: string; - title: string; - updated: string; - entries: Entry[]; -}; - -export type Entry = { - id: string; - linkToAlternate: string; - published: string; - summary: string; - title: string; - updated: string; -}; - -const BASE_NAME = "atom.xml"; - -export function generateFeedPageFromEntries( - alternateLink: string, - feedSlug: string, - feedTitle: string, - entries: Array<PostPage | SlidePage>, - site: "default" | "blog" | "slides", - config: Config, -): Page { - const entries_: Entry[] = []; - for (const entry of entries) { - entries_.push({ - id: `urn:uuid:${entry.uuid}`, - linkToAlternate: `https://${ - "event" in entry ? config.sites.slides.fqdn : config.sites.blog.fqdn - }${entry.href}`, - title: entry.title, - summary: entry.description, - published: dateToRfc3339String(entry.published), - updated: dateToRfc3339String(entry.updated), - }); - } - // Sort by published date in ascending order. - entries_.sort((a, b) => { - if (a.published < b.published) { - return 1; - } else if (a.published > b.published) { - return -1; - } - return 0; - }); - const feedPath = `${alternateLink}${BASE_NAME}`; - const feed: Feed = { - author: config.site.author, - icon: `https://${config.sites[site].fqdn}/favicon.svg`, - id: `tag:${ - config.sites[site].fqdn - },${config.site.copyrightYear}:${feedSlug}`, - linkToSelf: `https://${config.sites[site].fqdn}${feedPath}`, - linkToAlternate: `https://${config.sites[site].fqdn}${alternateLink}`, - title: feedTitle, - updated: entries_.reduce( - (latest, entry) => entry.updated > latest ? entry.updated : latest, - entries_[0].updated, - ), - entries: entries_, - }; - - return { - root: AtomPage({ feed: feed }), - renderer: "xml", - site, - destFilePath: feedPath, - href: feedPath, - }; -} diff --git a/services/nuldoc/nuldoc-src/generators/home.ts b/services/nuldoc/nuldoc-src/generators/home.ts deleted file mode 100644 index 1839f5dd..00000000 --- a/services/nuldoc/nuldoc-src/generators/home.ts +++ /dev/null @@ -1,17 +0,0 @@ -import HomePage from "../pages/HomePage.ts"; -import { Config } from "../config.ts"; -import { Page } from "../page.ts"; - -export type HomePage = Page; - -export async function generateHomePage(config: Config): Promise<HomePage> { - const html = await HomePage(config); - - return { - root: html, - renderer: "html", - site: "default", - destFilePath: "/index.html", - href: "/", - }; -} diff --git a/services/nuldoc/nuldoc-src/generators/not_found.ts b/services/nuldoc/nuldoc-src/generators/not_found.ts deleted file mode 100644 index 8a5593c3..00000000 --- a/services/nuldoc/nuldoc-src/generators/not_found.ts +++ /dev/null @@ -1,20 +0,0 @@ -import NotFoundPage from "../pages/NotFoundPage.ts"; -import { Config } from "../config.ts"; -import { Page } from "../page.ts"; - -export type NotFoundPage = Page; - -export async function generateNotFoundPage( - site: "default" | "about" | "blog" | "slides", - config: Config, -): Promise<NotFoundPage> { - const html = await NotFoundPage(site, config); - - return { - root: html, - renderer: "html", - site, - destFilePath: "/404.html", - href: "/404.html", - }; -} diff --git a/services/nuldoc/nuldoc-src/generators/post.ts b/services/nuldoc/nuldoc-src/generators/post.ts deleted file mode 100644 index 87205624..00000000 --- a/services/nuldoc/nuldoc-src/generators/post.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { join } from "@std/path"; -import PostPage from "../pages/PostPage.ts"; -import { Config } from "../config.ts"; -import { Document } from "../markdown/document.ts"; -import { Page } from "../page.ts"; -import { Date, Revision } from "../revision.ts"; - -export interface PostPage extends Page { - title: string; - description: string; - tags: string[]; - revisions: Revision[]; - published: Date; - updated: Date; - uuid: string; - sourceFilePath: string; -} - -export function getPostPublishedDate(page: { revisions: Revision[] }): Date { - for (const rev of page.revisions) { - if (!rev.isInternal) { - return rev.date; - } - } - return page.revisions[0].date; -} - -export function getPostUpdatedDate(page: { revisions: Revision[] }): Date { - return page.revisions[page.revisions.length - 1].date; -} - -export function postHasAnyUpdates(page: { revisions: Revision[] }): boolean { - return 2 <= page.revisions.filter((rev) => !rev.isInternal).length; -} - -export async function generatePostPage( - doc: Document, - config: Config, -): Promise<PostPage> { - const html = await PostPage(doc, config); - - const cwd = Deno.cwd(); - const contentDir = join(cwd, config.locations.contentDir); - const destFilePath = join( - doc.sourceFilePath.replace(contentDir, "").replace(".md", ""), - "index.html", - ); - return { - root: html, - renderer: "html", - site: "blog", - destFilePath: destFilePath, - href: destFilePath.replace("index.html", ""), - title: doc.title, - description: doc.description, - tags: doc.tags, - revisions: doc.revisions, - published: getPostPublishedDate(doc), - updated: getPostUpdatedDate(doc), - uuid: doc.uuid, - sourceFilePath: doc.sourceFilePath, - }; -} diff --git a/services/nuldoc/nuldoc-src/generators/post_list.ts b/services/nuldoc/nuldoc-src/generators/post_list.ts deleted file mode 100644 index 3be4ec05..00000000 --- a/services/nuldoc/nuldoc-src/generators/post_list.ts +++ /dev/null @@ -1,56 +0,0 @@ -import PostListPage from "../pages/PostListPage.ts"; -import { Config } from "../config.ts"; -import { Page } from "../page.ts"; -import { PostPage } from "./post.ts"; - -export type PostListPage = Page; - -export async function generatePostListPages( - posts: PostPage[], - config: Config, -): Promise<PostListPage[]> { - const postsPerPage = config.sites.blog.postsPerPage; - const totalPages = Math.ceil(posts.length / postsPerPage); - const pages: PostListPage[] = []; - - for (let pageIndex = 0; pageIndex < totalPages; pageIndex++) { - const pagePosts = posts.slice( - pageIndex * postsPerPage, - (pageIndex + 1) * postsPerPage, - ); - - const page = await generatePostListPage( - pagePosts, - config, - pageIndex + 1, - totalPages, - ); - - pages.push(page); - } - - return pages; -} - -async function generatePostListPage( - posts: PostPage[], - config: Config, - currentPage: number, - totalPages: number, -): Promise<PostListPage> { - const html = await PostListPage(posts, config, currentPage, totalPages); - - const destFilePath = currentPage === 1 - ? "/posts/index.html" - : `/posts/${currentPage}/index.html`; - - const href = currentPage === 1 ? "/posts/" : `/posts/${currentPage}/`; - - return { - root: html, - renderer: "html", - site: "blog", - destFilePath, - href, - }; -} diff --git a/services/nuldoc/nuldoc-src/generators/slide.ts b/services/nuldoc/nuldoc-src/generators/slide.ts deleted file mode 100644 index c13f6960..00000000 --- a/services/nuldoc/nuldoc-src/generators/slide.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { join } from "@std/path"; -import SlidePage from "../pages/SlidePage.ts"; -import { Config } from "../config.ts"; -import { Page } from "../page.ts"; -import { Date, Revision } from "../revision.ts"; -import { Slide } from "../slide/slide.ts"; -import { getPostPublishedDate, getPostUpdatedDate } from "./post.ts"; - -export interface SlidePage extends Page { - title: string; - description: string; - event: string; - talkType: string; - slideLink: string; - tags: string[]; - revisions: Revision[]; - published: Date; - updated: Date; - uuid: string; -} - -export async function generateSlidePage( - slide: Slide, - config: Config, -): Promise<SlidePage> { - const html = await SlidePage(slide, config); - - const cwd = Deno.cwd(); - const contentDir = join(cwd, config.locations.contentDir); - const destFilePath = join( - slide.sourceFilePath.replace(contentDir, "").replace(".toml", ""), - "index.html", - ); - return { - root: html, - renderer: "html", - site: "slides", - destFilePath: destFilePath, - href: destFilePath.replace("index.html", ""), - title: slide.title, - description: `${slide.event} (${slide.talkType})`, - event: slide.event, - talkType: slide.talkType, - slideLink: slide.slideLink, - tags: slide.tags, - revisions: slide.revisions, - published: getPostPublishedDate(slide), - updated: getPostUpdatedDate(slide), - uuid: slide.uuid, - }; -} diff --git a/services/nuldoc/nuldoc-src/generators/slide_list.ts b/services/nuldoc/nuldoc-src/generators/slide_list.ts deleted file mode 100644 index b65c9db5..00000000 --- a/services/nuldoc/nuldoc-src/generators/slide_list.ts +++ /dev/null @@ -1,21 +0,0 @@ -import SlideListPage from "../pages/SlideListPage.ts"; -import { Config } from "../config.ts"; -import { Page } from "../page.ts"; -import { SlidePage } from "./slide.ts"; - -export type SlideListPage = Page; - -export async function generateSlideListPage( - slides: SlidePage[], - config: Config, -): Promise<SlideListPage> { - const html = await SlideListPage(slides, config); - - return { - root: html, - renderer: "html", - site: "slides", - destFilePath: "/slides/index.html", - href: "/slides/", - }; -} diff --git a/services/nuldoc/nuldoc-src/generators/tag.ts b/services/nuldoc/nuldoc-src/generators/tag.ts deleted file mode 100644 index efe2da54..00000000 --- a/services/nuldoc/nuldoc-src/generators/tag.ts +++ /dev/null @@ -1,32 +0,0 @@ -import TagPage from "../pages/TagPage.ts"; -import { Config, getTagLabel } from "../config.ts"; -import { Page } from "../page.ts"; -import { TaggedPage } from "./tagged_page.ts"; - -export interface TagPage extends Page { - tagSlug: string; - tagLabel: string; - numOfPosts: number; - numOfSlides: number; -} - -export async function generateTagPage( - tagSlug: string, - pages: TaggedPage[], - site: "blog" | "slides", - config: Config, -): Promise<TagPage> { - const html = await TagPage(tagSlug, pages, site, config); - - return { - root: html, - renderer: "html", - site, - destFilePath: `/tags/${tagSlug}/index.html`, - href: `/tags/${tagSlug}/`, - tagSlug: tagSlug, - tagLabel: getTagLabel(config, tagSlug), - numOfPosts: pages.filter((p) => !("event" in p)).length, - numOfSlides: pages.filter((p) => "event" in p).length, - }; -} diff --git a/services/nuldoc/nuldoc-src/generators/tag_list.ts b/services/nuldoc/nuldoc-src/generators/tag_list.ts deleted file mode 100644 index 96faa663..00000000 --- a/services/nuldoc/nuldoc-src/generators/tag_list.ts +++ /dev/null @@ -1,22 +0,0 @@ -import TagListPage from "../pages/TagListPage.ts"; -import { Config } from "../config.ts"; -import { Page } from "../page.ts"; -import { TagPage } from "./tag.ts"; - -export type TagListPage = Page; - -export async function generateTagListPage( - tags: TagPage[], - site: "blog" | "slides", - config: Config, -): Promise<TagListPage> { - const html = await TagListPage(tags, site, config); - - return { - root: html, - renderer: "html", - site, - destFilePath: "/tags/index.html", - href: "/tags/", - }; -} diff --git a/services/nuldoc/nuldoc-src/generators/tagged_page.ts b/services/nuldoc/nuldoc-src/generators/tagged_page.ts deleted file mode 100644 index 23de8cb4..00000000 --- a/services/nuldoc/nuldoc-src/generators/tagged_page.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PostPage } from "./post.ts"; -import { SlidePage } from "./slide.ts"; - -export type TaggedPage = PostPage | SlidePage; diff --git a/services/nuldoc/nuldoc-src/main.ts b/services/nuldoc/nuldoc-src/main.ts deleted file mode 100644 index af6acc2e..00000000 --- a/services/nuldoc/nuldoc-src/main.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { runBuildCommand } from "./commands/build.ts"; -import { runNewCommand } from "./commands/new.ts"; -import { runServeCommand } from "./commands/serve.ts"; -import { getDefaultConfigPath, loadConfig } from "./config.ts"; - -const config = await loadConfig(getDefaultConfigPath()); - -if (import.meta.main) { - const command = Deno.args[0] ?? "build"; - if (command === "build") { - await runBuildCommand(config); - } else if (command === "new") { - runNewCommand(config); - } else if (command === "serve") { - runServeCommand(config); - } else { - console.error(`Unknown command: ${command}`); - } -} diff --git a/services/nuldoc/nuldoc-src/markdown/document.ts b/services/nuldoc/nuldoc-src/markdown/document.ts deleted file mode 100644 index 1aee87b9..00000000 --- a/services/nuldoc/nuldoc-src/markdown/document.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { Root as MdastRoot } from "mdast"; -import { join } from "@std/path"; -import { z } from "zod/mod.ts"; -import { Config } from "../config.ts"; -import { Element } from "../dom.ts"; -import { Revision, stringToDate } from "../revision.ts"; -import { mdast2ndoc } from "./mdast2ndoc.ts"; - -export const PostMetadataSchema = z.object({ - article: z.object({ - uuid: z.string(), - title: z.string(), - description: z.string(), - tags: z.array(z.string()), - toc: z.boolean().optional(), - revisions: z.array(z.object({ - date: z.string(), - remark: z.string(), - isInternal: z.boolean().optional(), - })), - }), -}); - -export type PostMetadata = z.infer<typeof PostMetadataSchema>; - -export type TocEntry = { - id: string; - text: string; - level: number; - children: TocEntry[]; -}; - -export type TocRoot = { - entries: TocEntry[]; -}; - -export type Document = { - root: Element; - sourceFilePath: string; - uuid: string; - link: string; - title: string; - description: string; - tags: string[]; - revisions: Revision[]; - toc?: TocRoot; - isTocEnabled: boolean; -}; - -export function createNewDocumentFromMdast( - root: MdastRoot, - meta: PostMetadata, - sourceFilePath: string, - config: Config, -): Document { - const cwd = Deno.cwd(); - const contentDir = join(cwd, config.locations.contentDir); - const link = sourceFilePath.replace(contentDir, "").replace(".xml", "/"); - return { - root: mdast2ndoc(root), - sourceFilePath, - uuid: meta.article.uuid, - link: link, - title: meta.article.title, - description: meta.article.description, - tags: meta.article.tags, - revisions: meta.article.revisions.map((r, i) => ({ - number: i, - date: stringToDate(r.date), - remark: r.remark, - isInternal: !!r.isInternal, - })), - isTocEnabled: meta.article.toc !== false, - }; -} diff --git a/services/nuldoc/nuldoc-src/markdown/mdast2ndoc.ts b/services/nuldoc/nuldoc-src/markdown/mdast2ndoc.ts deleted file mode 100644 index 626f1191..00000000 --- a/services/nuldoc/nuldoc-src/markdown/mdast2ndoc.ts +++ /dev/null @@ -1,589 +0,0 @@ -import type { - Blockquote, - Code, - Definition, - Delete, - Emphasis, - FootnoteDefinition, - FootnoteReference, - Heading, - Html, - Image, - InlineCode, - Link, - List, - ListItem, - Paragraph, - PhrasingContent, - Root, - RootContent, - Strong, - Table, - TableCell, - TableRow, - Text as MdastText, - ThematicBreak, -} from "mdast"; -import type { - ContainerDirective, - LeafDirective, - TextDirective, -} from "mdast-util-directive"; -import { - a, - article, - div, - elem, - Element, - img, - li, - Node, - ol, - p, - rawHTML, - section, - span, - text, - ul, -} from "../dom.ts"; - -type DirectiveNode = ContainerDirective | LeafDirective | TextDirective; - -function isDirective(node: RootContent): node is DirectiveNode { - return ( - node.type === "containerDirective" || - node.type === "leafDirective" || - node.type === "textDirective" - ); -} - -// Extract section ID and attributes from heading if present -// Supports syntax like {#id} or {#id attr="value"} -function extractSectionId( - node: Heading, -): { - id: string | null; - attributes: Record<string, string>; - children: Heading["children"]; -} { - if (node.children.length === 0) { - return { id: null, attributes: {}, children: node.children }; - } - - const lastChild = node.children[node.children.length - 1]; - if (lastChild && lastChild.type === "text") { - // Match {#id ...} or {#id attr="value" ...} - const match = lastChild.value.match(/\s*\{#([^\s}]+)([^}]*)\}\s*$/); - if (match) { - const id = match[1]; - const attrString = match[2].trim(); - const attributes: Record<string, string> = {}; - - // Parse attributes like toc="false" (supports smart quotes too) - // U+0022 = ", U+201C = ", U+201D = " - const attrRegex = - /(\w+)=["\u201c\u201d]([^"\u201c\u201d]*)["\u201c\u201d]/g; - let attrMatch; - while ((attrMatch = attrRegex.exec(attrString)) !== null) { - attributes[attrMatch[1]] = attrMatch[2]; - } - - const newValue = lastChild.value.replace(/\s*\{#[^}]+\}\s*$/, ""); - if (newValue === "") { - return { id, attributes, children: node.children.slice(0, -1) }; - } else { - const newChildren = [...node.children]; - newChildren[newChildren.length - 1] = { ...lastChild, value: newValue }; - return { id, attributes, children: newChildren }; - } - } - } - - return { id: null, attributes: {}, children: node.children }; -} - -function processBlock(node: RootContent): Element | Element[] | null { - switch (node.type) { - case "heading": - // Headings are handled specially in mdast2ndoc - return null; - case "paragraph": - return processParagraph(node); - case "thematicBreak": - return processThematicBreak(node); - case "blockquote": - return processBlockquote(node); - case "code": - return processCode(node); - case "list": - return processList(node); - case "table": - return processTable(node); - case "html": - return processHtmlBlock(node); - case "definition": - return processDefinition(node); - case "footnoteDefinition": - return processFootnoteDefinition(node); - default: - if (isDirective(node)) { - return processDirective(node); - } - return null; - } -} - -function processParagraph(node: Paragraph): Element { - return p({}, ...node.children.map(processInline)); -} - -function processThematicBreak(_node: ThematicBreak): Element { - return elem("hr", {}); -} - -function processBlockquote(node: Blockquote): Element { - const children: Node[] = []; - for (const child of node.children) { - const result = processBlock(child); - if (result) { - if (Array.isArray(result)) { - children.push(...result); - } else { - children.push(result); - } - } - } - return elem("blockquote", {}, ...children); -} - -function processCode(node: Code): Element { - const attributes: Record<string, string> = {}; - - if (node.lang) { - attributes.language = node.lang; - } - - // Parse meta string for filename and numbered attributes - if (node.meta) { - const filenameMatch = node.meta.match(/filename="([^"]+)"/); - if (filenameMatch) { - attributes.filename = filenameMatch[1]; - } - - if (node.meta.includes("numbered")) { - attributes.numbered = "true"; - } - } - - return elem("codeblock", attributes, text(node.value)); -} - -function processList(node: List): Element { - const attributes: Record<string, string> = {}; - attributes.__tight = node.spread === false ? "true" : "false"; - - const isTaskList = node.children.some( - (item) => item.checked !== null && item.checked !== undefined, - ); - - if (isTaskList) { - attributes.type = "task"; - } - - if (node.ordered && node.start !== null && node.start !== 1) { - attributes.start = node.start!.toString(); - } - - const children = node.children.map((item) => - processListItem(item, isTaskList) - ); - - return node.ordered - ? ol(attributes, ...children) - : ul(attributes, ...children); -} - -function processListItem(node: ListItem, isTaskList: boolean): Element { - const attributes: Record<string, string> = {}; - - if (isTaskList) { - attributes.checked = node.checked ? "true" : "false"; - } - - const children: Node[] = []; - for (const child of node.children) { - const result = processBlock(child); - if (result) { - if (Array.isArray(result)) { - children.push(...result); - } else { - children.push(result); - } - } - } - - return li(attributes, ...children); -} - -function processTable(node: Table): Element { - const tableElement = elem("table", {}); - const headerRows: Element[] = []; - const bodyRows: Element[] = []; - - node.children.forEach((row, rowIndex) => { - const rowElement = processTableRow(row, rowIndex === 0, node.align); - if (rowIndex === 0) { - headerRows.push(rowElement); - } else { - bodyRows.push(rowElement); - } - }); - - if (headerRows.length > 0) { - tableElement.children.push(elem("thead", undefined, ...headerRows)); - } - - if (bodyRows.length > 0) { - tableElement.children.push(elem("tbody", undefined, ...bodyRows)); - } - - return tableElement; -} - -function processTableRow( - node: TableRow, - isHeader: boolean, - alignments: (string | null)[] | null | undefined, -): Element { - const cells = node.children.map((cell, index) => - processTableCell(cell, isHeader, alignments?.[index]) - ); - return elem("tr", {}, ...cells); -} - -function processTableCell( - node: TableCell, - isHeader: boolean, - alignment: string | null | undefined, -): Element { - const attributes: Record<string, string> = {}; - if (alignment && alignment !== "none") { - attributes.align = alignment; - } - - return elem( - isHeader ? "th" : "td", - attributes, - ...node.children.map(processInline), - ); -} - -function processHtmlBlock(node: Html): Element { - return div({ class: "raw-html" }, rawHTML(node.value)); -} - -function processDefinition(_node: Definition): null { - // Link definitions are handled elsewhere - return null; -} - -function processFootnoteDefinition(node: FootnoteDefinition): Element { - const children: Node[] = []; - for (const child of node.children) { - const result = processBlock(child); - if (result) { - if (Array.isArray(result)) { - children.push(...result); - } else { - children.push(result); - } - } - } - return elem("footnote", { id: node.identifier }, ...children); -} - -function processDirective(node: DirectiveNode): Element | null { - const name = node.name; - - if (name === "note" || name === "edit") { - const attributes: Record<string, string> = {}; - - // Copy directive attributes - if (node.attributes) { - for (const [key, value] of Object.entries(node.attributes)) { - if (value !== undefined && value !== null) { - attributes[key] = String(value); - } - } - } - - const children: Node[] = []; - if ("children" in node && node.children) { - for (const child of node.children as RootContent[]) { - const result = processBlock(child); - if (result) { - if (Array.isArray(result)) { - children.push(...result); - } else { - children.push(result); - } - } - } - } - - return elem("note", attributes, ...children); - } - - // For other directives, treat as div - const children: Node[] = []; - if ("children" in node && node.children) { - for (const child of node.children as RootContent[]) { - const result = processBlock(child); - if (result) { - if (Array.isArray(result)) { - children.push(...result); - } else { - children.push(result); - } - } - } - } - - return div( - node.attributes as Record<string, string> || {}, - ...children, - ); -} - -function processInline(node: PhrasingContent): Node { - switch (node.type) { - case "text": - return processText(node); - case "emphasis": - return processEmphasis(node); - case "strong": - return processStrong(node); - case "inlineCode": - return processInlineCode(node); - case "link": - return processLink(node); - case "image": - return processImage(node); - case "delete": - return processDelete(node); - case "break": - return elem("br"); - case "html": - return rawHTML(node.value); - case "footnoteReference": - return processFootnoteReference(node); - default: - // Handle any unexpected node types - if ("value" in node) { - return text(String(node.value)); - } - if ("children" in node && Array.isArray(node.children)) { - return span( - {}, - ...node.children.map((c: PhrasingContent) => processInline(c)), - ); - } - return text(""); - } -} - -function processText(node: MdastText): Node { - return text(node.value); -} - -function processEmphasis(node: Emphasis): Element { - return elem("em", {}, ...node.children.map(processInline)); -} - -function processStrong(node: Strong): Element { - return elem("strong", {}, ...node.children.map(processInline)); -} - -function processInlineCode(node: InlineCode): Element { - return elem("code", {}, text(node.value)); -} - -function processLink(node: Link): Element { - const attributes: Record<string, string> = {}; - if (node.url) { - attributes.href = node.url; - } - if (node.title) { - attributes.title = node.title; - } - // Detect autolinks (URL equals link text) - const isAutolink = node.children.length === 1 && - node.children[0].type === "text" && - node.children[0].value === node.url; - if (isAutolink) { - attributes.class = "url"; - } - return a(attributes, ...node.children.map(processInline)); -} - -function processImage(node: Image): Element { - const attributes: Record<string, string> = {}; - if (node.url) { - attributes.src = node.url; - } - if (node.alt) { - attributes.alt = node.alt; - } - if (node.title) { - attributes.title = node.title; - } - return img(attributes); -} - -function processDelete(node: Delete): Element { - return elem("del", {}, ...node.children.map(processInline)); -} - -function processFootnoteReference(node: FootnoteReference): Element { - return elem("footnoteref", { reference: node.identifier }); -} - -// Build hierarchical section structure from flat mdast -// This mimics Djot's section structure where headings create nested sections -export function mdast2ndoc(root: Root): Element { - const footnotes: Element[] = []; - const nonFootnoteChildren: RootContent[] = []; - - // Separate footnotes from other content - for (const child of root.children) { - if (child.type === "footnoteDefinition") { - const footnote = processFootnoteDefinition(child); - footnotes.push(footnote); - } else { - nonFootnoteChildren.push(child); - } - } - - // Build hierarchical sections - const articleContent = buildSectionHierarchy(nonFootnoteChildren); - - // Add footnotes section if any exist - if (footnotes.length > 0) { - const footnoteSection = section( - { class: "footnotes" }, - ...footnotes, - ); - articleContent.push(footnoteSection); - } - - return elem( - "__root__", - undefined, - article(undefined, ...articleContent), - ); -} - -type SectionInfo = { - id: string | null; - attributes: Record<string, string>; - level: number; - heading: Element; - children: Node[]; -}; - -function buildSectionHierarchy(nodes: RootContent[]): Node[] { - // Group nodes into sections based on headings - // Each heading starts a new section at its level - const result: Node[] = []; - const sectionStack: SectionInfo[] = []; - - for (const node of nodes) { - if (node.type === "heading") { - const level = node.depth; - const { id, attributes, children } = extractSectionId(node); - - // Create heading element - const headingElement = elem( - "h", - {}, - ...children.map(processInline), - ); - - // Close sections that are at same or deeper level - while ( - sectionStack.length > 0 && - sectionStack[sectionStack.length - 1].level >= level - ) { - const closedSection = sectionStack.pop()!; - const sectionElement = createSectionElement(closedSection); - - if (sectionStack.length > 0) { - // Add to parent section - sectionStack[sectionStack.length - 1].children.push(sectionElement); - } else { - // Add to result - result.push(sectionElement); - } - } - - // Start new section - const newSection: SectionInfo = { - id, - attributes, - level, - heading: headingElement, - children: [], - }; - sectionStack.push(newSection); - } else { - // Non-heading content - const processed = processBlock(node); - if (processed) { - if (sectionStack.length > 0) { - // Add to current section - if (Array.isArray(processed)) { - sectionStack[sectionStack.length - 1].children.push(...processed); - } else { - sectionStack[sectionStack.length - 1].children.push(processed); - } - } else { - // Content before any heading - if (Array.isArray(processed)) { - result.push(...processed); - } else { - result.push(processed); - } - } - } - } - } - - // Close remaining sections - while (sectionStack.length > 0) { - const closedSection = sectionStack.pop()!; - const sectionElement = createSectionElement(closedSection); - - if (sectionStack.length > 0) { - // Add to parent section - sectionStack[sectionStack.length - 1].children.push(sectionElement); - } else { - // Add to result - result.push(sectionElement); - } - } - - return result; -} - -function createSectionElement(sectionInfo: SectionInfo): Element { - const attributes: Record<string, string> = { ...sectionInfo.attributes }; - if (sectionInfo.id) { - attributes.id = sectionInfo.id; - } - - return section( - attributes, - sectionInfo.heading, - ...sectionInfo.children, - ); -} diff --git a/services/nuldoc/nuldoc-src/markdown/parse.ts b/services/nuldoc/nuldoc-src/markdown/parse.ts deleted file mode 100644 index c0875a25..00000000 --- a/services/nuldoc/nuldoc-src/markdown/parse.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { Root as MdastRoot } from "mdast"; -import { unified } from "unified"; -import remarkParse from "remark-parse"; -import remarkGfm from "remark-gfm"; -import remarkDirective from "remark-directive"; -import remarkSmartypants from "remark-smartypants"; -import { parse as parseToml } from "@std/toml"; -import { Config } from "../config.ts"; -import { - createNewDocumentFromMdast, - Document, - PostMetadata, - PostMetadataSchema, -} from "./document.ts"; -import toHtml from "./to_html.ts"; - -export async function parseMarkdownFile( - filePath: string, - config: Config, -): Promise<Document> { - try { - const fileContent = await Deno.readTextFile(filePath); - const [, frontmatter, ...rest] = fileContent.split(/^---$/m); - const meta = parseMetadata(frontmatter); - const content = rest.join("---"); - - const processor = unified() - .use(remarkParse) - .use(remarkGfm) - .use(remarkDirective) - .use(remarkSmartypants); - - const root = await processor.run(processor.parse(content)) as MdastRoot; - - const doc = createNewDocumentFromMdast(root, meta, filePath, config); - return await toHtml(doc); - } catch (e) { - if (e instanceof Error) { - e.message = `${e.message} in ${filePath}`; - } - throw e; - } -} - -function parseMetadata(s: string): PostMetadata { - return PostMetadataSchema.parse(parseToml(s)); -} diff --git a/services/nuldoc/nuldoc-src/markdown/to_html.ts b/services/nuldoc/nuldoc-src/markdown/to_html.ts deleted file mode 100644 index 8758b0d3..00000000 --- a/services/nuldoc/nuldoc-src/markdown/to_html.ts +++ /dev/null @@ -1,496 +0,0 @@ -import { BundledLanguage, bundledLanguages, codeToHtml } from "shiki"; -import { Document, TocEntry } from "./document.ts"; -import { NuldocError } from "../errors.ts"; -import { - a, - addClass, - div, - Element, - forEachChild, - forEachChildRecursively, - forEachChildRecursivelyAsync, - forEachElementOfType, - innerText, - Node, - processTextNodesInElement, - RawHTML, - rawHTML, - Text, - text, -} from "../dom.ts"; - -export default async function toHtml(doc: Document): Promise<Document> { - mergeConsecutiveTextNodes(doc); - removeUnnecessaryTextNode(doc); - transformLinkLikeToAnchorElement(doc); - transformSectionIdAttribute(doc); - setSectionTitleAnchor(doc); - transformSectionTitleElement(doc); - transformNoteElement(doc); - addAttributesToExternalLinkElement(doc); - traverseFootnotes(doc); - removeUnnecessaryParagraphNode(doc); - await transformAndHighlightCodeBlockElement(doc); - mergeConsecutiveTextNodes(doc); - generateTableOfContents(doc); - removeTocAttributes(doc); - return doc; -} - -function mergeConsecutiveTextNodes(doc: Document) { - forEachChildRecursively(doc.root, (n) => { - if (n.kind !== "element") { - return; - } - - const newChildren: Node[] = []; - let currentTextContent = ""; - - for (const child of n.children) { - if (child.kind === "text") { - currentTextContent += child.content; - } else { - if (currentTextContent !== "") { - newChildren.push(text(currentTextContent)); - currentTextContent = ""; - } - newChildren.push(child); - } - } - - if (currentTextContent !== "") { - newChildren.push(text(currentTextContent)); - } - - n.children = newChildren; - }); -} - -function removeUnnecessaryTextNode(doc: Document) { - forEachChildRecursively(doc.root, (n) => { - if (n.kind !== "element") { - return; - } - - let changed = true; - while (changed) { - changed = false; - if (n.children.length === 0) { - break; - } - const firstChild = n.children[0]; - if (firstChild.kind === "text" && firstChild.content.trim() === "") { - n.children.shift(); - changed = true; - } - if (n.children.length === 0) { - break; - } - const lastChild = n.children[n.children.length - 1]; - if (lastChild.kind === "text" && lastChild.content.trim() === "") { - n.children.pop(); - changed = true; - } - } - }); -} - -function transformLinkLikeToAnchorElement(doc: Document) { - forEachChildRecursively(doc.root, (n) => { - if ( - n.kind !== "element" || n.name === "a" || n.name === "code" || - n.name === "codeblock" - ) { - return; - } - - processTextNodesInElement(n, (content) => { - const nodes: Node[] = []; - let restContent = content; - while (restContent !== "") { - const match = /^(.*?)(https?:\/\/[^ \n]+)(.*)$/s.exec(restContent); - if (!match) { - nodes.push(text(restContent)); - restContent = ""; - break; - } - const [_, prefix, url, suffix] = match; - nodes.push(text(prefix)); - nodes.push(a({ href: url, class: "url" }, text(url))); - restContent = suffix; - } - return nodes; - }); - }); -} - -function transformSectionIdAttribute(doc: Document) { - const sectionStack: string[] = []; - const usedIds = new Set<string>(); - - const processNode = (n: Node) => { - if (n.kind !== "element") { - return; - } - - if (n.name === "section") { - const idAttr = n.attributes.id; - if (!idAttr) { - return; - } - - let newId: string; - if (sectionStack.length === 0) { - newId = `section--${idAttr}`; - } else { - newId = `section--${sectionStack.join("--")}--${idAttr}`; - } - - if (usedIds.has(newId)) { - throw new NuldocError( - `[nuldoc.tohtml] Duplicate section ID: ${newId}`, - ); - } - - usedIds.add(newId); - n.attributes.id = newId; - sectionStack.push(idAttr); - - forEachChild(n, processNode); - - sectionStack.pop(); - } else { - forEachChild(n, processNode); - } - }; - - forEachChild(doc.root, processNode); -} - -function setSectionTitleAnchor(doc: Document) { - const sectionStack: Element[] = []; - const g = (c: Node) => { - if (c.kind !== "element") { - return; - } - - if (c.name === "section") { - sectionStack.push(c); - } - forEachChild(c, g); - if (c.name === "section") { - sectionStack.pop(); - } - if (c.name === "h") { - const currentSection = sectionStack[sectionStack.length - 1]; - if (!currentSection) { - throw new NuldocError( - "[nuldoc.tohtml] <h> element must be inside <section>", - ); - } - const sectionId = currentSection.attributes.id; - const aElement = a(undefined, ...c.children); - aElement.attributes.href = `#${sectionId}`; - c.children = [aElement]; - } - }; - forEachChild(doc.root, g); -} - -function transformSectionTitleElement(doc: Document) { - let sectionLevel = 1; - const g = (c: Node) => { - if (c.kind !== "element") { - return; - } - - if (c.name === "section") { - sectionLevel += 1; - c.attributes.__sectionLevel = sectionLevel.toString(); - } - forEachChild(c, g); - if (c.name === "section") { - sectionLevel -= 1; - } - if (c.name === "h") { - c.name = `h${sectionLevel}`; - } - }; - forEachChild(doc.root, g); -} - -function transformNoteElement(doc: Document) { - forEachElementOfType(doc.root, "note", (n) => { - const editatAttr = n.attributes?.editat; - const operationAttr = n.attributes?.operation; - const isEditBlock = editatAttr && operationAttr; - - const labelElement = div( - { class: "admonition-label" }, - text(isEditBlock ? `${editatAttr} ${operationAttr}` : "NOTE"), - ); - const contentElement = div( - { class: "admonition-content" }, - ...n.children, - ); - n.name = "div"; - addClass(n, "admonition"); - n.children = [labelElement, contentElement]; - }); -} - -function addAttributesToExternalLinkElement(doc: Document) { - forEachElementOfType(doc.root, "a", (n) => { - const href = n.attributes.href ?? ""; - if (!href.startsWith("http")) { - return; - } - n.attributes.target = "_blank"; - n.attributes.rel = "noreferrer"; - }); -} - -function traverseFootnotes(doc: Document) { - let footnoteCounter = 0; - const footnoteMap = new Map<string, number>(); - - forEachElementOfType(doc.root, "footnoteref", (n) => { - const reference = n.attributes.reference; - if (!reference) { - return; - } - - let footnoteNumber: number; - if (footnoteMap.has(reference)) { - footnoteNumber = footnoteMap.get(reference)!; - } else { - footnoteNumber = ++footnoteCounter; - footnoteMap.set(reference, footnoteNumber); - } - - n.name = "sup"; - delete n.attributes.reference; - n.attributes.class = "footnote"; - n.children = [ - a( - { - id: `footnoteref--${reference}`, - class: "footnote", - href: `#footnote--${reference}`, - }, - text(`[${footnoteNumber}]`), - ), - ]; - }); - - forEachElementOfType(doc.root, "footnote", (n) => { - const id = n.attributes.id; - if (!id || !footnoteMap.has(id)) { - n.name = "span"; - n.children = []; - return; - } - - const footnoteNumber = footnoteMap.get(id)!; - - n.name = "div"; - delete n.attributes.id; - n.attributes.class = "footnote"; - n.attributes.id = `footnote--${id}`; - - n.children = [ - a( - { href: `#footnoteref--${id}` }, - text(`${footnoteNumber}. `), - ), - ...n.children, - ]; - }); -} - -function removeUnnecessaryParagraphNode(doc: Document) { - forEachChildRecursively(doc.root, (n) => { - if (n.kind !== "element" || (n.name !== "ul" && n.name !== "ol")) { - return; - } - - const isTight = n.attributes.__tight === "true"; - if (!isTight) { - return; - } - - for (const child of n.children) { - if (child.kind !== "element" || child.name !== "li") { - continue; - } - const newGrandChildren: Node[] = []; - for (const grandChild of child.children) { - if (grandChild.kind === "element" && grandChild.name === "p") { - newGrandChildren.push(...grandChild.children); - } else { - newGrandChildren.push(grandChild); - } - } - child.children = newGrandChildren; - } - }); -} - -async function transformAndHighlightCodeBlockElement(doc: Document) { - await forEachChildRecursivelyAsync(doc.root, async (n) => { - if (n.kind !== "element" || n.name !== "codeblock") { - return; - } - - const language = n.attributes.language || "text"; - const filename = n.attributes.filename; - const numbered = n.attributes.numbered; - const sourceCodeNode = n.children[0] as Text | RawHTML; - const sourceCode = sourceCodeNode.kind === "text" - ? sourceCodeNode.content.trimEnd() - : sourceCodeNode.html.trimEnd(); - - const highlighted = await codeToHtml(sourceCode, { - lang: language in bundledLanguages ? language as BundledLanguage : "text", - theme: "github-light", - colorReplacements: { - "#fff": "#f5f5f5", - }, - }); - - n.name = "div"; - n.attributes.class = "codeblock"; - delete n.attributes.language; - - if (numbered === "true") { - delete n.attributes.numbered; - addClass(n, "numbered"); - } - if (filename) { - delete n.attributes.filename; - - n.children = [ - div({ class: "filename" }, text(filename)), - rawHTML(highlighted), - ]; - } else { - if (sourceCodeNode.kind === "text") { - n.children[0] = rawHTML(highlighted); - } else { - sourceCodeNode.html = highlighted; - } - } - }); -} - -function generateTableOfContents(doc: Document) { - if (!doc.isTocEnabled) { - return; - } - const tocEntries: TocEntry[] = []; - const stack: TocEntry[] = []; - const excludedLevels: number[] = []; // Track levels to exclude - - const processNode = (node: Node) => { - if (node.kind !== "element") { - return; - } - - const match = node.name.match(/^h(\d+)$/); - if (match) { - const level = parseInt(match[1]); - - let parentSection: Element | null = null; - const findParentSection = (n: Node, target: Node): Element | null => { - if (n.kind !== "element") return null; - - for (const child of n.children) { - if (child === target && n.name === "section") { - return n; - } - const result = findParentSection(child, target); - if (result) return result; - } - return null; - }; - - parentSection = findParentSection(doc.root, node); - if (!parentSection) return; - - // Check if this section has toc=false attribute - const tocAttribute = parentSection.attributes.toc; - if (tocAttribute === "false") { - // Add this level to excluded levels and remove deeper levels - excludedLevels.length = 0; - excludedLevels.push(level); - return; - } - - // Check if this header should be excluded based on parent exclusion - const shouldExclude = excludedLevels.some((excludedLevel) => - level > excludedLevel - ); - if (shouldExclude) { - return; - } - - // Clean up excluded levels that are now at same or deeper level - while ( - excludedLevels.length > 0 && - excludedLevels[excludedLevels.length - 1] >= level - ) { - excludedLevels.pop(); - } - - const sectionId = parentSection.attributes.id; - if (!sectionId) return; - - let headingText = ""; - for (const child of node.children) { - if (child.kind === "element" && child.name === "a") { - headingText = innerText(child); - } - } - - const entry: TocEntry = { - id: sectionId, - text: headingText, - level: level, - children: [], - }; - - while (stack.length > 0 && stack[stack.length - 1].level >= level) { - stack.pop(); - } - - if (stack.length === 0) { - tocEntries.push(entry); - } else { - stack[stack.length - 1].children.push(entry); - } - - stack.push(entry); - } - - forEachChild(node, processNode); - }; - - forEachChild(doc.root, processNode); - - // Don't generate TOC if there's only one top-level section with no children - if (tocEntries.length === 1 && tocEntries[0].children.length === 0) { - return; - } - - doc.toc = { - entries: tocEntries, - }; -} - -function removeTocAttributes(doc: Document) { - forEachChildRecursively(doc.root, (node) => { - if (node.kind === "element" && node.name === "section") { - delete node.attributes.toc; - } - }); -} diff --git a/services/nuldoc/nuldoc-src/page.ts b/services/nuldoc/nuldoc-src/page.ts deleted file mode 100644 index 26cb4dee..00000000 --- a/services/nuldoc/nuldoc-src/page.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Element } from "./dom.ts"; -import { RendererType } from "./render.ts"; - -export interface Page { - root: Element; - renderer: RendererType; - site: "default" | "about" | "blog" | "slides"; - destFilePath: string; - href: string; -} diff --git a/services/nuldoc/nuldoc-src/pages/AboutPage.ts b/services/nuldoc/nuldoc-src/pages/AboutPage.ts deleted file mode 100644 index 5ae2ff52..00000000 --- a/services/nuldoc/nuldoc-src/pages/AboutPage.ts +++ /dev/null @@ -1,154 +0,0 @@ -import GlobalFooter from "../components/GlobalFooter.ts"; -import GlobalHeader from "../components/AboutGlobalHeader.ts"; -import PageLayout from "../components/PageLayout.ts"; -import StaticScript from "../components/StaticScript.ts"; -import { Config } from "../config.ts"; -import { dateToString } from "../revision.ts"; -import { getPostPublishedDate } from "../generators/post.ts"; -import { SlidePage } from "../generators/slide.ts"; -import { - a, - article, - div, - elem, - Element, - h1, - h2, - header, - img, - li, - p, - section, - ul, -} from "../dom.ts"; - -export default async function AboutPage( - slides: SlidePage[], - config: Config, -): Promise<Element> { - return await PageLayout({ - metaCopyrightYear: config.site.copyrightYear, - metaDescription: "このサイトの著者について", - metaTitle: `About|${config.sites.about.siteName}`, - site: "about", - config, - children: elem( - "body", - { class: "single" }, - GlobalHeader({ config }), - elem( - "main", - { class: "main" }, - article( - { class: "post-single" }, - header( - { class: "post-header" }, - h1({ class: "post-title" }, "nsfisis"), - div( - { class: "my-icon" }, - div( - { id: "myIcon" }, - img({ src: "/favicon.svg" }), - ), - await StaticScript({ - site: "about", - fileName: "/my-icon.js", - defer: "true", - config, - }), - ), - ), - div( - { class: "post-content" }, - section( - {}, - h2({}, "読み方"), - p( - {}, - "読み方は決めていません。音にする必要があるときは本名である「いまむら」をお使いください。", - ), - ), - section( - {}, - h2({}, "アカウント"), - ul( - {}, - li( - {}, - a( - { - href: "https://twitter.com/nsfisis", - target: "_blank", - rel: "noreferrer", - }, - "Twitter (現 𝕏): @nsfisis", - ), - ), - li( - {}, - a( - { - href: "https://github.com/nsfisis", - target: "_blank", - rel: "noreferrer", - }, - "GitHub: @nsfisis", - ), - ), - ), - ), - section( - {}, - h2({}, "仕事"), - ul( - {}, - li( - {}, - "2021-01~現在: ", - a( - { - href: "https://www.dgcircus.com/", - target: "_blank", - rel: "noreferrer", - }, - "デジタルサーカス株式会社", - ), - ), - ), - ), - section( - {}, - h2({}, "登壇"), - ul( - {}, - ...Array.from(slides) - .sort((s1, s2) => { - const ta = dateToString(getPostPublishedDate(s1)); - const tb = dateToString(getPostPublishedDate(s2)); - if (ta > tb) return -1; - if (ta < tb) return 1; - return 0; - }) - .map((slide) => - li( - {}, - a( - { - href: - `https://${config.sites.slides.fqdn}${slide.href}`, - }, - `${ - dateToString(getPostPublishedDate(slide)) - }: ${slide.event} (${slide.talkType})`, - ), - ) - ), - ), - ), - ), - ), - ), - GlobalFooter({ config }), - ), - }); -} diff --git a/services/nuldoc/nuldoc-src/pages/AtomPage.ts b/services/nuldoc/nuldoc-src/pages/AtomPage.ts deleted file mode 100644 index b39902ee..00000000 --- a/services/nuldoc/nuldoc-src/pages/AtomPage.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Feed } from "../generators/atom.ts"; -import { elem, Element, link } from "../dom.ts"; - -export default function AtomPage({ feed }: { feed: Feed }): Element { - return elem( - "feed", - { xmlns: "http://www.w3.org/2005/Atom" }, - elem("id", {}, feed.id), - elem("title", {}, feed.title), - link({ rel: "alternate", href: feed.linkToAlternate }), - link({ rel: "self", href: feed.linkToSelf }), - elem("author", {}, elem("name", {}, feed.author)), - elem("updated", {}, feed.updated), - ...feed.entries.map((entry) => - elem( - "entry", - {}, - elem("id", {}, entry.id), - link({ rel: "alternate", href: entry.linkToAlternate }), - elem("title", {}, entry.title), - elem("summary", {}, entry.summary), - elem("published", {}, entry.published), - elem("updated", {}, entry.updated), - ) - ), - ); -} diff --git a/services/nuldoc/nuldoc-src/pages/HomePage.ts b/services/nuldoc/nuldoc-src/pages/HomePage.ts deleted file mode 100644 index 6e984586..00000000 --- a/services/nuldoc/nuldoc-src/pages/HomePage.ts +++ /dev/null @@ -1,66 +0,0 @@ -import GlobalFooter from "../components/GlobalFooter.ts"; -import GlobalHeader from "../components/DefaultGlobalHeader.ts"; -import PageLayout from "../components/PageLayout.ts"; -import { Config } from "../config.ts"; -import { a, article, elem, Element, h2, header } from "../dom.ts"; - -export default async function HomePage(config: Config): Promise<Element> { - return await PageLayout({ - metaCopyrightYear: config.site.copyrightYear, - metaDescription: "nsfisis のサイト", - metaTitle: config.sites.default.siteName, - metaAtomFeedHref: `https://${config.sites.default.fqdn}/atom.xml`, - site: "default", - config, - children: elem( - "body", - { class: "single" }, - GlobalHeader({ config }), - elem( - "main", - { class: "main" }, - article( - { class: "post-single" }, - article( - { class: "post-entry" }, - a( - { href: `https://${config.sites.about.fqdn}/` }, - header( - { class: "entry-header" }, - h2({}, "About"), - ), - ), - ), - article( - { class: "post-entry" }, - a( - { href: `https://${config.sites.blog.fqdn}/posts/` }, - header({ class: "entry-header" }, h2({}, "Blog")), - ), - ), - article( - { class: "post-entry" }, - a( - { href: `https://${config.sites.slides.fqdn}/slides/` }, - header( - { class: "entry-header" }, - h2({}, "Slides"), - ), - ), - ), - article( - { class: "post-entry" }, - a( - { href: `https://repos.${config.sites.default.fqdn}/` }, - header( - { class: "entry-header" }, - h2({}, "Repositories"), - ), - ), - ), - ), - ), - GlobalFooter({ config }), - ), - }); -} diff --git a/services/nuldoc/nuldoc-src/pages/NotFoundPage.ts b/services/nuldoc/nuldoc-src/pages/NotFoundPage.ts deleted file mode 100644 index 62080665..00000000 --- a/services/nuldoc/nuldoc-src/pages/NotFoundPage.ts +++ /dev/null @@ -1,40 +0,0 @@ -import GlobalFooter from "../components/GlobalFooter.ts"; -import AboutGlobalHeader from "../components/AboutGlobalHeader.ts"; -import BlogGlobalHeader from "../components/BlogGlobalHeader.ts"; -import SlidesGlobalHeader from "../components/SlidesGlobalHeader.ts"; -import DefaultGlobalHeader from "../components/DefaultGlobalHeader.ts"; -import PageLayout from "../components/PageLayout.ts"; -import { Config } from "../config.ts"; -import { article, div, elem, Element } from "../dom.ts"; - -export default async function NotFoundPage( - site: "default" | "about" | "blog" | "slides", - config: Config, -): Promise<Element> { - const GlobalHeader = site === "about" - ? AboutGlobalHeader - : site === "blog" - ? BlogGlobalHeader - : site === "slides" - ? SlidesGlobalHeader - : DefaultGlobalHeader; - - return await PageLayout({ - metaCopyrightYear: config.site.copyrightYear, - metaDescription: "リクエストされたページが見つかりません", - metaTitle: `Page Not Found|${config.sites[site].siteName}`, - site, - config, - children: elem( - "body", - { class: "single" }, - GlobalHeader({ config }), - elem( - "main", - { class: "main" }, - article({}, div({ class: "not-found" }, "404")), - ), - GlobalFooter({ config }), - ), - }); -} diff --git a/services/nuldoc/nuldoc-src/pages/PostListPage.ts b/services/nuldoc/nuldoc-src/pages/PostListPage.ts deleted file mode 100644 index ef7bfc57..00000000 --- a/services/nuldoc/nuldoc-src/pages/PostListPage.ts +++ /dev/null @@ -1,48 +0,0 @@ -import GlobalFooter from "../components/GlobalFooter.ts"; -import GlobalHeader from "../components/BlogGlobalHeader.ts"; -import PageLayout from "../components/PageLayout.ts"; -import Pagination from "../components/Pagination.ts"; -import PostPageEntry from "../components/PostPageEntry.ts"; -import { Config } from "../config.ts"; -import { PostPage } from "../generators/post.ts"; -import { elem, Element, h1, header } from "../dom.ts"; - -export default async function PostListPage( - posts: PostPage[], - config: Config, - currentPage: number, - totalPages: number, -): Promise<Element> { - const pageTitle = "投稿一覧"; - - const pageInfoSuffix = ` (${currentPage}ページ目)`; - const metaTitle = - `${pageTitle}${pageInfoSuffix}|${config.sites.blog.siteName}`; - const metaDescription = `投稿した記事の一覧${pageInfoSuffix}`; - - return await PageLayout({ - metaCopyrightYear: config.site.copyrightYear, - metaDescription, - metaTitle, - metaAtomFeedHref: `https://${config.sites.blog.fqdn}/posts/atom.xml`, - site: "blog", - config, - children: elem( - "body", - { class: "list" }, - GlobalHeader({ config }), - elem( - "main", - { class: "main" }, - header( - { class: "page-header" }, - h1({}, pageTitle + pageInfoSuffix), - ), - Pagination({ currentPage, totalPages, basePath: "/posts/" }), - ...posts.map((post) => PostPageEntry({ post, config })), - Pagination({ currentPage, totalPages, basePath: "/posts/" }), - ), - GlobalFooter({ config }), - ), - }); -} diff --git a/services/nuldoc/nuldoc-src/pages/PostPage.ts b/services/nuldoc/nuldoc-src/pages/PostPage.ts deleted file mode 100644 index 20eec996..00000000 --- a/services/nuldoc/nuldoc-src/pages/PostPage.ts +++ /dev/null @@ -1,94 +0,0 @@ -import GlobalFooter from "../components/GlobalFooter.ts"; -import GlobalHeader from "../components/BlogGlobalHeader.ts"; -import PageLayout from "../components/PageLayout.ts"; -import TableOfContents from "../components/TableOfContents.ts"; -import { Config, getTagLabel } from "../config.ts"; -import { - a, - article, - div, - elem, - Element, - h1, - h2, - header, - li, - ol, - section, - ul, -} from "../dom.ts"; -import { Document } from "../markdown/document.ts"; -import { dateToString } from "../revision.ts"; -import { getPostPublishedDate } from "../generators/post.ts"; - -export default async function PostPage( - doc: Document, - config: Config, -): Promise<Element> { - return await PageLayout({ - metaCopyrightYear: getPostPublishedDate(doc).year, - metaDescription: doc.description, - metaKeywords: doc.tags.map((slug) => getTagLabel(config, slug)), - metaTitle: `${doc.title}|${config.sites.blog.siteName}`, - requiresSyntaxHighlight: true, - site: "blog", - config, - children: elem( - "body", - { class: "single" }, - GlobalHeader({ config }), - elem( - "main", - { class: "main" }, - article( - { class: "post-single" }, - header( - { class: "post-header" }, - h1({ class: "post-title" }, doc.title), - doc.tags.length !== 0 - ? ul( - { class: "post-tags" }, - ...doc.tags.map((slug) => - li( - { class: "tag" }, - a( - { class: "tag-inner", href: `/tags/${slug}/` }, - getTagLabel(config, slug), - ), - ) - ), - ) - : null, - ), - doc.toc && doc.toc.entries.length > 0 - ? TableOfContents({ toc: doc.toc }) - : null, - div( - { class: "post-content" }, - section( - { id: "changelog" }, - h2({}, a({ href: "#changelog" }, "更新履歴")), - ol( - {}, - ...doc.revisions.map((rev) => - li( - { class: "revision" }, - elem( - "time", - { datetime: dateToString(rev.date) }, - dateToString(rev.date), - ), - `: ${rev.remark}`, - ) - ), - ), - ), - // TODO: refactor - ...(doc.root.children[0] as Element).children, - ), - ), - ), - GlobalFooter({ config }), - ), - }); -} diff --git a/services/nuldoc/nuldoc-src/pages/SlideListPage.ts b/services/nuldoc/nuldoc-src/pages/SlideListPage.ts deleted file mode 100644 index f1b1a2a1..00000000 --- a/services/nuldoc/nuldoc-src/pages/SlideListPage.ts +++ /dev/null @@ -1,45 +0,0 @@ -import GlobalFooter from "../components/GlobalFooter.ts"; -import GlobalHeader from "../components/SlidesGlobalHeader.ts"; -import PageLayout from "../components/PageLayout.ts"; -import SlidePageEntry from "../components/SlidePageEntry.ts"; -import { Config } from "../config.ts"; -import { dateToString } from "../revision.ts"; -import { getPostPublishedDate } from "../generators/post.ts"; -import { SlidePage } from "../generators/slide.ts"; -import { elem, Element, h1, header } from "../dom.ts"; - -export default async function SlideListPage( - slides: SlidePage[], - config: Config, -): Promise<Element> { - const pageTitle = "スライド一覧"; - - return await PageLayout({ - metaCopyrightYear: config.site.copyrightYear, - metaDescription: "登壇したイベントで使用したスライドの一覧", - metaTitle: `${pageTitle}|${config.sites.slides.siteName}`, - metaAtomFeedHref: `https://${config.sites.slides.fqdn}/slides/atom.xml`, - site: "slides", - config, - children: elem( - "body", - { class: "list" }, - GlobalHeader({ config }), - elem( - "main", - { class: "main" }, - header({ class: "page-header" }, h1({}, pageTitle)), - ...Array.from(slides) - .sort((s1, s2) => { - const ta = dateToString(getPostPublishedDate(s1)); - const tb = dateToString(getPostPublishedDate(s2)); - if (ta > tb) return -1; - if (ta < tb) return 1; - return 0; - }) - .map((slide) => SlidePageEntry({ slide, config })), - ), - GlobalFooter({ config }), - ), - }); -} diff --git a/services/nuldoc/nuldoc-src/pages/SlidePage.ts b/services/nuldoc/nuldoc-src/pages/SlidePage.ts deleted file mode 100644 index 149ecf8e..00000000 --- a/services/nuldoc/nuldoc-src/pages/SlidePage.ts +++ /dev/null @@ -1,140 +0,0 @@ -import GlobalFooter from "../components/GlobalFooter.ts"; -import GlobalHeader from "../components/SlidesGlobalHeader.ts"; -import PageLayout from "../components/PageLayout.ts"; -import StaticStylesheet from "../components/StaticStylesheet.ts"; -import StaticScript from "../components/StaticScript.ts"; -import { Config, getTagLabel } from "../config.ts"; -import { dateToString } from "../revision.ts"; -import { Slide } from "../slide/slide.ts"; -import { getPostPublishedDate } from "../generators/post.ts"; -import { - a, - article, - button, - div, - elem, - Element, - h1, - h2, - header, - li, - ol, - section, - ul, -} from "../dom.ts"; - -export default async function SlidePage( - slide: Slide, - config: Config, -): Promise<Element> { - return await PageLayout({ - metaCopyrightYear: getPostPublishedDate(slide).year, - metaDescription: `「${slide.title}」(${slide.event} で登壇)`, - metaKeywords: slide.tags.map((slug) => getTagLabel(config, slug)), - metaTitle: - `${slide.title} (${slide.event})|${config.sites.slides.siteName}`, - requiresSyntaxHighlight: true, - site: "slides", - config, - children: elem( - "body", - { class: "single" }, - await StaticStylesheet({ - site: "slides", - fileName: "/slides.css", - config, - }), - GlobalHeader({ config }), - elem( - "main", - { class: "main" }, - article( - { class: "post-single" }, - header( - { class: "post-header" }, - h1({ class: "post-title" }, slide.title), - slide.tags.length !== 0 - ? ul( - { class: "post-tags" }, - ...slide.tags.map((slug) => - li( - { class: "tag" }, - a( - { class: "tag-inner", href: `/tags/${slug}/` }, - getTagLabel(config, slug), - ), - ) - ), - ) - : null, - ), - div( - { class: "post-content" }, - section( - { id: "changelog" }, - h2({}, a({ href: "#changelog" }, "更新履歴")), - ol( - {}, - ...slide.revisions.map((rev) => - li( - { class: "revision" }, - elem( - "time", - { datetime: dateToString(rev.date) }, - dateToString(rev.date), - ), - `: ${rev.remark}`, - ) - ), - ), - ), - elem("canvas", { id: "slide", "data-slide-link": slide.slideLink }), - div( - { class: "controllers" }, - div( - { class: "controllers-buttons" }, - button( - { id: "prev", type: "button" }, - elem( - "svg", - { - width: "20", - height: "20", - viewBox: "0 0 24 24", - fill: "none", - stroke: "currentColor", - "stroke-width": "2", - }, - elem("path", { d: "M15 18l-6-6 6-6" }), - ), - ), - button( - { id: "next", type: "button" }, - elem( - "svg", - { - width: "20", - height: "20", - viewBox: "0 0 24 24", - fill: "none", - stroke: "currentColor", - "stroke-width": "2", - }, - elem("path", { d: "M9 18l6-6-6-6" }), - ), - ), - ), - ), - await StaticScript({ - site: "slides", - fileName: "/slide.js", - type: "module", - config, - }), - ), - ), - ), - GlobalFooter({ config }), - ), - }); -} diff --git a/services/nuldoc/nuldoc-src/pages/TagListPage.ts b/services/nuldoc/nuldoc-src/pages/TagListPage.ts deleted file mode 100644 index cf1ec517..00000000 --- a/services/nuldoc/nuldoc-src/pages/TagListPage.ts +++ /dev/null @@ -1,67 +0,0 @@ -import GlobalFooter from "../components/GlobalFooter.ts"; -import BlogGlobalHeader from "../components/BlogGlobalHeader.ts"; -import SlidesGlobalHeader from "../components/SlidesGlobalHeader.ts"; -import PageLayout from "../components/PageLayout.ts"; -import { Config } from "../config.ts"; -import { TagPage } from "../generators/tag.ts"; -import { a, article, elem, Element, footer, h1, h2, header } from "../dom.ts"; - -export default async function TagListPage( - tags: TagPage[], - site: "blog" | "slides", - config: Config, -): Promise<Element> { - const pageTitle = "タグ一覧"; - - const GlobalHeader = site === "blog" ? BlogGlobalHeader : SlidesGlobalHeader; - - return await PageLayout({ - metaCopyrightYear: config.site.copyrightYear, - metaDescription: "タグの一覧", - metaTitle: `${pageTitle}|${config.sites[site].siteName}`, - site, - config, - children: elem( - "body", - { class: "list" }, - GlobalHeader({ config }), - elem( - "main", - { class: "main" }, - header({ class: "page-header" }, h1({}, pageTitle)), - ...Array.from(tags) - .sort((t1, t2) => { - const ta = t1.tagSlug; - const tb = t2.tagSlug; - if (ta < tb) return -1; - if (ta > tb) return 1; - return 0; - }) - .map((tag) => { - const posts = tag.numOfPosts === 0 - ? "" - : `${tag.numOfPosts}件の記事`; - const slides = tag.numOfSlides === 0 - ? "" - : `${tag.numOfSlides}件のスライド`; - const footerText = `${posts}${ - posts && slides ? "、" : "" - }${slides}`; - - return article( - { class: "post-entry" }, - a( - { href: tag.href }, - header( - { class: "entry-header" }, - h2({}, tag.tagLabel), - ), - footer({ class: "entry-footer" }, footerText), - ), - ); - }), - ), - GlobalFooter({ config }), - ), - }); -} diff --git a/services/nuldoc/nuldoc-src/pages/TagPage.ts b/services/nuldoc/nuldoc-src/pages/TagPage.ts deleted file mode 100644 index 1826219c..00000000 --- a/services/nuldoc/nuldoc-src/pages/TagPage.ts +++ /dev/null @@ -1,50 +0,0 @@ -import GlobalFooter from "../components/GlobalFooter.ts"; -import BlogGlobalHeader from "../components/BlogGlobalHeader.ts"; -import SlidesGlobalHeader from "../components/SlidesGlobalHeader.ts"; -import PageLayout from "../components/PageLayout.ts"; -import PostPageEntry from "../components/PostPageEntry.ts"; -import SlidePageEntry from "../components/SlidePageEntry.ts"; -import { Config, getTagLabel } from "../config.ts"; -import { getPostPublishedDate } from "../generators/post.ts"; -import { TaggedPage } from "../generators/tagged_page.ts"; -import { elem, Element, h1, header } from "../dom.ts"; - -export default async function TagPage( - tagSlug: string, - pages: TaggedPage[], - site: "blog" | "slides", - config: Config, -): Promise<Element> { - const tagLabel = getTagLabel(config, tagSlug); - const pageTitle = `タグ「${tagLabel}」一覧`; - - const GlobalHeader = site === "blog" ? BlogGlobalHeader : SlidesGlobalHeader; - - return await PageLayout({ - metaCopyrightYear: getPostPublishedDate(pages[pages.length - 1]).year, - metaDescription: `タグ「${tagLabel}」のついた記事またはスライドの一覧`, - metaKeywords: [tagLabel], - metaTitle: `${pageTitle}|${config.sites[site].siteName}`, - metaAtomFeedHref: `https://${ - config.sites[site].fqdn - }/tags/${tagSlug}/atom.xml`, - site, - config, - children: elem( - "body", - { class: "list" }, - GlobalHeader({ config }), - elem( - "main", - { class: "main" }, - header({ class: "page-header" }, h1({}, pageTitle)), - ...pages.map((page) => - "event" in page - ? SlidePageEntry({ slide: page, config }) - : PostPageEntry({ post: page, config }) - ), - ), - GlobalFooter({ config }), - ), - }); -} diff --git a/services/nuldoc/nuldoc-src/render.ts b/services/nuldoc/nuldoc-src/render.ts deleted file mode 100644 index fbad25ab..00000000 --- a/services/nuldoc/nuldoc-src/render.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Node } from "./dom.ts"; -import { renderHtml } from "./renderers/html.ts"; -import { renderXml } from "./renderers/xml.ts"; - -export type RendererType = "html" | "xml"; - -export function render(root: Node, renderer: RendererType): string { - if (renderer === "html") { - return renderHtml(root); - } else { - return renderXml(root); - } -} diff --git a/services/nuldoc/nuldoc-src/renderers/html.ts b/services/nuldoc/nuldoc-src/renderers/html.ts deleted file mode 100644 index 0fa02d51..00000000 --- a/services/nuldoc/nuldoc-src/renderers/html.ts +++ /dev/null @@ -1,311 +0,0 @@ -import { Element, forEachChild, Node, Text } from "../dom.ts"; -import { NuldocError } from "../errors.ts"; - -export function renderHtml(root: Node): string { - return `<!DOCTYPE html>\n` + nodeToHtmlText(root, { - indentLevel: 0, - isInPre: false, - }); -} - -type Context = { - indentLevel: number; - isInPre: boolean; -}; - -type Dtd = { type: "block" | "inline"; self_closing?: boolean }; - -function getDtd(name: string): Dtd { - switch (name) { - case "a": - return { type: "inline" }; - case "article": - return { type: "block" }; - case "blockquote": - return { type: "block" }; - case "body": - return { type: "block" }; - case "br": - return { type: "block", self_closing: true }; - case "button": - return { type: "block" }; - case "canvas": - return { type: "block" }; - case "caption": - return { type: "block" }; - case "code": - return { type: "inline" }; - case "del": - return { type: "block" }; - case "div": - return { type: "block" }; - case "em": - return { type: "inline" }; - case "footer": - return { type: "block" }; - case "h1": - return { type: "inline" }; - case "h2": - return { type: "inline" }; - case "h3": - return { type: "inline" }; - case "h4": - return { type: "inline" }; - case "h5": - return { type: "inline" }; - case "h6": - return { type: "inline" }; - case "head": - return { type: "block" }; - case "header": - return { type: "block" }; - case "hr": - return { type: "block", self_closing: true }; - case "html": - return { type: "block" }; - case "i": - return { type: "inline" }; - case "li": - return { type: "block" }; - case "link": - return { type: "block", self_closing: true }; - case "img": - return { type: "inline", self_closing: true }; - case "ins": - return { type: "block" }; - case "main": - return { type: "block" }; - case "mark": - return { type: "inline" }; - case "meta": - return { type: "block", self_closing: true }; - case "nav": - return { type: "block" }; - case "noscript": - return { type: "block" }; - case "ol": - return { type: "block" }; - case "p": - return { type: "block" }; - case "pre": - return { type: "block" }; - case "script": - return { type: "block" }; - case "section": - return { type: "block" }; - case "span": - return { type: "inline" }; - case "strong": - return { type: "inline" }; - case "sub": - return { type: "inline" }; - case "sup": - return { type: "inline" }; - case "table": - return { type: "block" }; - case "tbody": - return { type: "block" }; - case "td": // TODO - return { type: "block" }; - case "tfoot": - return { type: "block" }; - case "th": - return { type: "block" }; - case "thead": - return { type: "block" }; - case "time": - return { type: "inline" }; - case "title": // TODO - return { type: "inline" }; - case "tr": - return { type: "block" }; - case "ul": - return { type: "block" }; - case "svg": // TODO - case "path": // TODO - return { type: "block" }; - default: - throw new NuldocError(`[html.write] Unknown element name: ${name}`); - } -} - -function isInlineNode(n: Node): boolean { - if (n.kind === "text" || n.kind === "raw") { - return true; - } - if (n.name !== "a") { - return getDtd(n.name).type === "inline"; - } - - // a tag: check if all children are inline elements. - let allInline = true; - forEachChild(n, (c) => allInline &&= isInlineNode(c)); - return allInline; -} - -function isBlockNode(n: Node): boolean { - return !isInlineNode(n); -} - -function nodeToHtmlText(n: Node, ctx: Context): string { - if (n.kind === "text") { - return textNodeToHtmlText(n, ctx); - } else if (n.kind === "raw") { - return n.html; - } else { - return elementNodeToHtmlText(n, ctx); - } -} - -function textNodeToHtmlText(t: Text, ctx: Context): string { - const s = encodeSpecialCharacters(t.content); - if (ctx.isInPre) return s; - - return s.replaceAll(/\n */g, (_match, offset, subject) => { - const last_char = subject[offset - 1]; - if (last_char === "。" || last_char === "、") { - // 日本語で改行するときはスペースを入れない - return ""; - } else { - return " "; - } - }); -} - -function encodeSpecialCharacters(s: string): string { - return s.replaceAll(/&(?!\w+;)/g, "&") - .replaceAll(/</g, "<") - .replaceAll(/>/g, ">") - .replaceAll(/'/g, "'") - .replaceAll(/"/g, """); -} - -function elementNodeToHtmlText(e: Element, ctx: Context): string { - const dtd = getDtd(e.name); - - let s = ""; - - if (isBlockNode(e)) { - s += indent(ctx); - } - s += `<${e.name}`; - const attributes = getElementAttributes(e); - if (attributes.length > 0) { - s += " "; - for (let i = 0; i < attributes.length; i++) { - const [name, value] = attributes[i]; - if (name === "defer" && value === "true") { - // TODO - s += "defer"; - } else { - s += `${name === "className" ? "class" : name}="${ - encodeSpecialCharacters(value) - }"`; - } - if (i !== attributes.length - 1) { - s += " "; - } - } - } - s += ">"; - if (isBlockNode(e) && e.name !== "pre") { - s += "\n"; - } - - ctx.indentLevel += 1; - - let prevChild: Node | null = null; - if (e.name === "pre") { - ctx.isInPre = true; - } - forEachChild(e, (c) => { - if (isBlockNode(e) && !ctx.isInPre) { - if (isInlineNode(c)) { - if (needsIndent(prevChild)) { - s += indent(ctx); - } - } else { - if (needsLineBreak(prevChild)) { - s += "\n"; - } - } - } - s += nodeToHtmlText(c, ctx); - prevChild = c; - }); - if (e.name === "pre") { - ctx.isInPre = false; - } - - ctx.indentLevel -= 1; - if (!dtd.self_closing) { - if (e.name !== "pre") { - if (isBlockNode(e)) { - if (needsLineBreak(prevChild)) { - s += "\n"; - } - s += indent(ctx); - } - } - s += `</${e.name}>`; - if (isBlockNode(e)) { - s += "\n"; - } - } - return s; -} - -function indent(ctx: Context): string { - return " ".repeat(ctx.indentLevel); -} - -function getElementAttributes(e: Element): [string, string][] { - return [...Object.entries(e.attributes)] - .filter((a) => !a[0].startsWith("__")) - .filter((a) => a[1] !== undefined) - .sort( - (a, b) => { - // Special rules: - if (e.name === "meta") { - if (a[0] === "content" && b[0] === "name") { - return 1; - } - if (a[0] === "name" && b[0] === "content") { - return -1; - } - if (a[0] === "content" && b[0] === "property") { - return 1; - } - if (a[0] === "property" && b[0] === "content") { - return -1; - } - } - if (e.name === "link") { - if (a[0] === "href" && b[0] === "rel") { - return 1; - } - if (a[0] === "rel" && b[0] === "href") { - return -1; - } - if (a[0] === "href" && b[0] === "type") { - return 1; - } - if (a[0] === "type" && b[0] === "href") { - return -1; - } - } - // General rules: - if (a[0] > b[0]) return 1; - else if (a[0] < b[0]) return -1; - else return 0; - }, - ); -} - -function needsIndent(prevChild: Node | null): boolean { - return !prevChild || isBlockNode(prevChild); -} - -function needsLineBreak(prevChild: Node | null): boolean { - return !needsIndent(prevChild); -} diff --git a/services/nuldoc/nuldoc-src/renderers/xml.ts b/services/nuldoc/nuldoc-src/renderers/xml.ts deleted file mode 100644 index 523567ab..00000000 --- a/services/nuldoc/nuldoc-src/renderers/xml.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { Element, forEachChild, Node, Text } from "../dom.ts"; - -export function renderXml(root: Node): string { - return `<?xml version="1.0" encoding="utf-8"?>\n` + nodeToXmlText(root, { - indentLevel: 0, - }); -} - -type Context = { - indentLevel: number; -}; - -type Dtd = { type: "block" | "inline" }; - -function getDtd(name: string): Dtd { - switch (name) { - case "feed": - case "entry": - case "author": - return { type: "block" }; - default: - return { type: "inline" }; - } -} - -function isInlineNode(n: Node): boolean { - if (n.kind === "text" || n.kind === "raw") { - return true; - } - return getDtd(n.name).type === "inline"; -} - -function isBlockNode(n: Node): boolean { - return !isInlineNode(n); -} - -function nodeToXmlText(n: Node, ctx: Context): string { - if (n.kind === "text") { - return textNodeToXmlText(n); - } else if (n.kind === "raw") { - return n.html; - } else { - return elementNodeToXmlText(n, ctx); - } -} - -function textNodeToXmlText(t: Text): string { - const s = encodeSpecialCharacters(t.content); - - // TODO: 日本語で改行するときはスペースを入れない - return s.replaceAll(/\n */g, " "); -} - -function encodeSpecialCharacters(s: string): string { - return s.replaceAll(/&(?!\w+;)/g, "&") - .replaceAll(/</g, "<") - .replaceAll(/>/g, ">") - .replaceAll(/'/g, "'") - .replaceAll(/"/g, """); -} - -function elementNodeToXmlText(e: Element, ctx: Context): string { - let s = ""; - - s += indent(ctx); - s += `<${e.name}`; - const attributes = getElementAttributes(e); - if (attributes.length > 0) { - s += " "; - for (let i = 0; i < attributes.length; i++) { - const [name, value] = attributes[i]; - s += `${name}="${encodeSpecialCharacters(value)}"`; - if (i !== attributes.length - 1) { - s += " "; - } - } - } - s += ">"; - if (isBlockNode(e)) { - s += "\n"; - } - ctx.indentLevel += 1; - - forEachChild(e, (c) => { - s += nodeToXmlText(c, ctx); - }); - - ctx.indentLevel -= 1; - if (isBlockNode(e)) { - s += indent(ctx); - } - s += `</${e.name}>`; - s += "\n"; - - return s; -} - -function indent(ctx: Context): string { - return " ".repeat(ctx.indentLevel); -} - -function getElementAttributes(e: Element): [string, string][] { - return [...Object.entries(e.attributes)] - .filter((a) => !a[0].startsWith("__")) - .sort( - (a, b) => { - // Special rules: - if (e.name === "link") { - if (a[0] === "href" && b[0] === "rel") { - return 1; - } - if (a[0] === "rel" && b[0] === "href") { - return -1; - } - if (a[0] === "href" && b[0] === "type") { - return 1; - } - if (a[0] === "type" && b[0] === "href") { - return -1; - } - } - // General rules: - if (a[0] > b[0]) return 1; - else if (a[0] < b[0]) return -1; - else return 0; - }, - ); -} diff --git a/services/nuldoc/nuldoc-src/revision.ts b/services/nuldoc/nuldoc-src/revision.ts deleted file mode 100644 index a22b6bc4..00000000 --- a/services/nuldoc/nuldoc-src/revision.ts +++ /dev/null @@ -1,37 +0,0 @@ -export type Date = { - year: number; - month: number; - day: number; -}; - -export function stringToDate(s: string): Date { - const match = s.match(/(\d{4})-(\d{2})-(\d{2})/); - if (match === null) { - throw new Error(); - } - const [_, y, m, d] = match; - return { year: parseInt(y), month: parseInt(m), day: parseInt(d) }; -} - -export function dateToString(date: Date): string { - const y = `${date.year}`.padStart(4, "0"); - const m = `${date.month}`.padStart(2, "0"); - const d = `${date.day}`.padStart(2, "0"); - return `${y}-${m}-${d}`; -} - -export function dateToRfc3339String(date: Date): string { - // 2021-01-01T12:00:00+00:00 - // TODO: currently, time part is fixed to 00:00:00. - const y = `${date.year}`.padStart(4, "0"); - const m = `${date.month}`.padStart(2, "0"); - const d = `${date.day}`.padStart(2, "0"); - return `${y}-${m}-${d}T00:00:00+09:00`; -} - -export type Revision = { - number: number; - date: Date; - remark: string; - isInternal: boolean; -}; diff --git a/services/nuldoc/nuldoc-src/slide/parse.ts b/services/nuldoc/nuldoc-src/slide/parse.ts deleted file mode 100644 index c5a89675..00000000 --- a/services/nuldoc/nuldoc-src/slide/parse.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { parse as parseToml } from "@std/toml"; -import { - createNewSlideFromMetadata, - Slide, - SlideMetadataSchema, -} from "./slide.ts"; - -export async function parseSlideFile(filePath: string): Promise<Slide> { - try { - const root = SlideMetadataSchema.parse( - parseToml(await Deno.readTextFile(filePath)), - ); - return createNewSlideFromMetadata(root, filePath); - } catch (e) { - if (e instanceof Error) { - e.message = `${e.message} in ${filePath}`; - } - throw e; - } -} diff --git a/services/nuldoc/nuldoc-src/slide/slide.ts b/services/nuldoc/nuldoc-src/slide/slide.ts deleted file mode 100644 index 8fe99eab..00000000 --- a/services/nuldoc/nuldoc-src/slide/slide.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { SlideError } from "../errors.ts"; -import { Revision, stringToDate } from "../revision.ts"; -import { z } from "zod/mod.ts"; - -export const SlideMetadataSchema = z.object({ - slide: z.object({ - uuid: z.string(), - title: z.string(), - event: z.string(), - talkType: z.string(), - link: z.string(), - tags: z.array(z.string()), - revisions: z.array(z.object({ - date: z.string(), - remark: z.string(), - isInternal: z.boolean().optional(), - })), - }), -}); - -export type SlideMetadata = z.infer<typeof SlideMetadataSchema>; - -export type Slide = { - sourceFilePath: string; - uuid: string; - title: string; - event: string; - talkType: string; - slideLink: string; - tags: string[]; - revisions: Revision[]; -}; - -export function createNewSlideFromMetadata( - { slide }: SlideMetadata, - sourceFilePath: string, -): Slide { - const revisions = slide.revisions.map( - (rev, i) => { - const date = rev.date; - const remark = rev.remark; - const isInternal = rev.isInternal ?? false; - return { - number: i + 1, - date: stringToDate(date), - remark, - isInternal, - }; - }, - ); - if (revisions.length === 0) { - throw new SlideError( - `[slide.new] 'slide.revisions' field is empty`, - ); - } - - return { - sourceFilePath: sourceFilePath, - uuid: slide.uuid, - title: slide.title, - event: slide.event, - talkType: slide.talkType, - slideLink: slide.link, - tags: slide.tags, - revisions: revisions, - }; -} diff --git a/services/nuldoc/public/blog/posts/2021-03-05/my-first-post/index.html b/services/nuldoc/public/blog/posts/2021-03-05/my-first-post/index.html index 651adf12..9ca54465 100644 --- a/services/nuldoc/public/blog/posts/2021-03-05/my-first-post/index.html +++ b/services/nuldoc/public/blog/posts/2021-03-05/my-first-post/index.html @@ -175,7 +175,8 @@ </blockquote> <hr> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#005CC5">puts</span><span style="color:#032F62"> "Hello, World!"</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #953800">puts</span> <span style="color: #0a3069">"Hello, World!"</span> +</code></pre> </div> <p> <strong>emph</strong> <em>strong</em> diff --git a/services/nuldoc/public/blog/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.md b/services/nuldoc/public/blog/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.md index 70068754..fb8c8798 100644 --- a/services/nuldoc/public/blog/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.md +++ b/services/nuldoc/public/blog/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.md @@ -60,8 +60,7 @@ $ clang –std=c++17 hoge.cpp 別件で [cppreference.com の identifier のページ](https://en.cppreference.com/w/cpp/language/identifiers)を読んでいた時、次の文が目に止まった。 > * the identifiers that are keywords cannot be used for other purposes; -> -> * The only place they can be used as non-keywords is in an attribute-token. (e.g. [[private]] is a valid attribute) (since C++11) +> * The only place they can be used as non-keywords is in an attribute-token. (e.g. [[private]] is a valid attribute) (since C++11) キーワードでも属性として指定する場合は非キーワードとして使えるらしい。 実際にやってみる。 diff --git a/services/nuldoc/public/blog/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html b/services/nuldoc/public/blog/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html index 79f7ebdd..57412b03 100644 --- a/services/nuldoc/public/blog/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html +++ b/services/nuldoc/public/blog/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html @@ -72,40 +72,43 @@ タイトル落ち。まずはこのコードを見て欲しい。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">#include</span><span style="color:#032F62"> <iostream></span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">alignas</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">alignof</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">and</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">and_eq</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">asm</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">auto</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">bitand</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">bitor</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">bool</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">break</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">case</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">catch</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">char</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">char16_t</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">char32_t</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">class</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">compl</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">const</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">const_cast</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">constexpr</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">continue</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">decltype</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">default</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">delete</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">do</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">double</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">dynamic_cast</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">else</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">enum</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">explicit</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">export</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">extern</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">false</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">final</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">float</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">for</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">friend</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">goto</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">if</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">inline</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">int</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">long</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">mutable</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">namespace</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">new</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">noexcept</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">not</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">not_eq</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">nullptr</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">operator</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">or</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">or_eq</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">override</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">private</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">protected</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">public</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">register</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">reinterpret_cast</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">return</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">short</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">signed</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">sizeof</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">static</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">static_assert</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">static_cast</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">struct</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">switch</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">template</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">this</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">thread_local</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">throw</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">true</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">try</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">typedef</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">typeid</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">typename</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">union</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">unsigned</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#6F42C1">virtual</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">void</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">volatile</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">wchar_t</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">while</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">xor</span><span style="color:#005CC5">]]</span><span style="color:#005CC5"> [[</span><span style="color:#6F42C1">xor_eq</span><span style="color:#005CC5">]]</span></span> -<span class="line"><span style="color:#6A737D">// [[using]]</span></span> -<span class="line"><span style="color:#D73A49">int</span><span style="color:#6F42C1"> main</span><span style="color:#24292E">() {</span></span> -<span class="line"><span style="color:#6F42C1"> std</span><span style="color:#24292E">::cout </span><span style="color:#D73A49"><<</span><span style="color:#032F62"> "Hello, World!"</span><span style="color:#D73A49"> <<</span><span style="color:#6F42C1"> std</span><span style="color:#24292E">::endl;</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781">#include</span> <span style="color: #6e7781"><iostream></span><span style="color: #6e7781"> +</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">alignas</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">alignof</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #24292f;background-color: #f6f8fa">and</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #24292f;background-color: #f6f8fa">and_eq</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">asm</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">auto</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #24292f;background-color: #f6f8fa">bitand</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #24292f;background-color: #f6f8fa">bitor</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">bool</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">break</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">case</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">catch</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">char</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">char16_t</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">char32_t</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">class</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #24292f;background-color: #f6f8fa">compl</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">const</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">const_cast</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">constexpr</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">continue</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">decltype</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">default</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">delete</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">do</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">double</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">dynamic_cast</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">else</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">enum</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">explicit</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">export</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">extern</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #953800">false</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">final</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">float</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">for</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">friend</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">goto</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">if</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">inline</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">int</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">long</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">mutable</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">namespace</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">new</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">noexcept</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #24292f;background-color: #f6f8fa">not</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #24292f;background-color: #f6f8fa">not_eq</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #953800">nullptr</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">operator</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #24292f;background-color: #f6f8fa">or</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #24292f;background-color: #f6f8fa">or_eq</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">override</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">private</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">protected</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">public</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">register</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">reinterpret_cast</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">return</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">short</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">signed</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">sizeof</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">static</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">static_assert</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">static_cast</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">struct</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">switch</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">template</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">this</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">thread_local</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">throw</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #953800">true</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">try</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">typedef</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">typeid</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">typename</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">union</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">unsigned</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">virtual</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">void</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">volatile</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">wchar_t</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">while</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #24292f;background-color: #f6f8fa">xor</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #24292f;background-color: #f6f8fa">xor_eq</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> +<span style="color: #6e7781">// [[using]]</span> +<span style="color: #cf222e">int</span> <span style="color: #24292f;background-color: #f6f8fa">main</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">std</span><span style="color: #0550ae">::</span><span style="color: #24292f;background-color: #f6f8fa">cout</span> <span style="color: #0550ae"><<</span> <span style="color: #0a3069">"Hello, World!"</span> <span style="color: #0550ae"><<</span> <span style="color: #24292f;background-color: #f6f8fa">std</span><span style="color: #0550ae">::</span><span style="color: #24292f;background-color: #f6f8fa">endl</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> コンパイラのバージョン </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ clang++ –version Apple clang version 11.0.0</span></span> -<span class="line"><span>(clang-1100.0.33.8) Target: x86_64-apple-darwin19.6.0 Thread model:</span></span> -<span class="line"><span>posix InstalledDir:</span></span> -<span class="line"><span>/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ clang++ –version Apple clang version 11.0.0 +(clang-1100.0.33.8) Target: x86_64-apple-darwin19.6.0 Thread model: +posix InstalledDir: +/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin +</code></pre> </div> <p> コンパイルコマンド (C++17 指定) </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ clang –std=c++17 hoge.cpp</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ clang –std=c++17 hoge.cpp +</code></pre> </div> <p> この記事から得られるものはこれ以上ないので以下は蛇足になる。 @@ -135,8 +138,9 @@ 上のコードでは <code>[[using]]</code> をコメントアウトしているが、これは <code>using</code> キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">// using の例</span></span> -<span class="line"><span style="color:#005CC5">[[</span><span style="color:#D73A49">using</span><span style="color:#6F42C1"> foo</span><span style="color:#005CC5">: </span><span style="color:#6F42C1">attr1</span><span style="color:#005CC5">, </span><span style="color:#6F42C1">attr2</span><span style="color:#005CC5">]]</span><span style="color:#D73A49"> int</span><span style="color:#24292E"> x;</span><span style="color:#6A737D"> // [[foo::attr1, foo::attr2]] の糖衣構文</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781">// using の例</span> +<span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #cf222e">using</span> <span style="color: #24292f;background-color: #f6f8fa">foo</span><span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">attr1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">attr2</span><span style="color: #24292f;background-color: #f6f8fa">]]</span> <span style="color: #cf222e">int</span> <span style="color: #24292f;background-color: #f6f8fa">x</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #6e7781">// [[foo::attr1, foo::attr2]] の糖衣構文</span> +</code></pre> </div> <p> C++17 の仕様も見てみる (正確には標準化前のドラフト)。 diff --git a/services/nuldoc/public/blog/posts/2021-10-02/python-unbound-local-error/index.html b/services/nuldoc/public/blog/posts/2021-10-02/python-unbound-local-error/index.html index 26fb852f..03e01be0 100644 --- a/services/nuldoc/public/blog/posts/2021-10-02/python-unbound-local-error/index.html +++ b/services/nuldoc/public/blog/posts/2021-10-02/python-unbound-local-error/index.html @@ -75,13 +75,14 @@ Python でクロージャを作ろうと、次のようなコードを書いた。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">def</span><span style="color:#6F42C1"> f</span><span style="color:#24292E">():</span></span> -<span class="line"><span style="color:#24292E"> x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span></span> -<span class="line"><span style="color:#D73A49"> def</span><span style="color:#6F42C1"> g</span><span style="color:#24292E">():</span></span> -<span class="line"><span style="color:#24292E"> x </span><span style="color:#D73A49">+=</span><span style="color:#005CC5"> 1</span></span> -<span class="line"><span style="color:#24292E"> g()</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">f()</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">def</span> <span style="color: #8250df">f</span><span style="color: #24292f;background-color: #f6f8fa">():</span> + <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span> + <span style="color: #cf222e">def</span> <span style="color: #8250df">g</span><span style="color: #24292f;background-color: #f6f8fa">():</span> + <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae">+=</span> <span style="color: #0550ae">1</span> + <span style="color: #8250df">g</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + +<span style="color: #8250df">f</span><span style="color: #24292f;background-color: #f6f8fa">()</span> +</code></pre> </div> <p> 関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに 1 を足そうとしている。 これを実行すると <code>x += 1</code> の箇所でエラーが発生する。 @@ -95,27 +96,29 @@ local変数 <code>x</code> が代入前に参照された、とある。これは、<code>f</code> の <code>x</code> を参照するのではなく、新しく別の変数を <code>g</code> 内に作ってしまっているため。前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code> を変数宣言のための構文として擬似的に利用している。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D"># 注: var は正しい Python の文法ではない。上記参照のこと</span></span> -<span class="line"><span style="color:#D73A49">def</span><span style="color:#6F42C1"> f</span><span style="color:#24292E">():</span></span> -<span class="line"><span style="color:#24292E"> var x </span><span style="color:#6A737D"># f の local変数 'x' を宣言</span></span> -<span class="line"><span style="color:#24292E"> x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#6A737D"> # x に 0 を代入</span></span> -<span class="line"><span style="color:#D73A49"> def</span><span style="color:#6F42C1"> g</span><span style="color:#24292E">(): </span><span style="color:#6A737D"># f の内部関数 g を定義</span></span> -<span class="line"><span style="color:#24292E"> var x </span><span style="color:#6A737D"># g の local変数 'x' を宣言</span></span> -<span class="line"><span style="color:#6A737D"> # たまたま f にも同じ名前の変数があるが、それとは別の変数</span></span> -<span class="line"><span style="color:#24292E"> x </span><span style="color:#D73A49">+=</span><span style="color:#005CC5"> 1</span><span style="color:#6A737D"> # x に 1 を加算 (x = x + 1 の糖衣構文)</span></span> -<span class="line"><span style="color:#6A737D"> # 加算する前の値を参照しようとするが、まだ代入されていないためエラー</span></span> -<span class="line"><span style="color:#24292E"> g()</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"># 注: var は正しい Python の文法ではない。上記参照のこと +</span><span style="color: #cf222e">def</span> <span style="color: #8250df">f</span><span style="color: #24292f;background-color: #f6f8fa">():</span> + <span style="color: #24292f;background-color: #f6f8fa">var</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #6e7781"># f の local変数 'x' を宣言 +</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span> <span style="color: #6e7781"># x に 0 を代入 +</span> <span style="color: #cf222e">def</span> <span style="color: #8250df">g</span><span style="color: #24292f;background-color: #f6f8fa">():</span> <span style="color: #6e7781"># f の内部関数 g を定義 +</span> <span style="color: #24292f;background-color: #f6f8fa">var</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #6e7781"># g の local変数 'x' を宣言 +</span> <span style="color: #6e7781"># たまたま f にも同じ名前の変数があるが、それとは別の変数 +</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae">+=</span> <span style="color: #0550ae">1</span> <span style="color: #6e7781"># x に 1 を加算 (x = x + 1 の糖衣構文) +</span> <span style="color: #6e7781"># 加算する前の値を参照しようとするが、まだ代入されていないためエラー +</span> <span style="color: #8250df">g</span><span style="color: #24292f;background-color: #f6f8fa">()</span> +</code></pre> </div> <p> 当初の意図を表現するには、次のように書けばよい。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">def</span><span style="color:#6F42C1"> f</span><span style="color:#24292E">():</span></span> -<span class="line"><span style="color:#24292E"> x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span></span> -<span class="line"><span style="color:#D73A49"> def</span><span style="color:#6F42C1"> g</span><span style="color:#24292E">():</span></span> -<span class="line"><span style="color:#D73A49"> nonlocal</span><span style="color:#24292E"> x </span><span style="color:#6A737D">## (*)</span></span> -<span class="line"><span style="color:#24292E"> x </span><span style="color:#D73A49">+=</span><span style="color:#005CC5"> 1</span></span> -<span class="line"><span style="color:#24292E"> g()</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">def</span> <span style="color: #8250df">f</span><span style="color: #24292f;background-color: #f6f8fa">():</span> + <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span> + <span style="color: #cf222e">def</span> <span style="color: #8250df">g</span><span style="color: #24292f;background-color: #f6f8fa">():</span> + <span style="color: #cf222e">nonlocal</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #6e7781">## (*) +</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae">+=</span> <span style="color: #0550ae">1</span> + <span style="color: #8250df">g</span><span style="color: #24292f;background-color: #f6f8fa">()</span> +</code></pre> </div> <p> <code>(*)</code> のように、<code>nonlocal</code> を追加する。これにより一つ外側のスコープ (<code>g</code> の一つ外側 = <code>f</code>) で定義されている <code>x</code> を探しに行くようになる。 diff --git a/services/nuldoc/public/blog/posts/2021-10-02/ruby-detect-running-implementation/index.html b/services/nuldoc/public/blog/posts/2021-10-02/ruby-detect-running-implementation/index.html index b2e7a02a..db82851d 100644 --- a/services/nuldoc/public/blog/posts/2021-10-02/ruby-detect-running-implementation/index.html +++ b/services/nuldoc/public/blog/posts/2021-10-02/ruby-detect-running-implementation/index.html @@ -81,12 +81,13 @@ 上記ページの例から引用する: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ ruby-1.9.1 -ve 'p RUBY_ENGINE'</span></span> -<span class="line"><span>ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux]</span></span> -<span class="line"><span>"ruby"</span></span> -<span class="line"><span>$ jruby -ve 'p RUBY_ENGINE'</span></span> -<span class="line"><span>jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]</span></span> -<span class="line"><span>"jruby"</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>ruby-1.9.1 <span style="color: #116329">-ve</span> <span style="color: #0a3069">'p RUBY_ENGINE'</span> +<span style="color: #24292f;background-color: #f6f8fa">ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux] +"ruby" +</span><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>jruby <span style="color: #116329">-ve</span> <span style="color: #0a3069">'p RUBY_ENGINE'</span> +<span style="color: #24292f;background-color: #f6f8fa">jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] +"jruby"</span> +</code></pre> </div> <p> それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。 @@ -96,16 +97,17 @@ </p> <blockquote> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>| RUBY_ENGINE | Implementation |</span></span> -<span class="line"><span>|:-----------:|:------------------|</span></span> -<span class="line"><span>| <undefined> | MRI < 1.9 |</span></span> -<span class="line"><span>| 'ruby' | MRI >= 1.9 or REE |</span></span> -<span class="line"><span>| 'jruby' | JRuby |</span></span> -<span class="line"><span>| 'macruby' | MacRuby |</span></span> -<span class="line"><span>| 'rbx' | Rubinius |</span></span> -<span class="line"><span>| 'maglev' | MagLev |</span></span> -<span class="line"><span>| 'ironruby' | IronRuby |</span></span> -<span class="line"><span>| 'cardinal' | Cardinal |</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>| RUBY_ENGINE | Implementation | +|:-----------:|:------------------| +| <undefined> | MRI < 1.9 | +| 'ruby' | MRI >= 1.9 or REE | +| 'jruby' | JRuby | +| 'macruby' | MacRuby | +| 'rbx' | Rubinius | +| 'maglev' | MagLev | +| 'ironruby' | IronRuby | +| 'cardinal' | Cardinal | +</code></pre> </div> </blockquote> <p> @@ -121,10 +123,11 @@ <div class="filename"> version.h </div> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">/*</span></span> -<span class="line"><span style="color:#6A737D"> * Ruby engine.</span></span> -<span class="line"><span style="color:#6A737D"> */</span></span> -<span class="line"><span style="color:#D73A49">#define</span><span style="color:#6F42C1"> MRUBY_RUBY_ENGINE</span><span style="color:#032F62"> "mruby"</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781">/* + * Ruby engine. + */</span> +<span style="color: #6e7781">#define MRUBY_RUBY_ENGINE "mruby"</span> +</code></pre> </div> </div> </article> diff --git a/services/nuldoc/public/blog/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html b/services/nuldoc/public/blog/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html index 9035fa18..0592f0a6 100644 --- a/services/nuldoc/public/blog/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html +++ b/services/nuldoc/public/blog/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html @@ -103,36 +103,38 @@ 使われることは稀だが、Ruby では <code>then</code> がキーワードになっている。次のように使う: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> cond </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#005CC5"> puts</span><span style="color:#032F62"> "Y"</span></span> -<span class="line"><span style="color:#D73A49">else</span></span> -<span class="line"><span style="color:#005CC5"> puts</span><span style="color:#032F62"> "N"</span></span> -<span class="line"><span style="color:#D73A49">end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">cond</span> <span style="color: #cf222e">then</span> + <span style="color: #953800">puts</span> <span style="color: #0a3069">"Y"</span> +<span style="color: #cf222e">else</span> + <span style="color: #953800">puts</span> <span style="color: #0a3069">"N"</span> +<span style="color: #cf222e">end</span> +</code></pre> </div> <p> このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code> 構文がそれに当たる。 上記のように、何か条件を書いた後 <code>then</code> を置き、式がそこで終了していることを示すマーカーとして機能する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D"># Example:</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> x </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#24292E"> a</span></span> -<span class="line"><span style="color:#D73A49">end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">unless</span><span style="color:#24292E"> x </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#24292E"> a</span></span> -<span class="line"><span style="color:#D73A49">end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">begin</span></span> -<span class="line"><span style="color:#24292E"> a</span></span> -<span class="line"><span style="color:#D73A49">rescue</span><span style="color:#D73A49"> then</span></span> -<span class="line"><span style="color:#24292E"> b</span></span> -<span class="line"><span style="color:#D73A49">end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">case</span><span style="color:#24292E"> x</span></span> -<span class="line"><span style="color:#D73A49">when</span><span style="color:#005CC5"> p</span><span style="color:#D73A49"> then</span></span> -<span class="line"><span style="color:#24292E"> a</span></span> -<span class="line"><span style="color:#D73A49">end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"># Example:</span> + +<span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #cf222e">then</span> + <span style="color: #24292f;background-color: #f6f8fa">a</span> +<span style="color: #cf222e">end</span> + +<span style="color: #cf222e">unless</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #cf222e">then</span> + <span style="color: #24292f;background-color: #f6f8fa">a</span> +<span style="color: #cf222e">end</span> + +<span style="color: #cf222e">begin</span> + <span style="color: #24292f;background-color: #f6f8fa">a</span> +<span style="color: #cf222e">rescue</span> <span style="color: #cf222e">then</span> + <span style="color: #24292f;background-color: #f6f8fa">b</span> +<span style="color: #cf222e">end</span> + +<span style="color: #cf222e">case</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> +<span style="color: #cf222e">when</span> <span style="color: #953800">p</span> <span style="color: #cf222e">then</span> + <span style="color: #24292f;background-color: #f6f8fa">a</span> +<span style="color: #cf222e">end</span> +</code></pre> </div> </section> <section id="section--why-then-is-usually-unnecessary"> @@ -141,17 +143,19 @@ 普通 Ruby のコードで <code>then</code> を書くことはない。なぜか。次のコードを実行してみるとわかる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">if</span><span style="color:#005CC5"> true</span><span style="color:#005CC5"> puts</span><span style="color:#032F62"> 'Hello, World!'</span><span style="color:#D73A49"> end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">if</span> <span style="color: #cf222e">true</span> <span style="color: #953800">puts</span> <span style="color: #0a3069">'Hello, World!'</span> <span style="color: #cf222e">end</span> +</code></pre> </div> <p> 次のような構文エラーが出力される。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n'</span></span> -<span class="line"><span>if true puts 'Hello, World!' end</span></span> -<span class="line"><span> ^~~~</span></span> -<span class="line"><span>20:1: syntax error, unexpected `end', expecting end-of-input</span></span> -<span class="line"><span>...f true puts 'Hello, World!' end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n' +if true puts 'Hello, World!' end + ^~~~ +20:1: syntax error, unexpected `end', expecting end-of-input +...f true puts 'Hello, World!' end +</code></pre> </div> <p> 二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code> か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。 @@ -160,8 +164,9 @@ ポイントは改行が <code>then</code> (や <code>;</code>) の代わりとなることである。<code>true</code> の後に改行を入れてみる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">if</span><span style="color:#005CC5"> true</span></span> -<span class="line"><span style="color:#005CC5">puts</span><span style="color:#032F62"> 'Hello, World!'</span><span style="color:#D73A49"> end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">if</span> <span style="color: #cf222e">true</span> +<span style="color: #953800">puts</span> <span style="color: #0a3069">'Hello, World!'</span> <span style="color: #cf222e">end</span> +</code></pre> </div> <p> 無事 Hello, World! と出力されるようになった。 @@ -173,22 +178,25 @@ なぜ <code>then</code> や <code>;</code> や改行 (以下 「<code>then</code> 等」) が必要なのだろうか。次の例を見てほしい: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> a b </span><span style="color:#D73A49">end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">a</span> <span style="color: #24292f;background-color: #f6f8fa">b</span> <span style="color: #cf222e">end</span> +</code></pre> </div> <p> <code>then</code> も <code>;</code> も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。この例は二通りに解釈できる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span></span> -<span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> a </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#24292E">b</span></span> -<span class="line"><span style="color:#D73A49">end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span> +<span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">a</span> <span style="color: #cf222e">then</span> +<span style="color: #24292f;background-color: #f6f8fa">b</span> +<span style="color: #cf222e">end</span> +</code></pre> </div> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、</span></span> -<span class="line"><span style="color:#6A737D"># その結果が truthy なら何もしない</span></span> -<span class="line"><span style="color:#D73A49">if</span><span style="color:#6F42C1"> a</span><span style="color:#24292E">(b) </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#D73A49">end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、</span> +<span style="color: #6e7781"># その結果が truthy なら何もしない</span> +<span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">a</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">then</span> +<span style="color: #cf222e">end</span> +</code></pre> </div> <p> <code>then</code> 等はこの曖昧性を排除するためにあり、条件式は <code>if</code> から <code>then</code> 等までの間にある、ということを明確にする。 C系の <code>if</code> 後に来る <code>(</code>/<code>)</code> や、Python の <code>:</code>、Rust/Go/Swift などの <code>{</code> も同じ役割を持つ。 @@ -209,39 +217,41 @@ <div class="filename"> parse.y </div> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>p_case_body : keyword_in</span></span> -<span class="line"><span>{</span></span> -<span class="line"><span> SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);</span></span> -<span class="line"><span> p->command_start = FALSE;</span></span> -<span class="line"><span> $<ctxt>1 = p->ctxt;</span></span> -<span class="line"><span> p->ctxt.in_kwarg = 1;</span></span> -<span class="line"><span> $<tbl>$ = push_pvtbl(p);</span></span> -<span class="line"><span>}</span></span> -<span class="line"><span>{</span></span> -<span class="line"><span> $<tbl>$ = push_pktbl(p);</span></span> -<span class="line"><span>}</span></span> -<span class="line"><span>p_top_expr then</span></span> -<span class="line"><span>{</span></span> -<span class="line"><span> pop_pktbl(p, $<tbl>3);</span></span> -<span class="line"><span> pop_pvtbl(p, $<tbl>2);</span></span> -<span class="line"><span> p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;</span></span> -<span class="line"><span>}</span></span> -<span class="line"><span>compstmt</span></span> -<span class="line"><span>p_cases</span></span> -<span class="line"><span>{</span></span> -<span class="line"><span> /*%%%*/</span></span> -<span class="line"><span> $$ = NEW_IN($4, $7, $8, &@$);</span></span> -<span class="line"><span> /*% %*/</span></span> -<span class="line"><span> /*% ripper: in!($4, $7, escape_Qundef($8)) %*/</span></span> -<span class="line"><span>}</span></span> -<span class="line"><span>;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>p_case_body : keyword_in +{ + SET_LEX_STATE(EXPR_BEG|EXPR_LABEL); + p->command_start = FALSE; + $<ctxt>1 = p->ctxt; + p->ctxt.in_kwarg = 1; + $<tbl>$ = push_pvtbl(p); +} +{ + $<tbl>$ = push_pktbl(p); +} +p_top_expr then +{ + pop_pktbl(p, $<tbl>3); + pop_pvtbl(p, $<tbl>2); + p->ctxt.in_kwarg = $<ctxt>1.in_kwarg; +} +compstmt +p_cases +{ + /*%%%*/ + $$ = NEW_IN($4, $7, $8, &@$); + /*% %*/ + /*% ripper: in!($4, $7, escape_Qundef($8)) %*/ +} +; +</code></pre> </div> <p> 簡略版: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>p_case_body : keyword_in p_top_expr then compstmt p_cases</span></span> -<span class="line"><span>;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>p_case_body : keyword_in p_top_expr then compstmt p_cases +; +</code></pre> </div> <p> ここで、<code>keyword_in</code> は文字通り <code>in</code>、<code>p_top_expr</code> はいわゆるパターン、<code>then</code> は <code>then</code> キーワードのことではなく、この記事で <code>then</code> 等と呼んでいるもの、つまり <code>then</code> キーワード、<code>;</code>、改行のいずれかである。 @@ -250,36 +260,38 @@ これにより、<code>case</code> - <code>when</code> による従来の構文と同じように、<code>then</code> 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">case</span><span style="color:#24292E"> x</span></span> -<span class="line"><span style="color:#D73A49">in</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49"> then</span><span style="color:#24292E"> a</span></span> -<span class="line"><span style="color:#D73A49">in</span><span style="color:#005CC5"> 2</span><span style="color:#D73A49"> then</span><span style="color:#24292E"> b</span></span> -<span class="line"><span style="color:#D73A49">in</span><span style="color:#005CC5"> 3</span><span style="color:#D73A49"> then</span><span style="color:#24292E"> c</span></span> -<span class="line"><span style="color:#D73A49">end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">case</span><span style="color:#24292E"> x</span></span> -<span class="line"><span style="color:#D73A49">in</span><span style="color:#005CC5"> 1</span></span> -<span class="line"><span style="color:#24292E"> a</span></span> -<span class="line"><span style="color:#D73A49">in</span><span style="color:#005CC5"> 2</span></span> -<span class="line"><span style="color:#24292E"> b</span></span> -<span class="line"><span style="color:#D73A49">in</span><span style="color:#005CC5"> 3</span></span> -<span class="line"><span style="color:#24292E"> c</span></span> -<span class="line"><span style="color:#D73A49">end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">case</span><span style="color:#24292E"> x</span></span> -<span class="line"><span style="color:#D73A49">in</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">; a</span></span> -<span class="line"><span style="color:#D73A49">in</span><span style="color:#005CC5"> 2</span><span style="color:#24292E">; b</span></span> -<span class="line"><span style="color:#D73A49">in</span><span style="color:#005CC5"> 3</span><span style="color:#24292E">; c</span></span> -<span class="line"><span style="color:#D73A49">end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">case</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> +<span style="color: #cf222e">in</span> <span style="color: #0550ae">1</span> <span style="color: #cf222e">then</span> <span style="color: #24292f;background-color: #f6f8fa">a</span> +<span style="color: #cf222e">in</span> <span style="color: #0550ae">2</span> <span style="color: #cf222e">then</span> <span style="color: #24292f;background-color: #f6f8fa">b</span> +<span style="color: #cf222e">in</span> <span style="color: #0550ae">3</span> <span style="color: #cf222e">then</span> <span style="color: #24292f;background-color: #f6f8fa">c</span> +<span style="color: #cf222e">end</span> + +<span style="color: #cf222e">case</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> +<span style="color: #cf222e">in</span> <span style="color: #0550ae">1</span> + <span style="color: #24292f;background-color: #f6f8fa">a</span> +<span style="color: #cf222e">in</span> <span style="color: #0550ae">2</span> + <span style="color: #24292f;background-color: #f6f8fa">b</span> +<span style="color: #cf222e">in</span> <span style="color: #0550ae">3</span> + <span style="color: #24292f;background-color: #f6f8fa">c</span> +<span style="color: #cf222e">end</span> + +<span style="color: #cf222e">case</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> +<span style="color: #cf222e">in</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">a</span> +<span style="color: #cf222e">in</span> <span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">b</span> +<span style="color: #cf222e">in</span> <span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">c</span> +<span style="color: #cf222e">end</span> +</code></pre> </div> <p> ところで、<code>p_top_expr</code> には <code>if</code> による guard clause が書けるので、その場合は <code>if</code> - <code>then</code> と似たような見た目になる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">case</span><span style="color:#24292E"> x</span></span> -<span class="line"><span style="color:#D73A49">in</span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> then</span><span style="color:#24292E"> a</span></span> -<span class="line"><span style="color:#D73A49">in</span><span style="color:#24292E"> n </span><span style="color:#D73A49">if</span><span style="color:#24292E"> n </span><span style="color:#D73A49"><</span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> then</span><span style="color:#24292E"> b</span></span> -<span class="line"><span style="color:#D73A49">in</span><span style="color:#24292E"> n </span><span style="color:#D73A49">then</span><span style="color:#24292E"> c</span></span> -<span class="line"><span style="color:#D73A49">end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">case</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> +<span style="color: #cf222e">in</span> <span style="color: #0550ae">0</span> <span style="color: #cf222e">then</span> <span style="color: #24292f;background-color: #f6f8fa">a</span> +<span style="color: #cf222e">in</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">0</span> <span style="color: #cf222e">then</span> <span style="color: #24292f;background-color: #f6f8fa">b</span> +<span style="color: #cf222e">in</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #cf222e">then</span> <span style="color: #24292f;background-color: #f6f8fa">c</span> +<span style="color: #cf222e">end</span> +</code></pre> </div> </section> <section id="section--outro"> diff --git a/services/nuldoc/public/blog/posts/2021-10-02/rust-where-are-primitive-types-from/index.html b/services/nuldoc/public/blog/posts/2021-10-02/rust-where-are-primitive-types-from/index.html index b0db3192..5cd23728 100644 --- a/services/nuldoc/public/blog/posts/2021-10-02/rust-where-are-primitive-types-from/index.html +++ b/services/nuldoc/public/blog/posts/2021-10-02/rust-where-are-primitive-types-from/index.html @@ -88,26 +88,27 @@ Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">#![allow(non_camel_case_types)]</span></span> -<span class="line"><span style="color:#24292E">#![allow(dead_code)]</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> bool</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> char</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> i8</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> i16</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> i32</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> i64</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> i128</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> isize</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> u8</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> u16</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> u32</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> u64</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> u128</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> usize</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> f32</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> f64</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> str</span><span style="color:#24292E">;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #8250df">#![allow(non_camel_case_types)]</span> +<span style="color: #8250df">#![allow(dead_code)]</span> + +<span style="color: #cf222e">struct</span> <span style="color: #953800">bool</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">char</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">i8</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">i16</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">i32</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">i64</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">i128</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">isize</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">u8</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">u16</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">u32</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">u64</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">u128</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">usize</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">f32</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">f64</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">struct</span> <span style="color: #953800">str</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +</code></pre> </div> <p> では、普段単に <code>bool</code> と書いたとき、この <code>bool</code> は一体どこから来ているのか。rustc のソースを追ってみた。 @@ -134,23 +135,25 @@ <code>rustc</code> はセルフホストされている (= <code>rustc</code> 自身が Rust で書かれている) ので、<code>bool</code> や <code>char</code> などで適当に検索をかけてもノイズが多すぎて話にならない。しかし、お誂え向きなことに <code>i128</code>/<code>u128</code> というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って <code>git grep</code> してみる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ git grep "\bi128\b" | wc # i128</span></span> -<span class="line"><span>165 1069 15790</span></span> -<span class="line"><span></span></span> -<span class="line"><span>$ git grep "\bu128\b" | wc # u128</span></span> -<span class="line"><span>293 2127 26667</span></span> -<span class="line"><span></span></span> -<span class="line"><span>$ git grep "\bbool\b" | wc # cf. bool の結果</span></span> -<span class="line"><span>3563 23577 294659</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ git grep "\bi128\b" | wc # i128 +165 1069 15790 + +$ git grep "\bu128\b" | wc # u128 +293 2127 26667 + +$ git grep "\bbool\b" | wc # cf. bool の結果 +3563 23577 294659 +</code></pre> </div> <p> 165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ git grep "\bi128\b"</span></span> -<span class="line"><span>...</span></span> -<span class="line"><span>rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));</span></span> -<span class="line"><span>...</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ git grep "\bi128\b" +... +rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128)); +... +</code></pre> </div> <p> <code>rustc_resolve</code> というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。 @@ -159,72 +162,75 @@ <div class="filename"> rustc_resolve/src/lib.rs </div> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">/// Interns the names of the primitive types.</span></span> -<span class="line"><span style="color:#6A737D">///</span></span> -<span class="line"><span style="color:#6A737D">/// All other types are defined somewhere and possibly imported, but the primitive ones need</span></span> -<span class="line"><span style="color:#6A737D">/// special handling, since they have no place of origin.</span></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> PrimitiveTypeTable</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> primitive_types</span><span style="color:#D73A49">:</span><span style="color:#6F42C1"> FxHashMap</span><span style="color:#24292E"><</span><span style="color:#6F42C1">Symbol</span><span style="color:#24292E">, </span><span style="color:#6F42C1">PrimTy</span><span style="color:#24292E">>,</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">impl</span><span style="color:#6F42C1"> PrimitiveTypeTable</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> fn</span><span style="color:#6F42C1"> new</span><span style="color:#24292E">() </span><span style="color:#D73A49">-></span><span style="color:#6F42C1"> PrimitiveTypeTable</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> let</span><span style="color:#D73A49"> mut</span><span style="color:#24292E"> table </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> FxHashMap</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">default</span><span style="color:#24292E">();</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">bool</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Bool</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">char</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Char</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">f32</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Float</span><span style="color:#24292E">(</span><span style="color:#6F42C1">FloatTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">F32</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">f64</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Float</span><span style="color:#24292E">(</span><span style="color:#6F42C1">FloatTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">F64</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">isize</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Int</span><span style="color:#24292E">(</span><span style="color:#6F42C1">IntTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">Isize</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">i8</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Int</span><span style="color:#24292E">(</span><span style="color:#6F42C1">IntTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">I8</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">i16</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Int</span><span style="color:#24292E">(</span><span style="color:#6F42C1">IntTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">I16</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">i32</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Int</span><span style="color:#24292E">(</span><span style="color:#6F42C1">IntTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">I32</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">i64</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Int</span><span style="color:#24292E">(</span><span style="color:#6F42C1">IntTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">I64</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">i128</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Int</span><span style="color:#24292E">(</span><span style="color:#6F42C1">IntTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">I128</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">str</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Str</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">usize</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Uint</span><span style="color:#24292E">(</span><span style="color:#6F42C1">UintTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">Usize</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">u8</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Uint</span><span style="color:#24292E">(</span><span style="color:#6F42C1">UintTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">U8</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">u16</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Uint</span><span style="color:#24292E">(</span><span style="color:#6F42C1">UintTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">U16</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">u32</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Uint</span><span style="color:#24292E">(</span><span style="color:#6F42C1">UintTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">U32</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">u64</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Uint</span><span style="color:#24292E">(</span><span style="color:#6F42C1">UintTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">U64</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E"> table</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">insert</span><span style="color:#24292E">(</span><span style="color:#6F42C1">sym</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">u128</span><span style="color:#24292E">, </span><span style="color:#6F42C1">Uint</span><span style="color:#24292E">(</span><span style="color:#6F42C1">UintTy</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">U128</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#005CC5"> Self</span><span style="color:#24292E"> { primitive_types</span><span style="color:#D73A49">:</span><span style="color:#24292E"> table }</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781">/// Interns the names of the primitive types.</span> +<span style="color: #6e7781">///</span> +<span style="color: #6e7781">/// All other types are defined somewhere and possibly imported, but the primitive ones need</span> +<span style="color: #6e7781">/// special handling, since they have no place of origin.</span> +<span style="color: #cf222e">struct</span> <span style="color: #24292f;background-color: #f6f8fa">PrimitiveTypeTable</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">primitive_types</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #24292f;background-color: #f6f8fa">FxHashMap</span><span style="color: #0550ae"><</span><span style="color: #24292f;background-color: #f6f8fa">Symbol</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">PrimTy</span><span style="color: #0550ae">></span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">impl</span> <span style="color: #24292f;background-color: #f6f8fa">PrimitiveTypeTable</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">fn</span> <span style="color: #8250df">new</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #cf222e">-></span> <span style="color: #24292f;background-color: #f6f8fa">PrimitiveTypeTable</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">let</span> <span style="color: #cf222e">mut</span> <span style="color: #24292f;background-color: #f6f8fa">table</span> <span style="color: #0550ae">=</span> <span style="color: #953800">FxHashMap</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #8250df">default</span><span style="color: #24292f;background-color: #f6f8fa">();</span> + + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">bool</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">Bool</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">char</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">Char</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">f32</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Float</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">FloatTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">F32</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">f64</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Float</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">FloatTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">F64</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">isize</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Int</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">IntTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">Isize</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">i8</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Int</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">IntTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">I8</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">i16</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Int</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">IntTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">I16</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">i32</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Int</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">IntTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">I32</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">i64</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Int</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">IntTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">I64</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">i128</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Int</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">IntTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">I128</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">str</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">Str</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">usize</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Uint</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">UintTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">Usize</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">u8</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Uint</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">UintTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">U8</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">u16</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Uint</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">UintTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">U16</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">u32</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Uint</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">UintTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">U32</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">u64</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Uint</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">UintTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">U64</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">table</span><span style="color: #8250df">.insert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">sym</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">u128</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #8250df">Uint</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">UintTy</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">U128</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #cf222e">Self</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> <span style="color: #24292f;background-color: #f6f8fa">primitive_types</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #24292f;background-color: #f6f8fa">table</span> <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>All other types are defined somewhere and possibly imported, but the</span></span> -<span class="line"><span>primitive ones need special handling, since they have no place of</span></span> -<span class="line"><span>origin.</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>All other types are defined somewhere and possibly imported, but the +primitive ones need special handling, since they have no place of +origin. +</code></pre> </div> <p> とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.</span></span> -<span class="line"><span style="color:#6A737D">/// (略)</span></span> -<span class="line"><span style="color:#D73A49">fn</span><span style="color:#6F42C1"> resolve_ident_in_lexical_scope</span><span style="color:#24292E">(</span></span> -<span class="line"><span style="color:#D73A49"> &mut</span><span style="color:#005CC5"> self</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#D73A49"> mut</span><span style="color:#24292E"> ident</span><span style="color:#D73A49">:</span><span style="color:#6F42C1"> Ident</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> ns</span><span style="color:#D73A49">:</span><span style="color:#6F42C1"> Namespace</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#6A737D"> // (略)</span></span> -<span class="line"><span style="color:#24292E">) </span><span style="color:#D73A49">-></span><span style="color:#6F42C1"> Option</span><span style="color:#24292E"><</span><span style="color:#6F42C1">LexicalScopeBinding</span><span style="color:#24292E"><'</span><span style="color:#6F42C1">a</span><span style="color:#24292E">>> {</span></span> -<span class="line"><span style="color:#6A737D"> // (略)</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> ns </span><span style="color:#D73A49">==</span><span style="color:#6F42C1"> TypeNS</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> let</span><span style="color:#6F42C1"> Some</span><span style="color:#24292E">(prim_ty) </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> self</span><span style="color:#D73A49">.</span><span style="color:#24292E">primitive_type_table</span><span style="color:#D73A49">.</span><span style="color:#24292E">primitive_types</span><span style="color:#D73A49">.</span><span style="color:#6F42C1">get</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">ident</span><span style="color:#D73A49">.</span><span style="color:#24292E">name) {</span></span> -<span class="line"><span style="color:#D73A49"> let</span><span style="color:#24292E"> binding </span><span style="color:#D73A49">=</span></span> -<span class="line"><span style="color:#24292E"> (</span><span style="color:#6F42C1">Res</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">PrimTy</span><span style="color:#24292E">(</span><span style="color:#D73A49">*</span><span style="color:#24292E">prim_ty), </span><span style="color:#6F42C1">ty</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">Visibility</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">Public</span><span style="color:#24292E">, </span><span style="color:#005CC5">DUMMY_SP</span><span style="color:#24292E">, </span><span style="color:#6F42C1">ExpnId</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">root</span><span style="color:#24292E">())</span></span> -<span class="line"><span style="color:#D73A49"> .</span><span style="color:#6F42C1">to_name_binding</span><span style="color:#24292E">(</span><span style="color:#005CC5">self</span><span style="color:#D73A49">.</span><span style="color:#24292E">arenas);</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#6F42C1"> Some</span><span style="color:#24292E">(</span><span style="color:#6F42C1">LexicalScopeBinding</span><span style="color:#D73A49">::</span><span style="color:#6F42C1">Item</span><span style="color:#24292E">(binding));</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> None</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781">/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.</span> +<span style="color: #6e7781">/// (略)</span> +<span style="color: #cf222e">fn</span> <span style="color: #8250df">resolve_ident_in_lexical_scope</span><span style="color: #24292f;background-color: #f6f8fa">(</span> + <span style="color: #0550ae">&</span><span style="color: #cf222e">mut</span> <span style="color: #cf222e">self</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #cf222e">mut</span> <span style="color: #24292f;background-color: #f6f8fa">ident</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #24292f;background-color: #f6f8fa">Ident</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">ns</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #24292f;background-color: #f6f8fa">Namespace</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #6e7781">// (略)</span> +<span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">-></span> <span style="color: #953800">Option</span><span style="color: #0550ae"><</span><span style="color: #24292f;background-color: #f6f8fa">LexicalScopeBinding</span><span style="color: #0550ae"><</span><span style="color: #0550ae">'a</span><span style="color: #0550ae">>></span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #6e7781">// (略)</span> + + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">ns</span> <span style="color: #0550ae">==</span> <span style="color: #24292f;background-color: #f6f8fa">TypeNS</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">if</span> <span style="color: #cf222e">let</span> <span style="color: #8250df">Some</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">prim_ty</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">self</span><span style="color: #0550ae">.primitive_type_table.primitive_types</span><span style="color: #8250df">.get</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">ident</span><span style="color: #0550ae">.name</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">let</span> <span style="color: #24292f;background-color: #f6f8fa">binding</span> <span style="color: #0550ae">=</span> + <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">Res</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #8250df">PrimTy</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">*</span><span style="color: #24292f;background-color: #f6f8fa">prim_ty</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #953800">ty</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #953800">Visibility</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #24292f;background-color: #f6f8fa">Public</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">DUMMY_SP</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">ExpnId</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #8250df">root</span><span style="color: #24292f;background-color: #f6f8fa">())</span> + <span style="color: #8250df">.to_name_binding</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">self</span><span style="color: #0550ae">.arenas</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #cf222e">return</span> <span style="color: #8250df">Some</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">LexicalScopeBinding</span><span style="color: #24292f;background-color: #f6f8fa">::</span><span style="color: #8250df">Item</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">binding</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + + <span style="color: #953800">None</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> 関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。<code>if ns == TypeNS</code> のブロック内では、<code>primitive_type_table</code> (上記の <code>PrimitiveTypeTable::new()</code> で作られた変数) に含まれている識別子 (<code>bool</code>、<code>i32</code> など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。 @@ -239,13 +245,14 @@ 動作がわかったところで、例として次のコードを考える。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">#![allow(non_camel_case_types)]</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">struct</span><span style="color:#6F42C1"> bool</span><span style="color:#24292E">;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">fn</span><span style="color:#6F42C1"> main</span><span style="color:#24292E">() {</span></span> -<span class="line"><span style="color:#D73A49"> let</span><span style="color:#24292E"> _</span><span style="color:#D73A49">:</span><span style="color:#6F42C1"> bool</span><span style="color:#D73A49"> =</span><span style="color:#6F42C1"> bool</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #8250df">#![allow(non_camel_case_types)]</span> + +<span style="color: #cf222e">struct</span> <span style="color: #953800">bool</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + +<span style="color: #cf222e">fn</span> <span style="color: #8250df">main</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">let</span> <span style="color: #24292f;background-color: #f6f8fa">_</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #953800">bool</span> <span style="color: #0550ae">=</span> <span style="color: #953800">bool</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> ここで <code>main()</code> の <code>bool</code> は <code>struct bool</code> として解決される。なぜなら、プリミティブ型の判定をする前に <code>bool</code> という名前の別の型が見つかるからだ。 diff --git a/services/nuldoc/public/blog/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html b/services/nuldoc/public/blog/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html index cafadae1..275086e6 100644 --- a/services/nuldoc/public/blog/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html +++ b/services/nuldoc/public/blog/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html @@ -146,8 +146,9 @@ <div class="filename"> src/autocmd.c </div> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">{</span><span style="color:#032F62">"BufAdd"</span><span style="color:#24292E">, EVENT_BUFADD},</span></span> -<span class="line"><span style="color:#24292E">{</span><span style="color:#032F62">"BufCreate"</span><span style="color:#24292E">, EVENT_BUFADD},</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #0a3069">"BufAdd"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">EVENT_BUFADD</span><span style="color: #24292f;background-color: #f6f8fa">},</span> +<span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #0a3069">"BufCreate"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">EVENT_BUFADD</span><span style="color: #24292f;background-color: #f6f8fa">},</span> +</code></pre> </div> <p> <a class="url" href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97" rel="noreferrer" target="_blank">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97</a> @@ -156,9 +157,10 @@ <div class="filename"> src/autocmd.c </div> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">{</span><span style="color:#032F62">"BufRead"</span><span style="color:#24292E">, EVENT_BUFREADPOST},</span></span> -<span class="line"><span style="color:#24292E">{</span><span style="color:#032F62">"BufReadCmd"</span><span style="color:#24292E">, EVENT_BUFREADCMD},</span></span> -<span class="line"><span style="color:#24292E">{</span><span style="color:#032F62">"BufReadPost"</span><span style="color:#24292E">, EVENT_BUFREADPOST},</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #0a3069">"BufRead"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">EVENT_BUFREADPOST</span><span style="color: #24292f;background-color: #f6f8fa">},</span> +<span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #0a3069">"BufReadCmd"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">EVENT_BUFREADCMD</span><span style="color: #24292f;background-color: #f6f8fa">},</span> +<span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #0a3069">"BufReadPost"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">EVENT_BUFREADPOST</span><span style="color: #24292f;background-color: #f6f8fa">},</span> +</code></pre> </div> <p> <a class="url" href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105" rel="noreferrer" target="_blank">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105</a> @@ -167,9 +169,10 @@ <div class="filename"> src/autocmd.c </div> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">{</span><span style="color:#032F62">"BufWrite"</span><span style="color:#24292E">, EVENT_BUFWRITEPRE},</span></span> -<span class="line"><span style="color:#24292E">{</span><span style="color:#032F62">"BufWritePost"</span><span style="color:#24292E">, EVENT_BUFWRITEPOST},</span></span> -<span class="line"><span style="color:#24292E">{</span><span style="color:#032F62">"BufWritePre"</span><span style="color:#24292E">, EVENT_BUFWRITEPRE},</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #0a3069">"BufWrite"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">EVENT_BUFWRITEPRE</span><span style="color: #24292f;background-color: #f6f8fa">},</span> +<span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #0a3069">"BufWritePost"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">EVENT_BUFWRITEPOST</span><span style="color: #24292f;background-color: #f6f8fa">},</span> +<span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #0a3069">"BufWritePre"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">EVENT_BUFWRITEPRE</span><span style="color: #24292f;background-color: #f6f8fa">},</span> +</code></pre> </div> </section> <section id="section--code-reading--neovim"> @@ -184,12 +187,13 @@ <div class="filename"> src/nvim/auevents.lua </div> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">aliases </span><span style="color:#D73A49">=</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> BufCreate </span><span style="color:#D73A49">=</span><span style="color:#032F62"> 'BufAdd'</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> BufRead </span><span style="color:#D73A49">=</span><span style="color:#032F62"> 'BufReadPost'</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> BufWrite </span><span style="color:#D73A49">=</span><span style="color:#032F62"> 'BufWritePre'</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> FileEncoding </span><span style="color:#D73A49">=</span><span style="color:#032F62"> 'EncodingChanged'</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E">},</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">aliases</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">BufCreate</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">'BufAdd'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">BufRead</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">'BufReadPost'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">BufWrite</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">'BufWritePre'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">FileEncoding</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">'EncodingChanged'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #24292f;background-color: #f6f8fa">},</span> +</code></pre> </div> <p> ところで、上では取り上げなかった <code>FileEncoding</code> だが、これは <code>:help FileEncoding</code> にしっかりと書いてある。 @@ -198,9 +202,10 @@ <div class="filename"> :help FileEncoding </div> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span> *FileEncoding*</span></span> -<span class="line"><span>FileEncoding Obsolete. It still works and is equivalent</span></span> -<span class="line"><span> to |EncodingChanged|.</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code> *FileEncoding* +FileEncoding Obsolete. It still works and is equivalent + to |EncodingChanged|. +</code></pre> </div> </section> </section> diff --git a/services/nuldoc/public/blog/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html b/services/nuldoc/public/blog/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html index ddc23f90..92b7a7df 100644 --- a/services/nuldoc/public/blog/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html +++ b/services/nuldoc/public/blog/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html @@ -102,11 +102,12 @@ <section id="section--tl-dr"> <h2><a href="#section--tl-dr">TL; DR</a></h2> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">" License: Public Domain</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">command!</span><span style="color:#24292E"> -bar -</span><span style="color:#D73A49">range=</span><span style="color:#24292E">%</span></span> -<span class="line"><span style="color:#D73A49"> \</span><span style="color:#24292E"> Reverse</span></span> -<span class="line"><span style="color:#D73A49"> \</span><span style="color:#24292E"> keeppatterns <line1>,<line2>g</span><span style="color:#032F62">/^/</span><span style="color:#24292E">m<line1>-</span><span style="color:#005CC5">1</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781">" License: Public Domain</span> + +command<span style="color: #24292f;background-color: #f6f8fa">!</span> <span style="color: #24292f;background-color: #f6f8fa">-</span>bar <span style="color: #24292f;background-color: #f6f8fa">-</span><span style="color: #953800">range</span><span style="color: #24292f;background-color: #f6f8fa">=</span>% +<span style="color: #0a3069"> \</span> Reverse +<span style="color: #0a3069"> \</span> <span style="color: #cf222e">keeppatterns</span> <span style="color: #24292f;background-color: #f6f8fa"><</span>line1<span style="color: #24292f;background-color: #f6f8fa">>,<</span>line2<span style="color: #24292f;background-color: #f6f8fa">></span><span style="color: #cf222e">g</span><span style="color: #116329">/^/</span><span style="color: #cf222e">m</span><span style="color: #24292f;background-color: #f6f8fa"><</span>line1<span style="color: #24292f;background-color: #f6f8fa">></span><span style="color: #0550ae">-1</span> +</code></pre> </div> </section> <section id="section--version"> @@ -164,9 +165,10 @@ なお、<code>:g/^/m0</code> は全ての行を入れ替えるが、<code>:N,Mg/^/mN-1</code> とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">command!</span><span style="color:#24292E"> -bar -</span><span style="color:#D73A49">range=</span><span style="color:#24292E">%</span></span> -<span class="line"><span style="color:#D73A49"> \</span><span style="color:#24292E"> Reverse</span></span> -<span class="line"><span style="color:#D73A49"> \</span><span style="color:#24292E"> <line1>,<line2>g</span><span style="color:#032F62">/^/</span><span style="color:#24292E">m<line1>-</span><span style="color:#005CC5">1</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>command<span style="color: #24292f;background-color: #f6f8fa">!</span> <span style="color: #24292f;background-color: #f6f8fa">-</span>bar <span style="color: #24292f;background-color: #f6f8fa">-</span><span style="color: #953800">range</span><span style="color: #24292f;background-color: #f6f8fa">=</span>% +<span style="color: #0a3069"> \</span> Reverse +<span style="color: #0a3069"> \</span> <span style="color: #24292f;background-color: #f6f8fa"><</span>line1<span style="color: #24292f;background-color: #f6f8fa">>,<</span>line2<span style="color: #24292f;background-color: #f6f8fa">></span><span style="color: #cf222e">g</span><span style="color: #116329">/^/</span><span style="color: #cf222e">m</span><span style="color: #24292f;background-color: #f6f8fa"><</span>line1<span style="color: #24292f;background-color: #f6f8fa">></span><span style="color: #0550ae">-1</span> +</code></pre> </div> <p> これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。 @@ -200,13 +202,14 @@ 前述した <code>:Reverse</code> コマンドの定義を少し変えて、次のようにする: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">function!</span><span style="color:#6F42C1"> s:reverse_lines</span><span style="color:#24292E">(from, </span><span style="color:#005CC5">to</span><span style="color:#24292E">) </span><span style="color:#D73A49">abort</span></span> -<span class="line"><span style="color:#005CC5"> execute</span><span style="color:#6F42C1"> printf</span><span style="color:#24292E">(</span><span style="color:#032F62">"%d,%dg/^/m%d"</span><span style="color:#24292E">, a:from, a:to, a:from</span><span style="color:#D73A49"> - </span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49">endfunction</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">command!</span><span style="color:#24292E"> -bar -</span><span style="color:#D73A49">range=</span><span style="color:#24292E">%</span></span> -<span class="line"><span style="color:#D73A49"> \</span><span style="color:#24292E"> Reverse</span></span> -<span class="line"><span style="color:#D73A49"> \</span><span style="color:#D73A49"> call</span><span style="color:#24292E"> <</span><span style="color:#005CC5">SID</span><span style="color:#24292E">></span><span style="color:#6F42C1">reverse_lines</span><span style="color:#24292E">(<line1>, <line2>)</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">function</span><span style="color: #24292f;background-color: #f6f8fa">!</span> <span style="color: #0550ae">s:reverse_lines</span><span style="color: #24292f;background-color: #f6f8fa">(</span>from<span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">to</span><span style="color: #24292f;background-color: #f6f8fa">)</span> abort + <span style="color: #953800">execute</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"%d,%dg/^/m%d"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">a:from</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">a:to</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">a:from</span> <span style="color: #24292f;background-color: #f6f8fa">-</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #cf222e">endfunction</span> + +command<span style="color: #24292f;background-color: #f6f8fa">!</span> <span style="color: #24292f;background-color: #f6f8fa">-</span>bar <span style="color: #24292f;background-color: #f6f8fa">-</span><span style="color: #953800">range</span><span style="color: #24292f;background-color: #f6f8fa">=</span>% +<span style="color: #0a3069"> \</span> Reverse +<span style="color: #0a3069"> \</span> <span style="color: #cf222e">call</span> <span style="color: #24292f;background-color: #f6f8fa"><</span>SID<span style="color: #24292f;background-color: #f6f8fa">></span>reverse_lines<span style="color: #24292f;background-color: #f6f8fa">(<</span>line1<span style="color: #24292f;background-color: #f6f8fa">>,</span> <span style="color: #24292f;background-color: #f6f8fa"><</span>line2<span style="color: #24292f;background-color: #f6f8fa">>)</span> +</code></pre> </div> <p> 実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。 @@ -253,9 +256,10 @@ </div> </div> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">command!</span><span style="color:#24292E"> -bar -</span><span style="color:#D73A49">range=</span><span style="color:#24292E">%</span></span> -<span class="line"><span style="color:#D73A49"> \</span><span style="color:#24292E"> Reverse</span></span> -<span class="line"><span style="color:#D73A49"> \</span><span style="color:#24292E"> keeppatterns <line1>,<line2>g</span><span style="color:#032F62">/^/</span><span style="color:#24292E">m<line1>-</span><span style="color:#005CC5">1</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>command<span style="color: #24292f;background-color: #f6f8fa">!</span> <span style="color: #24292f;background-color: #f6f8fa">-</span>bar <span style="color: #24292f;background-color: #f6f8fa">-</span><span style="color: #953800">range</span><span style="color: #24292f;background-color: #f6f8fa">=</span>% +<span style="color: #0a3069"> \</span> Reverse +<span style="color: #0a3069"> \</span> <span style="color: #cf222e">keeppatterns</span> <span style="color: #24292f;background-color: #f6f8fa"><</span>line1<span style="color: #24292f;background-color: #f6f8fa">>,<</span>line2<span style="color: #24292f;background-color: #f6f8fa">></span><span style="color: #cf222e">g</span><span style="color: #116329">/^/</span><span style="color: #cf222e">m</span><span style="color: #24292f;background-color: #f6f8fa"><</span>line1<span style="color: #24292f;background-color: #f6f8fa">></span><span style="color: #0550ae">-1</span> +</code></pre> </div> <p> まさにこのための Exコマンド、<code>:keeppatterns</code> が存在する。<code>:keeppatterns {command}</code> のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。 diff --git a/services/nuldoc/public/blog/posts/2022-04-09/phperkaigi-2022-tokens/index.html b/services/nuldoc/public/blog/posts/2022-04-09/phperkaigi-2022-tokens/index.html index b3637d00..c5404c5e 100644 --- a/services/nuldoc/public/blog/posts/2022-04-09/phperkaigi-2022-tokens/index.html +++ b/services/nuldoc/public/blog/posts/2022-04-09/phperkaigi-2022-tokens/index.html @@ -166,75 +166,76 @@ <div class="filename"> brainf_ck.php </div> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">declare</span><span style="color:#24292E">(</span><span style="color:#005CC5">strict_types</span><span style="color:#D73A49">=</span><span style="color:#005CC5">0O1</span><span style="color:#24292E">);</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">namespace</span><span style="color:#6F42C1"> Dgcircus\PHPerKaigi\Y2022</span><span style="color:#24292E">;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D">/**</span></span> -<span class="line"><span style="color:#6A737D"> * </span><span style="color:#D73A49">@todo</span></span> -<span class="line"><span style="color:#6A737D"> * Run this program to acquire a PHPer token.</span></span> -<span class="line"><span style="color:#6A737D"> */</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5">https</span><span style="color:#D73A49">:</span><span style="color:#6A737D">//creativecommons.org/publicdomain/zero/1.0/</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5">\error_reporting</span><span style="color:#24292E">(</span><span style="color:#D73A49">~+!</span><span style="color:#032F62">'We are hiring!'</span><span style="color:#24292E">);</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$z </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> fn</span><span style="color:#24292E">($f) => (</span><span style="color:#D73A49">fn</span><span style="color:#24292E">($x) => $f(</span><span style="color:#D73A49">fn</span><span style="color:#24292E">(</span><span style="color:#D73A49">...</span><span style="color:#24292E">$xs) => $x($x)(</span><span style="color:#D73A49">...</span><span style="color:#24292E">$xs)))(</span><span style="color:#D73A49">fn</span><span style="color:#24292E">($x) => $f(</span><span style="color:#D73A49">fn</span><span style="color:#24292E">(</span><span style="color:#D73A49">...</span><span style="color:#24292E">$xs) => $x($x)(</span><span style="color:#D73A49">...</span><span style="color:#24292E">$xs)));</span></span> -<span class="line"><span style="color:#24292E">$id </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> \</span><span style="color:#6F42C1">spl_object_id</span><span style="color:#24292E">(</span><span style="color:#D73A49">...</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E">$put </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> fn</span><span style="color:#24292E">($c) => </span><span style="color:#005CC5">\</span><span style="color:#005CC5">printf</span><span style="color:#24292E">(</span><span style="color:#032F62">'%c'</span><span style="color:#24292E">, $c);</span></span> -<span class="line"><span style="color:#24292E">$mm </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> fn</span><span style="color:#24292E">($p, $n) => </span><span style="color:#D73A49">new</span><span style="color:#005CC5"> \ArrayObject</span><span style="color:#24292E">(</span><span style="color:#005CC5">\array_fill</span><span style="color:#24292E">(</span><span style="color:#D73A49">+!!</span><span style="color:#24292E">[], $n, $p));</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$👉 </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> fn</span><span style="color:#24292E">($m, $p, $b, $e, $mp, $pc) => [</span><span style="color:#D73A49">++</span><span style="color:#24292E">$mp, </span><span style="color:#D73A49">++</span><span style="color:#24292E">$pc];</span></span> -<span class="line"><span style="color:#24292E">$👈 </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> fn</span><span style="color:#24292E">($m, $p, $b, $e, $mp, $pc) => [</span><span style="color:#D73A49">--</span><span style="color:#24292E">$mp, </span><span style="color:#D73A49">++</span><span style="color:#24292E">$pc];</span></span> -<span class="line"><span style="color:#24292E">$👍 </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> fn</span><span style="color:#24292E">($m, $p, $b, $e, $mp, $pc) => [$mp, </span><span style="color:#D73A49">++</span><span style="color:#24292E">$pc, </span><span style="color:#D73A49">++</span><span style="color:#24292E">$m[$mp]];</span></span> -<span class="line"><span style="color:#24292E">$👎 </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> fn</span><span style="color:#24292E">($m, $p, $b, $e, $mp, $pc) => [$mp, </span><span style="color:#D73A49">++</span><span style="color:#24292E">$pc, </span><span style="color:#D73A49">--</span><span style="color:#24292E">$m[$mp]];</span></span> -<span class="line"><span style="color:#24292E">$📝 </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> fn</span><span style="color:#24292E">($m, $p, $b, $e, $mp, $pc) => [$mp, </span><span style="color:#D73A49">++</span><span style="color:#24292E">$pc, $put($m[$mp])];</span></span> -<span class="line"><span style="color:#24292E">$🤡 </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> fn</span><span style="color:#24292E">($m, $p, $b, $e, $mp, $pc) => </span><span style="color:#D73A49">match</span><span style="color:#24292E"> ($m[$mp]) {</span></span> -<span class="line"><span style="color:#D73A49"> +!!</span><span style="color:#24292E">[] </span><span style="color:#D73A49">=></span><span style="color:#24292E"> [$mp, $z(</span><span style="color:#D73A49">fn</span><span style="color:#24292E">($loop) => </span><span style="color:#D73A49">fn</span><span style="color:#24292E">($pc, $n) => </span><span style="color:#D73A49">match</span><span style="color:#24292E"> ($id($p[$pc])) {</span></span> -<span class="line"><span style="color:#24292E"> $b </span><span style="color:#D73A49">=></span><span style="color:#24292E"> $loop(</span><span style="color:#D73A49">++</span><span style="color:#24292E">$pc, </span><span style="color:#D73A49">++</span><span style="color:#24292E">$n),</span></span> -<span class="line"><span style="color:#24292E"> $e </span><span style="color:#D73A49">=></span><span style="color:#24292E"> $n </span><span style="color:#D73A49">===</span><span style="color:#D73A49"> +!!</span><span style="color:#24292E">[] </span><span style="color:#D73A49">?</span><span style="color:#D73A49"> ++</span><span style="color:#24292E">$pc </span><span style="color:#D73A49">:</span><span style="color:#24292E"> $loop(</span><span style="color:#D73A49">++</span><span style="color:#24292E">$pc, </span><span style="color:#D73A49">--</span><span style="color:#24292E">$n),</span></span> -<span class="line"><span style="color:#D73A49"> default</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $loop(</span><span style="color:#D73A49">++</span><span style="color:#24292E">$pc, $n),</span></span> -<span class="line"><span style="color:#24292E"> })($pc, </span><span style="color:#D73A49">-!</span><span style="color:#24292E">[])],</span></span> -<span class="line"><span style="color:#D73A49"> default</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> [$mp, </span><span style="color:#D73A49">++</span><span style="color:#24292E">$pc],</span></span> -<span class="line"><span style="color:#24292E">};</span></span> -<span class="line"><span style="color:#24292E">$🎪 </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> fn</span><span style="color:#24292E">($m, $p, $b, $e, $mp, $pc) => </span><span style="color:#D73A49">match</span><span style="color:#24292E"> ($m[$mp]) {</span></span> -<span class="line"><span style="color:#D73A49"> +!!</span><span style="color:#24292E">[] </span><span style="color:#D73A49">=></span><span style="color:#24292E"> [$mp, </span><span style="color:#D73A49">++</span><span style="color:#24292E">$pc],</span></span> -<span class="line"><span style="color:#D73A49"> default</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> [$mp, $z(</span><span style="color:#D73A49">fn</span><span style="color:#24292E">($loop) => </span><span style="color:#D73A49">fn</span><span style="color:#24292E">($pc, $n) => </span><span style="color:#D73A49">match</span><span style="color:#24292E"> ($id($p[$pc])) {</span></span> -<span class="line"><span style="color:#24292E"> $e </span><span style="color:#D73A49">=></span><span style="color:#24292E"> $loop(</span><span style="color:#D73A49">--</span><span style="color:#24292E">$pc, </span><span style="color:#D73A49">++</span><span style="color:#24292E">$n),</span></span> -<span class="line"><span style="color:#24292E"> $b </span><span style="color:#D73A49">=></span><span style="color:#24292E"> $n </span><span style="color:#D73A49">===</span><span style="color:#D73A49"> +!!</span><span style="color:#24292E">[] </span><span style="color:#D73A49">?</span><span style="color:#24292E"> $pc</span><span style="color:#D73A49">+!</span><span style="color:#24292E">[] </span><span style="color:#D73A49">:</span><span style="color:#24292E"> $loop(</span><span style="color:#D73A49">--</span><span style="color:#24292E">$pc, </span><span style="color:#D73A49">--</span><span style="color:#24292E">$n),</span></span> -<span class="line"><span style="color:#D73A49"> default</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $loop(</span><span style="color:#D73A49">--</span><span style="color:#24292E">$pc, $n),</span></span> -<span class="line"><span style="color:#24292E"> })($pc, </span><span style="color:#D73A49">-!</span><span style="color:#24292E">[])],</span></span> -<span class="line"><span style="color:#24292E">};</span></span> -<span class="line"><span style="color:#24292E">$🐘 </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> fn</span><span style="color:#24292E">($p) => $z(</span><span style="color:#D73A49">fn</span><span style="color:#24292E">($loop) => </span><span style="color:#D73A49">fn</span><span style="color:#24292E">($m, $p, $b, $e, $mp, $pc) =></span></span> -<span class="line"><span style="color:#005CC5"> isset</span><span style="color:#24292E">($p[$pc]) </span><span style="color:#D73A49">&&</span><span style="color:#24292E"> $loop($m, $p, $b, $e, </span><span style="color:#D73A49">...</span><span style="color:#24292E">($p[$pc]($m, $p, $b, $e, $mp, $pc)))</span></span> -<span class="line"><span style="color:#24292E">)($mm(</span><span style="color:#D73A49">+!!</span><span style="color:#24292E">[], </span><span style="color:#D73A49">+</span><span style="color:#24292E">(</span><span style="color:#D73A49">!</span><span style="color:#24292E">[]</span><span style="color:#D73A49">.</span><span style="color:#D73A49">!</span><span style="color:#24292E">[])), $p, $id($🤡), $id($🎪), </span><span style="color:#D73A49">+!!</span><span style="color:#24292E">[], </span><span style="color:#D73A49">+!!</span><span style="color:#24292E">[]);</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$🐘([</span></span> -<span class="line"><span style="color:#24292E"> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,</span></span> -<span class="line"><span style="color:#24292E"> $🤡,</span></span> -<span class="line"><span style="color:#24292E"> $👉, $👍, $👍, $👍,</span></span> -<span class="line"><span style="color:#24292E"> $👉, $👍, $👍, $👍, $👍, $👍,</span></span> -<span class="line"><span style="color:#24292E"> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,</span></span> -<span class="line"><span style="color:#24292E"> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,</span></span> -<span class="line"><span style="color:#24292E"> $👈, $👈, $👈, $👈, $👎,</span></span> -<span class="line"><span style="color:#24292E"> $🎪,</span></span> -<span class="line"><span style="color:#24292E"> $👉, $👍, $👍, $👍, $👍, $👍, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👎, $👎, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👉, $👎, $👎, $👎, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👉, $👎, $👎, $👎, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👎, $👎, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👎, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👈, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👉, $👉, $👎, $👎, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👈, $👎, $👎, $👎, $👎, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👈, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👉, $👍, $👍, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👉, $👎, $📝,</span></span> -<span class="line"><span style="color:#24292E"> $👈, $📝,</span></span> -<span class="line"><span style="color:#24292E">]);</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #cf222e">declare</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">strict_types</span><span style="color: #0550ae">=</span><span style="color: #0550ae">0O1</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + +<span style="color: #cf222e">namespace</span> <span style="color: #953800">Dgcircus\PHPerKaigi\Y2022</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + +<span style="color: #6e7781">/** + * @todo + * Run this program to acquire a PHPer token. + */</span> + +<span style="color: #24292f;background-color: #f6f8fa">https</span><span style="color: #0550ae">://</span><span style="color: #24292f;background-color: #f6f8fa">creativecommons</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">org</span><span style="color: #0550ae">/</span><span style="color: #24292f;background-color: #f6f8fa">publicdomain</span><span style="color: #0550ae">/</span><span style="color: #24292f;background-color: #f6f8fa">zero</span><span style="color: #0550ae">/</span><span style="color: #0550ae">1.0</span><span style="color: #0550ae">/</span> + +<span style="color: #8250df">\error_reporting</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">~+!</span><span style="color: #0a3069">'We are hiring!'</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + +<span style="color: #0550ae">$z</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$f</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$f</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(...</span><span style="color: #0550ae">$xs</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)(</span><span style="color: #0550ae">...</span><span style="color: #0550ae">$xs</span><span style="color: #24292f;background-color: #f6f8fa">)))(</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$f</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(...</span><span style="color: #0550ae">$xs</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)(</span><span style="color: #0550ae">...</span><span style="color: #0550ae">$xs</span><span style="color: #24292f;background-color: #f6f8fa">)));</span> +<span style="color: #0550ae">$id</span> <span style="color: #0550ae">=</span> <span style="color: #8250df">\spl_object_id</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">...</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #0550ae">$put</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$c</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #8250df">\printf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'%c'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$c</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #0550ae">$mm</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #cf222e">new</span> <span style="color: #953800">\ArrayObject</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #8250df">\array_fill</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">+!!</span><span style="color: #24292f;background-color: #f6f8fa">[],</span> <span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + +<span style="color: #f6f8fa;background-color: #82071e">$👉</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">++</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">++</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">];</span> +<span style="color: #f6f8fa;background-color: #82071e">$👈</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">--</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">++</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">];</span> +<span style="color: #f6f8fa;background-color: #82071e">$👍</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">++</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">++</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">]];</span> +<span style="color: #f6f8fa;background-color: #82071e">$👎</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">++</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">--</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">]];</span> +<span style="color: #f6f8fa;background-color: #82071e">$📝</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">++</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$put</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">])];</span> +<span style="color: #f6f8fa;background-color: #82071e">$🤡</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #cf222e">match</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">])</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">+!!</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">=></span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$z</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$loop</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #cf222e">match</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$id</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">]))</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">$b</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$loop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">++</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">++</span><span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">),</span> + <span style="color: #0550ae">$e</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$n</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">+!!</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">?</span> <span style="color: #0550ae">++</span><span style="color: #0550ae">$pc</span> <span style="color: #0550ae">:</span> <span style="color: #0550ae">$loop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">++</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">--</span><span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">),</span> + <span style="color: #cf222e">default</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$loop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">++</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">),</span> + <span style="color: #24292f;background-color: #f6f8fa">})(</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">-!</span><span style="color: #24292f;background-color: #f6f8fa">[])],</span> + <span style="color: #cf222e">default</span> <span style="color: #0550ae">=></span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">++</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">],</span> +<span style="color: #24292f;background-color: #f6f8fa">};</span> +<span style="color: #f6f8fa;background-color: #82071e">$🎪</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #cf222e">match</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">])</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">+!!</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">=></span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">++</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">],</span> + <span style="color: #cf222e">default</span> <span style="color: #0550ae">=></span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$z</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$loop</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #cf222e">match</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$id</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">]))</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">$e</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$loop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">--</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">++</span><span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">),</span> + <span style="color: #0550ae">$b</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$n</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">+!!</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">?</span> <span style="color: #0550ae">$pc</span><span style="color: #0550ae">+!</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">:</span> <span style="color: #0550ae">$loop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">--</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">--</span><span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">),</span> + <span style="color: #cf222e">default</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$loop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">--</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">),</span> + <span style="color: #24292f;background-color: #f6f8fa">})(</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">-!</span><span style="color: #24292f;background-color: #f6f8fa">[])],</span> +<span style="color: #24292f;background-color: #f6f8fa">};</span> +<span style="color: #f6f8fa;background-color: #82071e">$🐘</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$z</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$loop</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> + <span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">])</span> <span style="color: #0550ae">&&</span> <span style="color: #0550ae">$loop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">...</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">](</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$mp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">)))</span> +<span style="color: #24292f;background-color: #f6f8fa">)(</span><span style="color: #0550ae">$mm</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">+!!</span><span style="color: #24292f;background-color: #f6f8fa">[],</span> <span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">!</span><span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #0550ae">.</span><span style="color: #0550ae">!</span><span style="color: #24292f;background-color: #f6f8fa">[])),</span> <span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$id</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #f6f8fa;background-color: #82071e">$🤡</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #0550ae">$id</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #f6f8fa;background-color: #82071e">$🎪</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #0550ae">+!!</span><span style="color: #24292f;background-color: #f6f8fa">[],</span> <span style="color: #0550ae">+!!</span><span style="color: #24292f;background-color: #f6f8fa">[]);</span> + +<span style="color: #f6f8fa;background-color: #82071e">$🐘</span><span style="color: #24292f;background-color: #f6f8fa">([</span> + <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$🤡</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👉</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👉</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👉</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👉</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👈</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👈</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👈</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👈</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$🎪</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👉</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👉</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👉</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👈</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👉</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👉</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👈</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👈</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👉</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👍</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👉</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$👎</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #f6f8fa;background-color: #82071e">$👈</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #f6f8fa;background-color: #82071e">$📝</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #24292f;background-color: #f6f8fa">]);</span> +</code></pre> </div> <p> この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。 @@ -259,28 +260,29 @@ なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>+ + + + + + + + + +</span></span> -<span class="line"><span>[</span></span> -<span class="line"><span> > + + +</span></span> -<span class="line"><span> > + + + + +</span></span> -<span class="line"><span> > + + + + + + + + + + + +</span></span> -<span class="line"><span> > + + + + + + + + + +</span></span> -<span class="line"><span> < < < < -</span></span> -<span class="line"><span>]</span></span> -<span class="line"><span>> + + + + + .</span></span> -<span class="line"><span>- - .</span></span> -<span class="line"><span>> - - - .</span></span> -<span class="line"><span>> - - - .</span></span> -<span class="line"><span>- - .</span></span> -<span class="line"><span>- .</span></span> -<span class="line"><span>< .</span></span> -<span class="line"><span>> > - - .</span></span> -<span class="line"><span>+ + + + + + + .</span></span> -<span class="line"><span>< - - - - .</span></span> -<span class="line"><span>< .</span></span> -<span class="line"><span>> + + .</span></span> -<span class="line"><span>> - .</span></span> -<span class="line"><span>< .</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>+ + + + + + + + + + +[ + > + + + + > + + + + + + > + + + + + + + + + + + + + > + + + + + + + + + + + < < < < - +] +> + + + + + . +- - . +> - - - . +> - - - . +- - . +- . +< . +> > - - . ++ + + + + + + . +< - - - - . +< . +> + + . +> - . +< . +</code></pre> </div> <p> 実行結果はこちら: <a class="url" href="https://ideone.com/22VWmb" rel="noreferrer" target="_blank">https://ideone.com/22VWmb</a> @@ -336,7 +338,8 @@ ソースコードのライセンスを示したこの部分だが、 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6F42C1">https</span><span style="color:#24292E">:</span><span style="color:#6A737D">//creativecommons.org/publicdomain/zero/1.0/</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">https</span><span style="color: #0550ae">://</span><span style="color: #24292f;background-color: #f6f8fa">creativecommons</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">org</span><span style="color: #0550ae">/</span><span style="color: #24292f;background-color: #f6f8fa">publicdomain</span><span style="color: #0550ae">/</span><span style="color: #24292f;background-color: #f6f8fa">zero</span><span style="color: #0550ae">/</span><span style="color: #0550ae">1.0</span><span style="color: #0550ae">/</span> +</code></pre> </div> <p> 完全に合法な PHP のコードである。 <code>https:</code> 部分はラベル、<code>//</code> 以降は行コメントになっている。 @@ -348,11 +351,12 @@ ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。PHP では、型変換を利用することで任意の整数を作り出すことができる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#005CC5">assert</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#D73A49"> ===</span><span style="color:#D73A49"> +!!</span><span style="color:#24292E">[]);</span></span> -<span class="line"><span style="color:#005CC5">assert</span><span style="color:#24292E">(</span><span style="color:#005CC5">1</span><span style="color:#D73A49"> ===</span><span style="color:#D73A49"> +!</span><span style="color:#24292E">[]);</span></span> -<span class="line"><span style="color:#005CC5">assert</span><span style="color:#24292E">(</span><span style="color:#005CC5">2</span><span style="color:#D73A49"> ===</span><span style="color:#D73A49"> !</span><span style="color:#24292E">[]</span><span style="color:#D73A49">+!</span><span style="color:#24292E">[]);</span></span> -<span class="line"><span style="color:#005CC5">assert</span><span style="color:#24292E">(</span><span style="color:#005CC5">3</span><span style="color:#D73A49"> ===</span><span style="color:#D73A49"> !</span><span style="color:#24292E">[]</span><span style="color:#D73A49">+!</span><span style="color:#24292E">[]</span><span style="color:#D73A49">+!</span><span style="color:#24292E">[]);</span></span> -<span class="line"><span style="color:#005CC5">assert</span><span style="color:#24292E">(</span><span style="color:#005CC5">10</span><span style="color:#D73A49"> ===</span><span style="color:#D73A49"> +</span><span style="color:#24292E">(</span><span style="color:#D73A49">!</span><span style="color:#24292E">[]</span><span style="color:#D73A49">.</span><span style="color:#D73A49">+!!</span><span style="color:#24292E">[]));</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #953800">assert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">+!!</span><span style="color: #24292f;background-color: #f6f8fa">[]);</span> +<span style="color: #953800">assert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">1</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">+!</span><span style="color: #24292f;background-color: #f6f8fa">[]);</span> +<span style="color: #953800">assert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">2</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">!</span><span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #0550ae">+!</span><span style="color: #24292f;background-color: #f6f8fa">[]);</span> +<span style="color: #953800">assert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">3</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">!</span><span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #0550ae">+!</span><span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #0550ae">+!</span><span style="color: #24292f;background-color: #f6f8fa">[]);</span> +<span style="color: #953800">assert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">10</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">!</span><span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #0550ae">.</span><span style="color: #0550ae">+!!</span><span style="color: #24292f;background-color: #f6f8fa">[]));</span> +</code></pre> </div> <p> <code>[]</code> に <code>!</code> を適用すると <code>true</code> が返ってくる。それに <code>+</code> を適用すると、<code>bool</code> から <code>int</code> ヘの型変換が走り、<code>1</code> が生成される。<code>10</code> はさらにトリッキーだ。まず <code>1</code> と <code>0</code> を作り、<code>.</code> で文字列として結合する (<code>'10'</code>)。これに <code>+</code> を適用すると、<code>string</code> から <code>int</code> への型変換が走り、<code>10</code> が生まれる (コード量に頓着しないなら、<code>1</code> を 10 個足し合わせてももちろん 10 が作れる)。 @@ -390,40 +394,41 @@ <div class="filename"> riddle.php </div> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D">/*********************************************************</span></span> -<span class="line"><span style="color:#6A737D"> * This program displays a PHPer token. *</span></span> -<span class="line"><span style="color:#6A737D"> * Guess 'N'. *</span></span> -<span class="line"><span style="color:#6A737D"> * *</span></span> -<span class="line"><span style="color:#6A737D"> * Hints: *</span></span> -<span class="line"><span style="color:#6A737D"> * - N itself has no special meaning, e.g., 42, 8128, *</span></span> -<span class="line"><span style="color:#6A737D"> * it is selected at random. *</span></span> -<span class="line"><span style="color:#6A737D"> * - Each element of $token represents a single letter. *</span></span> -<span class="line"><span style="color:#6A737D"> * - One letter consists of 5x5 cells. *</span></span> -<span class="line"><span style="color:#6A737D"> * - Remember, the output is a complete PHPer token. *</span></span> -<span class="line"><span style="color:#6A737D"> * *</span></span> -<span class="line"><span style="color:#6A737D"> * License: *</span></span> -<span class="line"><span style="color:#6A737D"> * https://creativecommons.org/publicdomain/zero/1.0/ *</span></span> -<span class="line"><span style="color:#6A737D"> *********************************************************/</span></span> -<span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> N</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> 0</span><span style="color:#6A737D"> /* Change it to your answer. */</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#005CC5">assert</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#D73A49"> <=</span><span style="color:#005CC5"> N</span><span style="color:#D73A49"> &&</span><span style="color:#005CC5"> N</span><span style="color:#D73A49"> <=</span><span style="color:#005CC5"> 0b11111_11111_11111_11111_11111</span><span style="color:#24292E">);</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$token </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [</span></span> -<span class="line"><span style="color:#005CC5"> 0x14B499C</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 0x0BE34CC</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x01C9C69</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 0x0ECA069</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x01C2449</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x0FDB166</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x01C9C69</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 0x01C1C66</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x0FC1C47</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x01C1C66</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 0x10C5858</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1E4E3B8</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1A2F2F8</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E">];</span></span> -<span class="line"><span style="color:#D73A49">foreach</span><span style="color:#24292E"> ($token </span><span style="color:#D73A49">as</span><span style="color:#24292E"> $x) {</span></span> -<span class="line"><span style="color:#24292E"> $x </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">^</span><span style="color:#005CC5"> N</span><span style="color:#24292E">;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> $x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> sprintf</span><span style="color:#24292E">(</span><span style="color:#032F62">'%025b'</span><span style="color:#24292E">, $x);</span></span> -<span class="line"><span style="color:#24292E"> $x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> str_replace</span><span style="color:#24292E">(</span><span style="color:#6F42C1">search</span><span style="color:#24292E">: [</span><span style="color:#032F62">'0'</span><span style="color:#24292E">, </span><span style="color:#032F62">'1'</span><span style="color:#24292E">], </span><span style="color:#6F42C1">replace</span><span style="color:#24292E">: [</span><span style="color:#032F62">' '</span><span style="color:#24292E">, </span><span style="color:#032F62">'#'</span><span style="color:#24292E">], </span><span style="color:#6F42C1">subject</span><span style="color:#24292E">: $x);</span></span> -<span class="line"><span style="color:#24292E"> $x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> implode</span><span style="color:#24292E">(</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">, </span><span style="color:#005CC5">str_split</span><span style="color:#24292E">($x, </span><span style="color:#6F42C1">length</span><span style="color:#24292E">: </span><span style="color:#005CC5">5</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#005CC5"> echo</span><span style="color:#032F62"> "{</span><span style="color:#24292E">$x</span><span style="color:#032F62">}</span><span style="color:#005CC5">\n\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #6e7781">/********************************************************* + * This program displays a PHPer token. * + * Guess 'N'. * + * * + * Hints: * + * - N itself has no special meaning, e.g., 42, 8128, * + * it is selected at random. * + * - Each element of $token represents a single letter. * + * - One letter consists of 5x5 cells. * + * - Remember, the output is a complete PHPer token. * + * * + * License: * + * https://creativecommons.org/publicdomain/zero/1.0/ * + *********************************************************/</span> +<span style="color: #cf222e">const</span> <span style="color: #953800">N</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span> <span style="color: #6e7781">/* Change it to your answer. */</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #953800">assert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span> <span style="color: #0550ae"><=</span> <span style="color: #953800">N</span> <span style="color: #0550ae">&&</span> <span style="color: #953800">N</span> <span style="color: #0550ae"><=</span> <span style="color: #0550ae">0b11111_11111_11111_11111_11111</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + +<span style="color: #0550ae">$token</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">[</span> + <span style="color: #0550ae">0x14B499C</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">0x0BE34CC</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x01C9C69</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">0x0ECA069</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x01C2449</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x0FDB166</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x01C9C69</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">0x01C1C66</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x0FC1C47</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x01C1C66</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">0x10C5858</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1E4E3B8</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1A2F2F8</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #24292f;background-color: #f6f8fa">];</span> +<span style="color: #cf222e">foreach</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$token</span> <span style="color: #cf222e">as</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$x</span> <span style="color: #0550ae">^</span> <span style="color: #953800">N</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + + <span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #953800">sprintf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'%025b'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #953800">str_replace</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">search</span><span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">'0'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">'1'</span><span style="color: #24292f;background-color: #f6f8fa">],</span> <span style="color: #24292f;background-color: #f6f8fa">replace</span><span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">' '</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">'#'</span><span style="color: #24292f;background-color: #f6f8fa">],</span> <span style="color: #24292f;background-color: #f6f8fa">subject</span><span style="color: #0550ae">:</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">str_split</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">length</span><span style="color: #0550ae">:</span> <span style="color: #0550ae">5</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #cf222e">echo</span> <span style="color: #0a3069">"</span><span style="color: #24292f">{</span><span style="color: #0550ae">$x</span><span style="color: #24292f">}</span><span style="color: #0a3069">\n\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。 @@ -437,33 +442,38 @@ まずはソースコードを読んでいく。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$token </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [</span></span> -<span class="line"><span style="color:#6A737D"> // 略</span></span> -<span class="line"><span style="color:#24292E">];</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$token</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">[</span> + <span style="color: #6e7781">// 略</span> +<span style="color: #24292f;background-color: #f6f8fa">];</span> +</code></pre> </div> <p> 数値からなる <code>$token</code> があり、各要素をループしている。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">^</span><span style="color:#005CC5"> N</span><span style="color:#24292E">;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$x</span> <span style="color: #0550ae">^</span> <span style="color: #953800">N</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +</code></pre> </div> <p> まずは排他的論理和 (xor) を取り、 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> sprintf</span><span style="color:#24292E">(</span><span style="color:#032F62">'%025b'</span><span style="color:#24292E">, $x);</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #953800">sprintf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'%025b'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +</code></pre> </div> <p> 二進数に変換して、 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> str_replace</span><span style="color:#24292E">(</span><span style="color:#6F42C1">search</span><span style="color:#24292E">: [</span><span style="color:#032F62">'0'</span><span style="color:#24292E">, </span><span style="color:#032F62">'1'</span><span style="color:#24292E">], </span><span style="color:#6F42C1">replace</span><span style="color:#24292E">: [</span><span style="color:#032F62">' '</span><span style="color:#24292E">, </span><span style="color:#032F62">'#'</span><span style="color:#24292E">], </span><span style="color:#6F42C1">subject</span><span style="color:#24292E">: $x);</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #953800">str_replace</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">search</span><span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">'0'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">'1'</span><span style="color: #24292f;background-color: #f6f8fa">],</span> <span style="color: #24292f;background-color: #f6f8fa">replace</span><span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">' '</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">'#'</span><span style="color: #24292f;background-color: #f6f8fa">],</span> <span style="color: #24292f;background-color: #f6f8fa">subject</span><span style="color: #0550ae">:</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +</code></pre> </div> <p> 0 を空白に、1 を <code>#</code> にし、 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> implode</span><span style="color:#24292E">(</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">, </span><span style="color:#005CC5">str_split</span><span style="color:#24292E">($x, </span><span style="color:#6F42C1">length</span><span style="color:#24292E">: </span><span style="color:#005CC5">5</span><span style="color:#24292E">));</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">str_split</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">length</span><span style="color: #0550ae">:</span> <span style="color: #0550ae">5</span><span style="color: #24292f;background-color: #f6f8fa">));</span> +</code></pre> </div> <p> 5文字ごとに区切ったあと、改行で結合している。 @@ -501,49 +511,52 @@ <code>N</code> は高々 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#005CC5">assert</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#D73A49"> <=</span><span style="color:#005CC5"> N</span><span style="color:#D73A49"> &&</span><span style="color:#005CC5"> N</span><span style="color:#D73A49"> <=</span><span style="color:#005CC5"> 0b11111_11111_11111_11111_11111</span><span style="color:#24292E">);</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #953800">assert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span> <span style="color: #0550ae"><=</span> <span style="color: #953800">N</span> <span style="color: #0550ae">&&</span> <span style="color: #953800">N</span> <span style="color: #0550ae"><=</span> <span style="color: #0550ae">0b11111_11111_11111_11111_11111</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +</code></pre> </div> <p> なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0x14B499C</span><span style="color:#24292E">;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">^</span><span style="color:#005CC5"> N</span><span style="color:#24292E">;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> sprintf</span><span style="color:#24292E">(</span><span style="color:#032F62">'%025b'</span><span style="color:#24292E">, $x);</span></span> -<span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> str_replace</span><span style="color:#24292E">(</span><span style="color:#6F42C1">search</span><span style="color:#24292E">: [</span><span style="color:#032F62">'0'</span><span style="color:#24292E">, </span><span style="color:#032F62">'1'</span><span style="color:#24292E">], </span><span style="color:#6F42C1">replace</span><span style="color:#24292E">: [</span><span style="color:#032F62">' '</span><span style="color:#24292E">, </span><span style="color:#032F62">'#'</span><span style="color:#24292E">], </span><span style="color:#6F42C1">subject</span><span style="color:#24292E">: $x);</span></span> -<span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> implode</span><span style="color:#24292E">(</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">, </span><span style="color:#005CC5">str_split</span><span style="color:#24292E">($x, </span><span style="color:#6F42C1">length</span><span style="color:#24292E">: </span><span style="color:#005CC5">5</span><span style="color:#24292E">));</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5">assert</span><span style="color:#24292E">($x </span><span style="color:#D73A49">===</span></span> -<span class="line"><span style="color:#032F62">" # # </span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#D73A49"> .</span></span> -<span class="line"><span style="color:#032F62">"#####</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#D73A49"> .</span></span> -<span class="line"><span style="color:#032F62">" # # </span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#D73A49"> .</span></span> -<span class="line"><span style="color:#032F62">"#####</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#D73A49"> .</span></span> -<span class="line"><span style="color:#032F62">" # # "</span><span style="color:#24292E">);</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0x14B499C</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + +<span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$x</span> <span style="color: #0550ae">^</span> <span style="color: #953800">N</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + +<span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #953800">sprintf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'%025b'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #953800">str_replace</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">search</span><span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">'0'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">'1'</span><span style="color: #24292f;background-color: #f6f8fa">],</span> <span style="color: #24292f;background-color: #f6f8fa">replace</span><span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">' '</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">'#'</span><span style="color: #24292f;background-color: #f6f8fa">],</span> <span style="color: #24292f;background-color: #f6f8fa">subject</span><span style="color: #0550ae">:</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">str_split</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">length</span><span style="color: #0550ae">:</span> <span style="color: #0550ae">5</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + +<span style="color: #953800">assert</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span> <span style="color: #0550ae">===</span> +<span style="color: #0a3069">" # # </span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span> <span style="color: #0550ae">.</span> +<span style="color: #0a3069">"#####</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span> <span style="color: #0550ae">.</span> +<span style="color: #0a3069">" # # </span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span> <span style="color: #0550ae">.</span> +<span style="color: #0a3069">"#####</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span> <span style="color: #0550ae">.</span> +<span style="color: #0a3069">" # # "</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +</code></pre> </div> <p> この一連の変換に対する逆変換を考えると、次のようになる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span></span> -<span class="line"><span style="color:#032F62">" # # </span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#D73A49"> .</span></span> -<span class="line"><span style="color:#032F62">"#####</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#D73A49"> .</span></span> -<span class="line"><span style="color:#032F62">" # # </span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#D73A49"> .</span></span> -<span class="line"><span style="color:#032F62">"#####</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#D73A49"> .</span></span> -<span class="line"><span style="color:#032F62">" # # "</span><span style="color:#24292E">;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> implode</span><span style="color:#24292E">(</span><span style="color:#032F62">''</span><span style="color:#24292E">, </span><span style="color:#005CC5">explode</span><span style="color:#24292E">(</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">, $x));</span></span> -<span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> str_replace</span><span style="color:#24292E">(</span><span style="color:#6F42C1">search</span><span style="color:#24292E">: [</span><span style="color:#032F62">' '</span><span style="color:#24292E">, </span><span style="color:#032F62">'#'</span><span style="color:#24292E">], </span><span style="color:#6F42C1">replace</span><span style="color:#24292E">: [</span><span style="color:#032F62">'0'</span><span style="color:#24292E">, </span><span style="color:#032F62">'1'</span><span style="color:#24292E">], </span><span style="color:#6F42C1">subject</span><span style="color:#24292E">: $x);</span></span> -<span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> bindec</span><span style="color:#24292E">($x);</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$n </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">^</span><span style="color:#005CC5"> 0x14B499C</span><span style="color:#24292E">;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5">echo</span><span style="color:#032F62"> "N = </span><span style="color:#24292E">$n</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> +<span style="color: #0a3069">" # # </span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span> <span style="color: #0550ae">.</span> +<span style="color: #0a3069">"#####</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span> <span style="color: #0550ae">.</span> +<span style="color: #0a3069">" # # </span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span> <span style="color: #0550ae">.</span> +<span style="color: #0a3069">"#####</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span> <span style="color: #0550ae">.</span> +<span style="color: #0a3069">" # # "</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + +<span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">''</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">explode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">));</span> +<span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #953800">str_replace</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">search</span><span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">' '</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">'#'</span><span style="color: #24292f;background-color: #f6f8fa">],</span> <span style="color: #24292f;background-color: #f6f8fa">replace</span><span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">'0'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">'1'</span><span style="color: #24292f;background-color: #f6f8fa">],</span> <span style="color: #24292f;background-color: #f6f8fa">subject</span><span style="color: #0550ae">:</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #953800">bindec</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + +<span style="color: #0550ae">$n</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$x</span> <span style="color: #0550ae">^</span> <span style="color: #0550ae">0x14B499C</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + +<span style="color: #cf222e">echo</span> <span style="color: #0a3069">"N = </span><span style="color: #0550ae">$n</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +</code></pre> </div> <p> これを実行すると、<code>N</code> が得られる。 @@ -559,41 +572,43 @@ <div class="filename"> toquine.php </div> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D">// License: https://creativecommons.org/publicdomain/zero/1.0/</span></span> -<span class="line"><span style="color:#6A737D">// This is a quine-like program to generate a PHPer token.</span></span> -<span class="line"><span style="color:#6A737D">// Execute it like this: php toquine.php | php | php | php | ...</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$s </span><span style="color:#D73A49">=</span><span style="color:#032F62"> <<<'</span><span style="color:#D73A49">Q</span><span style="color:#032F62">'</span></span> -<span class="line"><span style="color:#032F62"><?cuc</span></span> -<span class="line"><span style="color:#032F62">// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/</span></span> -<span class="line"><span style="color:#032F62">// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra.</span></span> -<span class="line"><span style="color:#032F62">// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ...</span></span> -<span class="line"><span style="color:#032F62">%f$f = %f;</span></span> -<span class="line"><span style="color:#032F62">$f = fge_ebg13($f); $kf = [</span></span> -<span class="line"><span style="color:#032F62">%f,</span></span> -<span class="line"><span style="color:#032F62">];</span></span> -<span class="line"><span style="color:#032F62">$g = ahyy.snyfr; sbe ($v = 0; $v <= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr</span></span> -<span class="line"><span style="color:#032F62">$g .= vzcybqr("\a", fge_fcyvg(fge_ercynpr(['0','1'], [' ','##'], fcevags(pue(37) . '025o', $kf[$v])), 012)) . "\a\a";</span></span> -<span class="line"><span style="color:#032F62">$jf = neenl_znc(sa($j) => vzcybqr(', ', $j), neenl_puhax(neenl_znc(sa($k) => fcevags('0k' . pue(37) . '07K', $k), $kf), 10));</span></span> -<span class="line"><span style="color:#032F62">cevags($f, $g, fge_ebg13("<<<'Q'\a{$f}\aQ"), vzcybqr(",\a", $jf));</span></span> -<span class="line"><span style="color:#D73A49">Q</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$s </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> str_rot13</span><span style="color:#24292E">($s); $xs </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [</span></span> -<span class="line"><span style="color:#005CC5">0x0AFABEA</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F294A7</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F2109F</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F294A7</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x0002800</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F2109F</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x0117041</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F294A7</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1FAD6B5</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F295B7</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5">0x010FC21</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1FAD6B5</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1151151</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x010FC21</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F294A7</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F295B7</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1FAD6B5</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F294A7</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F295B7</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F8C63F</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5">0x1F8C631</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1FAD6B5</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x17AD6BD</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x17AD6BD</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F8C63F</span><span style="color:#24292E">, </span><span style="color:#005CC5">0x1F295B7</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E">];</span></span> -<span class="line"><span style="color:#24292E">$t </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> null</span><span style="color:#D73A49">.</span><span style="color:#005CC5">false</span><span style="color:#24292E">; </span><span style="color:#D73A49">for</span><span style="color:#24292E"> ($i </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; $i </span><span style="color:#D73A49"><=</span><span style="color:#005CC5"> intdiv</span><span style="color:#24292E">(</span><span style="color:#005CC5">__LINE__</span><span style="color:#D73A49">-</span><span style="color:#005CC5">035</span><span style="color:#24292E">,</span><span style="color:#005CC5">6</span><span style="color:#24292E">); </span><span style="color:#D73A49">++</span><span style="color:#24292E">$i) </span><span style="color:#D73A49">if</span><span style="color:#24292E"> (</span><span style="color:#D73A49">!</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($xs[$i])) </span><span style="color:#D73A49">break</span><span style="color:#24292E">; </span><span style="color:#D73A49">else</span></span> -<span class="line"><span style="color:#24292E">$t </span><span style="color:#D73A49">.=</span><span style="color:#005CC5"> implode</span><span style="color:#24292E">(</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">, </span><span style="color:#005CC5">str_split</span><span style="color:#24292E">(</span><span style="color:#005CC5">str_replace</span><span style="color:#24292E">([</span><span style="color:#032F62">'0'</span><span style="color:#24292E">,</span><span style="color:#032F62">'1'</span><span style="color:#24292E">], [</span><span style="color:#032F62">' '</span><span style="color:#24292E">,</span><span style="color:#032F62">'##'</span><span style="color:#24292E">], </span><span style="color:#005CC5">sprintf</span><span style="color:#24292E">(</span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">37</span><span style="color:#24292E">) </span><span style="color:#D73A49">.</span><span style="color:#032F62"> '025b'</span><span style="color:#24292E">, $xs[$i])), </span><span style="color:#005CC5">012</span><span style="color:#24292E">)) </span><span style="color:#D73A49">.</span><span style="color:#032F62"> "</span><span style="color:#005CC5">\n\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$ws </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> array_map</span><span style="color:#24292E">(</span><span style="color:#D73A49">fn</span><span style="color:#24292E">($w) => </span><span style="color:#005CC5">implode</span><span style="color:#24292E">(</span><span style="color:#032F62">', '</span><span style="color:#24292E">, $w), </span><span style="color:#005CC5">array_chunk</span><span style="color:#24292E">(</span><span style="color:#005CC5">array_map</span><span style="color:#24292E">(</span><span style="color:#D73A49">fn</span><span style="color:#24292E">($x) => </span><span style="color:#005CC5">sprintf</span><span style="color:#24292E">(</span><span style="color:#032F62">'0x'</span><span style="color:#D73A49"> .</span><span style="color:#005CC5"> chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">37</span><span style="color:#24292E">) </span><span style="color:#D73A49">.</span><span style="color:#032F62"> '07X'</span><span style="color:#24292E">, $x), $xs), </span><span style="color:#005CC5">10</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#005CC5">printf</span><span style="color:#24292E">($s, $t, </span><span style="color:#005CC5">str_rot13</span><span style="color:#24292E">(</span><span style="color:#032F62">"<<<'D'</span><span style="color:#005CC5">\n</span><span style="color:#032F62">{</span><span style="color:#24292E">$s</span><span style="color:#032F62">}</span><span style="color:#005CC5">\n</span><span style="color:#032F62">D"</span><span style="color:#24292E">), </span><span style="color:#005CC5">implode</span><span style="color:#24292E">(</span><span style="color:#032F62">",</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">, $ws));</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #6e7781">// License: https://creativecommons.org/publicdomain/zero/1.0/</span> +<span style="color: #6e7781">// This is a quine-like program to generate a PHPer token.</span> +<span style="color: #6e7781">// Execute it like this: php toquine.php | php | php | php | ...</span> + +<span style="color: #0550ae">$s</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069"><<<'Q' +<?cuc +// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/ +// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra. +// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ... +%f$f = %f; +$f = fge_ebg13($f); $kf = [ +%f, +]; +$g = ahyy.snyfr; sbe ($v = 0; $v <= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr +$g .= vzcybqr("\a", fge_fcyvg(fge_ercynpr(['0','1'], [' ','##'], fcevags(pue(37) . '025o', $kf[$v])), 012)) . "\a\a"; +$jf = neenl_znc(sa($j) => vzcybqr(', ', $j), neenl_puhax(neenl_znc(sa($k) => fcevags('0k' . pue(37) . '07K', $k), $kf), 10)); +cevags($f, $g, fge_ebg13("<<<'Q'\a{$f}\aQ"), vzcybqr(",\a", $jf)); +Q;</span> +<span style="color: #0550ae">$s</span> <span style="color: #0550ae">=</span> <span style="color: #953800">str_rot13</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">);</span> <span style="color: #0550ae">$xs</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">[</span> +<span style="color: #0550ae">0x0AFABEA</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F294A7</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F2109F</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F294A7</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x0002800</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F2109F</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x0117041</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F294A7</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1FAD6B5</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F295B7</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0550ae">0x010FC21</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1FAD6B5</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1151151</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x010FC21</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F294A7</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F295B7</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1FAD6B5</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F294A7</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F295B7</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F8C63F</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0550ae">0x1F8C631</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1FAD6B5</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x17AD6BD</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x17AD6BD</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F8C63F</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0x1F295B7</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #24292f;background-color: #f6f8fa">];</span> +<span style="color: #0550ae">$t</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">null</span><span style="color: #0550ae">.</span><span style="color: #0550ae">false</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$i</span> <span style="color: #0550ae"><=</span> <span style="color: #953800">intdiv</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">__LINE__</span><span style="color: #0550ae">-</span><span style="color: #0550ae">035</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">6</span><span style="color: #24292f;background-color: #f6f8fa">);</span> <span style="color: #0550ae">++</span><span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">!</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$xs</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">]))</span> <span style="color: #cf222e">break</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #cf222e">else</span> +<span style="color: #0550ae">$t</span> <span style="color: #0550ae">.</span><span style="color: #0550ae">=</span> <span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">str_split</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">str_replace</span><span style="color: #24292f;background-color: #f6f8fa">([</span><span style="color: #0a3069">'0'</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">'1'</span><span style="color: #24292f;background-color: #f6f8fa">],</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">' '</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">'##'</span><span style="color: #24292f;background-color: #f6f8fa">],</span> <span style="color: #953800">sprintf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">37</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">.</span> <span style="color: #0a3069">'025b'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$xs</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">])),</span> <span style="color: #0550ae">012</span><span style="color: #24292f;background-color: #f6f8fa">))</span> <span style="color: #0550ae">.</span> <span style="color: #0a3069">"</span><span style="color: #0a3069">\n\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$ws</span> <span style="color: #0550ae">=</span> <span style="color: #953800">array_map</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">', '</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #953800">array_chunk</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">array_map</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #953800">sprintf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'0x'</span> <span style="color: #0550ae">.</span> <span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">37</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">.</span> <span style="color: #0a3069">'07X'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #0550ae">$xs</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #0550ae">10</span><span style="color: #24292f;background-color: #f6f8fa">));</span> +<span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$t</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">str_rot13</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"<<<'D'</span><span style="color: #0a3069">\n</span><span style="color: #24292f">{</span><span style="color: #0550ae">$s</span><span style="color: #24292f">}</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">D"</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">",</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$ws</span><span style="color: #24292f;background-color: #f6f8fa">));</span> +</code></pre> </div> <p> コメントにもあるとおり、次のようにして実行すれば答えがでてくる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ php toquine.php | php | php | php | ...</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>php toquine.php | php | php | php | ... +</code></pre> </div> <p> 実際にはもう少しパイプで繋げなければならない。 diff --git a/services/nuldoc/public/blog/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html b/services/nuldoc/public/blog/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html index 67b601f7..480907c4 100644 --- a/services/nuldoc/public/blog/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html +++ b/services/nuldoc/public/blog/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html @@ -81,7 +81,8 @@ こんなものを作った。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ term-banner 'Hello, World!' 'こんにちは、' '世界!'</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ term-banner 'Hello, World!' 'こんにちは、' '世界!' +</code></pre> </div> <p> <img alt="term-banner が動作している様子のスクリーンショット" src="/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/screenshot.png"> diff --git a/services/nuldoc/public/blog/posts/2022-08-27/php-conference-okinawa-code-golf/index.html b/services/nuldoc/public/blog/posts/2022-08-27/php-conference-okinawa-code-golf/index.html index c9c27912..8a4ab91f 100644 --- a/services/nuldoc/public/blog/posts/2022-08-27/php-conference-okinawa-code-golf/index.html +++ b/services/nuldoc/public/blog/posts/2022-08-27/php-conference-okinawa-code-golf/index.html @@ -144,7 +144,8 @@ 書いたものがこちら: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">[</span><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#24292E"> $n</span><span style="color:#D73A49">=</span><span style="color:#24292E">$argv[</span><span style="color:#005CC5">1</span><span style="color:#24292E">];</span><span style="color:#D73A49">foreach</span><span style="color:#24292E">([</span><span style="color:#005CC5">1e4</span><span style="color:#24292E">,</span><span style="color:#005CC5">5e3</span><span style="color:#24292E">,</span><span style="color:#005CC5">2e3</span><span style="color:#24292E">,</span><span style="color:#005CC5">1e3</span><span style="color:#24292E">,</span><span style="color:#005CC5">500</span><span style="color:#24292E">,</span><span style="color:#005CC5">100</span><span style="color:#24292E">,</span><span style="color:#005CC5">50</span><span style="color:#24292E">,</span><span style="color:#005CC5">10</span><span style="color:#24292E">,</span><span style="color:#005CC5">5</span><span style="color:#24292E">,</span><span style="color:#005CC5">1</span><span style="color:#24292E">]</span><span style="color:#D73A49">as</span><span style="color:#24292E">$x)</span><span style="color:#D73A49">for</span><span style="color:#24292E">(;$n</span><span style="color:#D73A49">>=</span><span style="color:#24292E">$x;$n</span><span style="color:#D73A49">-=</span><span style="color:#24292E">$x)$r[]</span><span style="color:#D73A49">=</span><span style="color:#24292E">$x;</span><span style="color:#005CC5">echo</span><span style="color:#005CC5"> implode</span><span style="color:#24292E">(</span><span style="color:#032F62">', '</span><span style="color:#24292E">,$r</span><span style="color:#D73A49">??</span><span style="color:#24292E">[]);</span><span style="color:#D73A49">?></span><span style="color:#24292E">]</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>[<span style="color: #6e7781"><?php</span> <span style="color: #0550ae">$n</span><span style="color: #0550ae">=</span><span style="color: #0550ae">$argv</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">];</span><span style="color: #cf222e">foreach</span><span style="color: #24292f;background-color: #f6f8fa">([</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">e4</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">5</span><span style="color: #24292f;background-color: #f6f8fa">e3</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">e3</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">e3</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">500</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">100</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">50</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">10</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">5</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">]</span><span style="color: #cf222e">as</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #cf222e">for</span><span style="color: #24292f;background-color: #f6f8fa">(;</span><span style="color: #0550ae">$n</span><span style="color: #0550ae">>=</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #0550ae">$n</span><span style="color: #0550ae">-=</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">$r</span><span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #0550ae">=</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #cf222e">echo</span> <span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">', '</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">$r</span><span style="color: #0550ae">??</span><span style="color: #24292f;background-color: #f6f8fa">[]);</span><span style="color: #6e7781">?></span>] +</code></pre> </div> <p> しめて 123 バイトとなった (末尾改行を含めずにカウント)。 @@ -153,15 +154,16 @@ こちらは改行とスペースを追加したバージョン: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">[</span><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$n </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $argv[</span><span style="color:#005CC5">1</span><span style="color:#24292E">];</span></span> -<span class="line"><span style="color:#D73A49">foreach</span><span style="color:#24292E"> ([</span><span style="color:#005CC5">1e4</span><span style="color:#24292E">, </span><span style="color:#005CC5">5e3</span><span style="color:#24292E">, </span><span style="color:#005CC5">2e3</span><span style="color:#24292E">, </span><span style="color:#005CC5">1e3</span><span style="color:#24292E">, </span><span style="color:#005CC5">500</span><span style="color:#24292E">, </span><span style="color:#005CC5">100</span><span style="color:#24292E">, </span><span style="color:#005CC5">50</span><span style="color:#24292E">, </span><span style="color:#005CC5">10</span><span style="color:#24292E">, </span><span style="color:#005CC5">5</span><span style="color:#24292E">, </span><span style="color:#005CC5">1</span><span style="color:#24292E">] </span><span style="color:#D73A49">as</span><span style="color:#24292E"> $x)</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> (; $n </span><span style="color:#D73A49">>=</span><span style="color:#24292E"> $x; $n </span><span style="color:#D73A49">-=</span><span style="color:#24292E"> $x)</span></span> -<span class="line"><span style="color:#24292E"> $r[] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $x;</span></span> -<span class="line"><span style="color:#005CC5">echo</span><span style="color:#005CC5"> implode</span><span style="color:#24292E">(</span><span style="color:#032F62">', '</span><span style="color:#24292E">, $r </span><span style="color:#D73A49">??</span><span style="color:#24292E"> []);</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">?></span><span style="color:#24292E">]</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>[<span style="color: #6e7781"><?php</span> + +<span style="color: #0550ae">$n</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$argv</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">];</span> +<span style="color: #cf222e">foreach</span> <span style="color: #24292f;background-color: #f6f8fa">([</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">e4</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">5</span><span style="color: #24292f;background-color: #f6f8fa">e3</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">e3</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">e3</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">500</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">100</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">50</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">10</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">5</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #cf222e">as</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">(;</span> <span style="color: #0550ae">$n</span> <span style="color: #0550ae">>=</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$n</span> <span style="color: #0550ae">-=</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #0550ae">$r</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">echo</span> <span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">', '</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$r</span> <span style="color: #0550ae">??</span> <span style="color: #24292f;background-color: #f6f8fa">[]);</span> + +<span style="color: #6e7781">?></span>] +</code></pre> </div> </section> <section id="section--techniques"> diff --git a/services/nuldoc/public/blog/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html b/services/nuldoc/public/blog/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html index acdaaacb..bc241b69 100644 --- a/services/nuldoc/public/blog/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html +++ b/services/nuldoc/public/blog/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html @@ -158,80 +158,81 @@ 特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">#</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">i</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">n</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">c</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">l</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">u</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">d</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">e</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#D73A49"><</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">s</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">t</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">d</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">i</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">o</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">.</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">h</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#D73A49">></span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#6A737D">/*</span></span> -<span class="line"><span style="color:#6A737D">*/</span></span> -<span class="line"><span style="color:#24292E">i</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">n</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">t</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#6A737D">/*</span></span> -<span class="line"><span style="color:#6A737D">*/</span></span> -<span class="line"><span style="color:#24292E">m</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">a</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">i</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#6F42C1">n</span><span style="color:#24292E">(</span></span> -<span class="line"><span style="color:#24292E">){</span></span> -<span class="line"><span style="color:#24292E">f</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">o</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#6F42C1">r</span><span style="color:#24292E">(</span></span> -<span class="line"><span style="color:#24292E">i</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">n</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">t</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#6A737D">/*</span></span> -<span class="line"><span style="color:#6A737D">*/</span></span> -<span class="line"><span style="color:#24292E">i</span><span style="color:#D73A49">=</span></span> -<span class="line"><span style="color:#005CC5">1</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">i</span><span style="color:#D73A49"><</span></span> -<span class="line"><span style="color:#005CC5">1\</span></span> -<span class="line"><span style="color:#005CC5">0\</span></span> -<span class="line"><span style="color:#005CC5">0</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">i</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#D73A49">+</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#D73A49">+</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49">if</span></span> -<span class="line"><span style="color:#24292E">(i</span></span> -<span class="line"><span style="color:#D73A49">%</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#005CC5">15</span></span> -<span class="line"><span style="color:#D73A49">==</span></span> -<span class="line"><span style="color:#005CC5">0</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#24292E">p</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">r</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">i</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">n</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#24292E">t</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#6F42C1">f</span><span style="color:#24292E">(</span></span> -<span class="line"><span style="color:#032F62">"</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#032F62">F</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#032F62">i</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#032F62">z</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#032F62">z</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#032F62">B</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#032F62">u</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#032F62">z</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#032F62">z</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#B31D28;font-style:italic">%</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#032F62">c</span><span style="color:#005CC5">\</span></span> -<span class="line"><span style="color:#032F62">"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5">10</span></span> -<span class="line"><span style="color:#24292E">);</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D">/* あとは同じように普通のプログラムを変形するだけなので省略 */</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781">#\ +i\ +n\ +c\ +l\ +u\ +d\ +e\ +<\ +s\ +t\ +d\ +i\ +o\ +.\ +h\ +>\ +</span><span style="color: #6e7781">/* +*/</span><span style="color: #6e7781"> +</span><span style="color: #24292f;background-color: #f6f8fa">i</span>\ +<span style="color: #24292f;background-color: #f6f8fa">n</span>\ +<span style="color: #24292f;background-color: #f6f8fa">t</span>\ +<span style="color: #6e7781">/* +*/</span> +<span style="color: #24292f;background-color: #f6f8fa">m</span>\ +<span style="color: #24292f;background-color: #f6f8fa">a</span>\ +<span style="color: #24292f;background-color: #f6f8fa">i</span>\ +<span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #24292f;background-color: #f6f8fa">(</span> +<span style="color: #24292f;background-color: #f6f8fa">){</span> +<span style="color: #24292f;background-color: #f6f8fa">f</span>\ +<span style="color: #24292f;background-color: #f6f8fa">o</span>\ +<span style="color: #24292f;background-color: #f6f8fa">r</span><span style="color: #24292f;background-color: #f6f8fa">(</span> +<span style="color: #24292f;background-color: #f6f8fa">i</span>\ +<span style="color: #24292f;background-color: #f6f8fa">n</span>\ +<span style="color: #24292f;background-color: #f6f8fa">t</span>\ +<span style="color: #6e7781">/* +*/</span> +<span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #0550ae">=</span> +<span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #0550ae"><</span> +<span style="color: #0550ae">1</span>\ +<span style="color: #0550ae">0</span>\ +<span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">i</span>\ +<span style="color: #0550ae">+</span>\ +<span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #cf222e">if</span> +<span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">i</span> +<span style="color: #0550ae">%</span>\ +<span style="color: #0550ae">15</span> +<span style="color: #0550ae">==</span> +<span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #24292f;background-color: #f6f8fa">p</span>\ +<span style="color: #24292f;background-color: #f6f8fa">r</span>\ +<span style="color: #24292f;background-color: #f6f8fa">i</span>\ +<span style="color: #24292f;background-color: #f6f8fa">n</span>\ +<span style="color: #24292f;background-color: #f6f8fa">t</span>\ +<span style="color: #24292f;background-color: #f6f8fa">f</span><span style="color: #24292f;background-color: #f6f8fa">(</span> +<span style="color: #0a3069">"\ +F\ +i\ +z\ +z\ +B\ +u\ +z\ +z\ +%\ +c\ +"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0550ae">10</span> +<span style="color: #24292f;background-color: #f6f8fa">);</span> + +<span style="color: #6e7781">/* あとは同じように普通のプログラムを変形するだけなので省略 */</span> +</code></pre> </div> <p> バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。 @@ -273,10 +274,11 @@ また、2文字だと文字列がまともに書けないのも辛い。<code>''</code> だけで2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$a</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#032F62">'</span></span> -<span class="line"><span style="color:#032F62">a'</span></span> -<span class="line"><span style="color:#24292E">;;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$a</span> +<span style="color: #0550ae">=</span><span style="color: #0a3069">' +a'</span> +<span style="color: #24292f;background-color: #f6f8fa">;;</span> +</code></pre> </div> <p> とすると <code>$a</code> は <code>"\na"</code> になるのだが、余計な改行が入ってしまう。 @@ -293,11 +295,12 @@ まずは普通に書くとしよう。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">for</span><span style="color:#24292E"> ($i </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">; $i </span><span style="color:#D73A49"><</span><span style="color:#005CC5"> 100</span><span style="color:#24292E">; $i</span><span style="color:#D73A49">++</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#005CC5"> echo</span><span style="color:#24292E"> (($i </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 3</span><span style="color:#D73A49"> ?</span><span style="color:#032F62"> ''</span><span style="color:#D73A49"> :</span><span style="color:#032F62"> 'Fizz'</span><span style="color:#24292E">) </span><span style="color:#D73A49">.</span><span style="color:#24292E"> ($i </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 5</span><span style="color:#D73A49"> ?</span><span style="color:#032F62"> ''</span><span style="color:#D73A49"> :</span><span style="color:#032F62"> 'Buzz'</span><span style="color:#24292E">) </span><span style="color:#D73A49">?:</span><span style="color:#24292E"> $i) </span><span style="color:#D73A49">.</span><span style="color:#032F62"> "</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$i</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">100</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$i</span><span style="color: #0550ae">++</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">echo</span> <span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">3</span> <span style="color: #0550ae">?</span> <span style="color: #0a3069">''</span> <span style="color: #0550ae">:</span> <span style="color: #0a3069">'Fizz'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">.</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">5</span> <span style="color: #0550ae">?</span> <span style="color: #0a3069">''</span> <span style="color: #0550ae">:</span> <span style="color: #0a3069">'Buzz'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">?:</span> <span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">.</span> <span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> 素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。 @@ -309,14 +312,15 @@ <code>for</code> は、3文字もある長いキーワードである。こんなものは使えない。<code>array_</code> 系の関数を使って、適当に置き換えるとしよう。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$s </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> range</span><span style="color:#24292E">(</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#005CC5">100</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#005CC5">array_walk</span><span style="color:#24292E">(</span></span> -<span class="line"><span style="color:#24292E">$s,</span></span> -<span class="line"><span style="color:#D73A49">fn</span><span style="color:#24292E">($i) =></span></span> -<span class="line"><span style="color:#005CC5">printf</span><span style="color:#24292E">((($i </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 3</span><span style="color:#D73A49"> ?</span><span style="color:#032F62"> ''</span><span style="color:#D73A49"> :</span><span style="color:#032F62"> 'Fizz'</span><span style="color:#24292E">) </span><span style="color:#D73A49">.</span><span style="color:#24292E"> ($i </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 5</span><span style="color:#D73A49"> ?</span><span style="color:#032F62"> ''</span><span style="color:#D73A49"> :</span><span style="color:#032F62"> 'Buzz'</span><span style="color:#24292E">) </span><span style="color:#D73A49">?:</span><span style="color:#24292E"> $i) </span><span style="color:#D73A49">.</span><span style="color:#032F62"> "</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">),</span></span> -<span class="line"><span style="color:#24292E">);</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #0550ae">$s</span> <span style="color: #0550ae">=</span> <span style="color: #953800">range</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">100</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #953800">array_walk</span><span style="color: #24292f;background-color: #f6f8fa">(</span> +<span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> +<span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">(((</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">3</span> <span style="color: #0550ae">?</span> <span style="color: #0a3069">''</span> <span style="color: #0550ae">:</span> <span style="color: #0a3069">'Fizz'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">.</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">5</span> <span style="color: #0550ae">?</span> <span style="color: #0a3069">''</span> <span style="color: #0550ae">:</span> <span style="color: #0a3069">'Buzz'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">?:</span> <span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">.</span> <span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">),</span> +<span style="color: #24292f;background-color: #f6f8fa">);</span> +</code></pre> </div> <p> <code>array_walk</code> や <code>range</code>、<code>printf</code> といった <code>for</code> よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、<code>echo</code> は文 (statement) であり式 (expression) ではないので、式である <code>printf</code> に置き換えた。 @@ -328,18 +332,19 @@ <code>range</code>、<code>array_walk</code>、<code>printf</code> は長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$r </span><span style="color:#D73A49">=</span><span style="color:#032F62"> 'range'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$w </span><span style="color:#D73A49">=</span><span style="color:#032F62"> 'array_walk'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$p </span><span style="color:#D73A49">=</span><span style="color:#032F62"> 'printf'</span><span style="color:#24292E">;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$s </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $r(</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#005CC5">100</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E">$w(</span></span> -<span class="line"><span style="color:#24292E">$s,</span></span> -<span class="line"><span style="color:#D73A49">fn</span><span style="color:#24292E">($i) =></span></span> -<span class="line"><span style="color:#24292E">$p((($i </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 3</span><span style="color:#D73A49"> ?</span><span style="color:#032F62"> ''</span><span style="color:#D73A49"> :</span><span style="color:#032F62"> 'Fizz'</span><span style="color:#24292E">) </span><span style="color:#D73A49">.</span><span style="color:#24292E"> ($i </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 5</span><span style="color:#D73A49"> ?</span><span style="color:#032F62"> ''</span><span style="color:#D73A49"> :</span><span style="color:#032F62"> 'Buzz'</span><span style="color:#24292E">) </span><span style="color:#D73A49">?:</span><span style="color:#24292E"> $i) </span><span style="color:#D73A49">.</span><span style="color:#032F62"> "</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">),</span></span> -<span class="line"><span style="color:#24292E">);</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #0550ae">$r</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">'range'</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$w</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">'array_walk'</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$p</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">'printf'</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + +<span style="color: #0550ae">$s</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$r</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">100</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">(</span> +<span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> +<span style="color: #0550ae">$p</span><span style="color: #24292f;background-color: #f6f8fa">(((</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">3</span> <span style="color: #0550ae">?</span> <span style="color: #0a3069">''</span> <span style="color: #0550ae">:</span> <span style="color: #0a3069">'Fizz'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">.</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">5</span> <span style="color: #0550ae">?</span> <span style="color: #0a3069">''</span> <span style="color: #0550ae">:</span> <span style="color: #0a3069">'Buzz'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">?:</span> <span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">.</span> <span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">),</span> +<span style="color: #24292f;background-color: #f6f8fa">);</span> +</code></pre> </div> <p> これで関数を呼び出している所は短くなった。では、<code>$r</code> や <code>$w</code> や <code>$p</code>、また <code>'Fizz'</code> や <code>'Buzz'</code> はどうやって 1 行 2 文字に収めるのか。次のテクニックへ移ろう。 @@ -361,26 +366,28 @@ というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、 <code>Fizz</code> という文字列が欲しければ、次のようにする。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$f</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#005CC5">F</span></span> -<span class="line"><span style="color:#D73A49">.</span><span style="color:#005CC5">i</span></span> -<span class="line"><span style="color:#D73A49">.</span><span style="color:#005CC5">z</span></span> -<span class="line"><span style="color:#D73A49">.</span><span style="color:#005CC5">z</span></span> -<span class="line"><span style="color:#24292E">;;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$f</span> +<span style="color: #0550ae">=</span><span style="color: #953800">F</span> +<span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">i</span> +<span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">z</span> +<span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">z</span> +<span style="color: #24292f;background-color: #f6f8fa">;;</span> +</code></pre> </div> <p> こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、<code>@</code> 演算子を使って抑制してやるとよい。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$f</span></span> -<span class="line"><span style="color:#D73A49">=@</span></span> -<span class="line"><span style="color:#005CC5">F</span><span style="color:#D73A49">.</span></span> -<span class="line"><span style="color:#D73A49">@</span><span style="color:#005CC5">i</span></span> -<span class="line"><span style="color:#D73A49">.</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#D73A49">@</span><span style="color:#005CC5">z</span></span> -<span class="line"><span style="color:#D73A49">.</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#D73A49">@</span><span style="color:#005CC5">z</span></span> -<span class="line"><span style="color:#24292E">;;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$f</span> +<span style="color: #0550ae">=@</span> +<span style="color: #953800">F</span><span style="color: #0550ae">.</span> +<span style="color: #0550ae">@</span><span style="color: #24292f;background-color: #f6f8fa">i</span> +<span style="color: #0550ae">.</span><span style="color: #6e7781"># +@z</span> +<span style="color: #0550ae">.</span><span style="color: #6e7781"># +@z</span> +<span style="color: #24292f;background-color: #f6f8fa">;;</span> +</code></pre> </div> <p> むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。 @@ -395,66 +402,70 @@ ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (<code>&</code>、<code>|</code>、<code>^</code>) をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$a </span><span style="color:#D73A49">=</span><span style="color:#032F62"> "12345"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$b </span><span style="color:#D73A49">=</span><span style="color:#032F62"> "world"</span><span style="color:#24292E">;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D">// $a ^ $b は次のコードと同じ</span></span> -<span class="line"><span style="color:#24292E">$result </span><span style="color:#D73A49">=</span><span style="color:#032F62"> ''</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">for</span><span style="color:#24292E"> ($i </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; $i </span><span style="color:#D73A49"><</span><span style="color:#005CC5"> min</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($a), </span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($b)); $i</span><span style="color:#D73A49">++</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#24292E">$result </span><span style="color:#D73A49">.=</span><span style="color:#24292E"> $a[$i] </span><span style="color:#D73A49">^</span><span style="color:#24292E"> $b[$i];</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5">echo</span><span style="color:#24292E"> $result;</span></span> -<span class="line"><span style="color:#6A737D">// => F]AXQ</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$a</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">"12345"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$b</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">"world"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + +<span style="color: #6e7781">// $a ^ $b は次のコードと同じ</span> +<span style="color: #0550ae">$result</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">''</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$i</span> <span style="color: #0550ae"><</span> <span style="color: #953800">min</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$a</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">));</span> <span style="color: #0550ae">$i</span><span style="color: #0550ae">++</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> +<span style="color: #0550ae">$result</span> <span style="color: #0550ae">.</span><span style="color: #0550ae">=</span> <span style="color: #0550ae">$a</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">^</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">];</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">echo</span> <span style="color: #0550ae">$result</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #6e7781">// => F]AXQ</span> +</code></pre> </div> <p> これを踏まえ、次のコードを見てみよう。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$x </span><span style="color:#D73A49">=</span><span style="color:#032F62"> "x</span><span style="color:#005CC5">\n</span><span style="color:#032F62">Om</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$y </span><span style="color:#D73A49">=</span><span style="color:#032F62"> "</span><span style="color:#005CC5">\n</span><span style="color:#032F62">k!</span><span style="color:#005CC5">\n</span><span style="color:#032F62">o"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$r </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">^</span><span style="color:#24292E"> $y;</span></span> -<span class="line"><span style="color:#005CC5">echo</span><span style="color:#032F62"> "</span><span style="color:#24292E">$r</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">"x</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">Om</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$y</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">k!</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">o"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$r</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$x</span> <span style="color: #0550ae">^</span> <span style="color: #0550ae">$y</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">echo</span> <span style="color: #0a3069">"</span><span style="color: #0550ae">$r</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +</code></pre> </div> <p> 実行すると、<code>range</code> が表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#032F62">'x</span></span> -<span class="line"><span style="color:#032F62">Om</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#032F62">'</span></span> -<span class="line"><span style="color:#032F62">k!</span></span> -<span class="line"><span style="color:#032F62">o'</span></span> -<span class="line"><span style="color:#24292E">;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$r </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">^</span><span style="color:#24292E"> $y;</span></span> -<span class="line"><span style="color:#005CC5">echo</span><span style="color:#032F62"> "</span><span style="color:#24292E">$r</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$x</span> +<span style="color: #0550ae">=</span><span style="color: #0a3069">'x +Om +'</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$y</span> +<span style="color: #0550ae">=</span><span style="color: #0a3069">' +k! +o'</span> +<span style="color: #24292f;background-color: #f6f8fa">;</span> + +<span style="color: #0550ae">$r</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$x</span> <span style="color: #0550ae">^</span> <span style="color: #0550ae">$y</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">echo</span> <span style="color: #0a3069">"</span><span style="color: #0550ae">$r</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +</code></pre> </div> <p> さらに <code>#</code> を使って適当に調整すると、次のようになる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#032F62">'x</span></span> -<span class="line"><span style="color:#032F62">Om</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#032F62">'</span></span> -<span class="line"><span style="color:#032F62">k!</span></span> -<span class="line"><span style="color:#032F62">o'</span></span> -<span class="line"><span style="color:#24292E">;</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$r</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">^</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#24292E">;</span><span style="color:#6A737D">#</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5">echo</span><span style="color:#032F62"> "</span><span style="color:#24292E">$r</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$x</span> +<span style="color: #0550ae">=</span><span style="color: #6e7781"># +'x</span> +<span style="color: #953800">Om</span> +<span style="color: #0a3069">'; +$y +='</span> +<span style="color: #24292f;background-color: #f6f8fa">k</span><span style="color: #0550ae">!</span> +<span style="color: #24292f;background-color: #f6f8fa">o</span><span style="color: #f6f8fa;background-color: #82071e">'</span> +<span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #6e7781"># +$r</span> +<span style="color: #0550ae">=</span><span style="color: #6e7781"># +$x</span> +<span style="color: #0550ae">^</span><span style="color: #6e7781"># +$y</span> +<span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #6e7781"># +</span> +<span style="color: #cf222e">echo</span> <span style="color: #0a3069">"</span><span style="color: #0550ae">$r</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +</code></pre> </div> <p> 1行あたり2文字で、<code>range</code> という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。 @@ -470,155 +481,156 @@ 完成したものがこちら。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#032F62">'i</span></span> -<span class="line"><span style="color:#032F62">S'</span></span> -<span class="line"><span style="color:#24292E">;;</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#032F62">'</span></span> -<span class="line"><span style="color:#032F62">b!</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$c</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">^</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#24292E">;</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#032F62">'x</span></span> -<span class="line"><span style="color:#032F62">Om</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#032F62">'</span></span> -<span class="line"><span style="color:#032F62">k!</span></span> -<span class="line"><span style="color:#032F62">o'</span></span> -<span class="line"><span style="color:#24292E">;</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$r</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">^</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#24292E">;</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#032F62">'k</span></span> -<span class="line"><span style="color:#032F62">Sk</span></span> -<span class="line"><span style="color:#032F62">~}</span></span> -<span class="line"><span style="color:#032F62">Ma</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#032F62">'</span></span> -<span class="line"><span style="color:#032F62">x!</span></span> -<span class="line"><span style="color:#032F62">s!</span></span> -<span class="line"><span style="color:#032F62">k!</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$w</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">^</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#24292E">;</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#032F62">'z</span></span> -<span class="line"><span style="color:#032F62">Hd</span></span> -<span class="line"><span style="color:#032F62">G'</span></span> -<span class="line"><span style="color:#24292E">;</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#032F62">'</span></span> -<span class="line"><span style="color:#032F62">x!</span></span> -<span class="line"><span style="color:#032F62">~!</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$p</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">^</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#24292E">;</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#032F62">'L</span></span> -<span class="line"><span style="color:#032F62">[p</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#032F62">'</span></span> -<span class="line"><span style="color:#032F62">c!</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$f</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">^</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#24292E">;</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#032F62">'H</span></span> -<span class="line"><span style="color:#032F62">[p</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#032F62">'</span></span> -<span class="line"><span style="color:#032F62">_!</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$b</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$x</span></span> -<span class="line"><span style="color:#D73A49">^</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$y</span></span> -<span class="line"><span style="color:#24292E">;</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$b</span></span> -<span class="line"><span style="color:#24292E">[</span><span style="color:#005CC5">1</span></span> -<span class="line"><span style="color:#24292E">]</span><span style="color:#D73A49">=</span></span> -<span class="line"><span style="color:#24292E">$c</span></span> -<span class="line"><span style="color:#24292E">(</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#005CC5">13</span></span> -<span class="line"><span style="color:#D73A49">*</span><span style="color:#005CC5">9</span></span> -<span class="line"><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E">$s</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$r</span></span> -<span class="line"><span style="color:#24292E">(</span><span style="color:#005CC5">1</span></span> -<span class="line"><span style="color:#24292E">,(</span></span> -<span class="line"><span style="color:#005CC5">10</span></span> -<span class="line"><span style="color:#D73A49">**</span></span> -<span class="line"><span style="color:#005CC5">2</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E">$w</span></span> -<span class="line"><span style="color:#24292E">(</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$s</span></span> -<span class="line"><span style="color:#24292E">,</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#005CC5">fn</span></span> -<span class="line"><span style="color:#24292E">(</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$i</span></span> -<span class="line"><span style="color:#24292E">)</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#D73A49">=></span></span> -<span class="line"><span style="color:#24292E">$p</span></span> -<span class="line"><span style="color:#24292E">((</span></span> -<span class="line"><span style="color:#24292E">(</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$i</span></span> -<span class="line"><span style="color:#D73A49">%</span><span style="color:#005CC5">3</span></span> -<span class="line"><span style="color:#D73A49">?</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#032F62">''</span></span> -<span class="line"><span style="color:#D73A49">:</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$f</span></span> -<span class="line"><span style="color:#24292E">)</span><span style="color:#D73A49">.</span></span> -<span class="line"><span style="color:#24292E">(</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$i</span></span> -<span class="line"><span style="color:#D73A49">%</span><span style="color:#005CC5">5</span></span> -<span class="line"><span style="color:#D73A49">?</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#032F62">''</span></span> -<span class="line"><span style="color:#D73A49">:</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$b</span></span> -<span class="line"><span style="color:#24292E">)</span><span style="color:#D73A49">?</span></span> -<span class="line"><span style="color:#D73A49">:</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$i</span></span> -<span class="line"><span style="color:#24292E">)</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#D73A49">.</span><span style="color:#032F62">'</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#24292E">);</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #0550ae">$x</span> +<span style="color: #0550ae">=</span><span style="color: #6e7781"># +'i</span> +<span style="color: #953800">S</span><span style="color: #0a3069">' +;; +$y +='</span> +<span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #0550ae">!</span> +<span style="color: #0a3069">'; +$c +=# +$x +^# +$y +;# +$x +=# +'</span><span style="color: #24292f;background-color: #f6f8fa">x</span> +<span style="color: #953800">Om</span> +<span style="color: #0a3069">'; +$y +='</span> +<span style="color: #24292f;background-color: #f6f8fa">k</span><span style="color: #0550ae">!</span> +<span style="color: #24292f;background-color: #f6f8fa">o</span><span style="color: #0a3069">' +;# +$r +=# +$x +^# +$y +;# +$x +=# +'</span><span style="color: #24292f;background-color: #f6f8fa">k</span> +<span style="color: #953800">Sk</span> +<span style="color: #0550ae">~</span><span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #953800">Ma</span> +<span style="color: #0a3069">'; +$y +='</span> +<span style="color: #24292f;background-color: #f6f8fa">x</span><span style="color: #0550ae">!</span> +<span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #0550ae">!</span> +<span style="color: #24292f;background-color: #f6f8fa">k</span><span style="color: #0550ae">!</span> +<span style="color: #0a3069">'; +$w +=# +$x +^# +$y +;# +$x +=# +'</span><span style="color: #24292f;background-color: #f6f8fa">z</span> +<span style="color: #953800">Hd</span> +<span style="color: #953800">G</span><span style="color: #0a3069">' +;# +$y +='</span> +<span style="color: #24292f;background-color: #f6f8fa">x</span><span style="color: #0550ae">!</span> +<span style="color: #0550ae">~!</span> +<span style="color: #0a3069">'; +$p +=# +$x +^# +$y +;# +$x +=# +'</span><span style="color: #953800">L</span> +<span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">p</span> +<span style="color: #0a3069">'; +$y +='</span> +<span style="color: #24292f;background-color: #f6f8fa">c</span><span style="color: #0550ae">!</span> +<span style="color: #0a3069">'; +$f +=# +$x +^# +$y +;# +$x +=# +'</span><span style="color: #953800">H</span> +<span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">p</span> +<span style="color: #0a3069">'; +$y +='</span> +<span style="color: #24292f;background-color: #f6f8fa">_</span><span style="color: #0550ae">!</span> +<span style="color: #0a3069">'; +$b +=# +$x +^# +$y +;# +$b +[1 +]= +$c +(# +13 +*9 +); +$s +=# +$r +(1 +,( +10 +** +2) +); +$w +(# +$s +,# +fn +(# +$i +)# +=> +$p +(( +(# +$i +%3 +?# +'' +:# +$f +). +(# +$i +%5 +?# +'' +:# +$b +)? +:# +$i +)# +.'</span> +<span style="color: #f6f8fa;background-color: #82071e">'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #24292f;background-color: #f6f8fa">);</span> +</code></pre> </div> </section> <section id="section--outro"> @@ -636,18 +648,19 @@ PHP では、バッククォートを使ってシェルを呼び出せる。これは <code>shell_exec</code> 関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5">printf</span><span style="color:#24292E">(</span><span style="color:#032F62">`</span></span> -<span class="line"><span style="color:#032F62">e\</span></span> -<span class="line"><span style="color:#032F62">c\</span></span> -<span class="line"><span style="color:#032F62">h\</span></span> -<span class="line"><span style="color:#032F62">o\</span></span> -<span class="line"><span style="color:#032F62">\</span></span> -<span class="line"><span style="color:#032F62">1\</span></span> -<span class="line"><span style="color:#032F62">2\</span></span> -<span class="line"><span style="color:#032F62">3\</span></span> -<span class="line"><span style="color:#032F62">`</span><span style="color:#24292E">);</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #f6f8fa;background-color: #82071e">`</span> +<span style="color: #24292f;background-color: #f6f8fa">e</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #24292f;background-color: #f6f8fa">c</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #24292f;background-color: #f6f8fa">h</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #24292f;background-color: #f6f8fa">o</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #0550ae">1</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #0550ae">2</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #0550ae">3</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #f6f8fa;background-color: #82071e">`</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +</code></pre> </div> <p> なお、ここでは簡単のため出力に <code>printf</code> をそのまま使っているが、実際には <code>printf</code> という文字列を合成して可変関数で呼び出す。 @@ -669,56 +682,59 @@ もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$c </span><span style="color:#D73A49">=</span><span style="color:#032F62"> 'chr'</span><span style="color:#24292E">;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">${</span></span> -<span class="line"><span style="color:#032F62">'_</span></span> -<span class="line"><span style="color:#032F62">'</span><span style="color:#24292E">}</span></span> -<span class="line"><span style="color:#D73A49">=</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#24292E">$c</span></span> -<span class="line"><span style="color:#24292E">(</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#005CC5">32</span></span> -<span class="line"><span style="color:#24292E">)</span><span style="color:#D73A49">.</span></span> -<span class="line"><span style="color:#24292E">$c</span></span> -<span class="line"><span style="color:#24292E">(</span><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#005CC5">92</span></span> -<span class="line"><span style="color:#24292E">);</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5">printf</span><span style="color:#24292E">(</span><span style="color:#032F62">`</span></span> -<span class="line"><span style="color:#032F62">e\</span></span> -<span class="line"><span style="color:#032F62">c\</span></span> -<span class="line"><span style="color:#032F62">h\</span></span> -<span class="line"><span style="color:#032F62">o\</span></span> -<span class="line"><span style="color:#032F62">${</span></span> -<span class="line"><span style="color:#032F62">'_</span></span> -<span class="line"><span style="color:#032F62">'}</span></span> -<span class="line"><span style="color:#032F62">1\</span></span> -<span class="line"><span style="color:#032F62">2\</span></span> -<span class="line"><span style="color:#032F62">3\</span></span> -<span class="line"><span style="color:#032F62">`</span><span style="color:#24292E">);</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #0550ae">$c</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">'chr'</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + +<span style="color: #f6f8fa;background-color: #82071e">$</span><span style="color: #24292f;background-color: #f6f8fa">{</span> +<span style="color: #0a3069">'_ +'</span><span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #0550ae">=</span><span style="color: #6e7781"># +$c</span> +<span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #6e7781"># +32</span> +<span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span> +<span style="color: #0550ae">$c</span> +<span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #6e7781"># +92</span> +<span style="color: #24292f;background-color: #f6f8fa">);</span> + +<span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #f6f8fa;background-color: #82071e">`</span> +<span style="color: #24292f;background-color: #f6f8fa">e</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #24292f;background-color: #f6f8fa">c</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #24292f;background-color: #f6f8fa">h</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #24292f;background-color: #f6f8fa">o</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #f6f8fa;background-color: #82071e">$</span><span style="color: #24292f;background-color: #f6f8fa">{</span> +<span style="color: #0a3069">'_ +'</span><span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #0550ae">1</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #0550ae">2</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #0550ae">3</span><span style="color: #f6f8fa;background-color: #82071e">\</span> +<span style="color: #f6f8fa;background-color: #82071e">`</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +</code></pre> </div> <p> 先程と同じく、<code>chr</code> や <code>printf</code> を生成する部分は長くなるので省いた。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>${</span></span> -<span class="line"><span>'_</span></span> -<span class="line"><span>'}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>${ +'_ +'} +</code></pre> </div> <p> は変数で、中にはスペースとエスケープが入っている (<code>chr(32) . chr(92)</code>)。シェルに渡されている文字列は次のようになる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>e\</span></span> -<span class="line"><span>c\</span></span> -<span class="line"><span>h\</span></span> -<span class="line"><span>o\</span></span> -<span class="line"><span>\</span></span> -<span class="line"><span>1\</span></span> -<span class="line"><span>2\</span></span> -<span class="line"><span>3\</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>e\ +c\ +h\ +o\ +\ +1\ +2\ +3\ +</code></pre> </div> <p> これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。 @@ -730,9 +746,10 @@ ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>${</span></span> -<span class="line"><span>'_</span></span> -<span class="line"><span>'}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>${ +'_ +'} +</code></pre> </div> <p> 最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。 diff --git a/services/nuldoc/public/blog/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html b/services/nuldoc/public/blog/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html index 2c82b081..4cccc732 100644 --- a/services/nuldoc/public/blog/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html +++ b/services/nuldoc/public/blog/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html @@ -102,27 +102,28 @@ 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$π </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $argv[</span><span style="color:#005CC5">1</span><span style="color:#24292E">] </span><span style="color:#D73A49">??</span><span style="color:#005CC5"> null</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> ($π </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> null</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#D73A49"> exit</span><span style="color:#24292E">(</span><span style="color:#032F62">'No input.'</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"><span style="color:#24292E">$π </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> trim</span><span style="color:#24292E">($π);</span></span> -<span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> (</span><span style="color:#D73A49">!</span><span style="color:#005CC5">is_numeric</span><span style="color:#24292E">($π)) {</span></span> -<span class="line"><span style="color:#D73A49"> exit</span><span style="color:#24292E">(</span><span style="color:#032F62">'Invalid input.'</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">$s </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> implode</span><span style="color:#24292E">(</span><span style="color:#005CC5">array_map</span><span style="color:#24292E">(</span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#D73A49">...</span><span style="color:#24292E">), </span><span style="color:#005CC5">str_split</span><span style="color:#24292E">($π, </span><span style="color:#005CC5">2</span><span style="color:#24292E">)));</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5">preg_match</span><span style="color:#24292E">(</span><span style="color:#032F62">'/(</span><span style="color:#22863A;font-weight:bold">\x</span><span style="color:#032F62">23.</span><span style="color:#D73A49">+</span><span style="color:#032F62">?) /'</span><span style="color:#24292E">, $s, $m);</span></span> -<span class="line"><span style="color:#24292E">$t </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $m[</span><span style="color:#005CC5">1</span><span style="color:#24292E">] </span><span style="color:#D73A49">??</span><span style="color:#032F62"> ''</span><span style="color:#24292E">;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> (</span><span style="color:#005CC5">md5</span><span style="color:#24292E">($t) </span><span style="color:#D73A49">===</span><span style="color:#032F62"> '056e831a4146bf123e8ea16613303d2e'</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#005CC5"> echo</span><span style="color:#032F62"> "Token: {</span><span style="color:#24292E">$t</span><span style="color:#032F62">}</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">} </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#005CC5"> echo</span><span style="color:#032F62"> "Failed.</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #0550ae">$π</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$argv</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">??</span> <span style="color: #0550ae">null</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$π</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">null</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">exit</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'No input.'</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #0550ae">$π</span> <span style="color: #0550ae">=</span> <span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$π</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">!</span><span style="color: #953800">is_numeric</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$π</span><span style="color: #24292f;background-color: #f6f8fa">))</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">exit</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'Invalid input.'</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #0550ae">$s</span> <span style="color: #0550ae">=</span> <span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">array_map</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">...</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #953800">str_split</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$π</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">)));</span> + +<span style="color: #953800">preg_match</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'/(\x23.+?) /'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #0550ae">$t</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">??</span> <span style="color: #0a3069">''</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + +<span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">md5</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$t</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">===</span> <span style="color: #0a3069">'056e831a4146bf123e8ea16613303d2e'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">echo</span> <span style="color: #0a3069">"Token: </span><span style="color: #24292f">{</span><span style="color: #0550ae">$t</span><span style="color: #24292f">}</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">else</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">echo</span> <span style="color: #0a3069">"Failed.</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> </section> <section id="section--how-to-obtain-token"> @@ -131,15 +132,17 @@ ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。それを <code>$π</code> なる変数に代入しているので、円周率を渡してみる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ php Q.php 3.14</span></span> -<span class="line"><span>Failed.</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>php Q.php 3.14 +<span style="color: #24292f;background-color: #f6f8fa">Failed.</span> +</code></pre> </div> <p> 失敗してしまった。精度を上げてみる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ php Q.php 3.1415</span></span> -<span class="line"><span>Failed.</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>php Q.php 3.1415 +<span style="color: #24292f;background-color: #f6f8fa">Failed.</span> +</code></pre> </div> <p> だめだった。これを成功するまで繰り返す。 @@ -148,8 +151,9 @@ 最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ php Q.php 3.1415926535897932</span></span> -<span class="line"><span>Token: #YO</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>php Q.php 3.1415926535897932 +<span style="color: #24292f;background-color: #f6f8fa">Token: #</span>YO +</code></pre> </div> <p> めでたくトークン「<code>#YO</code>」が手に入った。 @@ -161,20 +165,22 @@ 短いので頭から追っていく。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$π </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $argv[</span><span style="color:#005CC5">1</span><span style="color:#24292E">] </span><span style="color:#D73A49">??</span><span style="color:#005CC5"> null</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> ($π </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> null</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#D73A49"> exit</span><span style="color:#24292E">(</span><span style="color:#032F62">'No input.'</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"><span style="color:#24292E">$π </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> trim</span><span style="color:#24292E">($π);</span></span> -<span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> (</span><span style="color:#D73A49">!</span><span style="color:#005CC5">is_numeric</span><span style="color:#24292E">($π)) {</span></span> -<span class="line"><span style="color:#D73A49"> exit</span><span style="color:#24292E">(</span><span style="color:#032F62">'Invalid input.'</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$π</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$argv</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">??</span> <span style="color: #0550ae">null</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$π</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">null</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">exit</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'No input.'</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #0550ae">$π</span> <span style="color: #0550ae">=</span> <span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$π</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">!</span><span style="color: #953800">is_numeric</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$π</span><span style="color: #24292f;background-color: #f6f8fa">))</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">exit</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'Invalid input.'</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> 入力のバリデーション部分。数値のみ受け付ける。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$s </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> implode</span><span style="color:#24292E">(</span><span style="color:#005CC5">array_map</span><span style="color:#24292E">(</span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#D73A49">...</span><span style="color:#24292E">), </span><span style="color:#005CC5">str_split</span><span style="color:#24292E">($π, </span><span style="color:#005CC5">2</span><span style="color:#24292E">)));</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$s</span> <span style="color: #0550ae">=</span> <span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">array_map</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">...</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #953800">str_split</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$π</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">)));</span> +</code></pre> </div> <p> <code>$π</code> を 2 文字ごとに区切り (<code>str_split</code>)、数値を ASCII コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。 @@ -183,14 +189,16 @@ 例えば、<code>$π</code> が <code>'656667'</code> だったとすると、<code>65</code>、<code>66</code>、<code>67</code> に対応した <code>'A'</code>、<code>'B'</code>、<code>'C'</code> へと変換され、<code>'ABC'</code> になる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$π </span><span style="color:#D73A49">=</span><span style="color:#032F62"> '656667'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$s </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> implode</span><span style="color:#24292E">(</span><span style="color:#005CC5">array_map</span><span style="color:#24292E">(</span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#D73A49">...</span><span style="color:#24292E">), </span><span style="color:#005CC5">str_split</span><span style="color:#24292E">($π, </span><span style="color:#005CC5">2</span><span style="color:#24292E">)));</span></span> -<span class="line"><span style="color:#005CC5">echo</span><span style="color:#24292E"> $s;</span></span> -<span class="line"><span style="color:#6A737D">// => ABC</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$π</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">'656667'</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$s</span> <span style="color: #0550ae">=</span> <span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">array_map</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">...</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #953800">str_split</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$π</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">)));</span> +<span style="color: #cf222e">echo</span> <span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #6e7781">// => ABC</span> +</code></pre> </div> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#005CC5">preg_match</span><span style="color:#24292E">(</span><span style="color:#032F62">'/(</span><span style="color:#22863A;font-weight:bold">\x</span><span style="color:#032F62">23.</span><span style="color:#D73A49">+</span><span style="color:#032F62">?) /'</span><span style="color:#24292E">, $s, $m);</span></span> -<span class="line"><span style="color:#24292E">$t </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $m[</span><span style="color:#005CC5">1</span><span style="color:#24292E">] </span><span style="color:#D73A49">??</span><span style="color:#032F62"> ''</span><span style="color:#24292E">;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #953800">preg_match</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'/(\x23.+?) /'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #0550ae">$t</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">??</span> <span style="color: #0a3069">''</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +</code></pre> </div> <p> 正規表現でマッチングしている。<code>\x23</code> は <code>#</code> と同じであることに留意すると、この正規表現は「<code>#</code> から始まる 2 以上の長さ (含 <code>#</code>) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。 @@ -199,11 +207,12 @@ なお、<code>#</code> を直接書いていないのは、<code>/#.+?) /</code> と書くと、<code>#.+?)</code> という意図せぬトークンが登録されてしまうからである。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> (</span><span style="color:#005CC5">md5</span><span style="color:#24292E">($t) </span><span style="color:#D73A49">===</span><span style="color:#032F62"> '056e831a4146bf123e8ea16613303d2e'</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#005CC5"> echo</span><span style="color:#032F62"> "Token: {</span><span style="color:#24292E">$t</span><span style="color:#032F62">}</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">} </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#005CC5"> echo</span><span style="color:#032F62"> "Failed.</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">md5</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$t</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">===</span> <span style="color: #0a3069">'056e831a4146bf123e8ea16613303d2e'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">echo</span> <span style="color: #0a3069">"Token: </span><span style="color: #24292f">{</span><span style="color: #0550ae">$t</span><span style="color: #24292f">}</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">else</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">echo</span> <span style="color: #0a3069">"Failed.</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> 最後にトークンのハッシュ値を見て、想定解かどうかを確認する。 diff --git a/services/nuldoc/public/blog/posts/2022-10-28/setup-server-for-this-site/index.html b/services/nuldoc/public/blog/posts/2022-10-28/setup-server-for-this-site/index.html index 79d11c10..9fd8d6c2 100644 --- a/services/nuldoc/public/blog/posts/2022-10-28/setup-server-for-this-site/index.html +++ b/services/nuldoc/public/blog/posts/2022-10-28/setup-server-for-this-site/index.html @@ -176,8 +176,9 @@ ローカルマシンで鍵を生成する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key</span></span> -<span class="line"><span>$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>ssh-keygen <span style="color: #116329">-t</span> ed25519 <span style="color: #116329">-b</span> 521 <span style="color: #116329">-f</span> ~/.ssh/teika.key +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>ssh-keygen <span style="color: #116329">-t</span> ed25519 <span style="color: #116329">-b</span> 521 <span style="color: #116329">-f</span> ~/.ssh/github2teika.key +</code></pre> </div> <p> <code>teika.key</code> はローカルからサーバへの接続用、<code>github2teika.key</code> は、GitHub Actions からサーバへのデプロイ用。 @@ -189,12 +190,13 @@ <code>.ssh/config</code> に設定しておく。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>Host teika</span></span> -<span class="line"><span> HostName **********</span></span> -<span class="line"><span> User **********</span></span> -<span class="line"><span> Port **********</span></span> -<span class="line"><span> IdentityFile ~/.ssh/teika.key</span></span> -<span class="line"><span> IdentitiesOnly yes</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>Host teika + HostName ********** + User ********** + Port ********** + IdentityFile ~/.ssh/teika.key + IdentitiesOnly yes +</code></pre> </div> </section> </section> @@ -212,24 +214,27 @@ 管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。<code>sudo</code> グループに追加して <code>sudo</code> できるようにし、<code>su</code> で切り替え。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo adduser **********</span></span> -<span class="line"><span>$ sudo adduser ********** sudo</span></span> -<span class="line"><span>$ su **********</span></span> -<span class="line"><span>$ cd</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>adduser <span style="color: #cf222e">**********</span> +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>adduser <span style="color: #cf222e">**********</span> <span style="color: #953800">sudo</span> +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>su <span style="color: #cf222e">**********</span> +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">cd</span> +</code></pre> </div> </section> <section id="section--basic-setup--hostname"> <h3><a href="#section--basic-setup--hostname">ホスト名を変える</a></h3> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo hostname teika</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo hostname </span>teika +</code></pre> </div> </section> <section id="section--basic-setup--public-key"> <h3><a href="#section--basic-setup--public-key">公開鍵を置く</a></h3> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ mkdir ~/.ssh</span></span> -<span class="line"><span>$ chmod 700 ~/.ssh</span></span> -<span class="line"><span>$ vi ~/.ssh/authorized_keys</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">mkdir</span> ~/.ssh +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">chmod </span>700 ~/.ssh +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>vi ~/.ssh/authorized_keys +</code></pre> </div> <p> <code>authorized_keys</code> には、ローカルで生成した <code>~/.ssh/teika.key.pub</code> と <code>~/.ssh/github2teika.key.pub</code> の内容をコピーする。 @@ -241,8 +246,9 @@ SSH の設定を変更し、少しでも安全にしておく。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak</span></span> -<span class="line"><span>$ sudo vi /etc/ssh/sshd_config</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo cp</span> /etc/ssh/sshd_config /etc/ssh/sshd_config.bak +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>vi /etc/ssh/sshd_config +</code></pre> </div> <ul> <li> @@ -259,8 +265,9 @@ そして設定を反映。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo systemctl restart sshd</span></span> -<span class="line"><span>$ sudo systemctl status sshd</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>systemctl restart sshd +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>systemctl status sshd +</code></pre> </div> </section> <section id="section--basic-setup--ssh-connect"> @@ -269,7 +276,8 @@ 今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ ssh teika</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>ssh teika +</code></pre> </div> </section> <section id="section--basic-setup--close-ports"> @@ -278,11 +286,12 @@ デフォルトの 22 番を閉じ、設定したポートだけ空ける。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo ufw deny ssh</span></span> -<span class="line"><span>$ sudo ufw allow *******</span></span> -<span class="line"><span>$ sudo ufw enable</span></span> -<span class="line"><span>$ sudo ufw reload</span></span> -<span class="line"><span>$ sudo ufw status</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>ufw deny ssh +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>ufw allow <span style="color: #cf222e">*******</span> +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>ufw <span style="color: #953800">enable</span> +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>ufw reload +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>ufw status +</code></pre> </div> <p> ここでもう一度 SSH の接続確認を挟む。 @@ -294,41 +303,46 @@ GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github.key</span></span> -<span class="line"><span>$ cat ~/.ssh/github.key.pub</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>ssh-keygen <span style="color: #116329">-t</span> ed25519 <span style="color: #116329">-b</span> 521 <span style="color: #116329">-f</span> ~/.ssh/github.key +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">cat</span> ~/.ssh/github.key.pub +</code></pre> </div> <p> <a href="https://github.com/settings/ssh" rel="noreferrer" target="_blank">GitHub の設定画面</a> から、この公開鍵を追加する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ vi ~/.ssh/config</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>vi ~/.ssh/config +</code></pre> </div> <p> 設定はこう。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>Host github.com</span></span> -<span class="line"><span> HostName github.com</span></span> -<span class="line"><span> User git</span></span> -<span class="line"><span> Port 22</span></span> -<span class="line"><span> IdentityFile ~/.ssh/github.key</span></span> -<span class="line"><span> IdentitiesOnly yes</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>Host github.com + HostName github.com + User git + Port 22 + IdentityFile ~/.ssh/github.key + IdentitiesOnly yes +</code></pre> </div> <p> 最後に接続できるか確認しておく。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ ssh -T github.com</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>ssh <span style="color: #116329">-T</span> github.com +</code></pre> </div> </section> <section id="section--basic-setup--upgrade-packages"> <h3><a href="#section--basic-setup--upgrade-packages">パッケージの更新</a></h3> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo apt update</span></span> -<span class="line"><span>$ sudo apt upgrade</span></span> -<span class="line"><span>$ sudo apt update</span></span> -<span class="line"><span>$ sudo apt upgrade</span></span> -<span class="line"><span>$ sudo apt autoremove</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>apt update +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>apt upgrade +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>apt update +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>apt upgrade +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>apt autoremove +</code></pre> </div> </section> </section> @@ -343,13 +357,15 @@ <section id="section--site-hosting-setup--install-softwares"> <h3><a href="#section--site-hosting-setup--install-softwares">使うソフトウェアのインストール</a></h3> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo apt install docker docker-compose git make</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>apt <span style="color: #953800">install </span>docker docker-compose git make +</code></pre> </div> </section> <section id="section--site-hosting-setup--docker"> <h3><a href="#section--site-hosting-setup--docker">メインユーザが Docker を使えるように</a></h3> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo adduser ********** docker</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>adduser <span style="color: #cf222e">**********</span> docker +</code></pre> </div> </section> <section id="section--site-hosting-setup--open-http-ports"> @@ -358,32 +374,36 @@ 80 番と 443 番を空ける。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo ufw allow 80/tcp</span></span> -<span class="line"><span>$ sudo ufw allow 443/tcp</span></span> -<span class="line"><span>$ sudo ufw reload</span></span> -<span class="line"><span>$ sudo ufw status</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>ufw allow 80/tcp +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>ufw allow 443/tcp +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>ufw reload +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">sudo </span>ufw status +</code></pre> </div> </section> <section id="section--site-hosting-setup--clone-repositories"> <h3><a href="#section--site-hosting-setup--clone-repositories">リポジトリのクローン</a></h3> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ cd</span></span> -<span class="line"><span>$ git clone git@github.com:nsfisis/nsfisis.dev.git</span></span> -<span class="line"><span>$ cd nsfisis.dev</span></span> -<span class="line"><span>$ git submodule update --init</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">cd</span> +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>git clone git@github.com:nsfisis/nsfisis.dev.git +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #953800">cd </span>nsfisis.dev +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>git submodule update <span style="color: #116329">--init</span> +</code></pre> </div> </section> <section id="section--site-hosting-setup--certbot"> <h3><a href="#section--site-hosting-setup--certbot">certbot で証明書取得</a></h3> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ docker-compose up -d acme-challenge</span></span> -<span class="line"><span>$ make setup</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>docker-compose up <span style="color: #116329">-d</span> acme-challenge +<span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>make setup +</code></pre> </div> </section> <section id="section--site-hosting-setup--run-server"> <h3><a href="#section--site-hosting-setup--run-server">サーバを稼動させる</a></h3> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ make serve</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">$</span><span style="color: #24292f;background-color: #f6f8fa"> </span>make serve +</code></pre> </div> </section> </section> diff --git a/services/nuldoc/public/blog/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html b/services/nuldoc/public/blog/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html index f11bb7d7..a8105af5 100644 --- a/services/nuldoc/public/blog/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html +++ b/services/nuldoc/public/blog/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html @@ -105,16 +105,17 @@ 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +</code></pre> </div> <p> “And Then There Were None” (そして誰もいなくなった) と名付けた作品。変則 quine (自分自身と同じソースコードを出力するプログラム) になっている。 @@ -126,46 +127,49 @@ 実行してみると、次のような出力が得られる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code># +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +</code></pre> </div> <p> 1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#005CC5">W</span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span> -<span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code># +W +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +<span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +</code></pre> </div> <p> 今度は 2 行目が書き換えられた。すべての行が変化するまで繰り返すと次のようになる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#005CC5">W</span></span> -<span class="line"><span style="color:#005CC5">E</span></span> -<span class="line"><span style="color:#005CC5">L</span></span> -<span class="line"><span style="color:#005CC5">O</span></span> -<span class="line"><span style="color:#005CC5">V</span></span> -<span class="line"><span style="color:#005CC5">E</span></span> -<span class="line"><span style="color:#005CC5">P</span></span> -<span class="line"><span style="color:#005CC5">H</span></span> -<span class="line"><span style="color:#005CC5">P</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"># +W</span> +<span style="color: #953800">E</span> +<span style="color: #953800">L</span> +<span style="color: #953800">O</span> +<span style="color: #953800">V</span> +<span style="color: #953800">E</span> +<span style="color: #953800">P</span> +<span style="color: #953800">H</span> +<span style="color: #953800">P</span> +</code></pre> </div> <p> トークン「#WELOVEPHP」が手に入った。 @@ -180,7 +184,8 @@ Vim で開くと次のようになる (1 行目を抜粋)。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span><span style="color:#005CC5"> printf</span><span style="color:#24292E">((</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">?fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">trim</span><span style="color:#24292E">($s,</span><span style="color:#032F62">"<200b>"</span><span style="color:#24292E">)</span><span style="color:#D73A49">:fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">))($s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color:#24292E">)</span><span style="color:#D73A49">.</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\x27</span><span style="color:#24292E">$s</span><span style="color:#005CC5">\x27</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span><span style="color:#D73A49">?></span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">?</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"<200b>"</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">:</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))(</span><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\x27</span><span style="color: #0550ae">$s</span><span style="color: #0a3069">\x27</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #6e7781">?></span> +</code></pre> </div> <p> <code><200b></code> と表示されているのは、Unicode の U+200b で、ゼロ幅スペースである。 @@ -202,13 +207,15 @@ 続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて <code><200b></code> と記載する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">fn</span><span style="color:#24292E">($s)=></span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">strlen</span><span style="color:#24292E">($s)</span><span style="color:#D73A49">/</span><span style="color:#005CC5">3</span><span style="color:#24292E">)</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">strlen</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">/</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +</code></pre> </div> <p> PHP の <code>strlen()</code> は文字列のバイト数を返す。1 行目の <code>$s</code> は以下の内容となっており、 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$s</span><span style="color:#D73A49">=</span><span style="color:#032F62">'<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</span> +</code></pre> </div> <p> このソースコードは UTF-8 で書かれているので、105 バイトになる。それを 3 で割ると 35 となり、これは <code>#</code> の ASCII コードと一致する。他の行も、同様にしてゼロ幅スペースを詰めることで文字列長を調整し、トークンをエンコードしている。 diff --git a/services/nuldoc/public/blog/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html b/services/nuldoc/public/blog/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html index 3c9f1e60..4937deb0 100644 --- a/services/nuldoc/public/blog/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html +++ b/services/nuldoc/public/blog/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html @@ -121,118 +121,119 @@ 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"><span style="color:#D73A49">try</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6F42C1"> f</span><span style="color:#24292E">(</span><span style="color:#6F42C1">g</span><span style="color:#24292E">() </span><span style="color:#D73A49">/</span><span style="color:#005CC5"> __LINE__</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E">} </span><span style="color:#D73A49">catch</span><span style="color:#24292E"> (</span><span style="color:#005CC5">Throwable</span><span style="color:#24292E"> $e) {</span></span> -<span class="line"><span style="color:#D73A49"> while</span><span style="color:#24292E"> ($e </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $e</span><span style="color:#D73A49">-></span><span style="color:#6F42C1">getPrevious</span><span style="color:#24292E">()) </span><span style="color:#005CC5">printf</span><span style="color:#24292E">(</span><span style="color:#032F62">'%c'</span><span style="color:#24292E">, $e</span><span style="color:#D73A49">-></span><span style="color:#6F42C1">getLine</span><span style="color:#24292E">() </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> 23</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#005CC5"> echo</span><span style="color:#032F62"> "</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"><span style="color:#D73A49">function</span><span style="color:#6F42C1"> f</span><span style="color:#24292E">(</span><span style="color:#D73A49">int</span><span style="color:#24292E"> $i) {</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> ($i </span><span style="color:#D73A49"><</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">) </span><span style="color:#6F42C1">f</span><span style="color:#24292E">();</span></span> -<span class="line"><span style="color:#D73A49"> try</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> match</span><span style="color:#24292E"> ($i) {</span></span> -<span class="line"><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 15</span><span style="color:#24292E">, </span><span style="color:#005CC5">36</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 14</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 37</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 6</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 5</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 22</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 34</span><span style="color:#24292E">, </span><span style="color:#005CC5">35</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 25</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 17</span><span style="color:#24292E">, </span><span style="color:#005CC5">21</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 24</span><span style="color:#24292E">, </span><span style="color:#005CC5">32</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 33</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 16</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 18</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 7</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 2</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 1</span><span style="color:#24292E">, </span><span style="color:#005CC5">20</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 10</span><span style="color:#24292E">, </span><span style="color:#005CC5">28</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 8</span><span style="color:#24292E">, </span><span style="color:#005CC5">12</span><span style="color:#24292E">, </span><span style="color:#005CC5">26</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 4</span><span style="color:#24292E">, </span><span style="color:#005CC5">9</span><span style="color:#24292E">, </span><span style="color:#005CC5">13</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 31</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 29</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 11</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 3</span><span style="color:#24292E">, </span><span style="color:#005CC5">19</span><span style="color:#24292E">, </span><span style="color:#005CC5">23</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 27</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 30</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> };</span></span> -<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">finally</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6F42C1"> f</span><span style="color:#24292E">($i </span><span style="color:#D73A49">-</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">function</span><span style="color:#6F42C1"> g</span><span style="color:#24292E">() {</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> __LINE__</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> +<span style="color: #cf222e">try</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #8250df">f</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #8250df">g</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #0550ae">/</span> <span style="color: #cf222e">__LINE__</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">catch</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">Throwable</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">while</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$e</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$e</span><span style="color: #0550ae">-></span><span style="color: #8250df">getPrevious</span><span style="color: #24292f;background-color: #f6f8fa">())</span> <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'%c'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$e</span><span style="color: #0550ae">-></span><span style="color: #8250df">getLine</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #0550ae">+</span> <span style="color: #0550ae">23</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #cf222e">echo</span> <span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #cf222e">function</span> <span style="color: #24292f;background-color: #f6f8fa">f</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">int</span> <span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #8250df">f</span><span style="color: #24292f;background-color: #f6f8fa">();</span> + <span style="color: #cf222e">try</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">match</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">0</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + + + <span style="color: #0550ae">15</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">36</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">14</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">37</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + + + + + + + + + + <span style="color: #0550ae">6</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + <span style="color: #0550ae">5</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + <span style="color: #0550ae">22</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + + + + <span style="color: #0550ae">34</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">35</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + + + + + + + + <span style="color: #0550ae">25</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">17</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">21</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + <span style="color: #0550ae">24</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">32</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + + + + + + + <span style="color: #0550ae">33</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + <span style="color: #0550ae">16</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + + <span style="color: #0550ae">18</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + + + + + + + + <span style="color: #0550ae">7</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + <span style="color: #0550ae">2</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">20</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">10</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">28</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">8</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">12</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">26</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">4</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">9</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">13</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + + + + + <span style="color: #0550ae">31</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + <span style="color: #0550ae">29</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + <span style="color: #0550ae">11</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + + + <span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">19</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">23</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + + <span style="color: #0550ae">27</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + <span style="color: #0550ae">30</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">};</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">finally</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #8250df">f</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae">-</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + + + + + + + +<span style="color: #cf222e">function</span> <span style="color: #24292f;background-color: #f6f8fa">g</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">return</span> <span style="color: #cf222e">__LINE__</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> “Catchline” と名付けた作品。実行するとトークン <code>#base64_decode('SGVsbG8sIFdvcmxkIQ==')</code> が得られる。 @@ -266,20 +267,21 @@ このうち 1つ目のケースは、 <code>finally</code> 節の中でエラーを投げると PHP 処理系が勝手に <code>$previous</code> を設定してくれる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">try</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> try</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> throw</span><span style="color:#D73A49"> new</span><span style="color:#005CC5"> Exception</span><span style="color:#24292E">(</span><span style="color:#032F62">"Error 1"</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">finally</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> throw</span><span style="color:#D73A49"> new</span><span style="color:#005CC5"> Exception</span><span style="color:#24292E">(</span><span style="color:#032F62">"Error 2"</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E">} </span><span style="color:#D73A49">catch</span><span style="color:#24292E"> (</span><span style="color:#005CC5">Exception</span><span style="color:#24292E"> $e) {</span></span> -<span class="line"><span style="color:#005CC5"> echo</span><span style="color:#24292E"> $e</span><span style="color:#D73A49">-></span><span style="color:#6F42C1">getMessage</span><span style="color:#24292E">() </span><span style="color:#D73A49">.</span><span style="color:#005CC5"> PHP_EOL</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#6A737D"> // => Error 2</span></span> -<span class="line"><span style="color:#005CC5"> echo</span><span style="color:#24292E"> $e</span><span style="color:#D73A49">-></span><span style="color:#6F42C1">getPrevious</span><span style="color:#24292E">()</span><span style="color:#D73A49">-></span><span style="color:#6F42C1">getMessage</span><span style="color:#24292E">() </span><span style="color:#D73A49">.</span><span style="color:#005CC5"> PHP_EOL</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#6A737D"> // => Error 1</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #cf222e">try</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">try</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">throw</span> <span style="color: #cf222e">new</span> <span style="color: #953800">Exception</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"Error 1"</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">finally</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">throw</span> <span style="color: #cf222e">new</span> <span style="color: #953800">Exception</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"Error 2"</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">catch</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">Exception</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">echo</span> <span style="color: #0550ae">$e</span><span style="color: #0550ae">-></span><span style="color: #8250df">getMessage</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #0550ae">.</span> <span style="color: #0550ae">PHP_EOL</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #6e7781">// => Error 2</span> + <span style="color: #cf222e">echo</span> <span style="color: #0550ae">$e</span><span style="color: #0550ae">-></span><span style="color: #8250df">getPrevious</span><span style="color: #24292f;background-color: #f6f8fa">()</span><span style="color: #0550ae">-></span><span style="color: #8250df">getMessage</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #0550ae">.</span> <span style="color: #0550ae">PHP_EOL</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #6e7781">// => Error 1</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> この知識を元に、トークンの出力部を解析してみる。 @@ -291,15 +293,16 @@ 出力部をコメントや改行を追加して再掲する: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"><span style="color:#D73A49">try</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6F42C1"> f</span><span style="color:#24292E">(</span><span style="color:#6F42C1">g</span><span style="color:#24292E">() </span><span style="color:#D73A49">/</span><span style="color:#005CC5"> __LINE__</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E">} </span><span style="color:#D73A49">catch</span><span style="color:#24292E"> (</span><span style="color:#005CC5">Throwable</span><span style="color:#24292E"> $e) {</span></span> -<span class="line"><span style="color:#D73A49"> while</span><span style="color:#24292E"> ($e </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $e</span><span style="color:#D73A49">-></span><span style="color:#6F42C1">getPrevious</span><span style="color:#24292E">()) {</span></span> -<span class="line"><span style="color:#005CC5"> printf</span><span style="color:#24292E">(</span><span style="color:#032F62">'%c'</span><span style="color:#24292E">, $e</span><span style="color:#D73A49">-></span><span style="color:#6F42C1">getLine</span><span style="color:#24292E">() </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> 23</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#005CC5"> echo</span><span style="color:#032F62"> "</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> +<span style="color: #cf222e">try</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #8250df">f</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #8250df">g</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #0550ae">/</span> <span style="color: #cf222e">__LINE__</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">catch</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">Throwable</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">while</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$e</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$e</span><span style="color: #0550ae">-></span><span style="color: #8250df">getPrevious</span><span style="color: #24292f;background-color: #f6f8fa">())</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #953800">printf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'%c'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$e</span><span style="color: #0550ae">-></span><span style="color: #8250df">getLine</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #0550ae">+</span> <span style="color: #0550ae">23</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #cf222e">echo</span> <span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> 出力をおこなう <code>catch</code> 節を見てみると、 <code>Throwable::getPrevious()</code> を呼び出してエラーチェインを辿り、 <code>Throwable::getLine()</code> でエラーが発生した行数を取得している。その行数に <code>23</code> なるマジックナンバーを足し、フォーマット指定子 <code>%c</code> で出力している。 @@ -308,7 +311,8 @@ フォーマット指定子 <code>%c</code> は、整数を ASCII コード<sup class="footnote"><a class="footnote" href="#footnote--ras-syndrome" id="footnoteref--ras-syndrome">[1]</a></sup> と見做して印字する。トークン <code>#base64_decode('SGVsbG8sIFdvcmxkIQ==')</code> の <code>b</code> であれば、ASCII コード <code>98</code> なので、75 行目で発生したエラー、 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#005CC5">20</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">20</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +</code></pre> </div> <p> によって表現されている。エラーを起こす方法はいろいろと考えられるが、今回はゼロ除算を使った。 @@ -323,39 +327,42 @@ <code>f()</code> の定義を再掲する (エラーオブジェクトの行数を利用しているので、一部分だけ抜き出すと値が変わることに注意): </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">function</span><span style="color:#6F42C1"> f</span><span style="color:#24292E">(</span><span style="color:#D73A49">int</span><span style="color:#24292E"> $i) {</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> ($i </span><span style="color:#D73A49"><</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">) </span><span style="color:#6F42C1">f</span><span style="color:#24292E">();</span></span> -<span class="line"><span style="color:#D73A49"> try</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> match</span><span style="color:#24292E"> ($i) {</span></span> -<span class="line"><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">, </span><span style="color:#6A737D">// 12 行目</span></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 15</span><span style="color:#24292E">, </span><span style="color:#005CC5">36</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 14</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 37</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D"> // (略)</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5"> 30</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> /</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">, </span><span style="color:#6A737D">// 97 行目</span></span> -<span class="line"><span style="color:#24292E"> };</span></span> -<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">finally</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6F42C1"> f</span><span style="color:#24292E">($i </span><span style="color:#D73A49">-</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">function</span> <span style="color: #24292f;background-color: #f6f8fa">f</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">int</span> <span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #8250df">f</span><span style="color: #24292f;background-color: #f6f8fa">();</span> + <span style="color: #cf222e">try</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">match</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">0</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// 12 行目</span> + + + + <span style="color: #0550ae">15</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">36</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">14</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">37</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + + <span style="color: #6e7781">// (略)</span> + + <span style="color: #0550ae">30</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">/</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// 97 行目</span> + <span style="color: #24292f;background-color: #f6f8fa">};</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">finally</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #8250df">f</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span> <span style="color: #0550ae">-</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> 前述のように、 <code>finally</code> 節でエラーを投げると PHP 処理系が <code>$previous</code> を設定する。ここでは、エラーを繋げるために <code>f()</code> を再帰呼び出ししている。最初に <code>f()</code> を呼び出している箇所を確認すると、 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"><span style="color:#D73A49">try</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6F42C1"> f</span><span style="color:#24292E">(</span><span style="color:#6F42C1">g</span><span style="color:#24292E">() </span><span style="color:#D73A49">/</span><span style="color:#005CC5"> __LINE__</span><span style="color:#24292E">); </span><span style="color:#6A737D">// 3 行目</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> +<span style="color: #cf222e">try</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #8250df">f</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #8250df">g</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #0550ae">/</span> <span style="color: #cf222e">__LINE__</span><span style="color: #24292f;background-color: #f6f8fa">);</span> <span style="color: #6e7781">// 3 行目</span> +</code></pre> </div> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">function</span><span style="color:#6F42C1"> g</span><span style="color:#24292E">() {</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> __LINE__</span><span style="color:#24292E">; </span><span style="color:#6A737D">// 111 行目</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">function</span> <span style="color: #24292f;background-color: #f6f8fa">g</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">return</span> <span style="color: #cf222e">__LINE__</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #6e7781">// 111 行目</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> <code>f()</code> には <code>111 / 3</code> で <code>37</code> が渡されることがわかる。そこから 1 ずつ減らして再帰呼び出ししていき、0 より小さくなったら <code>f()</code> を引数なしで呼び出す。引数の数が足りないと呼び出しに失敗するので、再帰はここで止まる。 diff --git a/services/nuldoc/public/blog/posts/2023-04-01/implementation-of-minimal-png-image-encoder.md b/services/nuldoc/public/blog/posts/2023-04-01/implementation-of-minimal-png-image-encoder.md index 6f4fb3c8..2fd69590 100644 --- a/services/nuldoc/public/blog/posts/2023-04-01/implementation-of-minimal-png-image-encoder.md +++ b/services/nuldoc/public/blog/posts/2023-04-01/implementation-of-minimal-png-image-encoder.md @@ -189,19 +189,19 @@ IHDR chunk は最初に配置される chunk である。次のようなデー 1. 画像の幅 (符号なし 4 バイト整数) 1. 画像の高さ (符号なし 4 バイト整数) 1. ビット深度 (符号なし 1 バイト整数) - * 1 色に使うビット数。1 ピクセルに 24 bit 使う truecolor 画像では 8 になる + * 1 色に使うビット数。1 ピクセルに 24 bit 使う truecolor 画像では 8 になる 1. 色タイプ (符号なし 1 バイト整数) - * 0: グレースケール - * 2: Truecolor (今回はこれに決め打ち) - * 3: パレットのインデックス - * 4: グレースケール + アルファ - * 6: Truecolor + アルファ + * 0: グレースケール + * 2: Truecolor (今回はこれに決め打ち) + * 3: パレットのインデックス + * 4: グレースケール + アルファ + * 6: Truecolor + アルファ 1. 圧縮方式 (符号なし 1 バイト整数) - * PNG の仕様書に 0 しか定義されていないので 0 で固定 + * PNG の仕様書に 0 しか定義されていないので 0 で固定 1. フィルタ方式 (符号なし 1 バイト整数) - * PNG の仕様書に 0 しか定義されていないので 0 で固定 + * PNG の仕様書に 0 しか定義されていないので 0 で固定 1. インターレース方式 (符号なし 1 バイト整数) - * 今回はインターレースしないので 0 + * 今回はインターレースしないので 0 今回ほとんどのデータは決め打ちするので、データに応じて変わるのは width と height だけになる。コードは次のようになる。 diff --git a/services/nuldoc/public/blog/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html b/services/nuldoc/public/blog/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html index 7ab1e9b5..07518f23 100644 --- a/services/nuldoc/public/blog/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html +++ b/services/nuldoc/public/blog/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html @@ -135,44 +135,45 @@ 以下のソースコードをベースにする。今回 PNG のデコーダは扱わないので、読み込みには Go の標準ライブラリ <code>image/png</code> を用いる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">package</span><span style="color:#6F42C1"> main</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">import</span><span style="color:#24292E"> (</span></span> -<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">image</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#24292E"> _ </span><span style="color:#032F62">"</span><span style="color:#6F42C1">image/png</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">io</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">os</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#24292E">)</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> main</span><span style="color:#24292E">() {</span></span> -<span class="line"><span style="color:#24292E"> inFile, err </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> os.</span><span style="color:#6F42C1">Open</span><span style="color:#24292E">(</span><span style="color:#032F62">"input.png"</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> err </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> nil</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6F42C1"> panic</span><span style="color:#24292E">(err)</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#D73A49"> defer</span><span style="color:#24292E"> inFile.</span><span style="color:#6F42C1">Close</span><span style="color:#24292E">()</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> img, _, err </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> image.</span><span style="color:#6F42C1">Decode</span><span style="color:#24292E">(inFile)</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> err </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> nil</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6F42C1"> panic</span><span style="color:#24292E">(err)</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> outFile, err </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> os.</span><span style="color:#6F42C1">Create</span><span style="color:#24292E">(</span><span style="color:#032F62">"output.png"</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> err </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> nil</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6F42C1"> panic</span><span style="color:#24292E">(err)</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#D73A49"> defer</span><span style="color:#24292E"> outFile.</span><span style="color:#6F42C1">Close</span><span style="color:#24292E">()</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> writePng</span><span style="color:#24292E">(outFile, img)</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writePng</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">img</span><span style="color:#6F42C1"> image</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Image</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#24292E"> width </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(img.</span><span style="color:#6F42C1">Bounds</span><span style="color:#24292E">().</span><span style="color:#6F42C1">Dx</span><span style="color:#24292E">())</span></span> -<span class="line"><span style="color:#24292E"> height </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(img.</span><span style="color:#6F42C1">Bounds</span><span style="color:#24292E">().</span><span style="color:#6F42C1">Dy</span><span style="color:#24292E">())</span></span> -<span class="line"><span style="color:#6F42C1"> writeSignature</span><span style="color:#24292E">(w)</span></span> -<span class="line"><span style="color:#6F42C1"> writeChunkIhdr</span><span style="color:#24292E">(w, width, height)</span></span> -<span class="line"><span style="color:#6F42C1"> writeChunkIdat</span><span style="color:#24292E">(w, width, height, img)</span></span> -<span class="line"><span style="color:#6F42C1"> writeChunkIend</span><span style="color:#24292E">(w)</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">package</span> <span style="color: #24292f;background-color: #f6f8fa">main</span> + +<span style="color: #cf222e">import</span> <span style="color: #24292f;background-color: #f6f8fa">(</span> + <span style="color: #0a3069">"image"</span> + <span style="color: #24292f;background-color: #f6f8fa">_</span> <span style="color: #0a3069">"image/png"</span> + <span style="color: #0a3069">"io"</span> + <span style="color: #0a3069">"os"</span> +<span style="color: #24292f;background-color: #f6f8fa">)</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">main</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">inFile</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">err</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">os</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Open</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"input.png"</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">err</span> <span style="color: #0550ae">!=</span> <span style="color: #953800">nil</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #953800">panic</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">err</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #cf222e">defer</span> <span style="color: #24292f;background-color: #f6f8fa">inFile</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Close</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + + <span style="color: #24292f;background-color: #f6f8fa">img</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">_</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">err</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">image</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Decode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">inFile</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">err</span> <span style="color: #0550ae">!=</span> <span style="color: #953800">nil</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #953800">panic</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">err</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + + <span style="color: #24292f;background-color: #f6f8fa">outFile</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">err</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">os</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Create</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"output.png"</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">err</span> <span style="color: #0550ae">!=</span> <span style="color: #953800">nil</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #953800">panic</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">err</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #cf222e">defer</span> <span style="color: #24292f;background-color: #f6f8fa">outFile</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Close</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + + <span style="color: #24292f;background-color: #f6f8fa">writePng</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">outFile</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">img</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">writePng</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span> <span style="color: #24292f;background-color: #f6f8fa">io</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Writer</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">img</span> <span style="color: #24292f;background-color: #f6f8fa">image</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Image</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">width</span> <span style="color: #0550ae">:=</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">img</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Bounds</span><span style="color: #24292f;background-color: #f6f8fa">()</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Dx</span><span style="color: #24292f;background-color: #f6f8fa">())</span> + <span style="color: #24292f;background-color: #f6f8fa">height</span> <span style="color: #0550ae">:=</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">img</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Bounds</span><span style="color: #24292f;background-color: #f6f8fa">()</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Dy</span><span style="color: #24292f;background-color: #f6f8fa">())</span> + <span style="color: #24292f;background-color: #f6f8fa">writeSignature</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">writeChunkIhdr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">width</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">height</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">writeChunkIdat</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">width</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">height</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">img</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">writeChunkIend</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> 以降は、<code>writeSignature</code> や <code>writeChunkIhdr</code> などを実装していく。 @@ -215,21 +216,22 @@ <code>writeSignature</code> の実装はこちら: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">import</span><span style="color:#032F62"> "</span><span style="color:#6F42C1">encoding/binary</span><span style="color:#032F62">"</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeSignature</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#24292E"> sig </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> [</span><span style="color:#005CC5">8</span><span style="color:#24292E">]</span><span style="color:#D73A49">uint8</span><span style="color:#24292E">{</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">89</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">50</span><span style="color:#24292E">, </span><span style="color:#6A737D">// P</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">4E</span><span style="color:#24292E">, </span><span style="color:#6A737D">// N</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">47</span><span style="color:#24292E">, </span><span style="color:#6A737D">// G</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">0D</span><span style="color:#24292E">, </span><span style="color:#6A737D">// CR</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">0A</span><span style="color:#24292E">, </span><span style="color:#6A737D">// LF</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">1A</span><span style="color:#24292E">, </span><span style="color:#6A737D">// EOF (^Z)</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">0A</span><span style="color:#24292E">, </span><span style="color:#6A737D">// LF</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, sig)</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">import</span> <span style="color: #0a3069">"encoding/binary"</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">writeSignature</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span> <span style="color: #24292f;background-color: #f6f8fa">io</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Writer</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">sig</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">8</span><span style="color: #24292f;background-color: #f6f8fa">]</span><span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">0x89</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">0x50</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// P</span> + <span style="color: #0550ae">0x4E</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// N</span> + <span style="color: #0550ae">0x47</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// G</span> + <span style="color: #0550ae">0x0D</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// CR</span> + <span style="color: #0550ae">0x0A</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// LF</span> + <span style="color: #0550ae">0x1A</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// EOF (^Z)</span> + <span style="color: #0550ae">0x0A</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// LF</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">sig</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> <code>encoding/binary</code> パッケージの <code>binary.Write</code> を使い、固定の 8 バイトを書き込む。 @@ -258,55 +260,57 @@ CRC (Cyclic Redundancy Check) は誤り検出符号の一種。Go 言語では <code>hash/crc32</code> パッケージにあるが、今回はこれも自前で実装する。PNG の仕様書に C 言語のサンプルコードが載っている ( <a href="https://www.w3.org/TR/png/#D-CRCAppendix" rel="noreferrer" target="_blank">D. Sample CRC implementation</a> ) ので、これを Go に移植する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">var</span><span style="color:#24292E"> (</span></span> -<span class="line"><span style="color:#24292E"> crcTable [</span><span style="color:#005CC5">256</span><span style="color:#24292E">]</span><span style="color:#D73A49">uint32</span></span> -<span class="line"><span style="color:#24292E"> crcTableComputed </span><span style="color:#D73A49">bool</span></span> -<span class="line"><span style="color:#24292E">)</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> makeCrcTable</span><span style="color:#24292E">() {</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> n </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; n </span><span style="color:#D73A49"><</span><span style="color:#005CC5"> 256</span><span style="color:#24292E">; n</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(n)</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> k </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; k </span><span style="color:#D73A49"><</span><span style="color:#005CC5"> 8</span><span style="color:#24292E">; k</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">&</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">EDB88320</span><span style="color:#D73A49"> ^</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 1</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">=</span><span style="color:#24292E"> c </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 1</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> crcTable[n] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> c</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> crcTableComputed </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> updateCrc</span><span style="color:#24292E">(</span><span style="color:#E36209">crc</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">, </span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> !</span><span style="color:#24292E">crcTableComputed {</span></span> -<span class="line"><span style="color:#6F42C1"> makeCrcTable</span><span style="color:#24292E">()</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> crc</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> n </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; n </span><span style="color:#D73A49"><</span><span style="color:#6F42C1"> len</span><span style="color:#24292E">(buf); n</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">=</span><span style="color:#24292E"> crcTable[(c</span><span style="color:#D73A49">^uint32</span><span style="color:#24292E">(buf[n]))</span><span style="color:#D73A49">&0x</span><span style="color:#005CC5">FF</span><span style="color:#24292E">] </span><span style="color:#D73A49">^</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 8</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> c</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> crc</span><span style="color:#24292E">(</span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#6F42C1"> updateCrc</span><span style="color:#24292E">(</span><span style="color:#D73A49">0x</span><span style="color:#005CC5">FFFFFFFF</span><span style="color:#24292E">, buf) </span><span style="color:#D73A49">^</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">FFFFFFFF</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">var</span> <span style="color: #24292f;background-color: #f6f8fa">(</span> + <span style="color: #24292f;background-color: #f6f8fa">crcTable</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">256</span><span style="color: #24292f;background-color: #f6f8fa">]</span><span style="color: #cf222e">uint32</span> + <span style="color: #24292f;background-color: #f6f8fa">crcTableComputed</span> <span style="color: #cf222e">bool</span> +<span style="color: #24292f;background-color: #f6f8fa">)</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">makeCrcTable</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae">:=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">256</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">:=</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">k</span> <span style="color: #0550ae">:=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">k</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">8</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">k</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">&</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">!=</span> <span style="color: #0550ae">0</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0xEDB88320</span> <span style="color: #0550ae">^</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">>></span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">else</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">>></span> <span style="color: #0550ae">1</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">crcTable</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">c</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">crcTableComputed</span> <span style="color: #0550ae">=</span> <span style="color: #953800">true</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">updateCrc</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">crc</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">uint32</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">if</span> <span style="color: #0550ae">!</span><span style="color: #24292f;background-color: #f6f8fa">crcTableComputed</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">makeCrcTable</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + + <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">crc</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae">:=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae"><</span> <span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">);</span> <span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">crcTable</span><span style="color: #24292f;background-color: #f6f8fa">[(</span><span style="color: #24292f;background-color: #f6f8fa">c</span><span style="color: #0550ae">^</span><span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #24292f;background-color: #f6f8fa">]))</span><span style="color: #0550ae">&</span><span style="color: #0550ae">0xFF</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">^</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">>></span> <span style="color: #0550ae">8</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">c</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">crc</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">buf</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">uint32</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">updateCrc</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0xFFFFFFFF</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">^</span> <span style="color: #0550ae">0xFFFFFFFF</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> できた <code>crc</code> 関数を使って、chunk 一般を書き込む関数も用意しておこう。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">chunkType</span><span style="color:#D73A49"> string</span><span style="color:#24292E">, </span><span style="color:#E36209">data</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#24292E"> typeAndData </span><span style="color:#D73A49">:=</span><span style="color:#6F42C1"> make</span><span style="color:#24292E">([]</span><span style="color:#D73A49">byte</span><span style="color:#24292E">, </span><span style="color:#005CC5">0</span><span style="color:#24292E">, </span><span style="color:#6F42C1">len</span><span style="color:#24292E">(chunkType)</span><span style="color:#D73A49">+</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(data))</span></span> -<span class="line"><span style="color:#24292E"> typeAndData </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> append</span><span style="color:#24292E">(typeAndData, []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">(chunkType)</span><span style="color:#D73A49">...</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#24292E"> typeAndData </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> append</span><span style="color:#24292E">(typeAndData, data</span><span style="color:#D73A49">...</span><span style="color:#24292E">)</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, </span><span style="color:#D73A49">uint32</span><span style="color:#24292E">(</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(data)))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, typeAndData)</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, </span><span style="color:#6F42C1">crc</span><span style="color:#24292E">(typeAndData))</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">writeChunk</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span> <span style="color: #24292f;background-color: #f6f8fa">io</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Writer</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">chunkType</span> <span style="color: #cf222e">string</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">data</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">typeAndData</span> <span style="color: #0550ae">:=</span> <span style="color: #953800">make</span><span style="color: #24292f;background-color: #f6f8fa">([]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">chunkType</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">+</span><span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">typeAndData</span> <span style="color: #0550ae">=</span> <span style="color: #953800">append</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">typeAndData</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">chunkType</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">...</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">typeAndData</span> <span style="color: #0550ae">=</span> <span style="color: #953800">append</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">typeAndData</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #0550ae">...</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #24292f;background-color: #f6f8fa">)))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">typeAndData</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">crc</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">typeAndData</span><span style="color: #24292f;background-color: #f6f8fa">))</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> 仕様どおり、<code>chunkType</code> と <code>data</code> から CRC を計算し、<code>data</code> の長さと合わせて書き込んでいる。PNG では基本的に big endian を使うことに注意する。 @@ -384,20 +388,21 @@ 今回ほとんどのデータは決め打ちするので、データに応じて変わるのは width と height だけになる。コードは次のようになる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">import</span><span style="color:#032F62"> "</span><span style="color:#6F42C1">bytes</span><span style="color:#032F62">"</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunkIhdr</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">width</span><span style="color:#24292E">, </span><span style="color:#E36209">height</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> buf </span><span style="color:#6F42C1">bytes</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Buffer</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, width)</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, height)</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">8</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">2</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(w, </span><span style="color:#032F62">"IHDR"</span><span style="color:#24292E">, buf.</span><span style="color:#6F42C1">Bytes</span><span style="color:#24292E">())</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">import</span> <span style="color: #0a3069">"bytes"</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">writeChunkIhdr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span> <span style="color: #24292f;background-color: #f6f8fa">io</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Writer</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">width</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">height</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">var</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span> <span style="color: #24292f;background-color: #f6f8fa">bytes</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Buffer</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">width</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">height</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">8</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + + <span style="color: #24292f;background-color: #f6f8fa">writeChunk</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">"IHDR"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Bytes</span><span style="color: #24292f;background-color: #f6f8fa">())</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> </section> <section id="section--implement-png-encoder--idat-chunk"> @@ -431,22 +436,23 @@ Adler-32 も CRC と同じく誤り検出符号である。こちらも zlib の仕様書に C 言語でサンプルコードが記載されている ( <a href="https://www.rfc-editor.org/rfc/rfc1950#section-9" rel="noreferrer" target="_blank">9. Appendix: Sample code</a> ) ので、Go に移植する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> adler32Base</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> 65521</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> updateAdler32</span><span style="color:#24292E">(</span><span style="color:#E36209">adler</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">, </span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> s1 </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> adler </span><span style="color:#D73A49">&</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">FFFF</span></span> -<span class="line"><span style="color:#24292E"> s2 </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> (adler </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 16</span><span style="color:#24292E">) </span><span style="color:#D73A49">&</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">FFFF</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> n </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; n </span><span style="color:#D73A49"><</span><span style="color:#6F42C1"> len</span><span style="color:#24292E">(buf); n</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> s1 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (s1 </span><span style="color:#D73A49">+</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(buf[n])) </span><span style="color:#D73A49">%</span><span style="color:#24292E"> adler32Base</span></span> -<span class="line"><span style="color:#24292E"> s2 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (s2 </span><span style="color:#D73A49">+</span><span style="color:#24292E"> s1) </span><span style="color:#D73A49">%</span><span style="color:#24292E"> adler32Base</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> (s2 </span><span style="color:#D73A49"><<</span><span style="color:#005CC5"> 16</span><span style="color:#24292E">) </span><span style="color:#D73A49">+</span><span style="color:#24292E"> s1</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> adler32</span><span style="color:#24292E">(</span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#6F42C1"> updateAdler32</span><span style="color:#24292E">(</span><span style="color:#005CC5">1</span><span style="color:#24292E">, buf)</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">const</span> <span style="color: #24292f;background-color: #f6f8fa">adler32Base</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">65521</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">updateAdler32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">adler</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">uint32</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">s1</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">adler</span> <span style="color: #0550ae">&</span> <span style="color: #0550ae">0xFFFF</span> + <span style="color: #24292f;background-color: #f6f8fa">s2</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">adler</span> <span style="color: #0550ae">>></span> <span style="color: #0550ae">16</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">&</span> <span style="color: #0550ae">0xFFFF</span> + + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae">:=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae"><</span> <span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">);</span> <span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">s1</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">s1</span> <span style="color: #0550ae">+</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #24292f;background-color: #f6f8fa">]))</span> <span style="color: #0550ae">%</span> <span style="color: #24292f;background-color: #f6f8fa">adler32Base</span> + <span style="color: #24292f;background-color: #f6f8fa">s2</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">s2</span> <span style="color: #0550ae">+</span> <span style="color: #24292f;background-color: #f6f8fa">s1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">%</span> <span style="color: #24292f;background-color: #f6f8fa">adler32Base</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">s2</span> <span style="color: #0550ae"><<</span> <span style="color: #0550ae">16</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">+</span> <span style="color: #24292f;background-color: #f6f8fa">s1</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">adler32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">buf</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">uint32</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">updateAdler32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> 「データ」の部分には圧縮したデータが入るのだが、真面目に deflate アルゴリズムを実装する必要はない。Zlib には無圧縮のデータブロックを格納することができるので、これを使う。本来は、データの圧縮効率の悪いランダムなデータをそのまま格納するためのものだが、今回は deflate の実装をサボるために使う。 @@ -472,30 +478,31 @@ 実際にこの手抜き zlib を実装したものがこちら: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> encodeZlib</span><span style="color:#24292E">(</span><span style="color:#E36209">data</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) []</span><span style="color:#D73A49">byte</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> buf </span><span style="color:#6F42C1">bytes</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Buffer</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#D73A49">0x</span><span style="color:#005CC5">78</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#D73A49">0x</span><span style="color:#005CC5">01</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#24292E"> blockSize </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 65535</span></span> -<span class="line"><span style="color:#24292E"> isFinalBlock </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> false</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> i </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; </span><span style="color:#D73A49">!</span><span style="color:#24292E">isFinalBlock; i</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> block []</span><span style="color:#D73A49">byte</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#6F42C1"> len</span><span style="color:#24292E">(data) </span><span style="color:#D73A49"><=</span><span style="color:#24292E"> (i</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize {</span></span> -<span class="line"><span style="color:#24292E"> block </span><span style="color:#D73A49">=</span><span style="color:#24292E"> data[i</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize:]</span></span> -<span class="line"><span style="color:#24292E"> isFinalBlock </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span></span> -<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> block </span><span style="color:#D73A49">=</span><span style="color:#24292E"> data[i</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize : (i</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize]</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, isFinalBlock)</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.LittleEndian, </span><span style="color:#D73A49">uint16</span><span style="color:#24292E">(</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(block)))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.LittleEndian, </span><span style="color:#D73A49">uint16</span><span style="color:#24292E">(</span><span style="color:#D73A49">^</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(block)))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.LittleEndian, block)</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#6F42C1">adler32</span><span style="color:#24292E">(data))</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> buf.</span><span style="color:#6F42C1">Bytes</span><span style="color:#24292E">()</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">encodeZlib</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">data</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">var</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span> <span style="color: #24292f;background-color: #f6f8fa">bytes</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Buffer</span> + + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0x78</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0x01</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">blockSize</span> <span style="color: #0550ae">:=</span> <span style="color: #0550ae">65535</span> + <span style="color: #24292f;background-color: #f6f8fa">isFinalBlock</span> <span style="color: #0550ae">:=</span> <span style="color: #953800">false</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">i</span> <span style="color: #0550ae">:=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">!</span><span style="color: #24292f;background-color: #f6f8fa">isFinalBlock</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">var</span> <span style="color: #24292f;background-color: #f6f8fa">block</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span> + <span style="color: #cf222e">if</span> <span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae"><=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #0550ae">+</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">*</span><span style="color: #24292f;background-color: #f6f8fa">blockSize</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">block</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #0550ae">*</span><span style="color: #24292f;background-color: #f6f8fa">blockSize</span><span style="color: #0550ae">:</span><span style="color: #24292f;background-color: #f6f8fa">]</span> + <span style="color: #24292f;background-color: #f6f8fa">isFinalBlock</span> <span style="color: #0550ae">=</span> <span style="color: #953800">true</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">else</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">block</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #0550ae">*</span><span style="color: #24292f;background-color: #f6f8fa">blockSize</span> <span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #0550ae">+</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">*</span><span style="color: #24292f;background-color: #f6f8fa">blockSize</span><span style="color: #24292f;background-color: #f6f8fa">]</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">isFinalBlock</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">LittleEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint16</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">block</span><span style="color: #24292f;background-color: #f6f8fa">)))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">LittleEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint16</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">^</span><span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">block</span><span style="color: #24292f;background-color: #f6f8fa">)))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">LittleEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">block</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">adler32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Bytes</span><span style="color: #24292f;background-color: #f6f8fa">()</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> </section> <section id="section--implement-png-encoder--idat-chunk--image-data"> @@ -510,20 +517,21 @@ 先ほどの <code>encodeZlib</code> も使って実際に実装したものがこちら: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunkIdat</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">width</span><span style="color:#24292E">, </span><span style="color:#E36209">height</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">, </span><span style="color:#E36209">img</span><span style="color:#6F42C1"> image</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Image</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> pixels </span><span style="color:#6F42C1">bytes</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Buffer</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> y </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">); y </span><span style="color:#D73A49"><</span><span style="color:#24292E"> height; y</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> x </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">); x </span><span style="color:#D73A49"><</span><span style="color:#24292E"> width; x</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> r, g, b, _ </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> img.</span><span style="color:#6F42C1">At</span><span style="color:#24292E">(</span><span style="color:#D73A49">int</span><span style="color:#24292E">(x), </span><span style="color:#D73A49">int</span><span style="color:#24292E">(y)).</span><span style="color:#6F42C1">RGBA</span><span style="color:#24292E">()</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(r))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(g))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(b))</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(w, </span><span style="color:#032F62">"IDAT"</span><span style="color:#24292E">, </span><span style="color:#6F42C1">encodeZlib</span><span style="color:#24292E">(pixels.</span><span style="color:#6F42C1">Bytes</span><span style="color:#24292E">()))</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">writeChunkIdat</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span> <span style="color: #24292f;background-color: #f6f8fa">io</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Writer</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">width</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">height</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">img</span> <span style="color: #24292f;background-color: #f6f8fa">image</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Image</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">var</span> <span style="color: #24292f;background-color: #f6f8fa">pixels</span> <span style="color: #24292f;background-color: #f6f8fa">bytes</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Buffer</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">y</span> <span style="color: #0550ae">:=</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">);</span> <span style="color: #24292f;background-color: #f6f8fa">y</span> <span style="color: #0550ae"><</span> <span style="color: #24292f;background-color: #f6f8fa">height</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">y</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">pixels</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae">:=</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">);</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae"><</span> <span style="color: #24292f;background-color: #f6f8fa">width</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">x</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">r</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">g</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">_</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">img</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">At</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">int</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">x</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #cf222e">int</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">y</span><span style="color: #24292f;background-color: #f6f8fa">))</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">RGBA</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">pixels</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">r</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">pixels</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">g</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">pixels</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + + <span style="color: #24292f;background-color: #f6f8fa">writeChunk</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">"IDAT"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">encodeZlib</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">pixels</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Bytes</span><span style="color: #24292f;background-color: #f6f8fa">()))</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> </section> </section> @@ -536,9 +544,10 @@ 特に追加のデータはなく、必要なのは chunk type の <code>IEND</code> くらいなので実装は簡単: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunkIend</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(w, </span><span style="color:#032F62">"IEND"</span><span style="color:#24292E">, </span><span style="color:#005CC5">nil</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">writeChunkIend</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span> <span style="color: #24292f;background-color: #f6f8fa">io</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Writer</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">writeChunk</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">"IEND"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">nil</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> </section> </section> @@ -548,180 +557,181 @@ 最後に全ソースコードを再掲しておく。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">package</span><span style="color:#6F42C1"> main</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">import</span><span style="color:#24292E"> (</span></span> -<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">bytes</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">encoding/binary</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">image</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#24292E"> _ </span><span style="color:#032F62">"</span><span style="color:#6F42C1">image/png</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">io</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">os</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#24292E">)</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> main</span><span style="color:#24292E">() {</span></span> -<span class="line"><span style="color:#24292E"> inFile, err </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> os.</span><span style="color:#6F42C1">Open</span><span style="color:#24292E">(</span><span style="color:#032F62">"input.png"</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> err </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> nil</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6F42C1"> panic</span><span style="color:#24292E">(err)</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#D73A49"> defer</span><span style="color:#24292E"> inFile.</span><span style="color:#6F42C1">Close</span><span style="color:#24292E">()</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> img, _, err </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> image.</span><span style="color:#6F42C1">Decode</span><span style="color:#24292E">(inFile)</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> err </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> nil</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6F42C1"> panic</span><span style="color:#24292E">(err)</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> outFile, err </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> os.</span><span style="color:#6F42C1">Create</span><span style="color:#24292E">(</span><span style="color:#032F62">"output.png"</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> err </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> nil</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6F42C1"> panic</span><span style="color:#24292E">(err)</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#D73A49"> defer</span><span style="color:#24292E"> outFile.</span><span style="color:#6F42C1">Close</span><span style="color:#24292E">()</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> writePng</span><span style="color:#24292E">(outFile, img)</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writePng</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">img</span><span style="color:#6F42C1"> image</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Image</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#24292E"> width </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(img.</span><span style="color:#6F42C1">Bounds</span><span style="color:#24292E">().</span><span style="color:#6F42C1">Dx</span><span style="color:#24292E">())</span></span> -<span class="line"><span style="color:#24292E"> height </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(img.</span><span style="color:#6F42C1">Bounds</span><span style="color:#24292E">().</span><span style="color:#6F42C1">Dy</span><span style="color:#24292E">())</span></span> -<span class="line"><span style="color:#6F42C1"> writeSignature</span><span style="color:#24292E">(w)</span></span> -<span class="line"><span style="color:#6F42C1"> writeChunkIhdr</span><span style="color:#24292E">(w, width, height)</span></span> -<span class="line"><span style="color:#6F42C1"> writeChunkIdat</span><span style="color:#24292E">(w, width, height, img)</span></span> -<span class="line"><span style="color:#6F42C1"> writeChunkIend</span><span style="color:#24292E">(w)</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeSignature</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#24292E"> sig </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> [</span><span style="color:#005CC5">8</span><span style="color:#24292E">]</span><span style="color:#D73A49">uint8</span><span style="color:#24292E">{</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">89</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">50</span><span style="color:#24292E">, </span><span style="color:#6A737D">// P</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">4E</span><span style="color:#24292E">, </span><span style="color:#6A737D">// N</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">47</span><span style="color:#24292E">, </span><span style="color:#6A737D">// G</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">0D</span><span style="color:#24292E">, </span><span style="color:#6A737D">// CR</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">0A</span><span style="color:#24292E">, </span><span style="color:#6A737D">// LF</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">1A</span><span style="color:#24292E">, </span><span style="color:#6A737D">// EOF (^Z)</span></span> -<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">0A</span><span style="color:#24292E">, </span><span style="color:#6A737D">// LF</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, sig)</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunkIhdr</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">width</span><span style="color:#24292E">, </span><span style="color:#E36209">height</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> buf </span><span style="color:#6F42C1">bytes</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Buffer</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, width)</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, height)</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">8</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">2</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(w, </span><span style="color:#032F62">"IHDR"</span><span style="color:#24292E">, buf.</span><span style="color:#6F42C1">Bytes</span><span style="color:#24292E">())</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunkIdat</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">width</span><span style="color:#24292E">, </span><span style="color:#E36209">height</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">, </span><span style="color:#E36209">img</span><span style="color:#6F42C1"> image</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Image</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> pixels </span><span style="color:#6F42C1">bytes</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Buffer</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> y </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">); y </span><span style="color:#D73A49"><</span><span style="color:#24292E"> height; y</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> x </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">); x </span><span style="color:#D73A49"><</span><span style="color:#24292E"> width; x</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> r, g, b, _ </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> img.</span><span style="color:#6F42C1">At</span><span style="color:#24292E">(</span><span style="color:#D73A49">int</span><span style="color:#24292E">(x), </span><span style="color:#D73A49">int</span><span style="color:#24292E">(y)).</span><span style="color:#6F42C1">RGBA</span><span style="color:#24292E">()</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(r))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(g))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(b))</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(w, </span><span style="color:#032F62">"IDAT"</span><span style="color:#24292E">, </span><span style="color:#6F42C1">encodeZlib</span><span style="color:#24292E">(pixels.</span><span style="color:#6F42C1">Bytes</span><span style="color:#24292E">()))</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> encodeZlib</span><span style="color:#24292E">(</span><span style="color:#E36209">data</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) []</span><span style="color:#D73A49">byte</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> buf </span><span style="color:#6F42C1">bytes</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Buffer</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#D73A49">0x</span><span style="color:#005CC5">78</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#D73A49">0x</span><span style="color:#005CC5">01</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#24292E"> blockSize </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 65535</span></span> -<span class="line"><span style="color:#24292E"> isFinalBlock </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> false</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> i </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; </span><span style="color:#D73A49">!</span><span style="color:#24292E">isFinalBlock; i</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> block []</span><span style="color:#D73A49">byte</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#6F42C1"> len</span><span style="color:#24292E">(data) </span><span style="color:#D73A49"><=</span><span style="color:#24292E"> (i</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize {</span></span> -<span class="line"><span style="color:#24292E"> block </span><span style="color:#D73A49">=</span><span style="color:#24292E"> data[i</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize:]</span></span> -<span class="line"><span style="color:#24292E"> isFinalBlock </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span></span> -<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> block </span><span style="color:#D73A49">=</span><span style="color:#24292E"> data[i</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize : (i</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize]</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, isFinalBlock)</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.LittleEndian, </span><span style="color:#D73A49">uint16</span><span style="color:#24292E">(</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(block)))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.LittleEndian, </span><span style="color:#D73A49">uint16</span><span style="color:#24292E">(</span><span style="color:#D73A49">^</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(block)))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.LittleEndian, block)</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#6F42C1">adler32</span><span style="color:#24292E">(data))</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> buf.</span><span style="color:#6F42C1">Bytes</span><span style="color:#24292E">()</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunkIend</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(w, </span><span style="color:#032F62">"IEND"</span><span style="color:#24292E">, </span><span style="color:#005CC5">nil</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">chunkType</span><span style="color:#D73A49"> string</span><span style="color:#24292E">, </span><span style="color:#E36209">data</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#24292E"> typeAndData </span><span style="color:#D73A49">:=</span><span style="color:#6F42C1"> make</span><span style="color:#24292E">([]</span><span style="color:#D73A49">byte</span><span style="color:#24292E">, </span><span style="color:#005CC5">0</span><span style="color:#24292E">, </span><span style="color:#6F42C1">len</span><span style="color:#24292E">(chunkType)</span><span style="color:#D73A49">+</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(data))</span></span> -<span class="line"><span style="color:#24292E"> typeAndData </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> append</span><span style="color:#24292E">(typeAndData, []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">(chunkType)</span><span style="color:#D73A49">...</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#24292E"> typeAndData </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> append</span><span style="color:#24292E">(typeAndData, data</span><span style="color:#D73A49">...</span><span style="color:#24292E">)</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, </span><span style="color:#D73A49">uint32</span><span style="color:#24292E">(</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(data)))</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, typeAndData)</span></span> -<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, </span><span style="color:#6F42C1">crc</span><span style="color:#24292E">(typeAndData))</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">var</span><span style="color:#24292E"> (</span></span> -<span class="line"><span style="color:#24292E"> crcTable [</span><span style="color:#005CC5">256</span><span style="color:#24292E">]</span><span style="color:#D73A49">uint32</span></span> -<span class="line"><span style="color:#24292E"> crcTableComputed </span><span style="color:#D73A49">bool</span></span> -<span class="line"><span style="color:#24292E">)</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> makeCrcTable</span><span style="color:#24292E">() {</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> n </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; n </span><span style="color:#D73A49"><</span><span style="color:#005CC5"> 256</span><span style="color:#24292E">; n</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(n)</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> k </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; k </span><span style="color:#D73A49"><</span><span style="color:#005CC5"> 8</span><span style="color:#24292E">; k</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">&</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">EDB88320</span><span style="color:#D73A49"> ^</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 1</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">=</span><span style="color:#24292E"> c </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 1</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> crcTable[n] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> c</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> crcTableComputed </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> updateCrc</span><span style="color:#24292E">(</span><span style="color:#E36209">crc</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">, </span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> !</span><span style="color:#24292E">crcTableComputed {</span></span> -<span class="line"><span style="color:#6F42C1"> makeCrcTable</span><span style="color:#24292E">()</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> crc</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> n </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; n </span><span style="color:#D73A49"><</span><span style="color:#6F42C1"> len</span><span style="color:#24292E">(buf); n</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">=</span><span style="color:#24292E"> crcTable[(c</span><span style="color:#D73A49">^uint32</span><span style="color:#24292E">(buf[n]))</span><span style="color:#D73A49">&0x</span><span style="color:#005CC5">FF</span><span style="color:#24292E">] </span><span style="color:#D73A49">^</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 8</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> c</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> crc</span><span style="color:#24292E">(</span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#6F42C1"> updateCrc</span><span style="color:#24292E">(</span><span style="color:#D73A49">0x</span><span style="color:#005CC5">FFFFFFFF</span><span style="color:#24292E">, buf) </span><span style="color:#D73A49">^</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">FFFFFFFF</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> adler32Base</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> 65521</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> updateAdler32</span><span style="color:#24292E">(</span><span style="color:#E36209">adler</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">, </span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> s1 </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> adler </span><span style="color:#D73A49">&</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">FFFF</span></span> -<span class="line"><span style="color:#24292E"> s2 </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> (adler </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 16</span><span style="color:#24292E">) </span><span style="color:#D73A49">&</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">FFFF</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> n </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; n </span><span style="color:#D73A49"><</span><span style="color:#6F42C1"> len</span><span style="color:#24292E">(buf); n</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> s1 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (s1 </span><span style="color:#D73A49">+</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(buf[n])) </span><span style="color:#D73A49">%</span><span style="color:#24292E"> adler32Base</span></span> -<span class="line"><span style="color:#24292E"> s2 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (s2 </span><span style="color:#D73A49">+</span><span style="color:#24292E"> s1) </span><span style="color:#D73A49">%</span><span style="color:#24292E"> adler32Base</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> (s2 </span><span style="color:#D73A49"><<</span><span style="color:#005CC5"> 16</span><span style="color:#24292E">) </span><span style="color:#D73A49">+</span><span style="color:#24292E"> s1</span></span> -<span class="line"><span style="color:#24292E">}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> adler32</span><span style="color:#24292E">(</span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#6F42C1"> updateAdler32</span><span style="color:#24292E">(</span><span style="color:#005CC5">1</span><span style="color:#24292E">, buf)</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">package</span> <span style="color: #24292f;background-color: #f6f8fa">main</span> + +<span style="color: #cf222e">import</span> <span style="color: #24292f;background-color: #f6f8fa">(</span> + <span style="color: #0a3069">"bytes"</span> + <span style="color: #0a3069">"encoding/binary"</span> + <span style="color: #0a3069">"image"</span> + <span style="color: #24292f;background-color: #f6f8fa">_</span> <span style="color: #0a3069">"image/png"</span> + <span style="color: #0a3069">"io"</span> + <span style="color: #0a3069">"os"</span> +<span style="color: #24292f;background-color: #f6f8fa">)</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">main</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">inFile</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">err</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">os</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Open</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"input.png"</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">err</span> <span style="color: #0550ae">!=</span> <span style="color: #953800">nil</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #953800">panic</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">err</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #cf222e">defer</span> <span style="color: #24292f;background-color: #f6f8fa">inFile</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Close</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + + <span style="color: #24292f;background-color: #f6f8fa">img</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">_</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">err</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">image</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Decode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">inFile</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">err</span> <span style="color: #0550ae">!=</span> <span style="color: #953800">nil</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #953800">panic</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">err</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + + <span style="color: #24292f;background-color: #f6f8fa">outFile</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">err</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">os</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Create</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"output.png"</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">err</span> <span style="color: #0550ae">!=</span> <span style="color: #953800">nil</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #953800">panic</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">err</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #cf222e">defer</span> <span style="color: #24292f;background-color: #f6f8fa">outFile</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Close</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + + <span style="color: #24292f;background-color: #f6f8fa">writePng</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">outFile</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">img</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">writePng</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span> <span style="color: #24292f;background-color: #f6f8fa">io</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Writer</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">img</span> <span style="color: #24292f;background-color: #f6f8fa">image</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Image</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">width</span> <span style="color: #0550ae">:=</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">img</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Bounds</span><span style="color: #24292f;background-color: #f6f8fa">()</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Dx</span><span style="color: #24292f;background-color: #f6f8fa">())</span> + <span style="color: #24292f;background-color: #f6f8fa">height</span> <span style="color: #0550ae">:=</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">img</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Bounds</span><span style="color: #24292f;background-color: #f6f8fa">()</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Dy</span><span style="color: #24292f;background-color: #f6f8fa">())</span> + <span style="color: #24292f;background-color: #f6f8fa">writeSignature</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">writeChunkIhdr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">width</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">height</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">writeChunkIdat</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">width</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">height</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">img</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">writeChunkIend</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">writeSignature</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span> <span style="color: #24292f;background-color: #f6f8fa">io</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Writer</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">sig</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">8</span><span style="color: #24292f;background-color: #f6f8fa">]</span><span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">0x89</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">0x50</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// P</span> + <span style="color: #0550ae">0x4E</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// N</span> + <span style="color: #0550ae">0x47</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// G</span> + <span style="color: #0550ae">0x0D</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// CR</span> + <span style="color: #0550ae">0x0A</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// LF</span> + <span style="color: #0550ae">0x1A</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// EOF (^Z)</span> + <span style="color: #0550ae">0x0A</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #6e7781">// LF</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">sig</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">writeChunkIhdr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span> <span style="color: #24292f;background-color: #f6f8fa">io</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Writer</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">width</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">height</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">var</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span> <span style="color: #24292f;background-color: #f6f8fa">bytes</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Buffer</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">width</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">height</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">8</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + + <span style="color: #24292f;background-color: #f6f8fa">writeChunk</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">"IHDR"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Bytes</span><span style="color: #24292f;background-color: #f6f8fa">())</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">writeChunkIdat</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span> <span style="color: #24292f;background-color: #f6f8fa">io</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Writer</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">width</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">height</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">img</span> <span style="color: #24292f;background-color: #f6f8fa">image</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Image</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">var</span> <span style="color: #24292f;background-color: #f6f8fa">pixels</span> <span style="color: #24292f;background-color: #f6f8fa">bytes</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Buffer</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">y</span> <span style="color: #0550ae">:=</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">);</span> <span style="color: #24292f;background-color: #f6f8fa">y</span> <span style="color: #0550ae"><</span> <span style="color: #24292f;background-color: #f6f8fa">height</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">y</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">pixels</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae">:=</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">);</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae"><</span> <span style="color: #24292f;background-color: #f6f8fa">width</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">x</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">r</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">g</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">_</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">img</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">At</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">int</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">x</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #cf222e">int</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">y</span><span style="color: #24292f;background-color: #f6f8fa">))</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">RGBA</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">pixels</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">r</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">pixels</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">g</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">pixels</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + + <span style="color: #24292f;background-color: #f6f8fa">writeChunk</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">"IDAT"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">encodeZlib</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">pixels</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Bytes</span><span style="color: #24292f;background-color: #f6f8fa">()))</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">encodeZlib</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">data</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">var</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span> <span style="color: #24292f;background-color: #f6f8fa">bytes</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Buffer</span> + + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0x78</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint8</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0x01</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">blockSize</span> <span style="color: #0550ae">:=</span> <span style="color: #0550ae">65535</span> + <span style="color: #24292f;background-color: #f6f8fa">isFinalBlock</span> <span style="color: #0550ae">:=</span> <span style="color: #953800">false</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">i</span> <span style="color: #0550ae">:=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">!</span><span style="color: #24292f;background-color: #f6f8fa">isFinalBlock</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">var</span> <span style="color: #24292f;background-color: #f6f8fa">block</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span> + <span style="color: #cf222e">if</span> <span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae"><=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #0550ae">+</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">*</span><span style="color: #24292f;background-color: #f6f8fa">blockSize</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">block</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #0550ae">*</span><span style="color: #24292f;background-color: #f6f8fa">blockSize</span><span style="color: #0550ae">:</span><span style="color: #24292f;background-color: #f6f8fa">]</span> + <span style="color: #24292f;background-color: #f6f8fa">isFinalBlock</span> <span style="color: #0550ae">=</span> <span style="color: #953800">true</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">else</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">block</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #0550ae">*</span><span style="color: #24292f;background-color: #f6f8fa">blockSize</span> <span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #0550ae">+</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">*</span><span style="color: #24292f;background-color: #f6f8fa">blockSize</span><span style="color: #24292f;background-color: #f6f8fa">]</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">isFinalBlock</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">LittleEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint16</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">block</span><span style="color: #24292f;background-color: #f6f8fa">)))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">LittleEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint16</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">^</span><span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">block</span><span style="color: #24292f;background-color: #f6f8fa">)))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">LittleEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">block</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">adler32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Bytes</span><span style="color: #24292f;background-color: #f6f8fa">()</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">writeChunkIend</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span> <span style="color: #24292f;background-color: #f6f8fa">io</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Writer</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">writeChunk</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">"IEND"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">nil</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">writeChunk</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span> <span style="color: #24292f;background-color: #f6f8fa">io</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Writer</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">chunkType</span> <span style="color: #cf222e">string</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">data</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">typeAndData</span> <span style="color: #0550ae">:=</span> <span style="color: #953800">make</span><span style="color: #24292f;background-color: #f6f8fa">([]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">chunkType</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">+</span><span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #24292f;background-color: #f6f8fa">typeAndData</span> <span style="color: #0550ae">=</span> <span style="color: #953800">append</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">typeAndData</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">chunkType</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">...</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">typeAndData</span> <span style="color: #0550ae">=</span> <span style="color: #953800">append</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">typeAndData</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #0550ae">...</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">data</span><span style="color: #24292f;background-color: #f6f8fa">)))</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">typeAndData</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Write</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">binary</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">BigEndian</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">crc</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">typeAndData</span><span style="color: #24292f;background-color: #f6f8fa">))</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">var</span> <span style="color: #24292f;background-color: #f6f8fa">(</span> + <span style="color: #24292f;background-color: #f6f8fa">crcTable</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">256</span><span style="color: #24292f;background-color: #f6f8fa">]</span><span style="color: #cf222e">uint32</span> + <span style="color: #24292f;background-color: #f6f8fa">crcTableComputed</span> <span style="color: #cf222e">bool</span> +<span style="color: #24292f;background-color: #f6f8fa">)</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">makeCrcTable</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae">:=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">256</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">:=</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">k</span> <span style="color: #0550ae">:=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">k</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">8</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">k</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">&</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">!=</span> <span style="color: #0550ae">0</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0xEDB88320</span> <span style="color: #0550ae">^</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">>></span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">else</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">>></span> <span style="color: #0550ae">1</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">crcTable</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">c</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">crcTableComputed</span> <span style="color: #0550ae">=</span> <span style="color: #953800">true</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">updateCrc</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">crc</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">uint32</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">if</span> <span style="color: #0550ae">!</span><span style="color: #24292f;background-color: #f6f8fa">crcTableComputed</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">makeCrcTable</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + + <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">crc</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae">:=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae"><</span> <span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">);</span> <span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">crcTable</span><span style="color: #24292f;background-color: #f6f8fa">[(</span><span style="color: #24292f;background-color: #f6f8fa">c</span><span style="color: #0550ae">^</span><span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #24292f;background-color: #f6f8fa">]))</span><span style="color: #0550ae">&</span><span style="color: #0550ae">0xFF</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">^</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">>></span> <span style="color: #0550ae">8</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">c</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">crc</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">buf</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">uint32</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">updateCrc</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0xFFFFFFFF</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">^</span> <span style="color: #0550ae">0xFFFFFFFF</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">const</span> <span style="color: #24292f;background-color: #f6f8fa">adler32Base</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">65521</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">updateAdler32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">adler</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">uint32</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">s1</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">adler</span> <span style="color: #0550ae">&</span> <span style="color: #0550ae">0xFFFF</span> + <span style="color: #24292f;background-color: #f6f8fa">s2</span> <span style="color: #0550ae">:=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">adler</span> <span style="color: #0550ae">>></span> <span style="color: #0550ae">16</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">&</span> <span style="color: #0550ae">0xFFFF</span> + + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae">:=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">n</span> <span style="color: #0550ae"><</span> <span style="color: #953800">len</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">);</span> <span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #0550ae">++</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">s1</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">s1</span> <span style="color: #0550ae">+</span> <span style="color: #cf222e">uint32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">n</span><span style="color: #24292f;background-color: #f6f8fa">]))</span> <span style="color: #0550ae">%</span> <span style="color: #24292f;background-color: #f6f8fa">adler32Base</span> + <span style="color: #24292f;background-color: #f6f8fa">s2</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">s2</span> <span style="color: #0550ae">+</span> <span style="color: #24292f;background-color: #f6f8fa">s1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">%</span> <span style="color: #24292f;background-color: #f6f8fa">adler32Base</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">s2</span> <span style="color: #0550ae"><<</span> <span style="color: #0550ae">16</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">+</span> <span style="color: #24292f;background-color: #f6f8fa">s1</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> + +<span style="color: #cf222e">func</span> <span style="color: #24292f;background-color: #f6f8fa">adler32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">buf</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">byte</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">uint32</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">updateAdler32</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> </section> <section id="section--references"> diff --git a/services/nuldoc/public/blog/posts/2023-10-02/compile-php-runtime-to-wasm/index.html b/services/nuldoc/public/blog/posts/2023-10-02/compile-php-runtime-to-wasm/index.html index 2788add7..82fdb5d9 100644 --- a/services/nuldoc/public/blog/posts/2023-10-02/compile-php-runtime-to-wasm/index.html +++ b/services/nuldoc/public/blog/posts/2023-10-02/compile-php-runtime-to-wasm/index.html @@ -142,18 +142,19 @@ <div class="filename"> index.mjs </div> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">import</span><span style="color:#24292E"> { readFile } </span><span style="color:#D73A49">from</span><span style="color:#032F62"> 'node:fs/promises'</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">import</span><span style="color:#24292E"> PHPWasm </span><span style="color:#D73A49">from</span><span style="color:#032F62"> './php-wasm.mjs'</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> code</span><span style="color:#D73A49"> =</span><span style="color:#D73A49"> await</span><span style="color:#6F42C1"> readFile</span><span style="color:#24292E">(</span><span style="color:#032F62">'/dev/stdin'</span><span style="color:#24292E">, { encoding: </span><span style="color:#032F62">'utf-8'</span><span style="color:#24292E"> });</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">const</span><span style="color:#24292E"> { </span><span style="color:#005CC5">ccall</span><span style="color:#24292E"> } </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> await</span><span style="color:#6F42C1"> PHPWasm</span><span style="color:#24292E">();</span></span> -<span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> result</span><span style="color:#D73A49"> =</span><span style="color:#6F42C1"> ccall</span><span style="color:#24292E">(</span></span> -<span class="line"><span style="color:#032F62"> 'php_wasm_run'</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62"> 'number'</span><span style="color:#24292E">, [</span><span style="color:#032F62">'string'</span><span style="color:#24292E">],</span></span> -<span class="line"><span style="color:#24292E"> [code],</span></span> -<span class="line"><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E">console.</span><span style="color:#6F42C1">log</span><span style="color:#24292E">(</span><span style="color:#032F62">`exit code: ${</span><span style="color:#24292E">result</span><span style="color:#032F62">}`</span><span style="color:#24292E">);</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">import</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> <span style="color: #24292f;background-color: #f6f8fa">readFile</span> <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">from</span> <span style="color: #0a3069">'</span><span style="color: #0a3069">node:fs/promises</span><span style="color: #0a3069">'</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">import</span> <span style="color: #24292f;background-color: #f6f8fa">PHPWasm</span> <span style="color: #cf222e">from</span> <span style="color: #0a3069">'</span><span style="color: #0a3069">./php-wasm.mjs</span><span style="color: #0a3069">'</span> + +<span style="color: #cf222e">const</span> <span style="color: #24292f;background-color: #f6f8fa">code</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">await</span> <span style="color: #8250df">readFile</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'</span><span style="color: #0a3069">/dev/stdin</span><span style="color: #0a3069">'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> <span style="color: #116329">encoding</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">'</span><span style="color: #0a3069">utf-8</span><span style="color: #0a3069">'</span> <span style="color: #24292f;background-color: #f6f8fa">});</span> + +<span style="color: #cf222e">const</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> <span style="color: #24292f;background-color: #f6f8fa">ccall</span> <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">await</span> <span style="color: #953800">PHPWasm</span><span style="color: #24292f;background-color: #f6f8fa">();</span> +<span style="color: #cf222e">const</span> <span style="color: #24292f;background-color: #f6f8fa">result</span> <span style="color: #0550ae">=</span> <span style="color: #8250df">ccall</span><span style="color: #24292f;background-color: #f6f8fa">(</span> + <span style="color: #0a3069">'</span><span style="color: #0a3069">php_wasm_run</span><span style="color: #0a3069">'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0a3069">'</span><span style="color: #0a3069">number</span><span style="color: #0a3069">'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">'</span><span style="color: #0a3069">string</span><span style="color: #0a3069">'</span><span style="color: #24292f;background-color: #f6f8fa">],</span> + <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">code</span><span style="color: #24292f;background-color: #f6f8fa">],</span> +<span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #24292f;background-color: #f6f8fa">console</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">log</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">`exit code: </span><span style="color: #24292f;background-color: #f6f8fa">${</span><span style="color: #24292f;background-color: #f6f8fa">result</span><span style="color: #24292f;background-color: #f6f8fa">}</span><span style="color: #0a3069">`</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +</code></pre> </div> <p> 標準入力から与えたコードを WebAssembly にコンパイルされた PHP 処理系の上で実行している。このような <code>php-wasm.mjs</code> (とそこから呼び出される <code>php-wasm.wasm</code>) を作成する。 @@ -167,30 +168,31 @@ 先ほどのコードでも使っていたエントリポイントである <code>php_wasm_run</code> を用意する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">#include</span><span style="color:#032F62"> <stdio.h></span></span> -<span class="line"><span style="color:#D73A49">#include</span><span style="color:#032F62"> <emscripten.h></span></span> -<span class="line"><span style="color:#D73A49">#include</span><span style="color:#032F62"> <Zend/zend_execute.h></span></span> -<span class="line"><span style="color:#D73A49">#include</span><span style="color:#032F62"> <sapi/embed/php_embed.h></span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">int</span><span style="color:#24292E"> EMSCRIPTEN_KEEPALIVE </span><span style="color:#6F42C1">php_wasm_run</span><span style="color:#24292E">(</span><span style="color:#D73A49">const</span><span style="color:#D73A49"> char*</span><span style="color:#E36209"> code</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#24292E"> zend_result result;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49"> int</span><span style="color:#24292E"> argc </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49"> char*</span><span style="color:#24292E"> argv</span><span style="color:#D73A49">[]</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> { </span><span style="color:#032F62">"php.wasm"</span><span style="color:#24292E">, </span><span style="color:#005CC5">NULL</span><span style="color:#24292E"> };</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> PHP_EMBED_START_BLOCK</span><span style="color:#24292E">(argc, argv);</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> result </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> zend_eval_string_ex</span><span style="color:#24292E">(code, </span><span style="color:#005CC5">NULL</span><span style="color:#24292E">, </span><span style="color:#032F62">"php.wasm code"</span><span style="color:#24292E">, </span><span style="color:#005CC5">1</span><span style="color:#24292E">);</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> PHP_EMBED_END_BLOCK</span><span style="color:#24292E">();</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> fprintf</span><span style="color:#24292E">(stdout, </span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#6F42C1"> fflush</span><span style="color:#24292E">(stdout);</span></span> -<span class="line"><span style="color:#6F42C1"> fprintf</span><span style="color:#24292E">(stderr, </span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#6F42C1"> fflush</span><span style="color:#24292E">(stderr);</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> result </span><span style="color:#D73A49">==</span><span style="color:#24292E"> SUCCESS </span><span style="color:#D73A49">?</span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> :</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781">#include</span> <span style="color: #6e7781"><stdio.h></span><span style="color: #6e7781"> +#include</span> <span style="color: #6e7781"><emscripten.h></span><span style="color: #6e7781"> +#include</span> <span style="color: #6e7781"><Zend/zend_execute.h></span><span style="color: #6e7781"> +#include</span> <span style="color: #6e7781"><sapi/embed/php_embed.h></span><span style="color: #6e7781"> +</span> +<span style="color: #cf222e">int</span> <span style="color: #24292f;background-color: #f6f8fa">EMSCRIPTEN_KEEPALIVE</span> <span style="color: #8250df">php_wasm_run</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">const</span> <span style="color: #cf222e">char</span><span style="color: #0550ae">*</span> <span style="color: #24292f;background-color: #f6f8fa">code</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">zend_result</span> <span style="color: #24292f;background-color: #f6f8fa">result</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + + <span style="color: #cf222e">int</span> <span style="color: #24292f;background-color: #f6f8fa">argc</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">char</span><span style="color: #0550ae">*</span> <span style="color: #24292f;background-color: #f6f8fa">argv</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> <span style="color: #0a3069">"php.wasm"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">NULL</span> <span style="color: #24292f;background-color: #f6f8fa">};</span> + + <span style="color: #24292f;background-color: #f6f8fa">PHP_EMBED_START_BLOCK</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">argc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">argv</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + + <span style="color: #24292f;background-color: #f6f8fa">result</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">zend_eval_string_ex</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">code</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">NULL</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">"php.wasm code"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + + <span style="color: #24292f;background-color: #f6f8fa">PHP_EMBED_END_BLOCK</span><span style="color: #24292f;background-color: #f6f8fa">();</span> + + <span style="color: #24292f;background-color: #f6f8fa">fprintf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">stdout</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">fflush</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">stdout</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">fprintf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">stderr</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">fflush</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">stderr</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">result</span> <span style="color: #0550ae">==</span> <span style="color: #24292f;background-color: #f6f8fa">SUCCESS</span> <span style="color: #0550ae">?</span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">:</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> ほとんどはただの PHP の公開 API を使ったコードだが、Emscripten 向けの注意点が 2点ある。 @@ -213,15 +215,16 @@ デフォルトの出力方法は <code>index.mjs</code> の中で <code>PHPWasm()</code> を呼ぶとき、<code>stdout</code>・<code>stderr</code> というオプションを渡せば変更できる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">const</span><span style="color:#24292E"> { </span><span style="color:#005CC5">ccall</span><span style="color:#24292E"> } </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> await</span><span style="color:#6F42C1"> PHPWasm</span><span style="color:#24292E">({</span></span> -<span class="line"><span style="color:#6F42C1"> stdout</span><span style="color:#24292E">: (</span><span style="color:#E36209">c</span><span style="color:#24292E">) </span><span style="color:#D73A49">=></span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> null</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#6A737D"> // flush the standard output.</span></span> -<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6A737D"> // output c to the standard output.</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> },</span></span> -<span class="line"><span style="color:#24292E">});</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">const</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> <span style="color: #24292f;background-color: #f6f8fa">ccall</span> <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">await</span> <span style="color: #953800">PHPWasm</span><span style="color: #24292f;background-color: #f6f8fa">({</span> + <span style="color: #116329">stdout</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">c</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">if </span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">null</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #6e7781">// flush the standard output.</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">else</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #6e7781">// output c to the standard output.</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">},</span> +<span style="color: #24292f;background-color: #f6f8fa">});</span> +</code></pre> </div> <p> <code>c</code> は <code>null</code> か 1バイト符号つき整数を取り、<code>null</code> が flush 要求を意味する。 @@ -241,49 +244,52 @@ まずは <a href="https://hub.docker.com/r/emscripten/emsdk" rel="noreferrer" target="_blank">Emscripten 公式が提供している Docker イメージ</a> を使って、PHP 処理系と先ほど示した C 言語のソースコードを WebAssembly にコンパイルする。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">FROM</span><span style="color:#24292E"> emscripten/emsdk:3.1.46 </span><span style="color:#D73A49">AS</span><span style="color:#24292E"> wasm-builder</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">FROM</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069">emscripten/emsdk:3.1.46</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #cf222e">AS</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069">wasm-builder</span> +</code></pre> </div> <p> 次に、 <a href="https://github.com/php/php-src" rel="noreferrer" target="_blank">php/php-src</a> から PHP 処理系のソースコードを取得し、ビルドに必要な apt パッケージを取ってくる。有効にする拡張を増やしたいなら、ここでインストールするパッケージも増やすことになるだろう。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">RUN</span><span style="color:#24292E"> git clone --depth=1 --branch=php-8.2.10 https://github.com/php/php-src</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">RUN</span><span style="color:#24292E"> apt-get update && \</span></span> -<span class="line"><span style="color:#24292E"> apt-get install -y --no-install-recommends \</span></span> -<span class="line"><span style="color:#24292E"> autoconf \</span></span> -<span class="line"><span style="color:#24292E"> bison \</span></span> -<span class="line"><span style="color:#24292E"> pkg-config \</span></span> -<span class="line"><span style="color:#24292E"> re2c \</span></span> -<span class="line"><span style="color:#24292E"> && \</span></span> -<span class="line"><span style="color:#24292E"> :</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">RUN </span>git clone <span style="color: #116329">--depth</span><span style="color: #0550ae">=</span>1 <span style="color: #116329">--branch</span><span style="color: #0550ae">=</span>php-8.2.10 https://github.com/php/php-src + +<span style="color: #cf222e">RUN </span>apt-get update <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> apt-get <span style="color: #953800">install</span> <span style="color: #116329">-y</span> <span style="color: #116329">--no-install-recommends</span> <span style="color: #0a3069">\ +</span> autoconf <span style="color: #0a3069">\ +</span> bison <span style="color: #0a3069">\ +</span> pkg-config <span style="color: #0a3069">\ +</span> re2c <span style="color: #0a3069">\ +</span> <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> : +</code></pre> </div> <p> 続けて、Emscripten のツールチェインを用いて PHP 処理系をビルドする。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">RUN</span><span style="color:#24292E"> cd php-src && \</span></span> -<span class="line"><span style="color:#24292E"> ./buildconf --force && \</span></span> -<span class="line"><span style="color:#24292E"> emconfigure ./configure \</span></span> -<span class="line"><span style="color:#24292E"> --disable-all \</span></span> -<span class="line"><span style="color:#24292E"> --disable-mbregex \</span></span> -<span class="line"><span style="color:#24292E"> --disable-fiber-asm \</span></span> -<span class="line"><span style="color:#24292E"> --disable-cli \</span></span> -<span class="line"><span style="color:#24292E"> --disable-cgi \</span></span> -<span class="line"><span style="color:#24292E"> --disable-phpdbg \</span></span> -<span class="line"><span style="color:#24292E"> --enable-embed=static \</span></span> -<span class="line"><span style="color:#24292E"> --enable-mbstring \</span></span> -<span class="line"><span style="color:#24292E"> --without-iconv \</span></span> -<span class="line"><span style="color:#24292E"> --without-libxml \</span></span> -<span class="line"><span style="color:#24292E"> --without-pcre-jit \</span></span> -<span class="line"><span style="color:#24292E"> --without-pdo-sqlite \</span></span> -<span class="line"><span style="color:#24292E"> --without-sqlite3 \</span></span> -<span class="line"><span style="color:#24292E"> && \</span></span> -<span class="line"><span style="color:#24292E"> EMCC_CFLAGS=</span><span style="color:#032F62">'-s ERROR_ON_UNDEFINED_SYMBOLS=0'</span><span style="color:#24292E"> emmake make -j$(nproc) && \</span></span> -<span class="line"><span style="color:#24292E"> mv libs/libphp.a .. && \</span></span> -<span class="line"><span style="color:#24292E"> make clean && \</span></span> -<span class="line"><span style="color:#24292E"> git clean -fd && \</span></span> -<span class="line"><span style="color:#24292E"> :</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">RUN </span><span style="color: #953800">cd </span>php-src <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> ./buildconf <span style="color: #116329">--force</span> <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> emconfigure ./configure <span style="color: #0a3069">\ +</span> <span style="color: #116329">--disable-all</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">--disable-mbregex</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">--disable-fiber-asm</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">--disable-cli</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">--disable-cgi</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">--disable-phpdbg</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">--enable-embed</span><span style="color: #0550ae">=</span>static <span style="color: #0a3069">\ +</span> <span style="color: #116329">--enable-mbstring</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">--without-iconv</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">--without-libxml</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">--without-pcre-jit</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">--without-pdo-sqlite</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">--without-sqlite3</span> <span style="color: #0a3069">\ +</span> <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> <span style="color: #0550ae">EMCC_CFLAGS</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'-s ERROR_ON_UNDEFINED_SYMBOLS=0'</span> emmake make <span style="color: #116329">-j</span><span style="color: #24292f">$(</span><span style="color: #953800">nproc</span><span style="color: #24292f">)</span> <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> <span style="color: #953800">mv </span>libs/libphp.a .. <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> make clean <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> git clean <span style="color: #116329">-fd</span> <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> : +</code></pre> </div> <p> ここまでと比べると少し複雑なので、それぞれ詳しく見ていこう。 @@ -307,22 +313,23 @@ さて、PHP 処理系をライブラリ化できたので、次に先ほど載せた C のソースコードをビルドしていこう。<code>Dockerfile</code> と同じ場所に <code>php-wasm.c</code> という名前で保存し、次のようにする。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">COPY</span><span style="color:#24292E"> php-wasm.c /src/</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">RUN</span><span style="color:#24292E"> cd php-src && \</span></span> -<span class="line"><span style="color:#24292E"> emcc \</span></span> -<span class="line"><span style="color:#24292E"> -c \</span></span> -<span class="line"><span style="color:#24292E"> -o php-wasm.o \</span></span> -<span class="line"><span style="color:#24292E"> -I . \</span></span> -<span class="line"><span style="color:#24292E"> -I TSRM \</span></span> -<span class="line"><span style="color:#24292E"> -I Zend \</span></span> -<span class="line"><span style="color:#24292E"> -I main \</span></span> -<span class="line"><span style="color:#24292E"> ../php-wasm.c \</span></span> -<span class="line"><span style="color:#24292E"> && \</span></span> -<span class="line"><span style="color:#24292E"> mv php-wasm.o .. && \</span></span> -<span class="line"><span style="color:#24292E"> make clean && \</span></span> -<span class="line"><span style="color:#24292E"> git clean -fd && \</span></span> -<span class="line"><span style="color:#24292E"> :</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">COPY</span><span style="color: #0a3069"> php-wasm.c /src/</span> + +<span style="color: #cf222e">RUN </span><span style="color: #953800">cd </span>php-src <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> emcc <span style="color: #0a3069">\ +</span> <span style="color: #116329">-c</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">-o</span> php-wasm.o <span style="color: #0a3069">\ +</span> <span style="color: #116329">-I</span> <span style="color: #953800">.</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">-I</span> TSRM <span style="color: #0a3069">\ +</span> <span style="color: #116329">-I</span> Zend <span style="color: #0a3069">\ +</span> <span style="color: #116329">-I</span> main <span style="color: #0a3069">\ +</span> ../php-wasm.c <span style="color: #0a3069">\ +</span> <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> <span style="color: #953800">mv </span>php-wasm.o .. <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> make clean <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> git clean <span style="color: #116329">-fd</span> <span style="color: #0550ae">&&</span> <span style="color: #0a3069">\ +</span> : +</code></pre> </div> <p> <code>emcc</code> は <code>cc</code> (C コンパイラ/リンカ) の Emscripten 版で、<code>-c</code> は「コンパイル」の意。<code>-o</code> や <code>-I</code> は普通の C コンパイラと同様、出力ファイルの指定とインクルードパスの指定である。 @@ -331,18 +338,19 @@ <code>libphp.a</code> と <code>php-wasm.o</code> が手に入ったので、これらをリンクして WebAssembly のバイナリとそのラッパである JavaScript ファイルを生成する。これにも <code>emcc</code> コマンドを使う。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">RUN</span><span style="color:#24292E"> emcc \</span></span> -<span class="line"><span style="color:#24292E"> -s ENVIRONMENT=node \</span></span> -<span class="line"><span style="color:#24292E"> -s ERROR_ON_UNDEFINED_SYMBOLS=0 \</span></span> -<span class="line"><span style="color:#24292E"> -s EXPORTED_RUNTIME_METHODS=</span><span style="color:#032F62">'["ccall"]'</span><span style="color:#24292E"> \</span></span> -<span class="line"><span style="color:#24292E"> -s EXPORT_ES6=1 \</span></span> -<span class="line"><span style="color:#24292E"> -s INITIAL_MEMORY=16777216 \</span></span> -<span class="line"><span style="color:#24292E"> -s INVOKE_RUN=0 \</span></span> -<span class="line"><span style="color:#24292E"> -s MODULARIZE=1 \</span></span> -<span class="line"><span style="color:#24292E"> -o php-wasm.js \</span></span> -<span class="line"><span style="color:#24292E"> php-wasm.o \</span></span> -<span class="line"><span style="color:#24292E"> libphp.a \</span></span> -<span class="line"><span style="color:#24292E"> ;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">RUN </span>emcc <span style="color: #0a3069">\ +</span> <span style="color: #116329">-s</span> <span style="color: #0550ae">ENVIRONMENT</span><span style="color: #0550ae">=</span>node <span style="color: #0a3069">\ +</span> <span style="color: #116329">-s</span> <span style="color: #0550ae">ERROR_ON_UNDEFINED_SYMBOLS</span><span style="color: #0550ae">=</span>0 <span style="color: #0a3069">\ +</span> <span style="color: #116329">-s</span> <span style="color: #0550ae">EXPORTED_RUNTIME_METHODS</span><span style="color: #0550ae">=</span><span style="color: #0a3069">'["ccall"]'</span> <span style="color: #0a3069">\ +</span> <span style="color: #116329">-s</span> <span style="color: #0550ae">EXPORT_ES6</span><span style="color: #0550ae">=</span>1 <span style="color: #0a3069">\ +</span> <span style="color: #116329">-s</span> <span style="color: #0550ae">INITIAL_MEMORY</span><span style="color: #0550ae">=</span>16777216 <span style="color: #0a3069">\ +</span> <span style="color: #116329">-s</span> <span style="color: #0550ae">INVOKE_RUN</span><span style="color: #0550ae">=</span>0 <span style="color: #0a3069">\ +</span> <span style="color: #116329">-s</span> <span style="color: #0550ae">MODULARIZE</span><span style="color: #0550ae">=</span>1 <span style="color: #0a3069">\ +</span> <span style="color: #116329">-o</span> php-wasm.js <span style="color: #0a3069">\ +</span> php-wasm.o <span style="color: #0a3069">\ +</span> libphp.a <span style="color: #0a3069">\ +</span> <span style="color: #24292f;background-color: #f6f8fa">;</span> +</code></pre> </div> <p> それぞれのフラグについて解説する。 @@ -375,14 +383,15 @@ といっても、Node.js はビルトインで WebAssembly をサポートしているので、ほとんどやることはない。先ほど掲載した JavaScript のコードは、<code>Dockerfile</code> と同じディレクトリに <code>index.mjs</code> で配置すること。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">FROM</span><span style="color:#24292E"> node:20.7</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">WORKDIR</span><span style="color:#24292E"> /app</span></span> -<span class="line"><span style="color:#D73A49">COPY</span><span style="color:#24292E"> --from=wasm-builder /src/php-wasm.js /app/php-wasm.mjs</span></span> -<span class="line"><span style="color:#D73A49">COPY</span><span style="color:#24292E"> --from=wasm-builder /src/php-wasm.wasm /app/php-wasm.wasm</span></span> -<span class="line"><span style="color:#D73A49">COPY</span><span style="color:#24292E"> index.mjs /app/</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">ENTRYPOINT</span><span style="color:#24292E"> [</span><span style="color:#032F62">"node"</span><span style="color:#24292E">, </span><span style="color:#032F62">"index.mjs"</span><span style="color:#24292E">]</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">FROM</span><span style="color: #0a3069"> node:20.7</span> + +<span style="color: #cf222e">WORKDIR</span><span style="color: #0a3069"> /app</span> +<span style="color: #cf222e">COPY</span><span style="color: #0a3069"> --from=wasm-builder /src/php-wasm.js /app/php-wasm.mjs</span> +<span style="color: #cf222e">COPY</span><span style="color: #0a3069"> --from=wasm-builder /src/php-wasm.wasm /app/php-wasm.wasm</span> +<span style="color: #cf222e">COPY</span><span style="color: #0a3069"> index.mjs /app/</span> + +<span style="color: #cf222e">ENTRYPOINT</span><span style="color: #0a3069"> ["node", "index.mjs"]</span> +</code></pre> </div> </section> </section> @@ -392,12 +401,13 @@ <code>Dockerfile</code>、<code>php-wasm.c</code>、<code>index.mjs</code> を用意したら、Docker コンテナをビルドして実行する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ docker build -t php-wasm .</span></span> -<span class="line"><span>$ echo 'echo "Hello, World!", PHP_EOL;' | docker run --rm -i php-wasm</span></span> -<span class="line"><span>Hello, World!</span></span> -<span class="line"><span></span></span> -<span class="line"><span></span></span> -<span class="line"><span>exit code: 0</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ docker build -t php-wasm . +$ echo 'echo "Hello, World!", PHP_EOL;' | docker run --rm -i php-wasm +Hello, World! + + +exit code: 0 +</code></pre> </div> </section> <section id="section--outro"> diff --git a/services/nuldoc/public/blog/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html b/services/nuldoc/public/blog/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html index 35fa781a..b514f764 100644 --- a/services/nuldoc/public/blog/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html +++ b/services/nuldoc/public/blog/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html @@ -100,18 +100,20 @@ Neovim で空の PHP ファイルを開いたとき、そのファイルが置かれているディレクトリの構造に基づいて、自動的に <code>namespace</code> 宣言を挿入したい。具体的には、トップレベルの名前空間が <code>MyNamespace</code> であり、ファイル <code>src/Foo/Bar/Baz.php</code> を開いたときに、そのファイルが空であるなら、次のようなテンプレートが自動的に挿入されてほしい。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">namespace</span><span style="color:#6F42C1"> MyNamespace\Foo\Bar</span><span style="color:#24292E">;</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> + +<span style="color: #cf222e">namespace</span> <span style="color: #953800">MyNamespace\Foo\Bar</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +</code></pre> </div> </section> <section id="section--version"> <h2><a href="#section--version">バージョン情報</a></h2> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ nvim --version</span></span> -<span class="line"><span>NVIM v0.9.2</span></span> -<span class="line"><span>Build type: Release</span></span> -<span class="line"><span>LuaJIT 2.1.1693350652</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ nvim --version +NVIM v0.9.2 +Build type: Release +LuaJIT 2.1.1693350652 +</code></pre> </div> <p> 今回は Lua で処理を記述したため、Vim では動作しない。以下の説明でも Neovim に絞って述べる。また、パス区切りがスラッシュである前提で記述したため、Windows には対応していない。 @@ -135,13 +137,14 @@ ファイルタイプは読み込んだあとに変更されることもあるので、ftplugin は複数回実行されうる。二重読み込みを防ぐために、<code>did_ftplugin_<FILE_TYPE>_after</code> というバッファローカル変数を定義しておくのが慣習となっている。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">b</span><span style="color:#24292E">.</span><span style="color:#6F42C1">did_ftplugin_php_after</span><span style="color:#D73A49"> then</span></span> -<span class="line"><span style="color:#D73A49"> return</span></span> -<span class="line"><span style="color:#D73A49">end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D">-- ここに実際の処理を書く</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">vim.</span><span style="color:#6F42C1">b</span><span style="color:#24292E">.</span><span style="color:#6F42C1">did_ftplugin_php_after</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> true</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">did_ftplugin_php_after</span> <span style="color: #cf222e">then</span> + <span style="color: #cf222e">return</span> +<span style="color: #cf222e">end</span> + +<span style="color: #6e7781">-- ここに実際の処理を書く</span> + +<span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">did_ftplugin_php_after</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">true</span> +</code></pre> </div> </section> <section id="section--implement"> @@ -173,119 +176,120 @@ 実装を簡単にするため、Composer を用いない場合や PSR 4 以外のオートロード規則を使う場合には対応しない。少々長くなるが、以下にスクリプト全文を載せる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">b</span><span style="color:#24292E">.</span><span style="color:#6F42C1">did_ftplugin_php_after</span><span style="color:#D73A49"> then</span></span> -<span class="line"><span style="color:#D73A49"> return</span></span> -<span class="line"><span style="color:#D73A49">end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D">-- base_dir を起点としてディレクトリを上向きに辿っていき、composer.json を探す</span></span> -<span class="line"><span style="color:#6A737D">-- :help vim.fs.find()</span></span> -<span class="line"><span style="color:#D73A49">local</span><span style="color:#D73A49"> function</span><span style="color:#6F42C1"> find_composer_json</span><span style="color:#24292E">(base_dir)</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fs</span><span style="color:#24292E">.</span><span style="color:#005CC5">find</span><span style="color:#24292E">(</span><span style="color:#032F62">'composer.json'</span><span style="color:#24292E">, {</span></span> -<span class="line"><span style="color:#24292E"> path </span><span style="color:#D73A49">=</span><span style="color:#24292E"> base_dir,</span></span> -<span class="line"><span style="color:#24292E"> upward </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#6A737D"> -- ホームディレクトリまで到達したら探索を打ち切る</span></span> -<span class="line"><span style="color:#24292E"> stop </span><span style="color:#D73A49">=</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">loop</span><span style="color:#24292E">.</span><span style="color:#005CC5">os_homedir</span><span style="color:#24292E">(),</span></span> -<span class="line"><span style="color:#24292E"> type </span><span style="color:#D73A49">=</span><span style="color:#032F62"> 'file'</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> })[</span><span style="color:#005CC5">1</span><span style="color:#24292E">]</span></span> -<span class="line"><span style="color:#D73A49">end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D">-- JSON ファイルを読み込み、デコードして返す</span></span> -<span class="line"><span style="color:#6A737D">-- :help readblob()</span></span> -<span class="line"><span style="color:#6A737D">-- :help vim.json.decode</span></span> -<span class="line"><span style="color:#6A737D">-- :help luaref-pcall()</span></span> -<span class="line"><span style="color:#D73A49">local</span><span style="color:#D73A49"> function</span><span style="color:#6F42C1"> load_json</span><span style="color:#24292E">(file_path)</span></span> -<span class="line"><span style="color:#6A737D"> -- readblob() は Vim script では Blob オブジェクトを返すが、Lua から呼ぶと string に変換される</span></span> -<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> ok_read, content </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> pcall</span><span style="color:#24292E">(vim.</span><span style="color:#6F42C1">fn</span><span style="color:#24292E">.</span><span style="color:#6F42C1">readblob</span><span style="color:#24292E">, file_path)</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> not</span><span style="color:#24292E"> ok_read </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> ok_decode, obj </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> pcall</span><span style="color:#24292E">(vim.</span><span style="color:#6F42C1">json</span><span style="color:#24292E">.</span><span style="color:#6F42C1">decode</span><span style="color:#24292E">, content)</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> not</span><span style="color:#24292E"> ok_decode </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> obj</span></span> -<span class="line"><span style="color:#D73A49">end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D">-- 対象ファイルの置かれたディレクトリを基に namespace 宣言を生成する</span></span> -<span class="line"><span style="color:#6A737D">-- :help nvim_buf_get_name()</span></span> -<span class="line"><span style="color:#6A737D">-- :help vim.fs.dirname()</span></span> -<span class="line"><span style="color:#D73A49">local</span><span style="color:#D73A49"> function</span><span style="color:#6F42C1"> generate_namespace_declaration</span><span style="color:#24292E">()</span></span> -<span class="line"><span style="color:#6A737D"> -- composer.json を探し、トップレベルの名前空間とディレクトリを特定する</span></span> -<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> current_dir </span><span style="color:#D73A49">=</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fs</span><span style="color:#24292E">.</span><span style="color:#005CC5">dirname</span><span style="color:#24292E">(vim.</span><span style="color:#6F42C1">api</span><span style="color:#24292E">.</span><span style="color:#005CC5">nvim_buf_get_name</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span> -<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> path_to_composer_json </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> find_composer_json</span><span style="color:#24292E">(current_dir)</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> not</span><span style="color:#24292E"> path_to_composer_json </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span><span style="color:#6A737D"> -- failed to locate composer.json</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> composer_json </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> load_json</span><span style="color:#24292E">(path_to_composer_json)</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> not</span><span style="color:#24292E"> composer_json </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span><span style="color:#6A737D"> -- failed to load composer.json</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#6A737D"> -- autoload.psr-4 を探し、型が期待される型と一致するかどうか調べる</span></span> -<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> psr4 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> vim.</span><span style="color:#005CC5">tbl_get</span><span style="color:#24292E">(composer_json, </span><span style="color:#032F62">'autoload'</span><span style="color:#24292E">, </span><span style="color:#032F62">'psr-4'</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> not</span><span style="color:#24292E"> psr4 </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span><span style="color:#6A737D"> -- autoload.psr-4 section is absent</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> vim.</span><span style="color:#005CC5">tbl_count</span><span style="color:#24292E">(psr4) </span><span style="color:#D73A49">~=</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49"> then</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span><span style="color:#6A737D"> -- psr-4 section is ambiguous</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> psr4_namespace, psr4_dir</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> k, v </span><span style="color:#D73A49">in</span><span style="color:#005CC5"> pairs</span><span style="color:#24292E">(psr4) </span><span style="color:#D73A49">do</span></span> -<span class="line"><span style="color:#24292E"> psr4_namespace </span><span style="color:#D73A49">=</span><span style="color:#24292E"> k</span></span> -<span class="line"><span style="color:#24292E"> psr4_dir </span><span style="color:#D73A49">=</span><span style="color:#24292E"> v</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#005CC5"> type</span><span style="color:#24292E">(psr4_dir) </span><span style="color:#D73A49">==</span><span style="color:#032F62"> 'table' </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> #</span><span style="color:#24292E">psr4_dir </span><span style="color:#D73A49">==</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49"> then</span></span> -<span class="line"><span style="color:#24292E"> psr4_dir </span><span style="color:#D73A49">=</span><span style="color:#24292E"> psr4_dir[</span><span style="color:#005CC5">1</span><span style="color:#24292E">]</span></span> -<span class="line"><span style="color:#D73A49"> else</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span><span style="color:#6A737D"> -- psr-4 section is ambiguous</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#005CC5"> type</span><span style="color:#24292E">(psr4_namespace) </span><span style="color:#D73A49">~=</span><span style="color:#032F62"> 'string' </span><span style="color:#D73A49">or</span><span style="color:#005CC5"> type</span><span style="color:#24292E">(psr4_dir) </span><span style="color:#D73A49">~=</span><span style="color:#032F62"> 'string' </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span><span style="color:#6A737D"> -- psr-4 section is invalid</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#6A737D"> -- 末尾のスラッシュとバックスラッシュを取り除いておく</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#6F42C1"> psr4_namespace</span><span style="color:#24292E">:</span><span style="color:#005CC5">sub</span><span style="color:#24292E">(</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">) </span><span style="color:#D73A49">==</span><span style="color:#032F62"> '</span><span style="color:#005CC5">\\</span><span style="color:#032F62">' </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#24292E"> psr4_namespace </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> psr4_namespace</span><span style="color:#24292E">:</span><span style="color:#005CC5">sub</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">, </span><span style="color:#D73A49">-</span><span style="color:#005CC5">2</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#6F42C1"> psr4_dir</span><span style="color:#24292E">:</span><span style="color:#005CC5">sub</span><span style="color:#24292E">(</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">) </span><span style="color:#D73A49">==</span><span style="color:#032F62"> '/' </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#24292E"> psr4_dir </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> psr4_dir</span><span style="color:#24292E">:</span><span style="color:#005CC5">sub</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">, </span><span style="color:#D73A49">-</span><span style="color:#005CC5">2</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D"> -- 対象ファイルが置かれたディレクトリとトップレベルのディレクトリを比較し、その差分を名前空間とする</span></span> -<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> namespace_root_dir </span><span style="color:#D73A49">=</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fs</span><span style="color:#24292E">.</span><span style="color:#005CC5">dirname</span><span style="color:#24292E">(path_to_composer_json) </span><span style="color:#D73A49">..</span><span style="color:#032F62"> '/' </span><span style="color:#D73A49">..</span><span style="color:#24292E"> psr4_dir</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> not</span><span style="color:#24292E"> vim.</span><span style="color:#005CC5">startswith</span><span style="color:#24292E">(current_dir, namespace_root_dir) </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> current_path_suffix </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> current_dir</span><span style="color:#24292E">:</span><span style="color:#005CC5">sub</span><span style="color:#24292E">(</span><span style="color:#D73A49">#</span><span style="color:#24292E">namespace_root_dir </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> namespace </span><span style="color:#D73A49">=</span><span style="color:#24292E"> psr4_namespace </span><span style="color:#D73A49">..</span><span style="color:#6F42C1"> current_path_suffix</span><span style="color:#24292E">:</span><span style="color:#005CC5">gsub</span><span style="color:#24292E">(</span><span style="color:#032F62">'/'</span><span style="color:#24292E">, </span><span style="color:#032F62">'</span><span style="color:#005CC5">\\</span><span style="color:#032F62">'</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> (</span><span style="color:#032F62">"namespace %s;"</span><span style="color:#24292E">):</span><span style="color:#005CC5">format</span><span style="color:#24292E">(namespace)</span></span> -<span class="line"><span style="color:#D73A49">end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">local</span><span style="color:#D73A49"> function</span><span style="color:#6F42C1"> generate_template</span><span style="color:#24292E">()</span></span> -<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> lines </span><span style="color:#D73A49">=</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#032F62"> '<?php'</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62"> ''</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62"> 'declare(strict_types=1);'</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62"> ''</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> namespace_decl </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> generate_namespace_declaration</span><span style="color:#24292E">()</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> namespace_decl </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#24292E"> lines[</span><span style="color:#D73A49">#</span><span style="color:#24292E">lines </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> namespace_decl</span></span> -<span class="line"><span style="color:#24292E"> lines[</span><span style="color:#D73A49">#</span><span style="color:#24292E">lines </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">] </span><span style="color:#D73A49">=</span><span style="color:#032F62"> ''</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#24292E"> lines[</span><span style="color:#D73A49">#</span><span style="color:#24292E">lines </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">] </span><span style="color:#D73A49">=</span><span style="color:#032F62"> ''</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> lines</span></span> -<span class="line"><span style="color:#D73A49">end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fn</span><span style="color:#24292E">.</span><span style="color:#005CC5">line</span><span style="color:#24292E">(</span><span style="color:#032F62">'$'</span><span style="color:#24292E">) </span><span style="color:#D73A49">==</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49"> and</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fn</span><span style="color:#24292E">.</span><span style="color:#005CC5">getline</span><span style="color:#24292E">(</span><span style="color:#005CC5">1</span><span style="color:#24292E">) </span><span style="color:#D73A49">==</span><span style="color:#032F62"> '' </span><span style="color:#D73A49">then</span></span> -<span class="line"><span style="color:#6A737D"> -- 対象ファイルが空なら、テンプレートを挿入してカーソルを末尾に移動させる</span></span> -<span class="line"><span style="color:#6A737D"> -- :help setline()</span></span> -<span class="line"><span style="color:#6A737D"> -- :help cursor()</span></span> -<span class="line"><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fn</span><span style="color:#24292E">.</span><span style="color:#005CC5">setline</span><span style="color:#24292E">(</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#005CC5">generate_template</span><span style="color:#24292E">())</span></span> -<span class="line"><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fn</span><span style="color:#24292E">.</span><span style="color:#005CC5">cursor</span><span style="color:#24292E">(</span><span style="color:#032F62">'$'</span><span style="color:#24292E">, </span><span style="color:#005CC5">0</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49">end</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E">vim.</span><span style="color:#6F42C1">b</span><span style="color:#24292E">.</span><span style="color:#6F42C1">did_ftplugin_php_after</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> true</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">did_ftplugin_php_after</span> <span style="color: #cf222e">then</span> + <span style="color: #cf222e">return</span> +<span style="color: #cf222e">end</span> + +<span style="color: #6e7781">-- base_dir を起点としてディレクトリを上向きに辿っていき、composer.json を探す</span> +<span style="color: #6e7781">-- :help vim.fs.find()</span> +<span style="color: #cf222e">local</span> <span style="color: #cf222e">function</span> <span style="color: #8250df">find_composer_json</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">base_dir</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">fs</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">find</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'composer.json'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">path</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">base_dir</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">upward</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">true</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #6e7781">-- ホームディレクトリまで到達したら探索を打ち切る</span> + <span style="color: #24292f;background-color: #f6f8fa">stop</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">loop</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">os_homedir</span><span style="color: #24292f;background-color: #f6f8fa">(),</span> + <span style="color: #953800">type</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">'file'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">})[</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">]</span> +<span style="color: #cf222e">end</span> + +<span style="color: #6e7781">-- JSON ファイルを読み込み、デコードして返す</span> +<span style="color: #6e7781">-- :help readblob()</span> +<span style="color: #6e7781">-- :help vim.json.decode</span> +<span style="color: #6e7781">-- :help luaref-pcall()</span> +<span style="color: #cf222e">local</span> <span style="color: #cf222e">function</span> <span style="color: #8250df">load_json</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">file_path</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #6e7781">-- readblob() は Vim script では Blob オブジェクトを返すが、Lua から呼ぶと string に変換される</span> + <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">ok_read</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">content</span> <span style="color: #0550ae">=</span> <span style="color: #953800">pcall</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">fn</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">readblob</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">file_path</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">if</span> <span style="color: #0550ae">not</span> <span style="color: #24292f;background-color: #f6f8fa">ok_read</span> <span style="color: #cf222e">then</span> + <span style="color: #cf222e">return</span> <span style="color: #0550ae">nil</span> + <span style="color: #cf222e">end</span> + <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">ok_decode</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">obj</span> <span style="color: #0550ae">=</span> <span style="color: #953800">pcall</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">json</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">decode</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">content</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">if</span> <span style="color: #0550ae">not</span> <span style="color: #24292f;background-color: #f6f8fa">ok_decode</span> <span style="color: #cf222e">then</span> + <span style="color: #cf222e">return</span> <span style="color: #0550ae">nil</span> + <span style="color: #cf222e">end</span> + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">obj</span> +<span style="color: #cf222e">end</span> + +<span style="color: #6e7781">-- 対象ファイルの置かれたディレクトリを基に namespace 宣言を生成する</span> +<span style="color: #6e7781">-- :help nvim_buf_get_name()</span> +<span style="color: #6e7781">-- :help vim.fs.dirname()</span> +<span style="color: #cf222e">local</span> <span style="color: #cf222e">function</span> <span style="color: #8250df">generate_namespace_declaration</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + <span style="color: #6e7781">-- composer.json を探し、トップレベルの名前空間とディレクトリを特定する</span> + <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">current_dir</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">fs</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">dirname</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">api</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">nvim_buf_get_name</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">))</span> + <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">path_to_composer_json</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">find_composer_json</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">current_dir</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">if</span> <span style="color: #0550ae">not</span> <span style="color: #24292f;background-color: #f6f8fa">path_to_composer_json</span> <span style="color: #cf222e">then</span> + <span style="color: #cf222e">return</span> <span style="color: #0550ae">nil</span> <span style="color: #6e7781">-- failed to locate composer.json</span> + <span style="color: #cf222e">end</span> + <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">composer_json</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">load_json</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">path_to_composer_json</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">if</span> <span style="color: #0550ae">not</span> <span style="color: #24292f;background-color: #f6f8fa">composer_json</span> <span style="color: #cf222e">then</span> + <span style="color: #cf222e">return</span> <span style="color: #0550ae">nil</span> <span style="color: #6e7781">-- failed to load composer.json</span> + <span style="color: #cf222e">end</span> + <span style="color: #6e7781">-- autoload.psr-4 を探し、型が期待される型と一致するかどうか調べる</span> + <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">psr4</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">tbl_get</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">composer_json</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">'autoload'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">'psr-4'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">if</span> <span style="color: #0550ae">not</span> <span style="color: #24292f;background-color: #f6f8fa">psr4</span> <span style="color: #cf222e">then</span> + <span style="color: #cf222e">return</span> <span style="color: #0550ae">nil</span> <span style="color: #6e7781">-- autoload.psr-4 section is absent</span> + <span style="color: #cf222e">end</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">tbl_count</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">psr4</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">~=</span> <span style="color: #0550ae">1</span> <span style="color: #cf222e">then</span> + <span style="color: #cf222e">return</span> <span style="color: #0550ae">nil</span> <span style="color: #6e7781">-- psr-4 section is ambiguous</span> + <span style="color: #cf222e">end</span> + <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">psr4_namespace</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">psr4_dir</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">k</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">v</span> <span style="color: #cf222e">in</span> <span style="color: #953800">pairs</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">psr4</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">do</span> + <span style="color: #24292f;background-color: #f6f8fa">psr4_namespace</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">k</span> + <span style="color: #24292f;background-color: #f6f8fa">psr4_dir</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">v</span> + <span style="color: #cf222e">end</span> + <span style="color: #cf222e">if</span> <span style="color: #953800">type</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">psr4_dir</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">==</span> <span style="color: #0a3069">'table'</span> <span style="color: #cf222e">then</span> + <span style="color: #cf222e">if</span> <span style="color: #0550ae">#</span><span style="color: #24292f;background-color: #f6f8fa">psr4_dir</span> <span style="color: #0550ae">==</span> <span style="color: #0550ae">1</span> <span style="color: #cf222e">then</span> + <span style="color: #24292f;background-color: #f6f8fa">psr4_dir</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">psr4_dir</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">]</span> + <span style="color: #cf222e">else</span> + <span style="color: #cf222e">return</span> <span style="color: #0550ae">nil</span> <span style="color: #6e7781">-- psr-4 section is ambiguous</span> + <span style="color: #cf222e">end</span> + <span style="color: #cf222e">end</span> + <span style="color: #cf222e">if</span> <span style="color: #953800">type</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">psr4_namespace</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">~=</span> <span style="color: #0a3069">'string'</span> <span style="color: #0550ae">or</span> <span style="color: #953800">type</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">psr4_dir</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">~=</span> <span style="color: #0a3069">'string'</span> <span style="color: #cf222e">then</span> + <span style="color: #cf222e">return</span> <span style="color: #0550ae">nil</span> <span style="color: #6e7781">-- psr-4 section is invalid</span> + <span style="color: #cf222e">end</span> + <span style="color: #6e7781">-- 末尾のスラッシュとバックスラッシュを取り除いておく</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">psr4_namespace</span><span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #24292f;background-color: #f6f8fa">sub</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">==</span> <span style="color: #0a3069">'</span><span style="color: #0a3069">\\</span><span style="color: #0a3069">'</span> <span style="color: #cf222e">then</span> + <span style="color: #24292f;background-color: #f6f8fa">psr4_namespace</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">psr4_namespace</span><span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #24292f;background-color: #f6f8fa">sub</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">-</span><span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">end</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">psr4_dir</span><span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #24292f;background-color: #f6f8fa">sub</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">==</span> <span style="color: #0a3069">'/'</span> <span style="color: #cf222e">then</span> + <span style="color: #24292f;background-color: #f6f8fa">psr4_dir</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">psr4_dir</span><span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #24292f;background-color: #f6f8fa">sub</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">-</span><span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">end</span> + + <span style="color: #6e7781">-- 対象ファイルが置かれたディレクトリとトップレベルのディレクトリを比較し、その差分を名前空間とする</span> + <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">namespace_root_dir</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">fs</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">dirname</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">path_to_composer_json</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">..</span> <span style="color: #0a3069">'/'</span> <span style="color: #0550ae">..</span> <span style="color: #24292f;background-color: #f6f8fa">psr4_dir</span> + <span style="color: #cf222e">if</span> <span style="color: #0550ae">not</span> <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">startswith</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">current_dir</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">namespace_root_dir</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">then</span> + <span style="color: #cf222e">return</span> <span style="color: #0550ae">nil</span> + <span style="color: #cf222e">end</span> + <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">current_path_suffix</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">current_dir</span><span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #24292f;background-color: #f6f8fa">sub</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">#</span><span style="color: #24292f;background-color: #f6f8fa">namespace_root_dir</span> <span style="color: #0550ae">+</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">namespace</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">psr4_namespace</span> <span style="color: #0550ae">..</span> <span style="color: #24292f;background-color: #f6f8fa">current_path_suffix</span><span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #953800">gsub</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #116329">'/'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #116329">'</span><span style="color: #0a3069">\\</span><span style="color: #116329">'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"namespace %s;"</span><span style="color: #24292f;background-color: #f6f8fa">):</span><span style="color: #24292f;background-color: #f6f8fa">format</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">namespace</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #cf222e">end</span> + +<span style="color: #cf222e">local</span> <span style="color: #cf222e">function</span> <span style="color: #8250df">generate_template</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">lines</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0a3069">'<?php'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0a3069">''</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0a3069">'declare(strict_types=1);'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0a3069">''</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">namespace_decl</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">generate_namespace_declaration</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">namespace_decl</span> <span style="color: #cf222e">then</span> + <span style="color: #24292f;background-color: #f6f8fa">lines</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">#</span><span style="color: #24292f;background-color: #f6f8fa">lines</span> <span style="color: #0550ae">+</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">namespace_decl</span> + <span style="color: #24292f;background-color: #f6f8fa">lines</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">#</span><span style="color: #24292f;background-color: #f6f8fa">lines</span> <span style="color: #0550ae">+</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">''</span> + <span style="color: #cf222e">end</span> + <span style="color: #24292f;background-color: #f6f8fa">lines</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">#</span><span style="color: #24292f;background-color: #f6f8fa">lines</span> <span style="color: #0550ae">+</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">''</span> + <span style="color: #cf222e">return</span> <span style="color: #24292f;background-color: #f6f8fa">lines</span> +<span style="color: #cf222e">end</span> + +<span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">fn</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">line</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'$'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">==</span> <span style="color: #0550ae">1</span> <span style="color: #0550ae">and</span> <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">fn</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">getline</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">==</span> <span style="color: #0a3069">''</span> <span style="color: #cf222e">then</span> + <span style="color: #6e7781">-- 対象ファイルが空なら、テンプレートを挿入してカーソルを末尾に移動させる</span> + <span style="color: #6e7781">-- :help setline()</span> + <span style="color: #6e7781">-- :help cursor()</span> + <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">fn</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">setline</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">generate_template</span><span style="color: #24292f;background-color: #f6f8fa">())</span> + <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">fn</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">cursor</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'$'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #cf222e">end</span> + +<span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">did_ftplugin_php_after</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">true</span> +</code></pre> </div> </section> <section id="section--outro"> diff --git a/services/nuldoc/public/blog/posts/2024-02-03/install-wireguard-on-personal-server/index.html b/services/nuldoc/public/blog/posts/2024-02-03/install-wireguard-on-personal-server/index.html index 94a327b6..d5517d25 100644 --- a/services/nuldoc/public/blog/posts/2024-02-03/install-wireguard-on-personal-server/index.html +++ b/services/nuldoc/public/blog/posts/2024-02-03/install-wireguard-on-personal-server/index.html @@ -119,14 +119,16 @@ まずは個人用サービスをホストしている Ubuntu のサーバに WireGuard をインストールする。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo apt install wireguard</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ sudo apt install wireguard +</code></pre> </div> <p> 次に、WireGuard で使用する鍵を生成する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ wg genkey | sudo tee /etc/wireguard/server.key | wg pubkey | sudo tee /etc/wireguard/server.pub</span></span> -<span class="line"><span>$ sudo chmod 600 /etc/wireguard/server.{key,pub}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ wg genkey | sudo tee /etc/wireguard/server.key | wg pubkey | sudo tee /etc/wireguard/server.pub +$ sudo chmod 600 /etc/wireguard/server.{key,pub} +</code></pre> </div> </section> <section id="section--install-wireguard-client"> @@ -135,26 +137,28 @@ 公式サイトから各 OS 向けのクライアントソフトウェアを入手し、インストールする。次に、設定をおこなう。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D"># クライアント 1 の場合</span></span> -<span class="line"><span style="color:#6F42C1">[Interface]</span></span> -<span class="line"><span style="color:#D73A49">Address</span><span style="color:#24292E"> = 10.10.1.2/32</span></span> -<span class="line"><span style="color:#D73A49">PrivateKey</span><span style="color:#24292E"> = <クライアント 1 の秘密鍵></span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1">[Peer]</span></span> -<span class="line"><span style="color:#D73A49">PublicKey</span><span style="color:#24292E"> = <サーバの公開鍵></span></span> -<span class="line"><span style="color:#D73A49">AllowedIPs</span><span style="color:#24292E"> = <サーバの外部 IP アドレス>/32</span></span> -<span class="line"><span style="color:#D73A49">Endpoint</span><span style="color:#24292E"> = <サーバの外部 IP アドレス>:51820</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"># クライアント 1 の場合 +</span><span style="color: #953800">[Interface]</span><span style="color: #24292f;background-color: #f6f8fa"> +</span><span style="color: #0550ae">Address</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069">10.10.1.2/32</span> +<span style="color: #0550ae">PrivateKey</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069"><クライアント 1 の秘密鍵></span> +<span style="color: #24292f;background-color: #f6f8fa"> +</span><span style="color: #953800">[Peer]</span><span style="color: #24292f;background-color: #f6f8fa"> +</span><span style="color: #0550ae">PublicKey</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069"><サーバの公開鍵></span> +<span style="color: #0550ae">AllowedIPs</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069"><サーバの外部 IP アドレス>/32</span> +<span style="color: #0550ae">Endpoint</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069"><サーバの外部 IP アドレス>:51820</span> +</code></pre> </div> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D"># クライアント 2 の場合</span></span> -<span class="line"><span style="color:#6F42C1">[Interface]</span></span> -<span class="line"><span style="color:#D73A49">Address</span><span style="color:#24292E"> = 10.10.1.3/32</span></span> -<span class="line"><span style="color:#D73A49">PrivateKey</span><span style="color:#24292E"> = <クライアント 2 の秘密鍵></span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1">[Peer]</span></span> -<span class="line"><span style="color:#D73A49">PublicKey</span><span style="color:#24292E"> = <サーバの公開鍵></span></span> -<span class="line"><span style="color:#D73A49">AllowedIPs</span><span style="color:#24292E"> = <サーバの外部 IP アドレス>/32</span></span> -<span class="line"><span style="color:#D73A49">Endpoint</span><span style="color:#24292E"> = <サーバの外部 IP アドレス>:51820</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"># クライアント 2 の場合 +</span><span style="color: #953800">[Interface]</span><span style="color: #24292f;background-color: #f6f8fa"> +</span><span style="color: #0550ae">Address</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069">10.10.1.3/32</span> +<span style="color: #0550ae">PrivateKey</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069"><クライアント 2 の秘密鍵></span> +<span style="color: #24292f;background-color: #f6f8fa"> +</span><span style="color: #953800">[Peer]</span><span style="color: #24292f;background-color: #f6f8fa"> +</span><span style="color: #0550ae">PublicKey</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069"><サーバの公開鍵></span> +<span style="color: #0550ae">AllowedIPs</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069"><サーバの外部 IP アドレス>/32</span> +<span style="color: #0550ae">Endpoint</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069"><サーバの外部 IP アドレス>:51820</span> +</code></pre> </div> <p> <code>PrivateKey</code> や <code>PublicKey</code> は鍵ファイルのパスではなく中身を書くことに注意。 @@ -166,29 +170,32 @@ 一度サーバへ戻り、WireGuard の設定ファイルを書く。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo vim /etc/wireguard/wg0.conf</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ sudo vim /etc/wireguard/wg0.conf +</code></pre> </div> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6F42C1">[Interface]</span></span> -<span class="line"><span style="color:#D73A49">Address</span><span style="color:#24292E"> = 10.10.1.1/32</span></span> -<span class="line"><span style="color:#D73A49">SaveConfig</span><span style="color:#24292E"> = true</span></span> -<span class="line"><span style="color:#D73A49">PrivateKey</span><span style="color:#24292E"> = <サーバの秘密鍵></span></span> -<span class="line"><span style="color:#D73A49">ListenPort</span><span style="color:#24292E"> = 51820</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1">[Peer]</span></span> -<span class="line"><span style="color:#D73A49">PublicKey</span><span style="color:#24292E"> = <クライアント 1 の公開鍵></span></span> -<span class="line"><span style="color:#D73A49">AllowedIPs</span><span style="color:#24292E"> = 10.10.1.2/32</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1">[Peer]</span></span> -<span class="line"><span style="color:#D73A49">PublicKey</span><span style="color:#24292E"> = <クライアント 2 の公開鍵></span></span> -<span class="line"><span style="color:#D73A49">AllowedIPs</span><span style="color:#24292E"> = 10.10.1.3/32</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #953800">[Interface]</span><span style="color: #24292f;background-color: #f6f8fa"> +</span><span style="color: #0550ae">Address</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069">10.10.1.1/32</span> +<span style="color: #0550ae">SaveConfig</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069">true</span> +<span style="color: #0550ae">PrivateKey</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069"><サーバの秘密鍵></span> +<span style="color: #0550ae">ListenPort</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069">51820</span> +<span style="color: #24292f;background-color: #f6f8fa"> +</span><span style="color: #953800">[Peer]</span><span style="color: #24292f;background-color: #f6f8fa"> +</span><span style="color: #0550ae">PublicKey</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069"><クライアント 1 の公開鍵></span> +<span style="color: #0550ae">AllowedIPs</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069">10.10.1.2/32</span> +<span style="color: #24292f;background-color: #f6f8fa"> +</span><span style="color: #953800">[Peer]</span><span style="color: #24292f;background-color: #f6f8fa"> +</span><span style="color: #0550ae">PublicKey</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069"><クライアント 2 の公開鍵></span> +<span style="color: #0550ae">AllowedIPs</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">=</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0a3069">10.10.1.3/32</span> +</code></pre> </div> <p> 次に、WireGuard のサービスを起動する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo systemctl enable wg-quick@wg0</span></span> -<span class="line"><span>$ sudo systemctl start wg-quick@wg0</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ sudo systemctl enable wg-quick@wg0 +$ sudo systemctl start wg-quick@wg0 +</code></pre> </div> </section> <section id="section--configure-firewall"> @@ -197,23 +204,26 @@ 続けてファイアウォールを設定する。まずは WireGuard が使用する UDP のポートを開き、<code>wg0</code> を通る通信を許可する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo ufw allow 51820/udp</span></span> -<span class="line"><span>$ sudo ufw allow in on wg0</span></span> -<span class="line"><span>$ sudo ufw allow out on wg0</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ sudo ufw allow 51820/udp +$ sudo ufw allow in on wg0 +$ sudo ufw allow out on wg0 +</code></pre> </div> <p> 次に、80 や 443 などの必要なポートについて、<code>wg0</code> を経由してのアクセスのみ許可する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo ufw allow in on wg0 to any port 80 proto tcp</span></span> -<span class="line"><span>$ sudo ufw allow in on wg0 to any port 443 proto tcp</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ sudo ufw allow in on wg0 to any port 80 proto tcp +$ sudo ufw allow in on wg0 to any port 443 proto tcp +</code></pre> </div> <p> 最後に、<code>ufw</code> を有効にする。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ sudo ufw status</span></span> -<span class="line"><span>$ sudo ufw enable</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ sudo ufw status +$ sudo ufw enable +</code></pre> </div> </section> <section id="section--connect-each-other"> diff --git a/services/nuldoc/public/blog/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd/index.html b/services/nuldoc/public/blog/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd/index.html index c709dba1..97704903 100644 --- a/services/nuldoc/public/blog/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd/index.html +++ b/services/nuldoc/public/blog/posts/2024-04-21/pipefail-option-in-gitlab-ci-cd/index.html @@ -116,14 +116,15 @@ 例: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#22863A">hello-world</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#22863A"> stage</span><span style="color:#24292E">: </span><span style="color:#032F62">test</span></span> -<span class="line"><span style="color:#22863A"> image</span><span style="color:#24292E">: </span><span style="color:#032F62">alpine:latest</span></span> -<span class="line"><span style="color:#22863A"> script</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#24292E"> - </span><span style="color:#032F62">'echo "Hello, World!"'</span></span> -<span class="line"><span style="color:#22863A"> rules</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#24292E"> - </span><span style="color:#22863A">if</span><span style="color:#24292E">: </span><span style="color:#032F62">'$CI_MERGE_REQUEST_IID'</span></span> -<span class="line"><span style="color:#22863A"> when</span><span style="color:#24292E">: </span><span style="color:#032F62">always</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #116329">hello-world</span><span style="color: #24292f;background-color: #f6f8fa">:</span> + <span style="color: #116329">stage</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">test</span> + <span style="color: #116329">image</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">alpine:latest</span> + <span style="color: #116329">script</span><span style="color: #24292f;background-color: #f6f8fa">:</span> + <span style="color: #24292f;background-color: #f6f8fa">-</span> <span style="color: #0a3069">'</span><span style="color: #0a3069">echo</span><span style="color: #0550ae"> </span><span style="color: #0a3069">"Hello,</span><span style="color: #0550ae"> </span><span style="color: #0a3069">World!"'</span> + <span style="color: #116329">rules</span><span style="color: #24292f;background-color: #f6f8fa">:</span> + <span style="color: #24292f;background-color: #f6f8fa">-</span> <span style="color: #116329">if</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">'</span><span style="color: #0a3069">$CI_MERGE_REQUEST_IID'</span> + <span style="color: #116329">when</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">always</span> +</code></pre> </div> <p> ここで、<code>script</code> に指定したコマンドが失敗する (exit status が 0 以外になる) と、即座に実行が停止され、ジョブは失敗する。 @@ -132,14 +133,15 @@ では、次のようなケースだとどうなるか。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#22863A">hello-world</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#22863A"> stage</span><span style="color:#24292E">: </span><span style="color:#032F62">test</span></span> -<span class="line"><span style="color:#22863A"> image</span><span style="color:#24292E">: </span><span style="color:#032F62">alpine:latest</span></span> -<span class="line"><span style="color:#22863A"> script</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#24292E"> - </span><span style="color:#032F62">'exit 1 | exit 0'</span></span> -<span class="line"><span style="color:#22863A"> rules</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#24292E"> - </span><span style="color:#22863A">if</span><span style="color:#24292E">: </span><span style="color:#032F62">'$CI_MERGE_REQUEST_IID'</span></span> -<span class="line"><span style="color:#22863A"> when</span><span style="color:#24292E">: </span><span style="color:#032F62">always</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #116329">hello-world</span><span style="color: #24292f;background-color: #f6f8fa">:</span> + <span style="color: #116329">stage</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">test</span> + <span style="color: #116329">image</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">alpine:latest</span> + <span style="color: #116329">script</span><span style="color: #24292f;background-color: #f6f8fa">:</span> + <span style="color: #24292f;background-color: #f6f8fa">-</span> <span style="color: #0a3069">'</span><span style="color: #0a3069">exit</span><span style="color: #0550ae"> </span><span style="color: #0a3069">1</span><span style="color: #0550ae"> </span><span style="color: #0a3069">|</span><span style="color: #0550ae"> </span><span style="color: #0a3069">exit</span><span style="color: #0550ae"> </span><span style="color: #0a3069">0'</span> + <span style="color: #116329">rules</span><span style="color: #24292f;background-color: #f6f8fa">:</span> + <span style="color: #24292f;background-color: #f6f8fa">-</span> <span style="color: #116329">if</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">'</span><span style="color: #0a3069">$CI_MERGE_REQUEST_IID'</span> + <span style="color: #116329">when</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">always</span> +</code></pre> </div> <p> 失敗するコマンドをパイプに接続した。通常 Bash では、パイプの最後のコマンドの exit code が全体の exit code になる。 @@ -151,10 +153,11 @@ 前述したようなケースにおいて、途中で失敗したときに全体を失敗させるには、<code>pipefail</code> オプションを有効にする。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D"># On にする</span></span> -<span class="line"><span style="color:#005CC5">set</span><span style="color:#005CC5"> -o</span><span style="color:#032F62"> pipefail</span></span> -<span class="line"><span style="color:#6A737D"># Off にする</span></span> -<span class="line"><span style="color:#005CC5">set</span><span style="color:#032F62"> +o</span><span style="color:#032F62"> pipefail</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"># On にする</span> +<span style="color: #953800">set</span> <span style="color: #116329">-o</span> pipefail +<span style="color: #6e7781"># Off にする</span> +<span style="color: #953800">set</span> +o pipefail +</code></pre> </div> <p> こうすると、パイプ全体が失敗するようになる。この設定は、デフォルトだと off になっている。 @@ -167,14 +170,15 @@ 次のような GitLab CI/CD ジョブが失敗してしまった。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#22863A">hoge</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#22863A"> stage</span><span style="color:#24292E">: </span><span style="color:#032F62">test</span></span> -<span class="line"><span style="color:#22863A"> image</span><span style="color:#24292E">: </span><span style="color:#032F62">alpine:latest</span></span> -<span class="line"><span style="color:#22863A"> script</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#24292E"> - </span><span style="color:#032F62">'cat hoge.txt | grep piyo | sed -e "s/foo/bar/g"'</span></span> -<span class="line"><span style="color:#22863A"> rules</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#24292E"> - </span><span style="color:#22863A">if</span><span style="color:#24292E">: </span><span style="color:#032F62">'$CI_MERGE_REQUEST_IID'</span></span> -<span class="line"><span style="color:#22863A"> when</span><span style="color:#24292E">: </span><span style="color:#032F62">always</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #116329">hoge</span><span style="color: #24292f;background-color: #f6f8fa">:</span> + <span style="color: #116329">stage</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">test</span> + <span style="color: #116329">image</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">alpine:latest</span> + <span style="color: #116329">script</span><span style="color: #24292f;background-color: #f6f8fa">:</span> + <span style="color: #24292f;background-color: #f6f8fa">-</span> <span style="color: #0a3069">'</span><span style="color: #0a3069">cat</span><span style="color: #0550ae"> </span><span style="color: #0a3069">hoge.txt</span><span style="color: #0550ae"> </span><span style="color: #0a3069">|</span><span style="color: #0550ae"> </span><span style="color: #0a3069">grep</span><span style="color: #0550ae"> </span><span style="color: #0a3069">piyo</span><span style="color: #0550ae"> </span><span style="color: #0a3069">|</span><span style="color: #0550ae"> </span><span style="color: #0a3069">sed</span><span style="color: #0550ae"> </span><span style="color: #0a3069">-e</span><span style="color: #0550ae"> </span><span style="color: #0a3069">"s/foo/bar/g"'</span> + <span style="color: #116329">rules</span><span style="color: #24292f;background-color: #f6f8fa">:</span> + <span style="color: #24292f;background-color: #f6f8fa">-</span> <span style="color: #116329">if</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">'</span><span style="color: #0a3069">$CI_MERGE_REQUEST_IID'</span> + <span style="color: #116329">when</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">always</span> +</code></pre> </div> <p> <code>grep</code> コマンドは、パターンにマッチする行が一行もなかったとき、exit code 1 を返す。よって、<code>pipefail</code> が on になっていると、このジョブは失敗する。現在の <code>pipefail</code> がどうなっているか確かめるため <code>set +o</code> で全オプションを出力させたところ、<code>pipefail</code> が on になっていた。 @@ -183,20 +187,21 @@ しかし、先述したように Bash における <code>pipefail</code> のデフォルト値は off のはずだ。実際に、ローカルで <code>alpine:latest</code> を動かしてみたところ、 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ docker run --rm alpine:latest sh -c "set +o"</span></span> -<span class="line"><span>set +o errexit</span></span> -<span class="line"><span>set +o noglob</span></span> -<span class="line"><span>set +o ignoreeof</span></span> -<span class="line"><span>set +o monitor</span></span> -<span class="line"><span>set +o noexec</span></span> -<span class="line"><span>set +o xtrace</span></span> -<span class="line"><span>set +o verbose</span></span> -<span class="line"><span>set +o noclobber</span></span> -<span class="line"><span>set +o allexport</span></span> -<span class="line"><span>set +o notify</span></span> -<span class="line"><span>set +o nounset</span></span> -<span class="line"><span>set +o vi</span></span> -<span class="line"><span>set +o pipefail</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ docker run --rm alpine:latest sh -c "set +o" +set +o errexit +set +o noglob +set +o ignoreeof +set +o monitor +set +o noexec +set +o xtrace +set +o verbose +set +o noclobber +set +o allexport +set +o notify +set +o nounset +set +o vi +set +o pipefail +</code></pre> </div> <p> 確かに <code>pipefail</code> は無効になっている。 @@ -211,9 +216,10 @@ <code>.gitlab-ci.yml</code> で明示的には書いていないので、GitLab Runner (GitLab CI/CD のスクリプトを実行するプログラム) が勝手に追加しているに違いない。そう仮説を立てて <a href="https://gitlab.com/gitlab-org/gitlab-runner" rel="noreferrer" target="_blank">GitLab Runner のリポジトリ</a> を調査したところ、 <a href="https://gitlab.com/gitlab-org/gitlab-runner/-/blob/c75da0796a0e3048991dccfdf2784e3d931beda4/shells/bash.go#L276" rel="noreferrer" target="_blank">ソースコード中の以下の箇所</a> で <code>set -o pipefail</code> していることが判明した (コメントは筆者による)。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">// pipefail オプションが存在しない環境にも対応するため、</span></span> -<span class="line"><span style="color:#6A737D">// 先に set -o でオプション一覧を表示させたあと、set -o pipefail している</span></span> -<span class="line"><span style="color:#24292E">buf.</span><span style="color:#6F42C1">WriteString</span><span style="color:#24292E">(</span><span style="color:#032F62">"if set -o | grep pipefail > /dev/null; then set -o pipefail; fi; set -o errexit</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">)</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781">// pipefail オプションが存在しない環境にも対応するため、</span> +<span style="color: #6e7781">// 先に set -o でオプション一覧を表示させたあと、set -o pipefail している</span> +<span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">WriteString</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"if set -o | grep pipefail > /dev/null; then set -o pipefail; fi; set -o errexit</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +</code></pre> </div> </section> <section id="section--how-to-solve"> @@ -222,16 +228,17 @@ 通常の Bash スクリプトを書く場合と同様に、<code>pipefail</code> が on になっていては困る場所だけ off にしてやればよい。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#22863A"> hoge</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#22863A"> stage</span><span style="color:#24292E">: </span><span style="color:#032F62">test</span></span> -<span class="line"><span style="color:#22863A"> image</span><span style="color:#24292E">: </span><span style="color:#032F62">alpine:latest</span></span> -<span class="line"><span style="color:#22863A"> script</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#032F62">+ - 'set +o pipefail'</span></span> -<span class="line"><span style="color:#24292E"> - </span><span style="color:#032F62">'cat hoge.txt | grep piyo | sed -e "s/foo/bar/g"'</span></span> -<span class="line"><span style="color:#032F62">+ - 'set -o pipefail'</span><span style="color:#6A737D"> # この例の場合、ここで終わりなので戻さなくてもよい</span></span> -<span class="line"><span style="color:#22863A"> rules</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#24292E"> - </span><span style="color:#22863A">if</span><span style="color:#24292E">: </span><span style="color:#032F62">'$CI_MERGE_REQUEST_IID'</span></span> -<span class="line"><span style="color:#22863A"> when</span><span style="color:#24292E">: </span><span style="color:#032F62">always</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code> <span style="color: #116329">hoge</span><span style="color: #24292f;background-color: #f6f8fa">:</span> + <span style="color: #116329">stage</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">test</span> + <span style="color: #116329">image</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">alpine:latest</span> + <span style="color: #116329">script</span><span style="color: #24292f;background-color: #f6f8fa">:</span> +<span style="color: #0a3069">+ - 'set +o pipefail'</span> + <span style="color: #0a3069">- 'cat hoge.txt | grep piyo | sed -e "s/foo/bar/g"'</span> +<span style="color: #0a3069">+ - 'set -o pipefail'</span> <span style="color: #6e7781"># この例の場合、ここで終わりなので戻さなくてもよい</span> + <span style="color: #116329">rules</span><span style="color: #24292f;background-color: #f6f8fa">:</span> + <span style="color: #24292f;background-color: #f6f8fa">-</span> <span style="color: #116329">if</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">'</span><span style="color: #0a3069">$CI_MERGE_REQUEST_IID'</span> + <span style="color: #116329">when</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0a3069">always</span> +</code></pre> </div> </section> <section id="section--remarks"> diff --git a/services/nuldoc/public/blog/posts/2024-04-29/zsh-file-completion-for-composer-custom-commands/index.html b/services/nuldoc/public/blog/posts/2024-04-29/zsh-file-completion-for-composer-custom-commands/index.html index 39ccf3a6..4ef3d064 100644 --- a/services/nuldoc/public/blog/posts/2024-04-29/zsh-file-completion-for-composer-custom-commands/index.html +++ b/services/nuldoc/public/blog/posts/2024-04-29/zsh-file-completion-for-composer-custom-commands/index.html @@ -116,11 +116,12 @@ このことは、先ほどリンクを載せた <code>_composer</code> 関数を定義しているファイルの冒頭にも書かれている。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D"># - @todo We don't complete custom commands (including script aliases). This is</span></span> -<span class="line"><span style="color:#6A737D"># easy to do in the general case, but it probably requires some clever caching</span></span> -<span class="line"><span style="color:#6A737D"># to avoid introducing a noticeable lag to every completion operation, due to</span></span> -<span class="line"><span style="color:#6A737D"># the way command resolution works and the fact that discovering custom</span></span> -<span class="line"><span style="color:#6A737D"># commands requires making slow calls to Composer</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"># - @todo We don't complete custom commands (including script aliases). This is</span> +<span style="color: #6e7781"># easy to do in the general case, but it probably requires some clever caching</span> +<span style="color: #6e7781"># to avoid introducing a noticeable lag to every completion operation, due to</span> +<span style="color: #6e7781"># the way command resolution works and the fact that discovering custom</span> +<span style="color: #6e7781"># commands requires making slow calls to Composer</span> +</code></pre> </div> </section> <section id="section--what-i-want-to-achive"> @@ -138,7 +139,8 @@ まずは、Zsh で補完関数を提供する場合のボイラープレートコードを書く。以下は <code>~/.zshrc</code> にすべて書く前提だが、<code>autoload</code> を設定するなどすれば別ファイルに分離できる (詳細な手順は割愛)。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6F42C1">compdef</span><span style="color:#032F62"> _my_composer</span><span style="color:#032F62"> composer</span><span style="color:#032F62"> composer.phar</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>compdef _my_composer composer composer.phar +</code></pre> </div> <p> <code>compdef</code> は Zsh が用意している関数で、第一引数に補完関数の名前、第二引数以降に補完を適用するコマンド名を並べる。この場合は、<code>composer</code> コマンドや <code>composer.phar</code> コマンドに対して <code>_my_composer</code> を使って補完をおこなうよう定義している。 @@ -147,9 +149,10 @@ 次に <code>_my_composer</code> を定義する。基本的にはデフォルトの <code>composer</code> コマンドの補完関数 (つまり <code>_composer</code> 関数) を使い、それが何も返さなかった場合に限り、Zsh のファイル・ディレクトリ補完へフォールバックする。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">function</span><span style="color:#6F42C1"> _my_composer</span><span style="color:#24292E">() {</span></span> -<span class="line"><span style="color:#6F42C1"> _composer</span><span style="color:#032F62"> "</span><span style="color:#005CC5">$@</span><span style="color:#032F62">"</span><span style="color:#D73A49"> ||</span><span style="color:#6F42C1"> _files</span><span style="color:#032F62"> "</span><span style="color:#005CC5">$@</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">function </span>_my_composer<span style="color: #0550ae">()</span> <span style="color: #0550ae">{</span> + _composer <span style="color: #0a3069">"</span><span style="color: #0550ae">$@</span><span style="color: #0a3069">"</span> <span style="color: #0550ae">||</span> _files <span style="color: #0a3069">"</span><span style="color: #0550ae">$@</span><span style="color: #0a3069">"</span> +<span style="color: #0550ae">}</span> +</code></pre> </div> <p> <code>_composer</code> コマンドは何も補完候補がなかったとき非ゼロな exit status で終了するので、そうであったなら <code>_files</code> を呼び出す。<code>_files</code> は、Zsh がデフォルトで用意しているファイル・ディレクトリの補完をおこなう関数である。 diff --git a/services/nuldoc/public/blog/posts/2024-07-19/reparojson-fix-only-json-formatter/index.html b/services/nuldoc/public/blog/posts/2024-07-19/reparojson-fix-only-json-formatter/index.html index 50bbf5ee..bf60bb52 100644 --- a/services/nuldoc/public/blog/posts/2024-07-19/reparojson-fix-only-json-formatter/index.html +++ b/services/nuldoc/public/blog/posts/2024-07-19/reparojson-fix-only-json-formatter/index.html @@ -106,17 +106,18 @@ 次のように動作する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ echo '[ 1 2 ]' | reparojson</span></span> -<span class="line"><span>[ 1, 2 ]</span></span> -<span class="line"><span></span></span> -<span class="line"><span>$ echo '[ 1, 2, ]' | reparojson</span></span> -<span class="line"><span>[ 1, 2 ]</span></span> -<span class="line"><span></span></span> -<span class="line"><span>$ echo '{ "foo": 1 "bar": 2 }' | reparojson</span></span> -<span class="line"><span>{ "foo": 1, "bar": 2 }</span></span> -<span class="line"><span></span></span> -<span class="line"><span>$ echo '{ "foo": 1, "bar": 2, }' | reparojson</span></span> -<span class="line"><span>{ "foo": 1, "bar": 2 }</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ echo '[ 1 2 ]' | reparojson +[ 1, 2 ] + +$ echo '[ 1, 2, ]' | reparojson +[ 1, 2 ] + +$ echo '{ "foo": 1 "bar": 2 }' | reparojson +{ "foo": 1, "bar": 2 } + +$ echo '{ "foo": 1, "bar": 2, }' | reparojson +{ "foo": 1, "bar": 2 } +</code></pre> </div> <p> バージョン 0.1.1 時点で修正対象の文法エラーは次のとおり: @@ -148,33 +149,34 @@ ここでは、 <a href="https://github.com/neovim/nvim-lspconfig" rel="noreferrer" target="_blank">nvim-lspconfig</a> と <a href="https://github.com/mattn/efm-langserver" rel="noreferrer" target="_blank">efm-langserver</a> を用いた設定例を紹介する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> lspconfig </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> require</span><span style="color:#24292E">(</span><span style="color:#032F62">'lspconfig'</span><span style="color:#24292E">)</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> lspconfig.</span><span style="color:#6F42C1">efm</span><span style="color:#24292E">.</span><span style="color:#005CC5">setup</span><span style="color:#24292E">({</span></span> -<span class="line"><span style="color:#24292E"> init_options </span><span style="color:#D73A49">=</span><span style="color:#24292E"> { documentFormatting </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span><span style="color:#24292E"> },</span></span> -<span class="line"><span style="color:#24292E"> settings </span><span style="color:#D73A49">=</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> rootMarkers </span><span style="color:#D73A49">=</span><span style="color:#24292E"> {</span><span style="color:#032F62">".git/"</span><span style="color:#24292E">},</span></span> -<span class="line"><span style="color:#24292E"> languages </span><span style="color:#D73A49">=</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> json </span><span style="color:#D73A49">=</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> formatCommand </span><span style="color:#D73A49">=</span><span style="color:#032F62"> "reparojson -q"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> formatStdin </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> },</span></span> -<span class="line"><span style="color:#24292E"> },</span></span> -<span class="line"><span style="color:#24292E"> },</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> })</span></span> -<span class="line"></span> -<span class="line"><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">api</span><span style="color:#24292E">.</span><span style="color:#005CC5">nvim_create_autocmd</span><span style="color:#24292E">(</span><span style="color:#032F62">'LspAttach'</span><span style="color:#24292E">, {</span></span> -<span class="line"><span style="color:#6F42C1"> callback</span><span style="color:#D73A49"> =</span><span style="color:#D73A49"> function</span><span style="color:#24292E">(e)</span></span> -<span class="line"><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">api</span><span style="color:#24292E">.</span><span style="color:#005CC5">nvim_create_autocmd</span><span style="color:#24292E">(</span><span style="color:#032F62">'BufWritePre'</span><span style="color:#24292E">, {</span></span> -<span class="line"><span style="color:#24292E"> buffer </span><span style="color:#D73A49">=</span><span style="color:#24292E"> e.</span><span style="color:#6F42C1">buf</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#6F42C1"> callback</span><span style="color:#D73A49"> =</span><span style="color:#D73A49"> function</span><span style="color:#24292E">()</span></span> -<span class="line"><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">lsp</span><span style="color:#24292E">.</span><span style="color:#6F42C1">buf</span><span style="color:#24292E">.</span><span style="color:#005CC5">format</span><span style="color:#24292E">({ async </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> false</span><span style="color:#24292E"> })</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#24292E"> })</span></span> -<span class="line"><span style="color:#D73A49"> end</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> })</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code> <span style="color: #cf222e">local</span> <span style="color: #24292f;background-color: #f6f8fa">lspconfig</span> <span style="color: #0550ae">=</span> <span style="color: #953800">require</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'lspconfig'</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + + <span style="color: #24292f;background-color: #f6f8fa">lspconfig</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">efm</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">setup</span><span style="color: #24292f;background-color: #f6f8fa">({</span> + <span style="color: #24292f;background-color: #f6f8fa">init_options</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> <span style="color: #24292f;background-color: #f6f8fa">documentFormatting</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">true</span> <span style="color: #24292f;background-color: #f6f8fa">},</span> + <span style="color: #24292f;background-color: #f6f8fa">settings</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">rootMarkers</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #0a3069">".git/"</span><span style="color: #24292f;background-color: #f6f8fa">},</span> + <span style="color: #24292f;background-color: #f6f8fa">languages</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">json</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">formatCommand</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">"reparojson -q"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">formatStdin</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">true</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">},</span> + <span style="color: #24292f;background-color: #f6f8fa">},</span> + <span style="color: #24292f;background-color: #f6f8fa">},</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">})</span> + + <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">api</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">nvim_create_autocmd</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'LspAttach'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">callback</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">function</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">e</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">api</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">nvim_create_autocmd</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'BufWritePre'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">buffer</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">e</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">callback</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">function</span><span style="color: #24292f;background-color: #f6f8fa">()</span> + <span style="color: #24292f;background-color: #f6f8fa">vim</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">lsp</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">buf</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #24292f;background-color: #f6f8fa">format</span><span style="color: #24292f;background-color: #f6f8fa">({</span> <span style="color: #24292f;background-color: #f6f8fa">async</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">false</span> <span style="color: #24292f;background-color: #f6f8fa">})</span> + <span style="color: #cf222e">end</span> + <span style="color: #24292f;background-color: #f6f8fa">})</span> + <span style="color: #cf222e">end</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">})</span> +</code></pre> </div> <p> ほとんどは nvim-lspconfig と efm-langserver を使う際のボイラープレートだが、<code>formatCommand</code> で <code>-q</code> フラグを指定していることに注意してほしい。このツールは、デフォルトでは JSON が修正された場合 exit code 1 で終了する。これは、入力が最初から正しかった場合と修正して正しくなった場合を区別するためだが、異常終了してしまうと置き換えが発生しない。そのため、<code>-q</code> フラグを指定して、修正されたときも exit code 0 で終了するようにしている。 @@ -186,28 +188,31 @@ このツールが威力を発揮するのは、行の入れ換え時である。次のような JSON があり、 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#005CC5"> "a"</span><span style="color:#24292E">: </span><span style="color:#005CC5">true</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> "b"</span><span style="color:#24292E">: </span><span style="color:#005CC5">false</span></span> -<span class="line"><span style="color:#24292E"> }</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #24292f;background-color: #f6f8fa"> + </span><span style="color: #0550ae">"a"</span><span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0550ae">true</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #24292f;background-color: #f6f8fa"> + </span><span style="color: #0550ae">"b"</span><span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0550ae">false</span><span style="color: #24292f;background-color: #f6f8fa"> + </span><span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> 2行目と3行目を入れ換えて以下のように編集した。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#005CC5"> "b"</span><span style="color:#24292E">: </span><span style="color:#005CC5">false</span></span> -<span class="line"><span style="color:#032F62"> "a"</span><span style="color:#B31D28;font-style:italic">:</span><span style="color:#005CC5"> true</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> }</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #24292f;background-color: #f6f8fa"> + </span><span style="color: #0550ae">"b"</span><span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0550ae">false</span><span style="color: #24292f;background-color: #f6f8fa"> + </span><span style="color: #0550ae">"a"</span><span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0550ae">true</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #24292f;background-color: #f6f8fa"> + </span><span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> これは不正な JSON だが、このツールを通せば次のようになる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#005CC5"> "b"</span><span style="color:#24292E">: </span><span style="color:#005CC5">false</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> "a"</span><span style="color:#24292E">: </span><span style="color:#005CC5">true</span></span> -<span class="line"><span style="color:#24292E"> }</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #24292f;background-color: #f6f8fa"> + </span><span style="color: #0550ae">"b"</span><span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0550ae">false</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #24292f;background-color: #f6f8fa"> + </span><span style="color: #0550ae">"a"</span><span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #24292f;background-color: #f6f8fa"> </span><span style="color: #0550ae">true</span><span style="color: #24292f;background-color: #f6f8fa"> + </span><span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> もちろん、このような操作を文法を壊さずにおこなう Vim プラグインは存在する。しかし、単なる行の入れ換えであれば <code>ddp</code> の3ストロークでおこなうことができ、専用のキーバインドを覚える必要もない。このツールを用いることで、より Vimmer-friendly な JSON 編集が可能となる。 diff --git a/services/nuldoc/public/blog/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html b/services/nuldoc/public/blog/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html index 536926b5..6222f888 100644 --- a/services/nuldoc/public/blog/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html +++ b/services/nuldoc/public/blog/posts/2024-08-19/go-template-access-outer-scope-pipeline-within-with-or-range/index.html @@ -90,19 +90,20 @@ Go には、標準ライブラリにテンプレートライブラリ <code>text/template</code> がある。この <code>text/template</code> における制御構造、<code>with</code> と <code>range</code> は次のように使われる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span># {{ .Title }}</span></span> -<span class="line"><span></span></span> -<span class="line"><span># User</span></span> -<span class="line"><span></span></span> -<span class="line"><span>{{ with .User }}</span></span> -<span class="line"><span> {{ .Name }} ({{ .ID }})</span></span> -<span class="line"><span>{{ end }}</span></span> -<span class="line"><span></span></span> -<span class="line"><span># Items</span></span> -<span class="line"><span></span></span> -<span class="line"><span>{{ range .Items }}</span></span> -<span class="line"><span> - {{ . }}</span></span> -<span class="line"><span>{{ end }}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code># {{ .Title }} + +# User + +{{ with .User }} + {{ .Name }} ({{ .ID }}) +{{ end }} + +# Items + +{{ range .Items }} + - {{ . }} +{{ end }} +</code></pre> </div> <p> <code>text/template</code> の <code>.</code> は、現在の操作対象を表す特殊なオブジェクトである。 @@ -114,18 +115,19 @@ つまりこのテンプレートは、次のような構造をレンダリングしている (<code>Execute()</code> の第2引数)。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">tmpl.</span><span style="color:#6F42C1">Execute</span><span style="color:#24292E">(out, </span><span style="color:#6F42C1">Params</span><span style="color:#24292E">{</span></span> -<span class="line"><span style="color:#24292E"> Title: </span><span style="color:#032F62">"foo"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> User: </span><span style="color:#6F42C1">User</span><span style="color:#24292E">{</span></span> -<span class="line"><span style="color:#24292E"> ID: </span><span style="color:#005CC5">123</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> Name: </span><span style="color:#032F62">"john"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> },</span></span> -<span class="line"><span style="color:#24292E"> Items: []</span><span style="color:#D73A49">string</span><span style="color:#24292E">{</span></span> -<span class="line"><span style="color:#032F62"> "hoge"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62"> "piyo"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62"> "fuga"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> },</span></span> -<span class="line"><span style="color:#24292E">})</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">tmpl</span><span style="color: #0550ae">.</span><span style="color: #24292f;background-color: #f6f8fa">Execute</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">out</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">Params</span><span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">Title</span><span style="color: #0550ae">:</span> <span style="color: #0a3069">"foo"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">User</span><span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">User</span><span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">ID</span><span style="color: #0550ae">:</span> <span style="color: #0550ae">123</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">Name</span><span style="color: #0550ae">:</span> <span style="color: #0a3069">"john"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">},</span> + <span style="color: #24292f;background-color: #f6f8fa">Items</span><span style="color: #0550ae">:</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span><span style="color: #cf222e">string</span><span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0a3069">"hoge"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0a3069">"piyo"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0a3069">"fuga"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">},</span> +<span style="color: #24292f;background-color: #f6f8fa">})</span> +</code></pre> </div> </section> <section id="section--what-i-want-to-do"> @@ -134,13 +136,14 @@ 今回おこないたいのは、<code>with</code> や <code>range</code> の中で、その外側で使われていたトップレベルのオブジェクトを参照することだ。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>{{ with .User }}</span></span> -<span class="line"><span> ここから .Title を参照するには?</span></span> -<span class="line"><span>{{ end }}</span></span> -<span class="line"><span></span></span> -<span class="line"><span>{{ range .Items }}</span></span> -<span class="line"><span> ここから .User を参照するには?</span></span> -<span class="line"><span>{{ end }}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>{{ with .User }} + ここから .Title を参照するには? +{{ end }} + +{{ range .Items }} + ここから .User を参照するには? +{{ end }} +</code></pre> </div> <p> <code>with</code> や <code>range</code> は、<code>.</code> を自身の対象オブジェクトに変更するので、単に <code>{{ with .User }}</code> の中で <code>.Title</code> と書いても、それは <code>User</code> の <code>Title</code> プロパティを参照しているとみなされる。 @@ -149,7 +152,8 @@ <code>text/template</code> では変数が使えるので、テンプレートの先頭で </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>{{ $params := . }}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>{{ $params := . }} +</code></pre> </div> <p> とでもしておけば実現は可能である。 @@ -164,13 +168,14 @@ 常にトップレベルを指す特殊変数 <code>$</code> を使えばよい。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>{{ with .User }}</span></span> -<span class="line"><span> {{ $.Title }}</span></span> -<span class="line"><span>{{ end }}</span></span> -<span class="line"><span></span></span> -<span class="line"><span>{{ range .Items }}</span></span> -<span class="line"><span> {{ $.User.Name }}</span></span> -<span class="line"><span>{{ end }}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>{{ with .User }} + {{ $.Title }} +{{ end }} + +{{ range .Items }} + {{ $.User.Name }} +{{ end }} +</code></pre> </div> <p> <code>$</code> は、テンプレートが実行されるときに渡されたオブジェクトを指す。これを使えば現在の <code>.</code> に関係なくトップレベルを参照できる。 diff --git a/services/nuldoc/public/blog/posts/2024-12-04/cohackpp-report/index.html b/services/nuldoc/public/blog/posts/2024-12-04/cohackpp-report/index.html index 8201978a..050c47cd 100644 --- a/services/nuldoc/public/blog/posts/2024-12-04/cohackpp-report/index.html +++ b/services/nuldoc/public/blog/posts/2024-12-04/cohackpp-report/index.html @@ -157,129 +157,130 @@ <a class="url" href="https://github.com/nsfisis/cohackpp/blob/main/congrats.php" rel="noreferrer" target="_blank">https://github.com/nsfisis/cohackpp/blob/main/congrats.php</a> </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"><span style="color:#24292E">$s</span><span style="color:#D73A49">=</span><span style="color:#032F62"><<<'</span><span style="color:#D73A49">Q</span><span style="color:#032F62">'</span></span> -<span class="line"><span style="color:#032F62"><?php</span></span> -<span class="line"><span style="color:#032F62">%</span></span> -<span class="line"><span style="color:#032F62">$s=<<<'Q'</span></span> -<span class="line"><span style="color:#032F62">@$c=[`];</span></span> -<span class="line"><span style="color:#032F62">$m="";for($k=0;$k<min(13,intdiv(__LINE__-119,80)+1);$k++){$C=str_replace("\n","",</span></span> -<span class="line"><span style="color:#032F62">$c[$k]);$f=!0;foreach(str_split(base64_decode($C))as$l){$L=ord($l);$m.=str_repeat</span></span> -<span class="line"><span style="color:#032F62">($f?"#":chr(32),$L&127);$f=!$f;if($L&128){$m.="\n";$f=!0;continue;}}}print(</span></span> -<span class="line"><span style="color:#032F62">str_replace([chr(96),chr(37),chr(64)],[implode("\n",array_map(fn($C)=>"'".trim(</span></span> -<span class="line"><span style="color:#032F62">chunk_split(str_replace("\n","",$C),80,"\n"))."',",$c)),"\n{$m}","{$s}\nQ;\n"],$s));</span></span> -<span class="line"><span style="color:#D73A49">Q</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$c</span><span style="color:#D73A49">=</span><span style="color:#24292E">[</span><span style="color:#032F62">'0AFOgQFOgQFOgQFOgQFOgQFEAgiBAUIECIEBQwQHgQE8AQYFBoEBOgQGBAaBAToEBwQFgQE6BQYFBIEB</span></span> -<span class="line"><span style="color:#032F62">OwQHBASBATwEBgUDgQE8BQYEA4EBPQQGBAOBAT0FBgEFgQERBhsIBAQMgQERKQQFC4EBESkFAQ6BAREp</span></span> -<span class="line"><span style="color:#032F62">FIEBESkUgQERKRSBAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6B</span></span> -<span class="line"><span style="color:#032F62">AU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAQ4EPIEBDQY7gQENBjuBAQ0GO4EBDQU8gQENBTyBAQwG</span></span> -<span class="line"><span style="color:#032F62">PIEBDAY8gQEMBjyBAQwGPIEBDAY8gQEMBjyBAQwHO4EBDAc7gQENBzqBAQ0IOYEBDgg4gQEOCiUCD4EB</span></span> -<span class="line"><span style="color:#032F62">DwwdBw+BARAQDhEPgQERLg+BARItD4EBFCsPgQEXJRKBARsbGIEBToEBToEBToEBToEBToHQ'</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62">'0AFOgQFOgQFOgQEPASMFFoEBDwMhBRaBAQ4FIAUWgQEOBSAFFoEBDQUhBRaBAQ0FIQUWgQEMBSIFFoEB</span></span> -<span class="line"><span style="color:#032F62">DAUiBRaBAQsFIwUWgQELBQgBGgUWgQEKBQkDGAUWgQEKBQgGBCoDgQEJBQkFBSoDgQEFAQMECQYFKgOB</span></span> -<span class="line"><span style="color:#032F62">AQQDAQUJBQYqA4EBBAgJBQcqA4EBAwkJBRkFFoEBBAcJBRoFFoEBBQYIBRsFFoEBBgYHBRsFFoEBBwYF</span></span> -<span class="line"><span style="color:#032F62">BRwFFoEBCAYDBR0FFoEBCQYCBR0FFoEBCgseBRaBAQsJHwUWgQEMByAFFoEBDAcFAxgFFoEBDQUFBBgF</span></span> -<span class="line"><span style="color:#032F62">FoEBDQQGBRYGFoEBDAUHBAcmBYEBCwUIBQYmBYEBCwQKBAYmBYEBCgQLBQUmBYEBCQUMBS+BAQgFDAYv</span></span> -<span class="line"><span style="color:#032F62">gQEDHC+BAQMdLoEBAx0ugQEDHi2BAQMJBAUIBC2BARAFCAQtgQEQBQgELYEBEAUJAS+BARAFESEHgQEQ</span></span> -<span class="line"><span style="color:#032F62">BREhB4EBBwEIBQYBCiEHgQEHBAUFBAQJIQeBAQcEBQUEBAkEGAUHgQEGBQUFBAUIBBgFB4EBBgUFBQUE</span></span> -<span class="line"><span style="color:#032F62">CAQYBQeBAQYFBQUFBAgEGAUHgQEGBAYFBQUHBBgFB4EBBgQGBQYEBwQYBQeBAQUFBgUGBQYEGAUHgQEF</span></span> -<span class="line"><span style="color:#032F62">BQYFBwQGBBgFB4EBBQQHBQcEBgQYBQeBAQUEBwUHBQUEGAUHgQEEBQcFBwUFBBgFB4EBBAUHBQgEBQQY</span></span> -<span class="line"><span style="color:#032F62">BQeBAQQECAUIBAUEGAUHgQEDBQgFCAEIBBgFB4EBAwUIBREEGAUHgQECBQkFEQQYBQeBAQIFCQURIQeB</span></span> -<span class="line"><span style="color:#032F62">AQQCCgURIQeBARAFESEHgQEQBREhB4EBEAURIQeBARAFEQQYBQeBARAFEQQYBQeBARAFEQQYBQeBARAF</span></span> -<span class="line"><span style="color:#032F62">EQQYBQeBAU6BAU6BAU6B0A=='</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62">'0AFOgQFOgQFOgQEOAjEBDIEBDgUqBwqBAQ0FJwwJgQENBSETCIEBDQURAQcXDIEBDQURGxCBAQ0FERcU</span></span> -<span class="line"><span style="color:#032F62">gQENBBIOBAUUgQEMBRIGDAUUgQEMBRIFDQUUgQEMBRIFDgQUgQEMBRIFDgQUgQEMBBMFDgQUgQELBRMF</span></span> -<span class="line"><span style="color:#032F62">DgQUgQELBRMFDgUTgQELBRMFDgUTgQEDGQcFDgUTgQEDGwUoA4EBAxsFKAOBAQMbBSgDgQEDGwUoA4EB</span></span> -<span class="line"><span style="color:#032F62">CgUKBQUFDwUSgQEKBAsEBgUQBBKBAQkFCwQGBRAFEYEBCQULBAYFEAURgQEJBQoFBgUQBRGBAQkFCgUG</span></span> -<span class="line"><span style="color:#032F62">BREFEIEBCQQLBQYFEQUQgQEIBQsFBgUSBQkBBYEBCAULBQYFEgUJAwOBAQgFCwUGBQoFBAUIBAKBAQgF</span></span> -<span class="line"><span style="color:#032F62">CwQHBQQLBAYHAwOBAQgECwUHFAUGBQQDgQEHBQsFAxgFBwQEA4EBBwULBQMVCQ4DgQEHBQsFAw8QDQOB</span></span> -<span class="line"><span style="color:#032F62">AQcEDAUDCRcLBIEBBgULBQUCHwgFgQEGBQsFKAQHgQEGBQsFM4EBBgULBTOBAQYFCgUKIgiBAQUHCQUK</span></span> -<span class="line"><span style="color:#032F62">IgiBAQUICAUKIgiBAQUKBgUKIgiBAQULBAULBRgFCIEBBA0DBQsFGAUIgQEEBQIHAgULBRgFCIEBBgMD</span></span> -<span class="line"><span style="color:#032F62">DAwFGAUIgQENCwwFGAUIgQEOCgwFGAUIgQEQBw0FGAUIgQERBwwFGAUIgQERCAsiCIEBEAoKIgiBARAL</span></span> -<span class="line"><span style="color:#032F62">CSIIgQEPDQgiCIEBDwUCBwcFGAUIgQEOBgMHBgUYBQiBAQ0GBQcFBRgFCIEBDAcGBgUFGAUIgQELBwgE</span></span> -<span class="line"><span style="color:#032F62">BgUYBQiBAQoHCgMGBRgFCIEBCQcMAQcFGAUIgQEIBxUFGAUIgQEHCBUiCIEBBggWIgiBAQQJFyIIgQEF</span></span> -<span class="line"><span style="color:#032F62">BxgiCIEBBQUaBRgFCIEBBgMbBRgFCIEBJAUYBQiBAU6BAU6BAU6B0A=='</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQEZBi+BARkGL4EBGgUvgQEaBS+BARoFL4EBGgUvgQEaBS+BARoF</span></span> -<span class="line"><span style="color:#032F62">L4EBGgUvgQEaBRkBFYEBGgUZAxOBARoFDwEIBRKBARoFCwUIBxCBARoFBgoHCg6BARoVCQkNgQEJJgsJ</span></span> -<span class="line"><span style="color:#032F62">C4EBCSYMCQqBAQohEgkIgQEKGxoIB4EBChUhCQWBARkFIwkEgQEZBSUGBYEBGQUmBAaBARkFKAIGgQEZ</span></span> -<span class="line"><span style="color:#032F62">BTCBARkFMIEBGQUwgQEZBTCBARkFMIEBGQUwgQEZBTCBARkFCRAXgQEZBQQYFIEBGSMSgQEZJBGBARkS</span></span> -<span class="line"><span style="color:#032F62">CAwPgQEXDhIJDoEBFQwYCA2BARMMGwcNgQESDB0HDIEBEA4eBgyBAQ8IAwQfBguBAQ4IBAQfBguBAQ0H</span></span> -<span class="line"><span style="color:#032F62">BgQgBQuBAQwHBwQgBQuBAQsHCAUfBQuBAQoGCgUfBQuBAQoGCgUfBQuBAQkGCwUfBQuBAQkFDAUeBguB</span></span> -<span class="line"><span style="color:#032F62">AQgGDAUeBguBAQgGDAUdBwuBAQgGDAUdBgyBAQgGDAUcBwyBAQkFDAUbBw2BAQkGCwUZCQ2BAQkHCgUY</span></span> -<span class="line"><span style="color:#032F62">CQ6BAQoIBwYVCw+BAQsIBQcSDRCBAQwSChURgQENEQoTE4EBDhAKERWBARANDA4XgQESCwwLGoEBFQYO</span></span> -<span class="line"><span style="color:#032F62">BSCBAU6BAU6BAU6BAU6BAU6BAU6B0A=='</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQEuBhqBAS4FG4EBLgUbgQEuBRuBARICGQYbgQEPBRkGG4EBDgYZ</span></span> -<span class="line"><span style="color:#032F62">BRyBAQ8FGQUcgQEPBhgFHIEBDwYXBhyBARAFFwUdgQEQBRcFHYEBEAYNERqBAREFChcXgQERBQccFYEB</span></span> -<span class="line"><span style="color:#032F62">EQYEIBOBARIFAg4DExGBARIRBwYEChCBARIOCgUHCQ+BARMKDQUJCA6BARIJDgYKCA2BAREIEAUNBwyB</span></span> -<span class="line"><span style="color:#032F62">ARAJEAUOBgyBAQ8KDwYPBguBAQ4MDgUQBwqBAQ4MDgURBgqBAQ0GAgYMBRMFCoEBDAYEBQwFEwYJgQEM</span></span> -<span class="line"><span style="color:#032F62">BgQFCwYTBgmBAQsGBQYKBRUFCYEBCgYHBQkGFQYIgQEKBQgGCAYVBgiBAQkGCQUIBRcFCIEBCQUKBgYG</span></span> -<span class="line"><span style="color:#032F62">FwUIgQEJBQsFBgUYBQiBAQgFDAYEBhgFCIEBCAUNBQMGGQUIgQEIBQ0GAgYZBQiBAQcFDwwaBQiBAQcF</span></span> -<span class="line"><span style="color:#032F62">DwwaBQiBAQcFEAobBQiBAQcFEAoaBgiBAQcFEQgbBgiBAQcFEgYcBgiBAQcFEQgbBQmBAQcFEAoZBgmB</span></span> -<span class="line"><span style="color:#032F62">AQcFEAoZBgmBAQcFDwwXBgqBAQcFDg4VBwqBAQcGDAcCBxQGC4EBCAULBwQEFQcLgQEIBggIBgIVBwyB</span></span> -<span class="line"><span style="color:#032F62">AQgIBAkHARUHDYEBCRMcCQ2BAQoRHAkOgQELDhwKD4EBDAwbChGBAQ4HGwwSgQEsDxOBASgRFYEBKQ4X</span></span> -<span class="line"><span style="color:#032F62">gQEpDBmBASoIHIEBKwMggQFOgQFOgQFOgQFOgQFOgQFOgQFOgdA='</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQE1DwqBASkbCoEBHiYKgQETMQqBAQc9CoEBBjQU</span></span> -<span class="line"><span style="color:#032F62">gQEGIQQKGYEBBhcOBxyBAQcOFAcegQEHBhsHH4EBJwYhgQEmBiKBASUGFgEMgQEkBhUDDIEBIwYWBAuB</span></span> -<span class="line"><span style="color:#032F62">ASMGFwQKgQEiBg8DBgQKgQEhBg8EBwQJgQEhBhAEBwQIgQEgBhEFBgQIgQEgBRMEBwQHgQEfBhQEBgUG</span></span> -<span class="line"><span style="color:#032F62">gQEfBhQEBwQGgQEfBRYEBgIIgQEeBhYEEIEBHgYXBA+BAR4FGAMQgQEeBSuBAR0GK4EBHQYrgQEdBiuB</span></span> -<span class="line"><span style="color:#032F62">AR0GK4EBHQYrgQEdBiuBAR0GK4EBHQYrgQEdBiuBAR4FK4EBHgYqgQEeBiqBAR4HKYEBHwYpgQEfByiB</span></span> -<span class="line"><span style="color:#032F62">ASAHJ4EBIAcngQEhByaBASEJJIEBIgkjgQEjCiGBASQLH4EBJQwdgQEmDxmBASgTE4EBKhMRgQErEhGB</span></span> -<span class="line"><span style="color:#032F62">AS4PEYEBMAwSgQE0CBKBAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6B0A=='</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQEXATaBARQENoEBEgY2gQESBzWBARMGNYEBEwc0gQEUBjSB</span></span> -<span class="line"><span style="color:#032F62">ARQGNIEBFQYzgQEVBiABEoEBFgYeAxGBARYGHAYQgQEWBxoHEIEBFwYYCg+BARcHFQsQgQEYBhMLEoEB</span></span> -<span class="line"><span style="color:#032F62">GAYRCxSBARkGDgsWgQEZBgwLGIEBGgYJCxqBARoHBwocgQEbBgUKHoEBGwcCCiCBARwRIYEBHA8jgQEd</span></span> -<span class="line"><span style="color:#032F62">DCWBAR0KJ4EBHAoogQEbCSqBARoILIEBGQgtgQEXCC+BARYIMIEBFQgxgQEVBzKBARQHM4EBEwc0gQES</span></span> -<span class="line"><span style="color:#032F62">BzWBARIGNoEBEQY3gQERBjeBAREFOIEBEAY4gQEQBjiBARAGOIEBEAY4gQEQBjiBARAGOIEBEAY4gQEQ</span></span> -<span class="line"><span style="color:#032F62">BjiBARAHN4EBEAc3gQERBzaBAREINYEBEgkzgQETCiEDDYEBEw0WCw2BARQtDYEBFisNgQEXKg2BARon</span></span> -<span class="line"><span style="color:#032F62">DYEBHSARgQEjDxyBAU6BAU6BAU6BAU6BAU6BAU6BAU6B0A=='</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQEXBDOBARcLLIEBFxQjgQEXIRaBARchFoEBGh4WgQEiFhaBASsN</span></span> -<span class="line"><span style="color:#032F62">FoEBNgEXgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQEkDR2BAR4WGoEBGR0YgQEVIxaBARApFYEB</span></span> -<span class="line"><span style="color:#032F62">DRcLCxSBAQ4QFAkTgQEODBoIEoEBDgkeBxKBAQ4GIgcRgQEPAiYGEYEBNwcQgQE4BhCBATgGEIEBOAYQ</span></span> -<span class="line"><span style="color:#032F62">gQE4BhCBATkFEIEBOQUQgQE5BRCBATgGEIEBOAYQgQE4BhCBATgGEIEBNwcQgQE3BhGBATcGEYEBNgcR</span></span> -<span class="line"><span style="color:#032F62">gQE1BxKBATUHEoEBNAcTgQEzCBOBATIIFIEBMQgVgQEvCRaBAS4JF4EBLAoYgQEqCxmBAScMG4EBJQ0c</span></span> -<span class="line"><span style="color:#032F62">gQEhDx6BARwTH4EBGBQigQEZESSBARoNJ4EBGgoqgQEbBS6BAU6BAU6BAU6BAU6BAU6BAU6BAU6B0A=='</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62">'0AFOgQFOgQFOgQFOgQFOgQFDAgmBAUEECYEBQgQIgQE7AQYFB4EBOQQGBAeBATkEBwQGgQE5BQYFBYEB</span></span> -<span class="line"><span style="color:#032F62">OgQHBAWBATsEBgUEgQE7BQYEBIEBPAQGBASBATwFBgEGgQEQBhsIBAQNgQEQKQQFDIEBECkFAQ+BARAp</span></span> -<span class="line"><span style="color:#032F62">FYEBECkVgQEQKRWBAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6B</span></span> -<span class="line"><span style="color:#032F62">AU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAQ0EPYEBDAY8gQEMBjyBAQwGPIEBDAU9gQEMBT2BAQsG</span></span> -<span class="line"><span style="color:#032F62">PYEBCwY9gQELBj2BAQsGPYEBCwY9gQELBj2BAQsHPIEBCwc8gQEMBzuBAQwIOoEBDQg5gQENCiUCEIEB</span></span> -<span class="line"><span style="color:#032F62">DgwdBxCBAQ8QDhEQgQEQLhCBAREtEIEBEysQgQEWJROBARobGYEBToEBToEBToEBToEBToHQ'</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62">'0AFOgQFOgQFOgQFOgQFCAwmBAUEECYEBQQUIgQE5AwYFB4EBOAQHBAeBASkCDgQGBQaBASYGDQUGBAaB</span></span> -<span class="line"><span style="color:#032F62">ASYGDgQHBAWBASYGDgUGBAWBAScFDwQHBASBAScGDwQGAwWBAScGDwUNgQEoBRAEDYEBKAUQAw6BASgG</span></span> -<span class="line"><span style="color:#032F62">IIEBKQUQAw2BASkFDAcNgQEpBgYMDYEBCgMdFw2BAQsVAh8NgQELNQ6BAQsxEoEBCysYgQELJh2BARkI</span></span> -<span class="line"><span style="color:#032F62">CwUdgQEsBhyBAS0FHIEBLQUcgQEuBRuBAS4FG4EBLwUagQEvBRqBATAFGYEBMAYYgQExBRiBATEGF4EB</span></span> -<span class="line"><span style="color:#032F62">MgUXgQEyBhaBATMGFYEBNAUVgQE0BhSBATUGE4EBEAIWCgMHEoEBEAYSFRGBAQ8GExURgQEPBRQUEoEB</span></span> -<span class="line"><span style="color:#032F62">DgYaDROBAQ4GIwQTgQEOBTuBAQ0GO4EBDQY7gQENBTyBAQ0FPIEBDQU8gQENBTyBAQ0FPIEBDQU8gQEN</span></span> -<span class="line"><span style="color:#032F62">BjuBAQ0GO4EBDgY6gQEOBzmBAQ4IOIEBDwg3gQEQCh4BFYEBEQwVBxWBARInFYEBEyYVgQEVJBWBARgh</span></span> -<span class="line"><span style="color:#032F62">FYEBGxoZgQFOgQFOgQFOgQFOgdA='</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQEJBz6BAQkGP4EBCQY/gQEJBigDFIEB</span></span> -<span class="line"><span style="color:#032F62">CQYlBhSBAQkGJQcTgQEJBiYHEoEBCQYnBhKBAQkGJwcRgQEJBigGEYEBCQYoBxCBAQkGKQYQgQEJBioG</span></span> -<span class="line"><span style="color:#032F62">D4EBCQYqBg+BAQkGKgcOgQEJBisGDoEBCgUrBg6BAQoFLAYNgQEKBSwGDYEBCgUtBgyBAQoFLQYMgQEK</span></span> -<span class="line"><span style="color:#032F62">BS0GDIEBCgUuBguBAQoFLgYLgQEKBS4GC4EBCgYtBguBAQoGLgYKgQEKBi4GCoEBCgYuBgqBAQoGLwYJ</span></span> -<span class="line"><span style="color:#032F62">gQELBS8GCYEBCwUvBgmBAQsFLwYJgQELBhMBGgYJgQELBhMCGgYIgQELBhMDGQYIgQEMBRMEGAYIgQEM</span></span> -<span class="line"><span style="color:#032F62">BhEGFwYIgQEMBhEGFwYIgQEMBhAGGQUIgQENBg8GGQUIgQENBg8GGQUIgQENBg4GGgILgQEOBg0GJ4EB</span></span> -<span class="line"><span style="color:#032F62">DgcLBiiBAQ4HCgcogQEPBwgHKYEBEAcGCCmBARAKAQkqgQEREiuBARIRK4EBEhAsgQETDi2BARULLoEB</span></span> -<span class="line"><span style="color:#032F62">FwcwgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgdA='</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQElBiOBASYFI4EBJgUjgQEmBSOBASYFI4EBJgUjgQEmBSOBASYF</span></span> -<span class="line"><span style="color:#032F62">I4EBJgUQBQ6BAQ4IEAUGDw6BAQ4yDoEBDjIOgQEOMg6BAQ4rFYEBGhIigQEmBSOBASYFI4EBJgUjgQEm</span></span> -<span class="line"><span style="color:#032F62">BSOBASYFI4EBJgUjgQEmBSOBASYFI4EBJgUjgQEmBRQCDYEBDQMWBQwKDYEBDQ8JHA2BAQ4zDYEBDjMN</span></span> -<span class="line"><span style="color:#032F62">gQEOMg6BARAnF4EBJQYjgQEmBSOBASYFI4EBJgUjgQEmBSOBASYFI4EBJgUjgQEmBSOBASYFI4EBJgUj</span></span> -<span class="line"><span style="color:#032F62">gQEmBSOBAR0EBQUjgQEXFCOBARQZIYEBEh4egQERIRyBARAJDBAZgQEPBxARF4EBDgYSExWBAQ4FEwYD</span></span> -<span class="line"><span style="color:#032F62">CxSBAQ4FEwYFCxKBAQ0FFAYHChGBAQ0FFAYJCg+BAQ0FFAYKCg6BAQ0GEwYMCQ2BAQ4FEwYNCQyBAQ4G</span></span> -<span class="line"><span style="color:#032F62">EQYQBg2BAQ4HDwcRBQ2BAQ8IDAgSAw6BAQ8bFAEPgQERGCWBARIWJoEBFBIogQEXDSqBAU6BAU6BAU6B</span></span> -<span class="line"><span style="color:#032F62">AU6BAU6BAU6B0A=='</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#032F62">'0AFOgQFOgQFOgQFOgQFOgQFOgQEpBh+BASkGH4EBKQYfgQEqBR+BASoFH4EBKgUfgQEqBR+BASoFH4EB</span></span> -<span class="line"><span style="color:#032F62">KgUfgQEqBR+BARkuB4EBBkEHgQEHQAeBAQdAB4EBB0AHgQEHDBcFH4EBKgUfgQEqBR+BASoFH4EBKgUf</span></span> -<span class="line"><span style="color:#032F62">gQEqBR+BASoFH4EBKgUfgQEgDx+BAR4RH4EBHBMfgQEbFB+BARoIBAkfgQEZBwkGH4EBGQYLBh6BARgG</span></span> -<span class="line"><span style="color:#032F62">DQUegQEYBQ4GHYEBFwYPBR2BARcFEAUdgQEXBRAFHYEBFwUQBhyBARcFEAYcgQEXBQ8HHIEBFwUPBxyB</span></span> -<span class="line"><span style="color:#032F62">ARcGDgccgQEXBg0IHIEBGAYMBx2BARgHCggdgQEZCAYKHYEBGhcdgQEbFh2BARwVHYEBHgsBBh6BASAG</span></span> -<span class="line"><span style="color:#032F62">BAYegQEpBh+BASkGH4EBKAYggQEnByCBASYHIYEBJQcigQEkCCKBASIJI4EBIAokgQEeCyWBARwLJ4EB</span></span> -<span class="line"><span style="color:#032F62">GQ0ogQEWDiqBARcMK4EBGAktgQEZBTCBARoCMoEBToEBToEBToEBToEBToEBToHQ'</span><span style="color:#24292E">,];</span></span> -<span class="line"><span style="color:#24292E">$m</span><span style="color:#D73A49">=</span><span style="color:#032F62">""</span><span style="color:#24292E">;</span><span style="color:#D73A49">for</span><span style="color:#24292E">($k</span><span style="color:#D73A49">=</span><span style="color:#005CC5">0</span><span style="color:#24292E">;$k</span><span style="color:#D73A49"><</span><span style="color:#005CC5">min</span><span style="color:#24292E">(</span><span style="color:#005CC5">13</span><span style="color:#24292E">,</span><span style="color:#005CC5">intdiv</span><span style="color:#24292E">(</span><span style="color:#005CC5">__LINE__</span><span style="color:#D73A49">-</span><span style="color:#005CC5">119</span><span style="color:#24292E">,</span><span style="color:#005CC5">80</span><span style="color:#24292E">)</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">);$k</span><span style="color:#D73A49">++</span><span style="color:#24292E">){$C</span><span style="color:#D73A49">=</span><span style="color:#005CC5">str_replace</span><span style="color:#24292E">(</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">""</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E">$c[$k]);$f</span><span style="color:#D73A49">=!</span><span style="color:#005CC5">0</span><span style="color:#24292E">;</span><span style="color:#D73A49">foreach</span><span style="color:#24292E">(</span><span style="color:#005CC5">str_split</span><span style="color:#24292E">(</span><span style="color:#005CC5">base64_decode</span><span style="color:#24292E">($C))</span><span style="color:#D73A49">as</span><span style="color:#24292E">$l){$L</span><span style="color:#D73A49">=</span><span style="color:#005CC5">ord</span><span style="color:#24292E">($l);$m</span><span style="color:#D73A49">.=</span><span style="color:#005CC5">str_repeat</span></span> -<span class="line"><span style="color:#24292E">($f</span><span style="color:#D73A49">?</span><span style="color:#032F62">"#"</span><span style="color:#D73A49">:</span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">32</span><span style="color:#24292E">),$L</span><span style="color:#D73A49">&</span><span style="color:#005CC5">127</span><span style="color:#24292E">);$f</span><span style="color:#D73A49">=!</span><span style="color:#24292E">$f;</span><span style="color:#D73A49">if</span><span style="color:#24292E">($L</span><span style="color:#D73A49">&</span><span style="color:#005CC5">128</span><span style="color:#24292E">){$m</span><span style="color:#D73A49">.=</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;$f</span><span style="color:#D73A49">=!</span><span style="color:#005CC5">0</span><span style="color:#24292E">;</span><span style="color:#D73A49">continue</span><span style="color:#24292E">;}}}</span><span style="color:#005CC5">print</span><span style="color:#24292E">(</span></span> -<span class="line"><span style="color:#005CC5">str_replace</span><span style="color:#24292E">([</span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">96</span><span style="color:#24292E">),</span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">37</span><span style="color:#24292E">),</span><span style="color:#005CC5">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">64</span><span style="color:#24292E">)],[</span><span style="color:#005CC5">implode</span><span style="color:#24292E">(</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#005CC5">array_map</span><span style="color:#24292E">(</span><span style="color:#D73A49">fn</span><span style="color:#24292E">($C)=></span><span style="color:#032F62">"'"</span><span style="color:#D73A49">.</span><span style="color:#005CC5">trim</span><span style="color:#24292E">(</span></span> -<span class="line"><span style="color:#005CC5">chunk_split</span><span style="color:#24292E">(</span><span style="color:#005CC5">str_replace</span><span style="color:#24292E">(</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">,</span><span style="color:#032F62">""</span><span style="color:#24292E">,$C),</span><span style="color:#005CC5">80</span><span style="color:#24292E">,</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">))</span><span style="color:#D73A49">.</span><span style="color:#032F62">"',"</span><span style="color:#24292E">,$c)),</span><span style="color:#032F62">"</span><span style="color:#005CC5">\n</span><span style="color:#032F62">{</span><span style="color:#24292E">$m</span><span style="color:#032F62">}"</span><span style="color:#24292E">,</span><span style="color:#032F62">"{</span><span style="color:#24292E">$s</span><span style="color:#032F62">}</span><span style="color:#005CC5">\n</span><span style="color:#032F62">Q;</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">],$s));</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> +<span style="color: #0550ae">$s</span><span style="color: #0550ae">=</span><span style="color: #0a3069"><<<'Q' +<?php +% +$s=<<<'Q' +@$c=[`]; +$m="";for($k=0;$k<min(13,intdiv(__LINE__-119,80)+1);$k++){$C=str_replace("\n","", +$c[$k]);$f=!0;foreach(str_split(base64_decode($C))as$l){$L=ord($l);$m.=str_repeat +($f?"#":chr(32),$L&127);$f=!$f;if($L&128){$m.="\n";$f=!0;continue;}}}print( +str_replace([chr(96),chr(37),chr(64)],[implode("\n",array_map(fn($C)=>"'".trim( +chunk_split(str_replace("\n","",$C),80,"\n"))."',",$c)),"\n{$m}","{$s}\nQ;\n"],$s)); +Q;</span> +<span style="color: #0550ae">$c</span><span style="color: #0550ae">=</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">'0AFOgQFOgQFOgQFOgQFOgQFEAgiBAUIECIEBQwQHgQE8AQYFBoEBOgQGBAaBAToEBwQFgQE6BQYFBIEB +OwQHBASBATwEBgUDgQE8BQYEA4EBPQQGBAOBAT0FBgEFgQERBhsIBAQMgQERKQQFC4EBESkFAQ6BAREp +FIEBESkUgQERKRSBAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6B +AU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAQ4EPIEBDQY7gQENBjuBAQ0GO4EBDQU8gQENBTyBAQwG +PIEBDAY8gQEMBjyBAQwGPIEBDAY8gQEMBjyBAQwHO4EBDAc7gQENBzqBAQ0IOYEBDgg4gQEOCiUCD4EB +DwwdBw+BARAQDhEPgQERLg+BARItD4EBFCsPgQEXJRKBARsbGIEBToEBToEBToEBToEBToHQ'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0a3069">'0AFOgQFOgQFOgQEPASMFFoEBDwMhBRaBAQ4FIAUWgQEOBSAFFoEBDQUhBRaBAQ0FIQUWgQEMBSIFFoEB +DAUiBRaBAQsFIwUWgQELBQgBGgUWgQEKBQkDGAUWgQEKBQgGBCoDgQEJBQkFBSoDgQEFAQMECQYFKgOB +AQQDAQUJBQYqA4EBBAgJBQcqA4EBAwkJBRkFFoEBBAcJBRoFFoEBBQYIBRsFFoEBBgYHBRsFFoEBBwYF +BRwFFoEBCAYDBR0FFoEBCQYCBR0FFoEBCgseBRaBAQsJHwUWgQEMByAFFoEBDAcFAxgFFoEBDQUFBBgF +FoEBDQQGBRYGFoEBDAUHBAcmBYEBCwUIBQYmBYEBCwQKBAYmBYEBCgQLBQUmBYEBCQUMBS+BAQgFDAYv +gQEDHC+BAQMdLoEBAx0ugQEDHi2BAQMJBAUIBC2BARAFCAQtgQEQBQgELYEBEAUJAS+BARAFESEHgQEQ +BREhB4EBBwEIBQYBCiEHgQEHBAUFBAQJIQeBAQcEBQUEBAkEGAUHgQEGBQUFBAUIBBgFB4EBBgUFBQUE +CAQYBQeBAQYFBQUFBAgEGAUHgQEGBAYFBQUHBBgFB4EBBgQGBQYEBwQYBQeBAQUFBgUGBQYEGAUHgQEF +BQYFBwQGBBgFB4EBBQQHBQcEBgQYBQeBAQUEBwUHBQUEGAUHgQEEBQcFBwUFBBgFB4EBBAUHBQgEBQQY +BQeBAQQECAUIBAUEGAUHgQEDBQgFCAEIBBgFB4EBAwUIBREEGAUHgQECBQkFEQQYBQeBAQIFCQURIQeB +AQQCCgURIQeBARAFESEHgQEQBREhB4EBEAURIQeBARAFEQQYBQeBARAFEQQYBQeBARAFEQQYBQeBARAF +EQQYBQeBAU6BAU6BAU6B0A=='</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0a3069">'0AFOgQFOgQFOgQEOAjEBDIEBDgUqBwqBAQ0FJwwJgQENBSETCIEBDQURAQcXDIEBDQURGxCBAQ0FERcU +gQENBBIOBAUUgQEMBRIGDAUUgQEMBRIFDQUUgQEMBRIFDgQUgQEMBRIFDgQUgQEMBBMFDgQUgQELBRMF +DgQUgQELBRMFDgUTgQELBRMFDgUTgQEDGQcFDgUTgQEDGwUoA4EBAxsFKAOBAQMbBSgDgQEDGwUoA4EB +CgUKBQUFDwUSgQEKBAsEBgUQBBKBAQkFCwQGBRAFEYEBCQULBAYFEAURgQEJBQoFBgUQBRGBAQkFCgUG +BREFEIEBCQQLBQYFEQUQgQEIBQsFBgUSBQkBBYEBCAULBQYFEgUJAwOBAQgFCwUGBQoFBAUIBAKBAQgF +CwQHBQQLBAYHAwOBAQgECwUHFAUGBQQDgQEHBQsFAxgFBwQEA4EBBwULBQMVCQ4DgQEHBQsFAw8QDQOB +AQcEDAUDCRcLBIEBBgULBQUCHwgFgQEGBQsFKAQHgQEGBQsFM4EBBgULBTOBAQYFCgUKIgiBAQUHCQUK +IgiBAQUICAUKIgiBAQUKBgUKIgiBAQULBAULBRgFCIEBBA0DBQsFGAUIgQEEBQIHAgULBRgFCIEBBgMD +DAwFGAUIgQENCwwFGAUIgQEOCgwFGAUIgQEQBw0FGAUIgQERBwwFGAUIgQERCAsiCIEBEAoKIgiBARAL +CSIIgQEPDQgiCIEBDwUCBwcFGAUIgQEOBgMHBgUYBQiBAQ0GBQcFBRgFCIEBDAcGBgUFGAUIgQELBwgE +BgUYBQiBAQoHCgMGBRgFCIEBCQcMAQcFGAUIgQEIBxUFGAUIgQEHCBUiCIEBBggWIgiBAQQJFyIIgQEF +BxgiCIEBBQUaBRgFCIEBBgMbBRgFCIEBJAUYBQiBAU6BAU6BAU6B0A=='</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0a3069">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQEZBi+BARkGL4EBGgUvgQEaBS+BARoFL4EBGgUvgQEaBS+BARoF +L4EBGgUvgQEaBRkBFYEBGgUZAxOBARoFDwEIBRKBARoFCwUIBxCBARoFBgoHCg6BARoVCQkNgQEJJgsJ +C4EBCSYMCQqBAQohEgkIgQEKGxoIB4EBChUhCQWBARkFIwkEgQEZBSUGBYEBGQUmBAaBARkFKAIGgQEZ +BTCBARkFMIEBGQUwgQEZBTCBARkFMIEBGQUwgQEZBTCBARkFCRAXgQEZBQQYFIEBGSMSgQEZJBGBARkS +CAwPgQEXDhIJDoEBFQwYCA2BARMMGwcNgQESDB0HDIEBEA4eBgyBAQ8IAwQfBguBAQ4IBAQfBguBAQ0H +BgQgBQuBAQwHBwQgBQuBAQsHCAUfBQuBAQoGCgUfBQuBAQoGCgUfBQuBAQkGCwUfBQuBAQkFDAUeBguB +AQgGDAUeBguBAQgGDAUdBwuBAQgGDAUdBgyBAQgGDAUcBwyBAQkFDAUbBw2BAQkGCwUZCQ2BAQkHCgUY +CQ6BAQoIBwYVCw+BAQsIBQcSDRCBAQwSChURgQENEQoTE4EBDhAKERWBARANDA4XgQESCwwLGoEBFQYO +BSCBAU6BAU6BAU6BAU6BAU6BAU6B0A=='</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0a3069">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQEuBhqBAS4FG4EBLgUbgQEuBRuBARICGQYbgQEPBRkGG4EBDgYZ +BRyBAQ8FGQUcgQEPBhgFHIEBDwYXBhyBARAFFwUdgQEQBRcFHYEBEAYNERqBAREFChcXgQERBQccFYEB +EQYEIBOBARIFAg4DExGBARIRBwYEChCBARIOCgUHCQ+BARMKDQUJCA6BARIJDgYKCA2BAREIEAUNBwyB +ARAJEAUOBgyBAQ8KDwYPBguBAQ4MDgUQBwqBAQ4MDgURBgqBAQ0GAgYMBRMFCoEBDAYEBQwFEwYJgQEM +BgQFCwYTBgmBAQsGBQYKBRUFCYEBCgYHBQkGFQYIgQEKBQgGCAYVBgiBAQkGCQUIBRcFCIEBCQUKBgYG +FwUIgQEJBQsFBgUYBQiBAQgFDAYEBhgFCIEBCAUNBQMGGQUIgQEIBQ0GAgYZBQiBAQcFDwwaBQiBAQcF +DwwaBQiBAQcFEAobBQiBAQcFEAoaBgiBAQcFEQgbBgiBAQcFEgYcBgiBAQcFEQgbBQmBAQcFEAoZBgmB +AQcFEAoZBgmBAQcFDwwXBgqBAQcFDg4VBwqBAQcGDAcCBxQGC4EBCAULBwQEFQcLgQEIBggIBgIVBwyB +AQgIBAkHARUHDYEBCRMcCQ2BAQoRHAkOgQELDhwKD4EBDAwbChGBAQ4HGwwSgQEsDxOBASgRFYEBKQ4X +gQEpDBmBASoIHIEBKwMggQFOgQFOgQFOgQFOgQFOgQFOgQFOgdA='</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0a3069">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQE1DwqBASkbCoEBHiYKgQETMQqBAQc9CoEBBjQU +gQEGIQQKGYEBBhcOBxyBAQcOFAcegQEHBhsHH4EBJwYhgQEmBiKBASUGFgEMgQEkBhUDDIEBIwYWBAuB +ASMGFwQKgQEiBg8DBgQKgQEhBg8EBwQJgQEhBhAEBwQIgQEgBhEFBgQIgQEgBRMEBwQHgQEfBhQEBgUG +gQEfBhQEBwQGgQEfBRYEBgIIgQEeBhYEEIEBHgYXBA+BAR4FGAMQgQEeBSuBAR0GK4EBHQYrgQEdBiuB +AR0GK4EBHQYrgQEdBiuBAR0GK4EBHQYrgQEdBiuBAR4FK4EBHgYqgQEeBiqBAR4HKYEBHwYpgQEfByiB +ASAHJ4EBIAcngQEhByaBASEJJIEBIgkjgQEjCiGBASQLH4EBJQwdgQEmDxmBASgTE4EBKhMRgQErEhGB +AS4PEYEBMAwSgQE0CBKBAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6B0A=='</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0a3069">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQEXATaBARQENoEBEgY2gQESBzWBARMGNYEBEwc0gQEUBjSB +ARQGNIEBFQYzgQEVBiABEoEBFgYeAxGBARYGHAYQgQEWBxoHEIEBFwYYCg+BARcHFQsQgQEYBhMLEoEB +GAYRCxSBARkGDgsWgQEZBgwLGIEBGgYJCxqBARoHBwocgQEbBgUKHoEBGwcCCiCBARwRIYEBHA8jgQEd +DCWBAR0KJ4EBHAoogQEbCSqBARoILIEBGQgtgQEXCC+BARYIMIEBFQgxgQEVBzKBARQHM4EBEwc0gQES +BzWBARIGNoEBEQY3gQERBjeBAREFOIEBEAY4gQEQBjiBARAGOIEBEAY4gQEQBjiBARAGOIEBEAY4gQEQ +BjiBARAHN4EBEAc3gQERBzaBAREINYEBEgkzgQETCiEDDYEBEw0WCw2BARQtDYEBFisNgQEXKg2BARon +DYEBHSARgQEjDxyBAU6BAU6BAU6BAU6BAU6BAU6BAU6B0A=='</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0a3069">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQEXBDOBARcLLIEBFxQjgQEXIRaBARchFoEBGh4WgQEiFhaBASsN +FoEBNgEXgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQEkDR2BAR4WGoEBGR0YgQEVIxaBARApFYEB +DRcLCxSBAQ4QFAkTgQEODBoIEoEBDgkeBxKBAQ4GIgcRgQEPAiYGEYEBNwcQgQE4BhCBATgGEIEBOAYQ +gQE4BhCBATkFEIEBOQUQgQE5BRCBATgGEIEBOAYQgQE4BhCBATgGEIEBNwcQgQE3BhGBATcGEYEBNgcR +gQE1BxKBATUHEoEBNAcTgQEzCBOBATIIFIEBMQgVgQEvCRaBAS4JF4EBLAoYgQEqCxmBAScMG4EBJQ0c +gQEhDx6BARwTH4EBGBQigQEZESSBARoNJ4EBGgoqgQEbBS6BAU6BAU6BAU6BAU6BAU6BAU6BAU6B0A=='</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0a3069">'0AFOgQFOgQFOgQFOgQFOgQFDAgmBAUEECYEBQgQIgQE7AQYFB4EBOQQGBAeBATkEBwQGgQE5BQYFBYEB +OgQHBAWBATsEBgUEgQE7BQYEBIEBPAQGBASBATwFBgEGgQEQBhsIBAQNgQEQKQQFDIEBECkFAQ+BARAp +FYEBECkVgQEQKRWBAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6B +AU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAU6BAQ0EPYEBDAY8gQEMBjyBAQwGPIEBDAU9gQEMBT2BAQsG +PYEBCwY9gQELBj2BAQsGPYEBCwY9gQELBj2BAQsHPIEBCwc8gQEMBzuBAQwIOoEBDQg5gQENCiUCEIEB +DgwdBxCBAQ8QDhEQgQEQLhCBAREtEIEBEysQgQEWJROBARobGYEBToEBToEBToEBToEBToHQ'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0a3069">'0AFOgQFOgQFOgQFOgQFCAwmBAUEECYEBQQUIgQE5AwYFB4EBOAQHBAeBASkCDgQGBQaBASYGDQUGBAaB +ASYGDgQHBAWBASYGDgUGBAWBAScFDwQHBASBAScGDwQGAwWBAScGDwUNgQEoBRAEDYEBKAUQAw6BASgG +IIEBKQUQAw2BASkFDAcNgQEpBgYMDYEBCgMdFw2BAQsVAh8NgQELNQ6BAQsxEoEBCysYgQELJh2BARkI +CwUdgQEsBhyBAS0FHIEBLQUcgQEuBRuBAS4FG4EBLwUagQEvBRqBATAFGYEBMAYYgQExBRiBATEGF4EB +MgUXgQEyBhaBATMGFYEBNAUVgQE0BhSBATUGE4EBEAIWCgMHEoEBEAYSFRGBAQ8GExURgQEPBRQUEoEB +DgYaDROBAQ4GIwQTgQEOBTuBAQ0GO4EBDQY7gQENBTyBAQ0FPIEBDQU8gQENBTyBAQ0FPIEBDQU8gQEN +BjuBAQ0GO4EBDgY6gQEOBzmBAQ4IOIEBDwg3gQEQCh4BFYEBEQwVBxWBARInFYEBEyYVgQEVJBWBARgh +FYEBGxoZgQFOgQFOgQFOgQFOgdA='</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0a3069">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQEJBz6BAQkGP4EBCQY/gQEJBigDFIEB +CQYlBhSBAQkGJQcTgQEJBiYHEoEBCQYnBhKBAQkGJwcRgQEJBigGEYEBCQYoBxCBAQkGKQYQgQEJBioG +D4EBCQYqBg+BAQkGKgcOgQEJBisGDoEBCgUrBg6BAQoFLAYNgQEKBSwGDYEBCgUtBgyBAQoFLQYMgQEK +BS0GDIEBCgUuBguBAQoFLgYLgQEKBS4GC4EBCgYtBguBAQoGLgYKgQEKBi4GCoEBCgYuBgqBAQoGLwYJ +gQELBS8GCYEBCwUvBgmBAQsFLwYJgQELBhMBGgYJgQELBhMCGgYIgQELBhMDGQYIgQEMBRMEGAYIgQEM +BhEGFwYIgQEMBhEGFwYIgQEMBhAGGQUIgQENBg8GGQUIgQENBg8GGQUIgQENBg4GGgILgQEOBg0GJ4EB +DgcLBiiBAQ4HCgcogQEPBwgHKYEBEAcGCCmBARAKAQkqgQEREiuBARIRK4EBEhAsgQETDi2BARULLoEB +FwcwgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgQFOgdA='</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0a3069">'0AFOgQFOgQFOgQFOgQFOgQFOgQFOgQElBiOBASYFI4EBJgUjgQEmBSOBASYFI4EBJgUjgQEmBSOBASYF +I4EBJgUQBQ6BAQ4IEAUGDw6BAQ4yDoEBDjIOgQEOMg6BAQ4rFYEBGhIigQEmBSOBASYFI4EBJgUjgQEm +BSOBASYFI4EBJgUjgQEmBSOBASYFI4EBJgUjgQEmBRQCDYEBDQMWBQwKDYEBDQ8JHA2BAQ4zDYEBDjMN +gQEOMg6BARAnF4EBJQYjgQEmBSOBASYFI4EBJgUjgQEmBSOBASYFI4EBJgUjgQEmBSOBASYFI4EBJgUj +gQEmBSOBAR0EBQUjgQEXFCOBARQZIYEBEh4egQERIRyBARAJDBAZgQEPBxARF4EBDgYSExWBAQ4FEwYD +CxSBAQ4FEwYFCxKBAQ0FFAYHChGBAQ0FFAYJCg+BAQ0FFAYKCg6BAQ0GEwYMCQ2BAQ4FEwYNCQyBAQ4G +EQYQBg2BAQ4HDwcRBQ2BAQ8IDAgSAw6BAQ8bFAEPgQERGCWBARIWJoEBFBIogQEXDSqBAU6BAU6BAU6B +AU6BAU6BAU6B0A=='</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0a3069">'0AFOgQFOgQFOgQFOgQFOgQFOgQEpBh+BASkGH4EBKQYfgQEqBR+BASoFH4EBKgUfgQEqBR+BASoFH4EB +KgUfgQEqBR+BARkuB4EBBkEHgQEHQAeBAQdAB4EBB0AHgQEHDBcFH4EBKgUfgQEqBR+BASoFH4EBKgUf +gQEqBR+BASoFH4EBKgUfgQEgDx+BAR4RH4EBHBMfgQEbFB+BARoIBAkfgQEZBwkGH4EBGQYLBh6BARgG +DQUegQEYBQ4GHYEBFwYPBR2BARcFEAUdgQEXBRAFHYEBFwUQBhyBARcFEAYcgQEXBQ8HHIEBFwUPBxyB +ARcGDgccgQEXBg0IHIEBGAYMBx2BARgHCggdgQEZCAYKHYEBGhcdgQEbFh2BARwVHYEBHgsBBh6BASAG +BAYegQEpBh+BASkGH4EBKAYggQEnByCBASYHIYEBJQcigQEkCCKBASIJI4EBIAokgQEeCyWBARwLJ4EB +GQ0ogQEWDiqBARcMK4EBGAktgQEZBTCBARoCMoEBToEBToEBToEBToEBToEBToHQ'</span><span style="color: #24292f;background-color: #f6f8fa">,];</span> +<span style="color: #0550ae">$m</span><span style="color: #0550ae">=</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #cf222e">for</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$k</span><span style="color: #0550ae">=</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #0550ae">$k</span><span style="color: #0550ae"><</span><span style="color: #953800">min</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">13</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #953800">intdiv</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">__LINE__</span><span style="color: #0550ae">-</span><span style="color: #0550ae">119</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">80</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">+</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #0550ae">$k</span><span style="color: #0550ae">++</span><span style="color: #24292f;background-color: #f6f8fa">){</span><span style="color: #0550ae">$C</span><span style="color: #0550ae">=</span><span style="color: #953800">str_replace</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">,</span> +<span style="color: #0550ae">$c</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$k</span><span style="color: #24292f;background-color: #f6f8fa">]);</span><span style="color: #0550ae">$f</span><span style="color: #0550ae">=!</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #cf222e">foreach</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">str_split</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">base64_decode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$C</span><span style="color: #24292f;background-color: #f6f8fa">))</span><span style="color: #cf222e">as</span><span style="color: #0550ae">$l</span><span style="color: #24292f;background-color: #f6f8fa">){</span><span style="color: #0550ae">$L</span><span style="color: #0550ae">=</span><span style="color: #953800">ord</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$l</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #0550ae">$m</span><span style="color: #0550ae">.</span><span style="color: #0550ae">=</span><span style="color: #953800">str_repeat</span> +<span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$f</span><span style="color: #0550ae">?</span><span style="color: #0a3069">"#"</span><span style="color: #0550ae">:</span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">32</span><span style="color: #24292f;background-color: #f6f8fa">),</span><span style="color: #0550ae">$L</span><span style="color: #0550ae">&</span><span style="color: #0550ae">127</span><span style="color: #24292f;background-color: #f6f8fa">);</span><span style="color: #0550ae">$f</span><span style="color: #0550ae">=!</span><span style="color: #0550ae">$f</span><span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #cf222e">if</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$L</span><span style="color: #0550ae">&</span><span style="color: #0550ae">128</span><span style="color: #24292f;background-color: #f6f8fa">){</span><span style="color: #0550ae">$m</span><span style="color: #0550ae">.</span><span style="color: #0550ae">=</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #0550ae">$f</span><span style="color: #0550ae">=!</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #cf222e">continue</span><span style="color: #24292f;background-color: #f6f8fa">;}}}</span><span style="color: #cf222e">print</span><span style="color: #24292f;background-color: #f6f8fa">(</span> +<span style="color: #953800">str_replace</span><span style="color: #24292f;background-color: #f6f8fa">([</span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">96</span><span style="color: #24292f;background-color: #f6f8fa">),</span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">37</span><span style="color: #24292f;background-color: #f6f8fa">),</span><span style="color: #953800">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">64</span><span style="color: #24292f;background-color: #f6f8fa">)],[</span><span style="color: #953800">implode</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #953800">array_map</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$C</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">=></span><span style="color: #0a3069">"'"</span><span style="color: #0550ae">.</span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">(</span> +<span style="color: #953800">chunk_split</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">str_replace</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">$C</span><span style="color: #24292f;background-color: #f6f8fa">),</span><span style="color: #0550ae">80</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">))</span><span style="color: #0550ae">.</span><span style="color: #0a3069">"',"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0550ae">$c</span><span style="color: #24292f;background-color: #f6f8fa">)),</span><span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #24292f">{</span><span style="color: #0550ae">$m</span><span style="color: #24292f">}</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #0a3069">"</span><span style="color: #24292f">{</span><span style="color: #0550ae">$s</span><span style="color: #24292f">}</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">Q;</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">],</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">));</span> +</code></pre> </div> </section> </div> diff --git a/services/nuldoc/public/blog/posts/2025-01-08/phperkaigi-2023-tokens-q1/index.html b/services/nuldoc/public/blog/posts/2025-01-08/phperkaigi-2023-tokens-q1/index.html index 7231d693..3b35dd5b 100644 --- a/services/nuldoc/public/blog/posts/2025-01-08/phperkaigi-2023-tokens-q1/index.html +++ b/services/nuldoc/public/blog/posts/2025-01-08/phperkaigi-2023-tokens-q1/index.html @@ -167,7 +167,8 @@ まずはトークンを得る方法を解説抜きで説明する。次のように実行する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ echo "#iwillblog" | php Q1.png >/dev/null</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ echo "#iwillblog" | php Q1.png >/dev/null +</code></pre> </div> <p> 無事に実行できていれば「#ModernPHPisStaticallyTypedLanguage」というトークンが得られる。 @@ -181,7 +182,8 @@ まずは素直に画像として見てみよう。全体は QR コードになっている。適当な QR コードリーダで読み込むと、次のようなテキストが表示されるはずだ。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>Guess password. $ echo "password" | php Q1.png >/dev/null</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>Guess password. $ echo "password" | php Q1.png >/dev/null +</code></pre> </div> <p> メッセージは、この画像の実行方法とこの問題でやるべきこと (パスワードの推測) を示している。 @@ -196,8 +198,9 @@ 不正なパスワードを使って実行してみると、次のようなエラーメッセージが表示される。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ echo "foo" | php Q1.png >/dev/null</span></span> -<span class="line"><span>401 Unauthorized</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ echo "foo" | php Q1.png >/dev/null +401 Unauthorized +</code></pre> </div> <p> すでに <a href="#section--how-to-solve">「解き方」の節</a> で示したように、パスワードである PHPer トークンは「#iwillblog」である。これを与えて実行すると正解のトークンが得られる。 @@ -267,23 +270,25 @@ <code>strings</code> コマンドを使うと、隠されたデータを簡単に閲覧できる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>IHDR</span></span> -<span class="line"><span>-HHc</span></span> -<span class="line"><span><PLTE</span></span> -<span class="line"><span>IDATx</span></span> -<span class="line"><span>IEND</span></span> -<span class="line"><span><?php</span></span> -<span class="line"><span>error_reporting(-1);</span></span> -<span class="line"><span>$b = unpack('C*', file_get_contents(__FILE__));</span></span> -<span class="line"><span>$w = $b[20]+2;</span></span> -<span class="line"><span>$h = $b[24]+2;</span></span> -<span class="line"><span>// (以下略)</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>IHDR +-HHc +<PLTE +IDATx +IEND +<?php +error_reporting(-1); +$b = unpack('C*', file_get_contents(__FILE__)); +$w = $b[20]+2; +$h = $b[24]+2; +// (以下略) +</code></pre> </div> <p> <code>IHDR</code> や <code>IEND</code> が PNG 画像の一部で、<code><?php</code> からが実際のプログラムになっている。もちろんこれを PHP プログラムとして動かすと、PHP タグより前にある PNG 画像としてのデータはそのまま標準出力へと出力されてしまう。それを防ぐため、QR コードを読み込んだときの実行方法 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>Guess password. $ echo "password" | php Q1.png >/dev/null</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>Guess password. $ echo "password" | php Q1.png >/dev/null +</code></pre> </div> <p> には標準出力を捨てるよう <code>>/dev/null</code> と指定されている。 @@ -298,107 +303,108 @@ 画像の正体がわかったところで、画像に隠されていた PHP プログラムについて見ていこう。先ほどは一部しか記載しなかったので、全体を載せる。なお、ある程度ゴルフしながら書いたので、空白こそ残しているものの可読性は非常に低いことと思う。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"><?</span><span style="color:#005CC5">php</span></span> -<span class="line"><span style="color:#005CC5">error_reporting</span><span style="color:#24292E">(</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E">$b </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> unpack</span><span style="color:#24292E">(</span><span style="color:#032F62">'C*'</span><span style="color:#24292E">, </span><span style="color:#005CC5">file_get_contents</span><span style="color:#24292E">(</span><span style="color:#005CC5">__FILE__</span><span style="color:#24292E">));</span></span> -<span class="line"><span style="color:#24292E">$w </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $b[</span><span style="color:#005CC5">20</span><span style="color:#24292E">]</span><span style="color:#D73A49">+</span><span style="color:#005CC5">2</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$h </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $b[</span><span style="color:#005CC5">24</span><span style="color:#24292E">]</span><span style="color:#D73A49">+</span><span style="color:#005CC5">2</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$cs </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [];</span></span> -<span class="line"><span style="color:#D73A49">for</span><span style="color:#24292E"> ($y </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; $y </span><span style="color:#D73A49"><</span><span style="color:#24292E"> $h; $y</span><span style="color:#D73A49">++</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> ($x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; $x </span><span style="color:#D73A49"><</span><span style="color:#24292E"> $w; $x</span><span style="color:#D73A49">++</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#24292E"> $cs[$y</span><span style="color:#D73A49">*</span><span style="color:#24292E">$w </span><span style="color:#D73A49">+</span><span style="color:#24292E"> $x] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> ($x</span><span style="color:#D73A49">*</span><span style="color:#24292E">$y </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> ||</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $w</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#D73A49"> ||</span><span style="color:#24292E"> $y </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $h</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> ?</span><span style="color:#005CC5"> 0</span></span> -<span class="line"><span style="color:#D73A49"> :</span><span style="color:#24292E"> $b[</span><span style="color:#005CC5">122</span><span style="color:#D73A49">+</span><span style="color:#24292E">($y</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">($w</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">+</span><span style="color:#24292E">$x</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">];</span></span> -<span class="line"><span style="color:#24292E">$i </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> stream_isatty</span><span style="color:#24292E">(</span><span style="color:#005CC5">STDIN</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> ?</span><span style="color:#24292E"> []</span></span> -<span class="line"><span style="color:#D73A49"> :</span><span style="color:#005CC5"> array_map</span><span style="color:#24292E">(</span><span style="color:#005CC5">ord</span><span style="color:#24292E">(</span><span style="color:#D73A49">...</span><span style="color:#24292E">), </span><span style="color:#005CC5">str_split</span><span style="color:#24292E">(</span><span style="color:#005CC5">trim</span><span style="color:#24292E">((</span><span style="color:#D73A49">string</span><span style="color:#24292E">) </span><span style="color:#005CC5">fgets</span><span style="color:#24292E">(</span><span style="color:#005CC5">STDIN</span><span style="color:#24292E">))));</span></span> -<span class="line"><span style="color:#24292E">$m </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [];</span></span> -<span class="line"><span style="color:#24292E">$pc </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49">*</span><span style="color:#24292E">$w</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$dp </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$cc </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$c0 </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$b </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$ns </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">$o </span><span style="color:#D73A49">=</span><span style="color:#032F62"> ''</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49">while</span><span style="color:#24292E"> (</span><span style="color:#005CC5">true</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#24292E"> $ns</span><span style="color:#D73A49">++</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> ($ns </span><span style="color:#D73A49">></span><span style="color:#005CC5"> 1e5</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#005CC5"> echo</span><span style="color:#032F62"> "infinite loop detected</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49"> break</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E"> $c1 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $cs[$pc];</span></span> -<span class="line"><span style="color:#24292E"> $y </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (</span><span style="color:#005CC5">6</span><span style="color:#D73A49"> +</span><span style="color:#005CC5"> intdiv</span><span style="color:#24292E">($c1</span><span style="color:#D73A49">-</span><span style="color:#005CC5">2</span><span style="color:#24292E">, </span><span style="color:#005CC5">3</span><span style="color:#24292E">) </span><span style="color:#D73A49">-</span><span style="color:#005CC5"> intdiv</span><span style="color:#24292E">($c0</span><span style="color:#D73A49">-</span><span style="color:#005CC5">2</span><span style="color:#24292E">, </span><span style="color:#005CC5">3</span><span style="color:#24292E">)) </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 6</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E"> $x </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (</span><span style="color:#005CC5">3</span><span style="color:#D73A49"> +</span><span style="color:#24292E"> $c1</span><span style="color:#D73A49">%</span><span style="color:#005CC5">3</span><span style="color:#D73A49"> -</span><span style="color:#24292E"> $c0</span><span style="color:#D73A49">%</span><span style="color:#005CC5">3</span><span style="color:#24292E">) </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 3</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49"> match</span><span style="color:#24292E"> (($c0 </span><span style="color:#D73A49">!==</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) </span><span style="color:#D73A49">*</span><span style="color:#24292E"> ($c1 </span><span style="color:#D73A49">!==</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) </span><span style="color:#D73A49">*</span><span style="color:#24292E"> ($y</span><span style="color:#D73A49">*</span><span style="color:#005CC5">3</span><span style="color:#D73A49"> +</span><span style="color:#24292E"> $x)) {</span></span> -<span class="line"><span style="color:#005CC5"> 1</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $b,</span></span> -<span class="line"><span style="color:#005CC5"> 2</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($m),</span></span> -<span class="line"><span style="color:#005CC5"> 3</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($m) </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($m),</span></span> -<span class="line"><span style="color:#005CC5"> 4</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (</span><span style="color:#D73A49">fn</span><span style="color:#24292E">($x, $y) => $y </span><span style="color:#D73A49">-</span><span style="color:#24292E"> $x)(</span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m), </span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m)),</span></span> -<span class="line"><span style="color:#005CC5"> 5</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($m) </span><span style="color:#D73A49">*</span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($m),</span></span> -<span class="line"><span style="color:#005CC5"> 8</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($m) </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> ?</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49"> :</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> 11</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $cc </span><span style="color:#D73A49">*=</span><span style="color:#005CC5"> pow</span><span style="color:#24292E">(</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m)),</span></span> -<span class="line"><span style="color:#005CC5"> 12</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $m[</span><span style="color:#005CC5">count</span><span style="color:#24292E">($m)</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">],</span></span> -<span class="line"><span style="color:#005CC5"> 13</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (</span><span style="color:#D73A49">fn</span><span style="color:#24292E">($n, $d, $m, $l) => [</span></span> -<span class="line"><span style="color:#D73A49"> ...</span><span style="color:#005CC5">array_slice</span><span style="color:#24292E">($m, </span><span style="color:#005CC5">0</span><span style="color:#24292E">, $l</span><span style="color:#D73A49">-</span><span style="color:#24292E">$d),</span></span> -<span class="line"><span style="color:#D73A49"> ...</span><span style="color:#005CC5">array_reverse</span><span style="color:#24292E">([</span></span> -<span class="line"><span style="color:#D73A49"> ...</span><span style="color:#005CC5">array_reverse</span><span style="color:#24292E">(</span><span style="color:#005CC5">array_slice</span><span style="color:#24292E">($m, $l</span><span style="color:#D73A49">-</span><span style="color:#24292E">$d, $d</span><span style="color:#D73A49">-</span><span style="color:#24292E">$n)),</span></span> -<span class="line"><span style="color:#D73A49"> ...</span><span style="color:#005CC5">array_reverse</span><span style="color:#24292E">(</span><span style="color:#005CC5">array_slice</span><span style="color:#24292E">($m, $l</span><span style="color:#D73A49">-</span><span style="color:#24292E">$n)),</span></span> -<span class="line"><span style="color:#24292E"> ]),</span></span> -<span class="line"><span style="color:#24292E"> ])(</span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m), </span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m), $m, </span><span style="color:#005CC5">count</span><span style="color:#24292E">($m)),</span></span> -<span class="line"><span style="color:#005CC5"> 15</span><span style="color:#D73A49"> =></span><span style="color:#D73A49"> !</span><span style="color:#005CC5">empty</span><span style="color:#24292E">($i) </span><span style="color:#D73A49">and</span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> array_shift</span><span style="color:#24292E">($i),</span></span> -<span class="line"><span style="color:#005CC5"> 16</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $o </span><span style="color:#D73A49">.=</span><span style="color:#005CC5"> sprintf</span><span style="color:#24292E">(</span><span style="color:#032F62">'%d'</span><span style="color:#24292E">, </span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m)),</span></span> -<span class="line"><span style="color:#005CC5"> 17</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $o </span><span style="color:#D73A49">.=</span><span style="color:#005CC5"> sprintf</span><span style="color:#24292E">(</span><span style="color:#032F62">'%c'</span><span style="color:#24292E">, </span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m)),</span></span> -<span class="line"><span style="color:#D73A49"> default</span><span style="color:#D73A49"> =></span><span style="color:#032F62"> 'nop'</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> };</span></span> -<span class="line"><span style="color:#24292E"> $c0 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $c1;</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> ($j </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; $j </span><span style="color:#D73A49"><</span><span style="color:#005CC5"> 8</span><span style="color:#24292E">; $j</span><span style="color:#D73A49">++</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#24292E"> $v </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [];</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> ($c1 </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#24292E"> $x </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $pc </span><span style="color:#D73A49">%</span><span style="color:#24292E"> $w;</span></span> -<span class="line"><span style="color:#24292E"> $y </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> intdiv</span><span style="color:#24292E">($pc, $w);</span></span> -<span class="line"><span style="color:#24292E"> $e </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [($y</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">$w</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, ($h</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">$w</span><span style="color:#D73A49">+</span><span style="color:#24292E">$x, $y</span><span style="color:#D73A49">*</span><span style="color:#24292E">$w, $x][$dp];</span></span> -<span class="line"><span style="color:#24292E"> $z </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [</span><span style="color:#005CC5">1</span><span style="color:#24292E">, $w, </span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#D73A49">-</span><span style="color:#24292E">$w][$dp];</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> ($ep </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $pc; $ep </span><span style="color:#D73A49">!==</span><span style="color:#24292E"> $e; $ep </span><span style="color:#D73A49">+=</span><span style="color:#24292E"> $z)</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> ($cs[$ep] </span><span style="color:#D73A49">!==</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) </span><span style="color:#D73A49">break</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E"> $ep </span><span style="color:#D73A49">-=</span><span style="color:#24292E"> $z;</span></span> -<span class="line"><span style="color:#24292E"> $pc </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $ep;</span></span> -<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#24292E"> $q </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [$pc];</span></span> -<span class="line"><span style="color:#24292E"> $ep </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $pc;</span></span> -<span class="line"><span style="color:#D73A49"> while</span><span style="color:#24292E"> (</span><span style="color:#D73A49">!</span><span style="color:#005CC5">empty</span><span style="color:#24292E">($q)) {</span></span> -<span class="line"><span style="color:#24292E"> $qq </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($q);</span></span> -<span class="line"><span style="color:#24292E"> $v[$qq] </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49"> foreach</span><span style="color:#24292E"> ([$qq</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">, $qq</span><span style="color:#D73A49">+</span><span style="color:#24292E">$w, $qq</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, $qq</span><span style="color:#D73A49">-</span><span style="color:#24292E">$w] </span><span style="color:#D73A49">as</span><span style="color:#24292E"> $qp) {</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> ($cs[$qp] </span><span style="color:#D73A49">!==</span><span style="color:#24292E"> $c1) </span><span style="color:#D73A49">continue</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($v[$qp])) </span><span style="color:#D73A49">continue</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E"> $q[] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $qp;</span></span> -<span class="line"><span style="color:#24292E"> $qx </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $qp </span><span style="color:#D73A49">%</span><span style="color:#24292E"> $w;</span></span> -<span class="line"><span style="color:#24292E"> $qy </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> intdiv</span><span style="color:#24292E">($qp, $w);</span></span> -<span class="line"><span style="color:#24292E"> $x </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $ep </span><span style="color:#D73A49">%</span><span style="color:#24292E"> $w;</span></span> -<span class="line"><span style="color:#24292E"> $y </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> intdiv</span><span style="color:#24292E">($ep, $w);</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (</span></span> -<span class="line"><span style="color:#24292E"> ($dp </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> &&</span><span style="color:#24292E"> ($x </span><span style="color:#D73A49"><</span><span style="color:#24292E"> $qx </span><span style="color:#D73A49">||</span><span style="color:#24292E"> ($x </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $qx </span><span style="color:#D73A49">&&</span><span style="color:#24292E"> ($y</span><span style="color:#D73A49"><=></span><span style="color:#24292E">$qy) </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $cc)))</span></span> -<span class="line"><span style="color:#D73A49"> ||</span><span style="color:#24292E"> ($dp </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49"> &&</span><span style="color:#24292E"> ($y </span><span style="color:#D73A49"><</span><span style="color:#24292E"> $qy </span><span style="color:#D73A49">||</span><span style="color:#24292E"> ($y </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $qy </span><span style="color:#D73A49">&&</span><span style="color:#24292E"> ($qx</span><span style="color:#D73A49"><=></span><span style="color:#24292E">$x) </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $cc)))</span></span> -<span class="line"><span style="color:#D73A49"> ||</span><span style="color:#24292E"> ($dp </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 2</span><span style="color:#D73A49"> &&</span><span style="color:#24292E"> ($qx </span><span style="color:#D73A49"><</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">||</span><span style="color:#24292E"> ($qx </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">&&</span><span style="color:#24292E"> ($qy</span><span style="color:#D73A49"><=></span><span style="color:#24292E">$y) </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $cc)))</span></span> -<span class="line"><span style="color:#D73A49"> ||</span><span style="color:#24292E"> ($dp </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 3</span><span style="color:#D73A49"> &&</span><span style="color:#24292E"> ($qy </span><span style="color:#D73A49"><</span><span style="color:#24292E"> $y </span><span style="color:#D73A49">||</span><span style="color:#24292E"> ($qy </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $y </span><span style="color:#D73A49">&&</span><span style="color:#24292E"> ($x</span><span style="color:#D73A49"><=></span><span style="color:#24292E">$qx) </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $cc)))</span></span> -<span class="line"><span style="color:#24292E"> )</span></span> -<span class="line"><span style="color:#24292E"> $ep </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $qp;</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> $np </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $ep </span><span style="color:#D73A49">+</span><span style="color:#24292E"> [</span><span style="color:#005CC5">1</span><span style="color:#24292E">, $w, </span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#D73A49">-</span><span style="color:#24292E">$w][$dp];</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> ($cs[$np] </span><span style="color:#D73A49">!==</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#24292E"> $b </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> count</span><span style="color:#24292E">(</span><span style="color:#005CC5">array_keys</span><span style="color:#24292E">($v));</span></span> -<span class="line"><span style="color:#24292E"> $pc </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $np;</span></span> -<span class="line"><span style="color:#D73A49"> break</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> ($j </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 7</span><span style="color:#24292E">) </span><span style="color:#D73A49">break</span><span style="color:#005CC5"> 2</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> ($j </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 2</span><span style="color:#D73A49"> ===</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">) $cc </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> -</span><span style="color:#24292E">$cc;</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> ($j </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 2</span><span style="color:#D73A49"> ===</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) $dp </span><span style="color:#D73A49">=</span><span style="color:#24292E"> ($dp</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">) </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 4</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#6A737D">// The original Piet image is wrong: it outputs 403 error for invalid passwords.</span></span> -<span class="line"><span style="color:#6A737D">// Failure of authentication should be notified by 401, not 403.</span></span> -<span class="line"><span style="color:#6A737D">// I noticed that one month before PHPerKaigi, but I could not read or write (paint)</span></span> -<span class="line"><span style="color:#6A737D">// Piet any longer at that time.</span></span> -<span class="line"><span style="color:#005CC5">fwrite</span><span style="color:#24292E">(</span><span style="color:#005CC5">STDERR</span><span style="color:#24292E">, </span><span style="color:#005CC5">str_replace</span><span style="color:#24292E">(</span><span style="color:#032F62">'403 Forbidden'</span><span style="color:#24292E">, </span><span style="color:#032F62">'401 Unauthorized'</span><span style="color:#24292E">, $o));</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"><?php</span> +<span style="color: #953800">error_reporting</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">);</span> +<span style="color: #0550ae">$b</span> <span style="color: #0550ae">=</span> <span style="color: #953800">unpack</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'C*'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">file_get_contents</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">__FILE__</span><span style="color: #24292f;background-color: #f6f8fa">));</span> +<span style="color: #0550ae">$w</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">20</span><span style="color: #24292f;background-color: #f6f8fa">]</span><span style="color: #0550ae">+</span><span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$h</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">24</span><span style="color: #24292f;background-color: #f6f8fa">]</span><span style="color: #0550ae">+</span><span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$cs</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">[];</span> +<span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$y</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$y</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">$h</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$y</span><span style="color: #0550ae">++</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$x</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$x</span><span style="color: #0550ae">++</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #0550ae">$cs</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$y</span><span style="color: #0550ae">*</span><span style="color: #0550ae">$w</span> <span style="color: #0550ae">+</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #0550ae">*</span><span style="color: #0550ae">$y</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">||</span> <span style="color: #0550ae">$x</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">$w</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span> <span style="color: #0550ae">||</span> <span style="color: #0550ae">$y</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">$h</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #0550ae">?</span> <span style="color: #0550ae">0</span> + <span style="color: #0550ae">:</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">122</span><span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$y</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">*</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$w</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">+</span><span style="color: #0550ae">$x</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">];</span> +<span style="color: #0550ae">$i</span> <span style="color: #0550ae">=</span> <span style="color: #953800">stream_isatty</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">STDIN</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #0550ae">?</span> <span style="color: #24292f;background-color: #f6f8fa">[]</span> + <span style="color: #0550ae">:</span> <span style="color: #953800">array_map</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">ord</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">...</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #953800">str_split</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">trim</span><span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #24292f;background-color: #f6f8fa">string</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #953800">fgets</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">STDIN</span><span style="color: #24292f;background-color: #f6f8fa">))));</span> +<span style="color: #0550ae">$m</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">[];</span> +<span style="color: #0550ae">$pc</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">1</span><span style="color: #0550ae">*</span><span style="color: #0550ae">$w</span><span style="color: #0550ae">+</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$dp</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$cc</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$c0</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$b</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$ns</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #0550ae">$o</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">''</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #cf222e">while</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">true</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">$ns</span><span style="color: #0550ae">++</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$ns</span> <span style="color: #0550ae">></span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">e5</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">echo</span> <span style="color: #0a3069">"infinite loop detected</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">break</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #0550ae">$c1</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$cs</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">];</span> + <span style="color: #0550ae">$y</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">6</span> <span style="color: #0550ae">+</span> <span style="color: #953800">intdiv</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$c1</span><span style="color: #0550ae">-</span><span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">-</span> <span style="color: #953800">intdiv</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$c0</span><span style="color: #0550ae">-</span><span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">))</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">6</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">3</span> <span style="color: #0550ae">+</span> <span style="color: #0550ae">$c1</span><span style="color: #0550ae">%</span><span style="color: #0550ae">3</span> <span style="color: #0550ae">-</span> <span style="color: #0550ae">$c0</span><span style="color: #0550ae">%</span><span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">match</span> <span style="color: #24292f;background-color: #f6f8fa">((</span><span style="color: #0550ae">$c0</span> <span style="color: #0550ae">!==</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">*</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$c1</span> <span style="color: #0550ae">!==</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">*</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$y</span><span style="color: #0550ae">*</span><span style="color: #0550ae">3</span> <span style="color: #0550ae">+</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">))</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">1</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$b</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">2</span> <span style="color: #0550ae">=></span> <span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">),</span> + <span style="color: #0550ae">3</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">=</span> <span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">+</span> <span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">),</span> + <span style="color: #0550ae">4</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$y</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$y</span> <span style="color: #0550ae">-</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)(</span><span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">)),</span> + <span style="color: #0550ae">5</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">=</span> <span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">*</span> <span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">),</span> + <span style="color: #0550ae">8</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">=</span> <span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">?</span> <span style="color: #0550ae">1</span> <span style="color: #0550ae">:</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0550ae">11</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$cc</span> <span style="color: #0550ae">*=</span> <span style="color: #953800">pow</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">)),</span> + <span style="color: #0550ae">12</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #953800">count</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">],</span> + <span style="color: #0550ae">13</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$m</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">fn</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$d</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$l</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">=></span> <span style="color: #24292f;background-color: #f6f8fa">[</span> + <span style="color: #0550ae">...</span><span style="color: #953800">array_slice</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$l</span><span style="color: #0550ae">-</span><span style="color: #0550ae">$d</span><span style="color: #24292f;background-color: #f6f8fa">),</span> + <span style="color: #0550ae">...</span><span style="color: #953800">array_reverse</span><span style="color: #24292f;background-color: #f6f8fa">([</span> + <span style="color: #0550ae">...</span><span style="color: #953800">array_reverse</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">array_slice</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$l</span><span style="color: #0550ae">-</span><span style="color: #0550ae">$d</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$d</span><span style="color: #0550ae">-</span><span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">)),</span> + <span style="color: #0550ae">...</span><span style="color: #953800">array_reverse</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">array_slice</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$l</span><span style="color: #0550ae">-</span><span style="color: #0550ae">$n</span><span style="color: #24292f;background-color: #f6f8fa">)),</span> + <span style="color: #24292f;background-color: #f6f8fa">]),</span> + <span style="color: #24292f;background-color: #f6f8fa">])(</span><span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">),</span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">count</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">)),</span> + <span style="color: #0550ae">15</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">!</span><span style="color: #cf222e">empty</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">and</span> <span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">=</span> <span style="color: #953800">array_shift</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$i</span><span style="color: #24292f;background-color: #f6f8fa">),</span> + <span style="color: #0550ae">16</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$o</span> <span style="color: #0550ae">.</span><span style="color: #0550ae">=</span> <span style="color: #953800">sprintf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'%d'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">)),</span> + <span style="color: #0550ae">17</span> <span style="color: #0550ae">=></span> <span style="color: #0550ae">$o</span> <span style="color: #0550ae">.</span><span style="color: #0550ae">=</span> <span style="color: #953800">sprintf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'%c'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$m</span><span style="color: #24292f;background-color: #f6f8fa">)),</span> + <span style="color: #cf222e">default</span> <span style="color: #0550ae">=></span> <span style="color: #0a3069">'nop'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">};</span> + <span style="color: #0550ae">$c0</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$c1</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$j</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$j</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">8</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$j</span><span style="color: #0550ae">++</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">$v</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">[];</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$c1</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$pc</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #0550ae">$y</span> <span style="color: #0550ae">=</span> <span style="color: #953800">intdiv</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #0550ae">$e</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">[(</span><span style="color: #0550ae">$y</span><span style="color: #0550ae">+</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">*</span><span style="color: #0550ae">$w</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$h</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span><span style="color: #0550ae">*</span><span style="color: #0550ae">$w</span><span style="color: #0550ae">+</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$y</span><span style="color: #0550ae">*</span><span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">][</span><span style="color: #0550ae">$dp</span><span style="color: #24292f;background-color: #f6f8fa">];</span> + <span style="color: #0550ae">$z</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">-</span><span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">][</span><span style="color: #0550ae">$dp</span><span style="color: #24292f;background-color: #f6f8fa">];</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$ep</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$ep</span> <span style="color: #0550ae">!==</span> <span style="color: #0550ae">$e</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #0550ae">$ep</span> <span style="color: #0550ae">+=</span> <span style="color: #0550ae">$z</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$cs</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$ep</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">!==</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">break</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #0550ae">$ep</span> <span style="color: #0550ae">-=</span> <span style="color: #0550ae">$z</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #0550ae">$pc</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$ep</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">else</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">$q</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">];</span> + <span style="color: #0550ae">$ep</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$pc</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">while</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">!</span><span style="color: #cf222e">empty</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$q</span><span style="color: #24292f;background-color: #f6f8fa">))</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">$qq</span> <span style="color: #0550ae">=</span> <span style="color: #953800">array_pop</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$q</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #0550ae">$v</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$qq</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">true</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">foreach</span> <span style="color: #24292f;background-color: #f6f8fa">([</span><span style="color: #0550ae">$qq</span><span style="color: #0550ae">+</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$qq</span><span style="color: #0550ae">+</span><span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$qq</span><span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$qq</span><span style="color: #0550ae">-</span><span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #cf222e">as</span> <span style="color: #0550ae">$qp</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$cs</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$qp</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">!==</span> <span style="color: #0550ae">$c1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">continue</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">isset</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$v</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$qp</span><span style="color: #24292f;background-color: #f6f8fa">]))</span> <span style="color: #cf222e">continue</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #0550ae">$q</span><span style="color: #24292f;background-color: #f6f8fa">[]</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$qp</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #0550ae">$qx</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$qp</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #0550ae">$qy</span> <span style="color: #0550ae">=</span> <span style="color: #953800">intdiv</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$qp</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #0550ae">$x</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$ep</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #0550ae">$y</span> <span style="color: #0550ae">=</span> <span style="color: #953800">intdiv</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$ep</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span> + <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$dp</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">0</span> <span style="color: #0550ae">&&</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">$qx</span> <span style="color: #0550ae">||</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">$qx</span> <span style="color: #0550ae">&&</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$y</span><span style="color: #0550ae"><=></span><span style="color: #0550ae">$qy</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">$cc</span><span style="color: #24292f;background-color: #f6f8fa">)))</span> + <span style="color: #0550ae">||</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$dp</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">1</span> <span style="color: #0550ae">&&</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$y</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">$qy</span> <span style="color: #0550ae">||</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$y</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">$qy</span> <span style="color: #0550ae">&&</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$qx</span><span style="color: #0550ae"><=></span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">$cc</span><span style="color: #24292f;background-color: #f6f8fa">)))</span> + <span style="color: #0550ae">||</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$dp</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">2</span> <span style="color: #0550ae">&&</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$qx</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">$x</span> <span style="color: #0550ae">||</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$qx</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">$x</span> <span style="color: #0550ae">&&</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$qy</span><span style="color: #0550ae"><=></span><span style="color: #0550ae">$y</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">$cc</span><span style="color: #24292f;background-color: #f6f8fa">)))</span> + <span style="color: #0550ae">||</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$dp</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">3</span> <span style="color: #0550ae">&&</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$qy</span> <span style="color: #0550ae"><</span> <span style="color: #0550ae">$y</span> <span style="color: #0550ae">||</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$qy</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">$y</span> <span style="color: #0550ae">&&</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #0550ae"><=></span><span style="color: #0550ae">$qx</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">$cc</span><span style="color: #24292f;background-color: #f6f8fa">)))</span> + <span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #0550ae">$ep</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$qp</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #0550ae">$np</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$ep</span> <span style="color: #0550ae">+</span> <span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">-</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">-</span><span style="color: #0550ae">$w</span><span style="color: #24292f;background-color: #f6f8fa">][</span><span style="color: #0550ae">$dp</span><span style="color: #24292f;background-color: #f6f8fa">];</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$cs</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">$np</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">!==</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">$b</span> <span style="color: #0550ae">=</span> <span style="color: #953800">count</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">array_keys</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$v</span><span style="color: #24292f;background-color: #f6f8fa">));</span> + <span style="color: #0550ae">$pc</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">$np</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">break</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$j</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">7</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #cf222e">break</span> <span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$j</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">2</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">$cc</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">-</span><span style="color: #0550ae">$cc</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$j</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">2</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">$dp</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$dp</span><span style="color: #0550ae">+</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">4</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #6e7781">// The original Piet image is wrong: it outputs 403 error for invalid passwords.</span> +<span style="color: #6e7781">// Failure of authentication should be notified by 401, not 403.</span> +<span style="color: #6e7781">// I noticed that one month before PHPerKaigi, but I could not read or write (paint)</span> +<span style="color: #6e7781">// Piet any longer at that time.</span> +<span style="color: #953800">fwrite</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">STDERR</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">str_replace</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'403 Forbidden'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">'401 Unauthorized'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$o</span><span style="color: #24292f;background-color: #f6f8fa">));</span> +</code></pre> </div> <p> これは一体なんなのか。ずばり、難解プログラミング言語の一つ Piet のインタプリタである。Piet はピエト・モンドリアン (『赤・青・黄のコンポジション』などで知られる抽象画家) の作品にインスピレーションを受けて作られた、画像をソースコードとするプログラミング言語である。インタプリタは画像の各ピクセルの上を進みながら、色等に応じて特定の処理をおこなっていく。ここでは詳しい言語仕様については解説しないので、気になる方は <a href="https://ja.wikipedia.org/wiki/Piet" rel="noreferrer" target="_blank">Wikipedia の記事「Piet」</a> などを参照してほしい。 @@ -407,7 +413,8 @@ プログラムの冒頭にあるこの箇所 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$b </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> unpack</span><span style="color:#24292E">(</span><span style="color:#032F62">'C*'</span><span style="color:#24292E">, </span><span style="color:#005CC5">file_get_contents</span><span style="color:#24292E">(</span><span style="color:#005CC5">__FILE__</span><span style="color:#24292E">));</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #0550ae">$b</span> <span style="color: #0550ae">=</span> <span style="color: #953800">unpack</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'C*'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">file_get_contents</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">__FILE__</span><span style="color: #24292f;background-color: #f6f8fa">));</span> +</code></pre> </div> <p> で <code>__FILE__</code> つまりこの画像ファイルを読み込んでいる。先ほど Piet は画像をソースコードにしていると説明した。そう、今回の問題の画像ファイル <code>Q1.png</code> は、PHP 製 Piet インタプリタであると同時に、Piet のソースコード画像でもあるのだ。QR コード中央のカラフルな部分が Piet の命令になっている。 @@ -459,11 +466,12 @@ ところで、先ほど掲載した Piet のインタプリタのソースコード末尾には次のような箇所がある。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">// The original Piet image is wrong: it outputs 403 error for invalid passwords.</span></span> -<span class="line"><span style="color:#6A737D">// Failure of authentication should be notified by 401, not 403.</span></span> -<span class="line"><span style="color:#6A737D">// I noticed that one month before PHPerKaigi, but I could not read or write (paint)</span></span> -<span class="line"><span style="color:#6A737D">// Piet any longer at that time.</span></span> -<span class="line"><span style="color:#005CC5">fwrite</span><span style="color:#24292E">(</span><span style="color:#005CC5">STDERR</span><span style="color:#24292E">, </span><span style="color:#005CC5">str_replace</span><span style="color:#24292E">(</span><span style="color:#032F62">'403 Forbidden'</span><span style="color:#24292E">, </span><span style="color:#032F62">'401 Unauthorized'</span><span style="color:#24292E">, $o));</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781">// The original Piet image is wrong: it outputs 403 error for invalid passwords.</span> +<span style="color: #6e7781">// Failure of authentication should be notified by 401, not 403.</span> +<span style="color: #6e7781">// I noticed that one month before PHPerKaigi, but I could not read or write (paint)</span> +<span style="color: #6e7781">// Piet any longer at that time.</span> +<span style="color: #953800">fwrite</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">STDERR</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #953800">str_replace</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">'403 Forbidden'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0a3069">'401 Unauthorized'</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">$o</span><span style="color: #24292f;background-color: #f6f8fa">));</span> +</code></pre> </div> <p> コメントにも書かれているが、この Piet のソースコード画像には誤りがあった。本来 HTTP のステータスコードを真似るのなら、認証の失敗には 401 を返さなければならない。しかし、Piet のソースは 403 を返すように書いてしまっていた。そのことに私が気付いたのは PHPerKaigi 2023 が開催されるひと月前で、その時点で私はこの Piet のソースコードを (ちょうどこの記事でそうなっているのと同じように) 読解できなくなっていた。さらに悪いことに、正しいメッセージ「401 Unauthorized」は元の「403 Forbidden」よりも3文字長い。3文字出力が長くなるということは、それだけ Piet で塗るべきピクセルが増えることを意味する。もはや3文字追加で出力するだけの余白はこの画像に残されていなかった (と思う。腕ききの Piet プログラマならできるかもしれないので挑戦してみてほしい)。 diff --git a/services/nuldoc/public/blog/posts/2025-01-26/yaml-breaking-changes-between-v1-1-and-v1-2/index.html b/services/nuldoc/public/blog/posts/2025-01-26/yaml-breaking-changes-between-v1-1-and-v1-2/index.html index 496d5af3..305c976a 100644 --- a/services/nuldoc/public/blog/posts/2025-01-26/yaml-breaking-changes-between-v1-1-and-v1-2/index.html +++ b/services/nuldoc/public/blog/posts/2025-01-26/yaml-breaking-changes-between-v1-1-and-v1-2/index.html @@ -128,14 +128,15 @@ YAML 1.1 では、<code><<</code> という文字列をキーに指定することで、マップをマージすることができた。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#22863A">x</span><span style="color:#24292E">: </span><span style="color:#D73A49">&</span><span style="color:#6F42C1">base</span></span> -<span class="line"><span style="color:#22863A"> a</span><span style="color:#24292E">: </span><span style="color:#005CC5">123</span></span> -<span class="line"><span style="color:#6A737D"># => { "x": { "a": 123 } }</span></span> -<span class="line"></span> -<span class="line"><span style="color:#005CC5">y</span><span style="color:#24292E">:</span></span> -<span class="line"><span style="color:#005CC5"> <<</span><span style="color:#24292E">: </span><span style="color:#D73A49">*</span><span style="color:#24292E">base</span></span> -<span class="line"><span style="color:#22863A"> b</span><span style="color:#24292E">: </span><span style="color:#005CC5">456</span></span> -<span class="line"><span style="color:#6A737D"># => { "y": { "a": 123, "b": 456 } }</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #116329">x</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0550ae">&base</span> + <span style="color: #116329">a</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0550ae">123</span> +<span style="color: #6e7781"># => { "x": { "a": 123 } }</span> + +<span style="color: #116329">y</span><span style="color: #24292f;background-color: #f6f8fa">:</span> + <span style="color: #116329"><<</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0550ae">*base</span> + <span style="color: #116329">b</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #0550ae">456</span> +<span style="color: #6e7781"># => { "y": { "a": 123, "b": 456 } }</span> +</code></pre> </div> <p> 1.2 からはこれができなくなる。 diff --git a/services/nuldoc/public/blog/posts/2025-03-27/zip-function-like-command-paste-command/index.html b/services/nuldoc/public/blog/posts/2025-03-27/zip-function-like-command-paste-command/index.html index 75e953c2..3560fe20 100644 --- a/services/nuldoc/public/blog/posts/2025-03-27/zip-function-like-command-paste-command/index.html +++ b/services/nuldoc/public/blog/posts/2025-03-27/zip-function-like-command-paste-command/index.html @@ -80,28 +80,31 @@ <code>a.txt</code> </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>a1</span></span> -<span class="line"><span>a2</span></span> -<span class="line"><span>a3</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>a1 +a2 +a3 +</code></pre> </div> <p> <code>b.txt</code> </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>b1</span></span> -<span class="line"><span>b2</span></span> -<span class="line"><span>b3</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>b1 +b2 +b3 +</code></pre> </div> <p> <code>ab.txt</code> </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>a1</span></span> -<span class="line"><span>b1</span></span> -<span class="line"><span>a2</span></span> -<span class="line"><span>b2</span></span> -<span class="line"><span>a3</span></span> -<span class="line"><span>b3</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>a1 +b1 +a2 +b2 +a3 +b3 +</code></pre> </div> <p> ちょうど Python や Haskell などにある <code>zip</code> 関数のような動きをさせたい。 @@ -113,8 +116,9 @@ 記事タイトルに書いたように、<code>paste</code> コマンドを使うと実現できる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ paste -d '\</span></span> -<span class="line"><span>' a.txt b.txt > ab.txt</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ paste -d '\ +' a.txt b.txt > ab.txt +</code></pre> </div> <p> <code>paste</code> コマンドは複数のファイルを引数に取り、それらを1行ずつ消費しながら <code>-d</code> で指定した文字で区切って出力する。<code>-d</code> は区切り文字の指定で、デフォルトだとタブ区切りになる。 @@ -123,22 +127,24 @@ ファイル名には <code>-</code> を指定でき、その場合は標準入力から読み込んで出力する。このとき <code>paste - -</code> のように複数回 <code>-</code> を指定すると、指定した回数の行ごとに連結することができる。例えば <code>ab.txt</code> だとこうなる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ paste - - < ab.txt</span></span> -<span class="line"><span>a1 b1</span></span> -<span class="line"><span>a2 b2</span></span> -<span class="line"><span>a3 b3</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ paste - - < ab.txt +a1 b1 +a2 b2 +a3 b3 +</code></pre> </div> <p> これは標準入力を使うとき特有の挙動で、単に同じファイル名を指定してもこうはならない。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ paste ab.txt ab.txt</span></span> -<span class="line"><span>a1 a1</span></span> -<span class="line"><span>b1 b1</span></span> -<span class="line"><span>a2 a2</span></span> -<span class="line"><span>b2 b2</span></span> -<span class="line"><span>a3 a3</span></span> -<span class="line"><span>b3 b3</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ paste ab.txt ab.txt +a1 a1 +b1 b1 +a2 a2 +b2 b2 +a3 a3 +b3 b3 +</code></pre> </div> <p> ときどき便利。 diff --git a/services/nuldoc/public/blog/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html b/services/nuldoc/public/blog/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html index 52aef34c..74a1f48d 100644 --- a/services/nuldoc/public/blog/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html +++ b/services/nuldoc/public/blog/posts/2025-04-20/trick-2025-most-ruby-on-ruby-award/index.html @@ -119,7 +119,7 @@ <section id="section--my-work"> <h2><a href="#section--my-work">作品紹介</a></h2> <p> - 今回頂いたのは審査員賞の一つ eto award (公式の賞の名前に合わせて敬称略) で、“Most Ruby-on-Ruby” Award (『最もRuby on Ruby賞』) として受賞した (IOCCC と同じく、それぞれの賞に個別の名前が付く)。 + 今回頂いたのは審査員賞の一つ eto award (公式の賞の名前に合わせて敬称略) で、”Most Ruby-on-Ruby” Award (『最もRuby on Ruby賞』) として受賞した (IOCCC と同じく、それぞれの賞に個別の名前が付く)。 </p> <p> ソースコード等はこちら: <a class="url" href="https://github.com/tric/trick2025/tree/main/10-nsfisis" rel="noreferrer" target="_blank">https://github.com/tric/trick2025/tree/main/10-nsfisis</a> @@ -161,7 +161,8 @@ 表示している。つまり、Ruby プログラムにルビを振った作品である。例えば、先頭の2行目の <code>require</code> は次のような HTML で構成されている。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"><</span><span style="color:#22863A">ruby</span><span style="color:#6F42C1"> class</span><span style="color:#24292E">=</span><span style="color:#032F62">"IDENTIFIER"</span><span style="color:#24292E">>require<</span><span style="color:#22863A">rp</span><span style="color:#6F42C1"> class</span><span style="color:#24292E">=</span><span style="color:#032F62">""</span><span style="color:#24292E">>(</</span><span style="color:#22863A">rp</span><span style="color:#24292E">><</span><span style="color:#22863A">rt</span><span style="color:#6F42C1"> class</span><span style="color:#24292E">=</span><span style="color:#032F62">""</span><span style="color:#24292E">>リクワイア</</span><span style="color:#22863A">rt</span><span style="color:#24292E">><</span><span style="color:#22863A">rp</span><span style="color:#6F42C1"> class</span><span style="color:#24292E">=</span><span style="color:#032F62">""</span><span style="color:#24292E">>)</</span><span style="color:#22863A">rp</span><span style="color:#24292E">></</span><span style="color:#22863A">ruby</span><span style="color:#24292E">></span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #116329"><ruby</span> <span style="color: #116329">class=</span><span style="color: #0a3069">"IDENTIFIER"</span><span style="color: #116329">></span>require<span style="color: #116329"><rp</span> <span style="color: #116329">class=</span><span style="color: #0a3069">""</span><span style="color: #116329">></span>(<span style="color: #116329"></rp><rt</span> <span style="color: #116329">class=</span><span style="color: #0a3069">""</span><span style="color: #116329">></span>リクワイア<span style="color: #116329"></rt><rp</span> <span style="color: #116329">class=</span><span style="color: #0a3069">""</span><span style="color: #116329">></span>)<span style="color: #116329"></rp></ruby></span> +</code></pre> </div> <p> 順に使ったテクニックを解説していく。 @@ -172,11 +173,12 @@ 改めて quine について説明する。Quine とは、自身のソースコードを出力するようなプログラムである。Ruby では様々な方法で quine を書くことができるが、この作品で使っている基本形は以下のようなものである。 </p> <div class="codeblock numbered"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#005CC5">eval</span><span style="color:#24292E"> $s</span><span style="color:#032F62">=<<'EOS'</span></span> -<span class="line"><span style="color:#032F62">print "eval $s=<<'EOS'</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#032F62">print $s</span></span> -<span class="line"><span style="color:#032F62">print "EOS</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span></span> -<span class="line"><span style="color:#032F62">EOS</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #953800">eval</span> <span style="color: #0550ae">$s</span><span style="color: #0550ae">=<<</span><span style="color: #953800">'EOS'</span><span style="color: #0a3069"> +print "eval $s=<<'EOS'</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">" +print $s +print "EOS</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">" +</span><span style="color: #953800">EOS</span> +</code></pre> </div> <p> 変数 <code>$s</code> に 2 行目、3 行目、4 行目が入っており、それに加えて 1 行目と 5 行目を出力すれば元のソースコードが得られる。実際には <code>$s</code> を加工してシンタックスハイライトや振り仮名を振ることになる。 @@ -191,23 +193,24 @@ トークナイズには Ruby 3.4 からデフォルトのパーサになった <a href="https://github.com/ruby/prism" rel="noreferrer" target="_blank">Prism</a> を利用している。<code>Prism.lex()</code> を使うとトークナイズができるので、トークンに付いているソースコード位置の情報を使いつつ元のソースコードを復元する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#E36209">y</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> 1</span><span style="color:#6A737D"> # 現在の行</span></span> -<span class="line"><span style="color:#E36209">x</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> 0</span><span style="color:#6A737D"> # 現在の列</span></span> -<span class="line"><span style="color:#005CC5">Prism</span><span style="color:#24292E">.</span><span style="color:#6F42C1">lex</span><span style="color:#24292E">($s).</span><span style="color:#6F42C1">value</span><span style="color:#24292E">[..</span><span style="color:#D73A49">-</span><span style="color:#005CC5">2</span><span style="color:#24292E">].</span><span style="color:#6F42C1">each</span><span style="color:#24292E"> {|t, *|</span></span> -<span class="line"><span style="color:#E36209"> l</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> t.</span><span style="color:#6F42C1">location</span></span> -<span class="line"><span style="color:#E36209"> r</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> l.</span><span style="color:#6F42C1">start_line</span><span style="color:#6A737D"> # トークンの開始行</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> y </span><span style="color:#D73A49"><</span><span style="color:#24292E"> r </span><span style="color:#6A737D"># 改行が必要なら</span></span> -<span class="line"><span style="color:#005CC5"> p</span><span style="color:#032F62"> "</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#D73A49"> *</span><span style="color:#24292E"> (r </span><span style="color:#D73A49">-</span><span style="color:#24292E"> y) </span><span style="color:#6A737D"># 改行を挿入して</span></span> -<span class="line"><span style="color:#E36209"> x</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> 0</span><span style="color:#6A737D"> # 列の先頭へ戻る</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#E36209"> c</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> l.</span><span style="color:#6F42C1">start_column</span><span style="color:#6A737D"> # トークンの開始列</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> x </span><span style="color:#D73A49"><</span><span style="color:#24292E"> c </span><span style="color:#6A737D"># 空白が必要なら</span></span> -<span class="line"><span style="color:#005CC5"> p</span><span style="color:#032F62"> " "</span><span style="color:#D73A49"> *</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">-</span><span style="color:#24292E"> x) </span><span style="color:#6A737D"># 空白を挿入</span></span> -<span class="line"><span style="color:#D73A49"> end</span></span> -<span class="line"><span style="color:#005CC5"> p</span><span style="color:#6F42C1"> ruby</span><span style="color:#24292E">(t) </span><span style="color:#6A737D"># トークン本体を出力</span></span> -<span class="line"><span style="color:#E36209"> y</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> l.</span><span style="color:#6F42C1">end_line</span><span style="color:#6A737D"> # 現在行を更新</span></span> -<span class="line"><span style="color:#E36209"> x</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> l.</span><span style="color:#6F42C1">end_column</span><span style="color:#6A737D"> # 現在列を更新</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">y</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">1</span> <span style="color: #6e7781"># 現在の行</span> +<span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span> <span style="color: #6e7781"># 現在の列</span> +<span style="color: #953800">Prism</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">lex</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$s</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">value</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">..-</span><span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">].</span><span style="color: #8250df">each</span> <span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #0550ae">|</span><span style="color: #24292f;background-color: #f6f8fa">t</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #0550ae">*|</span> + <span style="color: #24292f;background-color: #f6f8fa">l</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">t</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">location</span> + <span style="color: #24292f;background-color: #f6f8fa">r</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">l</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">start_line</span> <span style="color: #6e7781"># トークンの開始行</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">y</span> <span style="color: #0550ae"><</span> <span style="color: #24292f;background-color: #f6f8fa">r</span> <span style="color: #6e7781"># 改行が必要なら</span> + <span style="color: #953800">p</span> <span style="color: #0a3069">"</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span> <span style="color: #0550ae">*</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">r</span> <span style="color: #0550ae">-</span> <span style="color: #24292f;background-color: #f6f8fa">y</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #6e7781"># 改行を挿入して</span> + <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">0</span> <span style="color: #6e7781"># 列の先頭へ戻る</span> + <span style="color: #cf222e">end</span> + <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">l</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">start_column</span> <span style="color: #6e7781"># トークンの開始列</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae"><</span> <span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #6e7781"># 空白が必要なら</span> + <span style="color: #953800">p</span> <span style="color: #0a3069">" "</span> <span style="color: #0550ae">*</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">c</span> <span style="color: #0550ae">-</span> <span style="color: #24292f;background-color: #f6f8fa">x</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #6e7781"># 空白を挿入</span> + <span style="color: #cf222e">end</span> + <span style="color: #953800">p</span> <span style="color: #24292f;background-color: #f6f8fa">ruby</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">t</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #6e7781"># トークン本体を出力</span> + <span style="color: #24292f;background-color: #f6f8fa">y</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">l</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">end_line</span> <span style="color: #6e7781"># 現在行を更新</span> + <span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">l</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">end_column</span> <span style="color: #6e7781"># 現在列を更新</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> 補足: 変数名がやたら短いのは、このあとの振り仮名データの量を削減するため。 @@ -216,20 +219,21 @@ トークン種別に応じた色付けは CSS でおこなっている。出力する HTML のクラス名に <code>Prism::Token#type</code> を指定しておいて、<code>index.html</code> でそれぞれのクラスにスタイルを当てた。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"> <</span><span style="color:#22863A">style</span><span style="color:#24292E">></span></span> -<span class="line"><span style="color:#6A737D"> /* ... */</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> .COMMENT</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#005CC5"> color</span><span style="color:#24292E">: </span><span style="color:#005CC5">#777</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#005CC5"> font-style</span><span style="color:#24292E">: </span><span style="color:#005CC5">italic</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1"> .CONSTANT</span><span style="color:#24292E">, </span><span style="color:#6F42C1">.GLOBAL_VARIABLE</span><span style="color:#24292E">, </span><span style="color:#6F42C1">.INSTANCE_VARIABLE</span><span style="color:#24292E">, </span><span style="color:#6F42C1">.IDENTIFIER</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#005CC5"> color</span><span style="color:#24292E">: </span><span style="color:#005CC5">#088</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D"> /* ... */</span></span> -<span class="line"><span style="color:#24292E"> </</span><span style="color:#22863A">style</span><span style="color:#24292E">></span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code> <span style="color: #116329"><style></span> + <span style="color: #6e7781">/* ... */</span> + + <span style="color: #953800">.COMMENT</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">color</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #24292f;background-color: #f6f8fa">#777</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #0550ae">font-style</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #953800">italic</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + + <span style="color: #953800">.CONSTANT</span><span style="color: #0550ae">,</span> <span style="color: #953800">.GLOBAL_VARIABLE</span><span style="color: #0550ae">,</span> <span style="color: #953800">.INSTANCE_VARIABLE</span><span style="color: #0550ae">,</span> <span style="color: #953800">.IDENTIFIER</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0550ae">color</span><span style="color: #24292f;background-color: #f6f8fa">:</span> <span style="color: #24292f;background-color: #f6f8fa">#088</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + + <span style="color: #6e7781">/* ... */</span> + <span style="color: #116329"></style></span> +</code></pre> </div> <p> トークン種別の列挙にはそれなりに文字数を使ってしまうのだが、今回の TRICK のレギュレーションでは <code>index.html</code> にサイズ制限がなかったので好きに色を付けることができた。 @@ -241,27 +245,28 @@ それぞれの英単語や記号に対応した振り仮名のデータは、プログラム中に埋め込まれている。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">def</span><span style="color:#6F42C1"> rt</span><span style="color:#24292E">(t)</span></span> -<span class="line"><span style="color:#E36209"> r</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#005CC5"> :"&&"</span><span style="color:#24292E"> => </span><span style="color:#032F62">"1136"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> :"="</span><span style="color:#24292E"> => </span><span style="color:#032F62">"04199275"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> :"||"</span><span style="color:#24292E"> => </span><span style="color:#032F62">"623147"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> :$s</span><span style="color:#24292E"> => </span><span style="color:#032F62">"41750825"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> :*</span><span style="color:#24292E"> => </span><span style="color:#032F62">"111775"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#6A737D"> # ...</span></span> -<span class="line"><span style="color:#005CC5"> type:</span><span style="color:#032F62"> "310455"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> utf_8:</span><span style="color:#032F62"> "70923803920853080440"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> value:</span><span style="color:#032F62"> "48746992"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> x:</span><span style="color:#032F62"> "08351525"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#005CC5"> y:</span><span style="color:#032F62"> "7904"</span><span style="color:#24292E">,</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#6F42C1"> kana</span><span style="color:#24292E">(</span></span> -<span class="line"><span style="color:#24292E"> r[</span><span style="color:#005CC5">:"#{t.</span><span style="color:#6F42C1">type</span><span style="color:#005CC5">}"</span><span style="color:#24292E">] </span><span style="color:#D73A49">||</span></span> -<span class="line"><span style="color:#24292E"> r[s </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> :"#{t.</span><span style="color:#6F42C1">value</span><span style="color:#005CC5">.</span><span style="color:#6F42C1">downcase</span><span style="color:#005CC5">}"</span><span style="color:#24292E">] </span><span style="color:#D73A49">||</span></span> -<span class="line"><span style="color:#24292E"> s.</span><span style="color:#6F42C1">end_with?</span><span style="color:#24292E">(</span><span style="color:#032F62">":"</span><span style="color:#24292E">) </span><span style="color:#D73A49">&&</span><span style="color:#24292E"> r[</span><span style="color:#005CC5">:"#{s[..</span><span style="color:#D73A49">-</span><span style="color:#005CC5">2]}"</span><span style="color:#24292E">] </span><span style="color:#D73A49">||</span></span> -<span class="line"><span style="color:#005CC5"> nil</span></span> -<span class="line"><span style="color:#24292E"> )</span></span> -<span class="line"><span style="color:#D73A49">end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">def</span> <span style="color: #8250df">rt</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">t</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">r</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #0a3069">:"&&"</span> <span style="color: #0550ae">=></span> <span style="color: #0a3069">"1136"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0a3069">:"="</span> <span style="color: #0550ae">=></span> <span style="color: #0a3069">"04199275"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0a3069">:"||"</span> <span style="color: #0550ae">=></span> <span style="color: #0a3069">"623147"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #0550ae">$s</span> <span style="color: #0550ae">=></span> <span style="color: #0a3069">"41750825"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">:</span><span style="color: #0550ae">*</span> <span style="color: #0550ae">=></span> <span style="color: #0a3069">"111775"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #6e7781"># ...</span> + <span style="color: #0a3069">type: </span><span style="color: #0a3069">"310455"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0a3069">utf_8: </span><span style="color: #0a3069">"70923803920853080440"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0a3069">value: </span><span style="color: #0a3069">"48746992"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0a3069">x: </span><span style="color: #0a3069">"08351525"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #0a3069">y: </span><span style="color: #0a3069">"7904"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">kana</span><span style="color: #24292f;background-color: #f6f8fa">(</span> + <span style="color: #24292f;background-color: #f6f8fa">r</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">:"</span><span style="color: #24292f">#{</span><span style="color: #24292f;background-color: #f6f8fa">t</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">type</span><span style="color: #24292f">}</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">||</span> + <span style="color: #24292f;background-color: #f6f8fa">r</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">s</span> <span style="color: #0550ae">=</span> <span style="color: #0a3069">:"</span><span style="color: #24292f">#{</span><span style="color: #24292f;background-color: #f6f8fa">t</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">value</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">downcase</span><span style="color: #24292f">}</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">||</span> + <span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">end_with?</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">":"</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">&&</span> <span style="color: #24292f;background-color: #f6f8fa">r</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0a3069">:"</span><span style="color: #24292f">#{</span><span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #0550ae">..-</span><span style="color: #0550ae">2</span><span style="color: #24292f;background-color: #f6f8fa">]</span><span style="color: #24292f">}</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">]</span> <span style="color: #0550ae">||</span> + <span style="color: #cf222e">nil</span> + <span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #cf222e">end</span> +</code></pre> </div> <p> トークンの種類 (<code>t.type</code>) またはトークンの文字列表現そのもの (<code>t.value.downcase</code>) を使ってテーブルを引いて振り仮名へ変換している。このテーブルのキー部分そのものにも振り仮名を振るために、トークンが <code>:</code> で終わっていれば <code>:</code> を取り除いて振り仮名を得ている (例: <code>"value:"</code> → <code>"value"</code> → <code>"48746992"</code>)。 @@ -270,25 +275,27 @@ このテーブルはサイズ制限を突破するために圧縮されており、<code>kana()</code> 関数で展開される。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">def</span><span style="color:#6F42C1"> kana</span><span style="color:#24292E">(s)</span></span> -<span class="line"><span style="color:#24292E"> s</span></span> -<span class="line"><span style="color:#D73A49"> &.</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/.{2}/</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49"> &.</span><span style="color:#6F42C1">map</span><span style="color:#24292E">{|c| (</span><span style="color:#005CC5">0x30A0</span><span style="color:#D73A49"> +</span><span style="color:#24292E"> c.</span><span style="color:#6F42C1">to_i</span><span style="color:#24292E">).</span><span style="color:#6F42C1">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">Encoding</span><span style="color:#24292E">::</span><span style="color:#005CC5">UTF_8</span><span style="color:#24292E">)}</span></span> -<span class="line"><span style="color:#D73A49"> &.*</span><span style="color:#24292E">(</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#D73A49">end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">def</span> <span style="color: #8250df">kana</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #24292f;background-color: #f6f8fa">s</span> + <span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">scan</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #116329">/.{2}/</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">map</span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #0550ae">|</span><span style="color: #24292f;background-color: #f6f8fa">c</span><span style="color: #0550ae">|</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0x30A0</span> <span style="color: #0550ae">+</span> <span style="color: #24292f;background-color: #f6f8fa">c</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">to_i</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">Encoding</span><span style="color: #0550ae">::</span><span style="color: #953800">UTF_8</span><span style="color: #24292f;background-color: #f6f8fa">)}</span> + <span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">*</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span> +<span style="color: #cf222e">end</span> +</code></pre> </div> <p> 例えば <code>value</code> に対応する振り仮名データ <code>"48746992"</code> であれば、次のような変換を経て振り仮名へと展開される。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"> s</span></span> -<span class="line"><span style="color:#6A737D"> # => "48746992"</span></span> -<span class="line"><span style="color:#D73A49"> &.</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/.{2}/</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#6A737D"> # => ["48", "74", "69", "92"]</span></span> -<span class="line"><span style="color:#D73A49"> &.</span><span style="color:#6F42C1">map</span><span style="color:#24292E">{|c| (</span><span style="color:#005CC5">0x30A0</span><span style="color:#D73A49"> +</span><span style="color:#24292E"> c.</span><span style="color:#6F42C1">to_i</span><span style="color:#24292E">).</span><span style="color:#6F42C1">chr</span><span style="color:#24292E">(</span><span style="color:#005CC5">Encoding</span><span style="color:#24292E">::</span><span style="color:#005CC5">UTF_8</span><span style="color:#24292E">)}</span></span> -<span class="line"><span style="color:#6A737D"> # => ["バ", "リ", "ュ", "ー"]</span></span> -<span class="line"><span style="color:#D73A49"> &.*</span><span style="color:#24292E">(</span><span style="color:#032F62">""</span><span style="color:#24292E">)</span></span> -<span class="line"><span style="color:#6A737D"> # => "バリュー"</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code> <span style="color: #24292f;background-color: #f6f8fa">s</span> + <span style="color: #6e7781"># => "48746992"</span> + <span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">scan</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #116329">/.{2}/</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #6e7781"># => ["48", "74", "69", "92"]</span> + <span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">map</span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #0550ae">|</span><span style="color: #24292f;background-color: #f6f8fa">c</span><span style="color: #0550ae">|</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">0x30A0</span> <span style="color: #0550ae">+</span> <span style="color: #24292f;background-color: #f6f8fa">c</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">to_i</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">chr</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">Encoding</span><span style="color: #0550ae">::</span><span style="color: #953800">UTF_8</span><span style="color: #24292f;background-color: #f6f8fa">)}</span> + <span style="color: #6e7781"># => ["バ", "リ", "ュ", "ー"]</span> + <span style="color: #0550ae">&</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">*</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">""</span><span style="color: #24292f;background-color: #f6f8fa">)</span> + <span style="color: #6e7781"># => "バリュー"</span> +</code></pre> </div> <p> これは後で気付いたのだが、Ruby は多倍長整数が扱えるので <code>"48746992"</code> のようなデータは単に <code>48746992</code> と書けばよかった。<code>kana()</code> 関数が多少長くはなるが、振り仮名データの数 x 2 バイト分サイズが減るのでこちらの方が短くなる。サイズ制限の都合で振り仮名を振るのを諦めた記号もあったのでもったいない。 diff --git a/services/nuldoc/public/blog/posts/2025-04-24/composer-patches-v2-does-not-require-gnu-patch-even-on-macos/index.html b/services/nuldoc/public/blog/posts/2025-04-24/composer-patches-v2-does-not-require-gnu-patch-even-on-macos/index.html index 7fb14431..70d84caa 100644 --- a/services/nuldoc/public/blog/posts/2025-04-24/composer-patches-v2-does-not-require-gnu-patch-even-on-macos/index.html +++ b/services/nuldoc/public/blog/posts/2025-04-24/composer-patches-v2-does-not-require-gnu-patch-even-on-macos/index.html @@ -126,8 +126,9 @@ ワークアラウンドとして、macOS にも GNU patch をインストールしてしまうという方法がある。例: </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ brew install gpatch</span></span> -<span class="line"><span>$ echo 'PATH="/opt/homebrew/opt/gpatch/libexec/gnubin:$PATH"' >> ~/.zshrc</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ brew install gpatch +$ echo 'PATH="/opt/homebrew/opt/gpatch/libexec/gnubin:$PATH"' >> ~/.zshrc +</code></pre> </div> <p> GNU patch を Homebrew などの手段でインストールし、BSD patch よりも優先されるパスに配置すれば問題が解消する。 diff --git a/services/nuldoc/public/blog/posts/2025-05-05/make-tiny-self-hosted-c-compiler/index.html b/services/nuldoc/public/blog/posts/2025-05-05/make-tiny-self-hosted-c-compiler/index.html index 29af749d..e2e8bb11 100644 --- a/services/nuldoc/public/blog/posts/2025-05-05/make-tiny-self-hosted-c-compiler/index.html +++ b/services/nuldoc/public/blog/posts/2025-05-05/make-tiny-self-hosted-c-compiler/index.html @@ -359,9 +359,10 @@ compilerbook では整数一つのパース・コード生成から始めるが、今回は以下のようなソースをパースしてコード生成するところからスタートすることにした。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">int</span><span style="color:#6F42C1"> main</span><span style="color:#24292E">() {</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> 42</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">int</span> <span style="color: #8250df">main</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">return</span> <span style="color: #0550ae">42</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> この時点で、<code>struct Token</code>、<code>struct Parser</code>、<code>struct AstNode</code>、<code>struct CodeGen</code> といった主要なデータ構造が定義され、この後もほぼ同じソース設計のまま進めている。 @@ -408,23 +409,24 @@ 一日の終わりには、次のようなプログラムのテストが通るようになった。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">int</span><span style="color:#6F42C1"> printf</span><span style="color:#24292E">();</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49">int</span><span style="color:#6F42C1"> main</span><span style="color:#24292E">() {</span></span> -<span class="line"><span style="color:#D73A49"> int</span><span style="color:#24292E"> i;</span></span> -<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> (i </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">; i </span><span style="color:#D73A49"><=</span><span style="color:#005CC5"> 100</span><span style="color:#24292E">; i </span><span style="color:#D73A49">=</span><span style="color:#24292E"> i </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (i </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 15</span><span style="color:#D73A49"> ==</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#6F42C1"> printf</span><span style="color:#24292E">(</span><span style="color:#032F62">"FizzBuzz</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#D73A49"> if</span><span style="color:#24292E"> (i </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 3</span><span style="color:#D73A49"> ==</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#6F42C1"> printf</span><span style="color:#24292E">(</span><span style="color:#032F62">"Fizz</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#D73A49"> if</span><span style="color:#24292E"> (i </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 5</span><span style="color:#D73A49"> ==</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#6F42C1"> printf</span><span style="color:#24292E">(</span><span style="color:#032F62">"Buzz</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6F42C1"> printf</span><span style="color:#24292E">(</span><span style="color:#032F62">"</span><span style="color:#005CC5">%d\n</span><span style="color:#032F62">"</span><span style="color:#24292E">, i);</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">int</span> <span style="color: #8250df">printf</span><span style="color: #24292f;background-color: #f6f8fa">();</span> + +<span style="color: #cf222e">int</span> <span style="color: #8250df">main</span><span style="color: #24292f;background-color: #f6f8fa">()</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">int</span> <span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">for</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">i</span> <span style="color: #0550ae">=</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">i</span> <span style="color: #0550ae"><=</span> <span style="color: #0550ae">100</span><span style="color: #24292f;background-color: #f6f8fa">;</span> <span style="color: #24292f;background-color: #f6f8fa">i</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">i</span> <span style="color: #0550ae">+</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">i</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">15</span> <span style="color: #0550ae">==</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">printf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"FizzBuzz</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">else</span> <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">i</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">3</span> <span style="color: #0550ae">==</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">printf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"Fizz</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">else</span> <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">i</span> <span style="color: #0550ae">%</span> <span style="color: #0550ae">5</span> <span style="color: #0550ae">==</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">printf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"Buzz</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> <span style="color: #cf222e">else</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #24292f;background-color: #f6f8fa">printf</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">"%d</span><span style="color: #0a3069">\n</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">,</span> <span style="color: #24292f;background-color: #f6f8fa">i</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #cf222e">return</span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">;</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> </section> <section id="section--development--day2"> @@ -513,13 +515,14 @@ 記念すべき (?) 最後のバグはこちら。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E"> gen_expr(g, ast->expr1, GEN_RVAL);</span></span> -<span class="line"><span style="color:#24292E"> } else {</span></span> -<span class="line"><span style="color:#24292E"> gen_expr(g, ast->expr1, GEN_RVAL);</span></span> -<span class="line"><span style="color:#B31D28">- gen_lval2rval(ast->expr1->ty);</span></span> -<span class="line"><span style="color:#22863A">+ gen_lval2rval(ast->expr1->ty->to);</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E"> }</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code> gen_expr(g, ast->expr1, GEN_RVAL); + } else { + gen_expr(g, ast->expr1, GEN_RVAL); +<span style="color: #82071e;background-color: #ffebe9">- gen_lval2rval(ast->expr1->ty); +</span><span style="color: #116329;background-color: #dafbe1">+ gen_lval2rval(ast->expr1->ty->to); +</span> } + } +</code></pre> </div> <p> メモリアドレスから参照先の値を得る際、その型によってロードする命令の種類を変える必要があるのだが、その切替をポインタ型でおこなっていた。正しくは、そのポインタ型が指す型を元にして切り替えなければならない。 @@ -534,16 +537,17 @@ 一体どこが異なるのか。<code>hexdump</code> の差分がこちら。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ diff -u <(hexdump -C p4dcc2) <(hexdump -C p4dcc3)</span></span> -<span class="line"><span>@@ -5090,7 +5090,7 @@</span></span> -<span class="line"><span> 00015db0 72 72 61 79 5f 65 6e 74 72 79 00 66 72 61 6d 65 |rray_entry.frame|</span></span> -<span class="line"><span> 00015dc0 5f 64 75 6d 6d 79 00 5f 5f 66 72 61 6d 65 5f 64 |_dummy.__frame_d|</span></span> -<span class="line"><span> 00015dd0 75 6d 6d 79 5f 69 6e 69 74 5f 61 72 72 61 79 5f |ummy_init_array_|</span></span> -<span class="line"><span>-00015de0 65 6e 74 72 79 00 63 63 6d 69 42 49 59 6b 2e 6f |entry.ccmiBIYk.o|</span></span> -<span class="line"><span>+00015de0 65 6e 74 72 79 00 63 63 53 71 64 47 76 57 2e 6f |entry.ccSqdGvW.o|</span></span> -<span class="line"><span> 00015df0 00 66 61 74 61 6c 5f 65 72 72 6f 72 00 72 65 61 |.fatal_error.rea|</span></span> -<span class="line"><span> 00015e00 64 5f 61 6c 6c 00 74 6f 6b 65 6e 69 7a 65 00 74 |d_all.tokenize.t|</span></span> -<span class="line"><span> 00015e10 79 70 65 5f 6e 65 77 00 74 79 70 65 5f 6e 65 77 |ype_new.type_new|</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>$ diff -u <(hexdump -C p4dcc2) <(hexdump -C p4dcc3) +@@ -5090,7 +5090,7 @@ + 00015db0 72 72 61 79 5f 65 6e 74 72 79 00 66 72 61 6d 65 |rray_entry.frame| + 00015dc0 5f 64 75 6d 6d 79 00 5f 5f 66 72 61 6d 65 5f 64 |_dummy.__frame_d| + 00015dd0 75 6d 6d 79 5f 69 6e 69 74 5f 61 72 72 61 79 5f |ummy_init_array_| +-00015de0 65 6e 74 72 79 00 63 63 6d 69 42 49 59 6b 2e 6f |entry.ccmiBIYk.o| ++00015de0 65 6e 74 72 79 00 63 63 53 71 64 47 76 57 2e 6f |entry.ccSqdGvW.o| + 00015df0 00 66 61 74 61 6c 5f 65 72 72 6f 72 00 72 65 61 |.fatal_error.rea| + 00015e00 64 5f 61 6c 6c 00 74 6f 6b 65 6e 69 7a 65 00 74 |d_all.tokenize.t| + 00015e10 79 70 65 5f 6e 65 77 00 74 79 70 65 5f 6e 65 77 |ype_new.type_new| +</code></pre> </div> <p> <code>fatal_error</code>、<code>read_all</code>、<code>tokenize</code> <code>type_new</code> はいずれも <code>main.c</code> で定義された関数の名前である。このことから考えると、これは GCC が埋め込んだシンボルテーブルである可能性が高い。わずかに異なっている 6バイトは、ランダム生成された何かのように見える。 diff --git a/services/nuldoc/public/blog/posts/2025-10-31/representing-single-value-with-half-open-float-interval/index.html b/services/nuldoc/public/blog/posts/2025-10-31/representing-single-value-with-half-open-float-interval/index.html index 10500010..deff05d3 100644 --- a/services/nuldoc/public/blog/posts/2025-10-31/representing-single-value-with-half-open-float-interval/index.html +++ b/services/nuldoc/public/blog/posts/2025-10-31/representing-single-value-with-half-open-float-interval/index.html @@ -152,8 +152,9 @@ <code>1</code> と <code>p</code> のビット列での表現を見てみよう。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>1 = 0011111111110000000000000000000000000000000000000000000000000000</span></span> -<span class="line"><span>p = 0011111111110000000000000000000000000000000000000000000000000001</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code>1 = 0011111111110000000000000000000000000000000000000000000000000000 +p = 0011111111110000000000000000000000000000000000000000000000000001 +</code></pre> </div> <p> <code>p</code> が <code>1</code> よりも一つ分だけ大きいのがわかるだろうか (ここでは <code>binary64</code> の具体的な表現について言及していないのでそうなる保証はないのだが、あくまで雰囲気として)。 @@ -182,37 +183,39 @@ <code>binary64</code> を 64 bit の整数に変換できるなら、他の言語でもほとんど同じ方法で実装できるはずだ。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"> public</span><span style="color:#D73A49"> static</span><span style="color:#D73A49"> function</span><span style="color:#6F42C1"> nextUp</span><span style="color:#24292E">(</span><span style="color:#D73A49">float</span><span style="color:#24292E"> $x)</span><span style="color:#D73A49">:</span><span style="color:#D73A49"> float</span></span> -<span class="line"><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6A737D"> // NaN (Not a Number) なら NaN を返す。</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (</span><span style="color:#005CC5">is_nan</span><span style="color:#24292E">($x)) {</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> NAN</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#6A737D"> // 正の無限大なら正の無限大を返す。</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (</span><span style="color:#005CC5">is_infinite</span><span style="color:#24292E">($x) </span><span style="color:#D73A49">&&</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">></span><span style="color:#005CC5"> 0</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> INF</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#6A737D"> // 0 なら minValue() を返す (後述)。</span></span> -<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> ($x </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 0.0</span><span style="color:#24292E">) {</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#D73A49"> self::</span><span style="color:#6F42C1">minValue</span><span style="color:#24292E">();</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#6A737D"> // binary64 を 64 bit 整数に変換する。</span></span> -<span class="line"><span style="color:#24292E"> $u </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> self::</span><span style="color:#6F42C1">floatToInt</span><span style="color:#24292E">($x);</span></span> -<span class="line"><span style="color:#6A737D"> // 正なら整数に +1 して binary64 に戻す。</span></span> -<span class="line"><span style="color:#6A737D"> // 負なら整数に -1 して binary64 に戻す。</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">></span><span style="color:#005CC5"> 0.0</span><span style="color:#D73A49"> ?</span><span style="color:#D73A49"> self::</span><span style="color:#6F42C1">intToFloat</span><span style="color:#24292E">($u </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) </span><span style="color:#D73A49">:</span><span style="color:#D73A49"> self::</span><span style="color:#6F42C1">intToFloat</span><span style="color:#24292E">($u </span><span style="color:#D73A49">-</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> }</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code> <span style="color: #cf222e">public</span> <span style="color: #cf222e">static</span> <span style="color: #cf222e">function</span> <span style="color: #24292f;background-color: #f6f8fa">nextUp</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #cf222e">float</span> <span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">):</span> <span style="color: #cf222e">float</span> + <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #6e7781">// NaN (Not a Number) なら NaN を返す。</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">is_nan</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">))</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">return</span> <span style="color: #953800">NAN</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #6e7781">// 正の無限大なら正の無限大を返す。</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #953800">is_infinite</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">&&</span> <span style="color: #0550ae">$x</span> <span style="color: #0550ae">></span> <span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">return</span> <span style="color: #953800">INF</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #6e7781">// 0 なら minValue() を返す (後述)。</span> + <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span> <span style="color: #0550ae">===</span> <span style="color: #0550ae">0.0</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">return</span> <span style="color: #cf222e">self</span><span style="color: #0550ae">::</span><span style="color: #8250df">minValue</span><span style="color: #24292f;background-color: #f6f8fa">();</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> + <span style="color: #6e7781">// binary64 を 64 bit 整数に変換する。</span> + <span style="color: #0550ae">$u</span> <span style="color: #0550ae">=</span> <span style="color: #cf222e">self</span><span style="color: #0550ae">::</span><span style="color: #8250df">floatToInt</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$x</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #6e7781">// 正なら整数に +1 して binary64 に戻す。</span> + <span style="color: #6e7781">// 負なら整数に -1 して binary64 に戻す。</span> + <span style="color: #cf222e">return</span> <span style="color: #0550ae">$x</span> <span style="color: #0550ae">></span> <span style="color: #0550ae">0.0</span> <span style="color: #0550ae">?</span> <span style="color: #cf222e">self</span><span style="color: #0550ae">::</span><span style="color: #8250df">intToFloat</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$u</span> <span style="color: #0550ae">+</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">)</span> <span style="color: #0550ae">:</span> <span style="color: #cf222e">self</span><span style="color: #0550ae">::</span><span style="color: #8250df">intToFloat</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$u</span> <span style="color: #0550ae">-</span> <span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> <p> <code>0</code> のときに返している <code>minValue()</code> は次のような値である。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49"> public</span><span style="color:#D73A49"> static</span><span style="color:#D73A49"> function</span><span style="color:#6F42C1"> minValue</span><span style="color:#24292E">()</span><span style="color:#D73A49">:</span><span style="color:#D73A49"> float</span></span> -<span class="line"><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#6A737D"> // 整数の 1 を binary64 と解釈した値を返す。</span></span> -<span class="line"><span style="color:#6A737D"> // binary64 で表せる最小の正の非正規化数。</span></span> -<span class="line"><span style="color:#D73A49"> return</span><span style="color:#D73A49"> self::</span><span style="color:#6F42C1">intToFloat</span><span style="color:#24292E">(</span><span style="color:#005CC5">1</span><span style="color:#24292E">);</span></span> -<span class="line"><span style="color:#24292E"> }</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code> <span style="color: #cf222e">public</span> <span style="color: #cf222e">static</span> <span style="color: #cf222e">function</span> <span style="color: #24292f;background-color: #f6f8fa">minValue</span><span style="color: #24292f;background-color: #f6f8fa">():</span> <span style="color: #cf222e">float</span> + <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #6e7781">// 整数の 1 を binary64 と解釈した値を返す。</span> + <span style="color: #6e7781">// binary64 で表せる最小の正の非正規化数。</span> + <span style="color: #cf222e">return</span> <span style="color: #cf222e">self</span><span style="color: #0550ae">::</span><span style="color: #8250df">intToFloat</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">1</span><span style="color: #24292f;background-color: #f6f8fa">);</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> </section> <section id="section--outro"> diff --git a/services/nuldoc/public/blog/posts/2025-11-27/anybatross-writeup/index.html b/services/nuldoc/public/blog/posts/2025-11-27/anybatross-writeup/index.html index f106611e..d4e8f183 100644 --- a/services/nuldoc/public/blog/posts/2025-11-27/anybatross-writeup/index.html +++ b/services/nuldoc/public/blog/posts/2025-11-27/anybatross-writeup/index.html @@ -132,7 +132,8 @@ <section id="section--hole-1--answer"> <h3><a href="#section--hole-1--answer">回答 (45 byte)</a></h3> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#005CC5">print</span><span style="color:#24292E">$a+=$\=</span><span style="color:#005CC5">y</span><span style="color:#032F62">/8B/0/</span><span style="color:#24292E">+</span><span style="color:#005CC5">y</span><span style="color:#032F62">/0469ADO-R//</span><span style="color:#24292E">.$/,</span><span style="color:#032F62">","</span><span style="color:#D73A49">for</span><span style="color:#24292E"><></span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">print</span><span style="color: #0550ae">$a</span><span style="color: #0550ae">+=</span><span style="color: #0550ae">$\</span><span style="color: #0550ae">=</span><span style="color: #116329">y/8B/0/</span><span style="color: #0550ae">+</span><span style="color: #116329">y/0469ADO-R//</span><span style="color: #0550ae">.</span><span style="color: #0550ae">$/</span><span style="color: #24292f;background-color: #f6f8fa">,"</span><span style="color: #0a3069">,</span><span style="color: #24292f;background-color: #f6f8fa">"</span><span style="color: #cf222e">for</span><span style="color: #0550ae"><></span> +</code></pre> </div> <p> Hole 1 については同一言語・同一スコアの回答が複数あるので詳細は省略する。 @@ -150,10 +151,11 @@ 最終スコアを見ると 4 位タイ (107 byte) が多く、3 位以上の回答と明確にアルゴリズムの差があるのでここから解説をスタートしようと思う。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#E36209">s</span><span style="color:#D73A49">=</span><span style="color:#005CC5">gets</span></span> -<span class="line"><span style="color:#005CC5">?A</span><span style="color:#24292E">.</span><span style="color:#6F42C1">upto</span><span style="color:#24292E">(</span><span style="color:#005CC5">?Z</span><span style="color:#24292E">){(b,),m</span><span style="color:#D73A49">=</span><span style="color:#24292E">s.</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/(?=(.</span><span style="color:#22863A;font-weight:bold">\B</span><span style="color:#032F62">.))/</span><span style="color:#24292E">).</span><span style="color:#6F42C1">tally</span><span style="color:#24292E">.</span><span style="color:#6F42C1">max_by</span><span style="color:#24292E">{</span><span style="color:#005CC5">_2</span><span style="color:#24292E">}</span></span> -<span class="line"><span style="color:#24292E">m</span><span style="color:#D73A49">></span><span style="color:#005CC5">1</span><span style="color:#D73A49">&&</span><span style="color:#24292E">(s.</span><span style="color:#6F42C1">gsub!b</span><span style="color:#24292E">,it;$*</span><span style="color:#D73A49"><<</span><span style="color:#24292E">it</span><span style="color:#D73A49">+</span><span style="color:#005CC5">?:</span><span style="color:#D73A49">+</span><span style="color:#24292E">b)}</span></span> -<span class="line"><span style="color:#005CC5">puts</span><span style="color:#24292E">$*</span><span style="color:#D73A49">*</span><span style="color:#005CC5">?,</span><span style="color:#24292E">,s</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #0550ae">=</span><span style="color: #953800">gets</span> +<span style="color: #0a3069">?A</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">upto</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">?Z</span><span style="color: #24292f;background-color: #f6f8fa">){(</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,),</span><span style="color: #24292f;background-color: #f6f8fa">m</span><span style="color: #0550ae">=</span><span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">scan</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #116329">/(?=(.\B.))/</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">tally</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">max_by</span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #24292f;background-color: #f6f8fa">_2</span><span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #24292f;background-color: #f6f8fa">m</span><span style="color: #0550ae">></span><span style="color: #0550ae">1</span><span style="color: #0550ae">&&</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">gsub!</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #24292f;background-color: #f6f8fa">it</span><span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #0550ae">$*</span><span style="color: #0550ae"><<</span><span style="color: #953800">it</span><span style="color: #0550ae">+</span><span style="color: #0a3069">?:</span><span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">)}</span><span style="color: #0a3069"> +puts$**?,,s</span> +</code></pre> </div> <p> 変数名などの細かい差異を除けば他の 107 byte 回答と同じだが、 <code>String#scan</code> に渡す正規表現にこれを採用していたのは私だけだったのではないだろうか。 <code>/(?=(\S\S))/</code> や <code>/(?=(\w\w))/</code> と比べて短くはならないので意味はない。 @@ -168,9 +170,10 @@ <code>Enumerable#max_by</code> で最頻値を取ってきた後は、多重代入を使って必要な値を取り出している。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#E36209">x</span><span style="color:#D73A49"> =</span><span style="color:#24292E"> [[</span><span style="color:#032F62">"la"</span><span style="color:#24292E">], </span><span style="color:#005CC5">3</span><span style="color:#24292E">]</span></span> -<span class="line"><span style="color:#24292E">(b,),m </span><span style="color:#D73A49">=</span><span style="color:#24292E"> x</span></span> -<span class="line"><span style="color:#6A737D"># => b = "la", m = 3</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">x</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">[[</span><span style="color: #0a3069">"la"</span><span style="color: #24292f;background-color: #f6f8fa">],</span> <span style="color: #0550ae">3</span><span style="color: #24292f;background-color: #f6f8fa">]</span> +<span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,),</span><span style="color: #24292f;background-color: #f6f8fa">m</span> <span style="color: #0550ae">=</span> <span style="color: #24292f;background-color: #f6f8fa">x</span> +<span style="color: #6e7781"># => b = "la", m = 3</span> +</code></pre> </div> <p> 置換テーブルのデータは <code>$*</code> へと追加しているが、これは Ruby の特殊変数で、本来は <code>Object::ARGV</code> を指す。ここでは単に最初から空配列で初期化されている便利な入れ物として用いている。 @@ -185,10 +188,11 @@ 回答 A をぐっと睨むと、<code>m>1&&(...)</code> の括弧を削りたくなる。しかしそれには <code>m>1&&</code> がどうしても邪魔になる。というわけで終了条件を工夫することでなんとか <code>m</code> を排除できないかを考えた。それがこちら。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#E36209">s</span><span style="color:#D73A49">=</span><span style="color:#005CC5">gets</span></span> -<span class="line"><span style="color:#005CC5">?A</span><span style="color:#24292E">.</span><span style="color:#6F42C1">upto</span><span style="color:#24292E">(</span><span style="color:#005CC5">?Z</span><span style="color:#24292E">){(b,),</span><span style="color:#D73A49">=</span><span style="color:#24292E">(</span><span style="color:#005CC5">?_</span><span style="color:#D73A49">+</span><span style="color:#24292E">s).</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/(?=(.</span><span style="color:#22863A;font-weight:bold">\B</span><span style="color:#032F62">.))/</span><span style="color:#24292E">).</span><span style="color:#6F42C1">tally</span><span style="color:#24292E">.</span><span style="color:#6F42C1">max_by</span><span style="color:#24292E">{</span><span style="color:#005CC5">_2</span><span style="color:#24292E">}</span></span> -<span class="line"><span style="color:#24292E">$*</span><span style="color:#D73A49"><<</span><span style="color:#24292E">it</span><span style="color:#D73A49">+</span><span style="color:#005CC5">?:</span><span style="color:#D73A49">+</span><span style="color:#24292E">b </span><span style="color:#D73A49">if</span><span style="color:#24292E"> s.</span><span style="color:#6F42C1">gsub!b</span><span style="color:#24292E">,it}</span></span> -<span class="line"><span style="color:#005CC5">puts</span><span style="color:#24292E">$*</span><span style="color:#D73A49">*</span><span style="color:#005CC5">?,</span><span style="color:#24292E">,s</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #0550ae">=</span><span style="color: #953800">gets</span> +<span style="color: #0a3069">?A</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">upto</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">?Z</span><span style="color: #24292f;background-color: #f6f8fa">){(</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,),</span><span style="color: #0550ae">=</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">?_</span><span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">scan</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #116329">/(?=(.\B.))/</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">tally</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">max_by</span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #24292f;background-color: #f6f8fa">_2</span><span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #0550ae">$*</span><span style="color: #0550ae"><<</span><span style="color: #953800">it</span><span style="color: #0550ae">+</span><span style="color: #0a3069">?:</span><span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">b</span> <span style="color: #cf222e">if</span> <span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">gsub!</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #24292f;background-color: #f6f8fa">it</span><span style="color: #24292f;background-color: #f6f8fa">}</span><span style="color: #0a3069"> +puts$**?,,s</span> +</code></pre> </div> <p> <code>s</code> の先頭に番兵 <code>_</code> を置くことで、bi-gram の出現頻度がすべて 1 になったとき、<code>b</code> へと代入される値が「<code>_</code> + (<code>s</code> の先頭の文字)」になる。これを <code>String#gsub!</code> で置き換えようとすると、そのような文字列は <code>s</code> 中にないので置換が発生しない。<code>String#gsub!</code> は置換が起きなかったとき <code>nil</code> を返すので、これを使って条件分岐ができる。<code>&&</code> だと優先度の関係から <code>String#gsub!</code> の括弧が省略できないが、後置 if なら省略できる。 @@ -203,10 +207,11 @@ <code>Kernel#gets</code> は、入力を特殊変数 <code>$_</code> へ代入する。これは Perl 由来の挙動で、Ruby にはいくつか <code>$_</code> を参照するものがある。これを使って変数 <code>s</code> を置き換えると次のようになる。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#005CC5">gets</span></span> -<span class="line"><span style="color:#005CC5">?A</span><span style="color:#24292E">.</span><span style="color:#6F42C1">upto</span><span style="color:#24292E">(</span><span style="color:#005CC5">?Z</span><span style="color:#24292E">){(b,),</span><span style="color:#D73A49">=</span><span style="color:#032F62">"_</span><span style="color:#24292E">#$_</span><span style="color:#032F62">"</span><span style="color:#24292E">.</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/(?=(.</span><span style="color:#22863A;font-weight:bold">\B</span><span style="color:#032F62">.))/</span><span style="color:#24292E">).</span><span style="color:#6F42C1">tally</span><span style="color:#24292E">.</span><span style="color:#6F42C1">max_by</span><span style="color:#24292E">{</span><span style="color:#005CC5">_2</span><span style="color:#24292E">}</span></span> -<span class="line"><span style="color:#24292E">$*</span><span style="color:#D73A49"><<</span><span style="color:#24292E">it</span><span style="color:#D73A49">+</span><span style="color:#005CC5">?:</span><span style="color:#D73A49">+</span><span style="color:#24292E">b </span><span style="color:#D73A49">if</span><span style="color:#24292E">$_.</span><span style="color:#6F42C1">gsub!b</span><span style="color:#24292E">,it}</span></span> -<span class="line"><span style="color:#005CC5">puts</span><span style="color:#24292E">$*</span><span style="color:#D73A49">*</span><span style="color:#005CC5">?,</span><span style="color:#24292E">,$_</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #953800">gets</span> +<span style="color: #0a3069">?A</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">upto</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">?Z</span><span style="color: #24292f;background-color: #f6f8fa">){(</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,),</span><span style="color: #0550ae">=</span><span style="color: #0a3069">"_</span><span style="color: #24292f">#$_</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">scan</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #116329">/(?=(.\B.))/</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">tally</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">max_by</span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #24292f;background-color: #f6f8fa">_2</span><span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #0550ae">$*</span><span style="color: #0550ae"><<</span><span style="color: #953800">it</span><span style="color: #0550ae">+</span><span style="color: #0a3069">?:</span><span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">b</span> <span style="color: #cf222e">if</span><span style="color: #0550ae">$_</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">gsub!</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #24292f;background-color: #f6f8fa">it</span><span style="color: #24292f;background-color: #f6f8fa">}</span><span style="color: #0a3069"> +puts$**?,,$_</span> +</code></pre> </div> <p> これで 1 byte 縮む。 @@ -218,9 +223,10 @@ 回答 C を眺めると、<code>b</code> への代入に文字を費やしすぎている。これを <code>String#gsub!</code> の第一引数に直接書いてはどうか。更に、直前のマッチしたパターンを指す特殊変数 <code>$&</code> を使えば、変数 <code>b</code> を排除できる。それがこちら。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#005CC5">gets</span></span> -<span class="line"><span style="color:#005CC5">?A</span><span style="color:#24292E">.</span><span style="color:#6F42C1">upto</span><span style="color:#24292E">(</span><span style="color:#005CC5">?Z</span><span style="color:#24292E">){$*</span><span style="color:#D73A49"><<</span><span style="color:#24292E">it</span><span style="color:#D73A49">+</span><span style="color:#005CC5">?:</span><span style="color:#D73A49">+</span><span style="color:#24292E">$&</span><span style="color:#D73A49">if</span><span style="color:#24292E">$_.</span><span style="color:#6F42C1">gsub!</span><span style="color:#032F62">"_</span><span style="color:#24292E">#$_</span><span style="color:#032F62">"</span><span style="color:#24292E">.</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/(?=(.</span><span style="color:#22863A;font-weight:bold">\B</span><span style="color:#032F62">.))/</span><span style="color:#24292E">).</span><span style="color:#6F42C1">tally</span><span style="color:#24292E">.</span><span style="color:#6F42C1">max_by</span><span style="color:#24292E">{</span><span style="color:#005CC5">_2</span><span style="color:#24292E">}[</span><span style="color:#005CC5">0</span><span style="color:#24292E">][</span><span style="color:#005CC5">0</span><span style="color:#24292E">],it}</span></span> -<span class="line"><span style="color:#005CC5">puts</span><span style="color:#24292E">$*</span><span style="color:#D73A49">*</span><span style="color:#005CC5">?,</span><span style="color:#24292E">,$_</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #953800">gets</span> +<span style="color: #0a3069">?A</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">upto</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">?Z</span><span style="color: #24292f;background-color: #f6f8fa">){</span><span style="color: #0550ae">$*</span><span style="color: #0550ae"><<</span><span style="color: #953800">it</span><span style="color: #0550ae">+</span><span style="color: #0a3069">?:</span><span style="color: #0550ae">+</span><span style="color: #0550ae">$&</span><span style="color: #cf222e">if</span><span style="color: #0550ae">$_</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">gsub!</span><span style="color: #0a3069">"_</span><span style="color: #24292f">#$_</span><span style="color: #0a3069">"</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">scan</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #116329">/(?=(.\B.))/</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">tally</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">max_by</span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #24292f;background-color: #f6f8fa">_2</span><span style="color: #24292f;background-color: #f6f8fa">}[</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">][</span><span style="color: #0550ae">0</span><span style="color: #24292f;background-color: #f6f8fa">],</span><span style="color: #24292f;background-color: #f6f8fa">it</span><span style="color: #24292f;background-color: #f6f8fa">}</span><span style="color: #0a3069"> +puts$**?,,$_</span> +</code></pre> </div> <p> これにより 2 bytes も一気に縮まった。 @@ -232,9 +238,10 @@ 回答 D を提出したことで tompng 氏のスコアを越え、氏のコードを閲覧できるようになった。そこから少し変更したものが、mame 氏と (変数名などの些事を除いて) 同じ以下のコードである。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#E36209">s</span><span style="color:#D73A49">=</span><span style="color:#005CC5">gets</span></span> -<span class="line"><span style="color:#005CC5">?A</span><span style="color:#24292E">.</span><span style="color:#6F42C1">upto</span><span style="color:#24292E">(</span><span style="color:#005CC5">?Z</span><span style="color:#24292E">){s.</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/(?=(.</span><span style="color:#22863A;font-weight:bold">\B</span><span style="color:#032F62">.))/</span><span style="color:#24292E">).</span><span style="color:#6F42C1">tally</span><span style="color:#24292E">.</span><span style="color:#6F42C1">max_by</span><span style="color:#24292E">{</span><span style="color:#005CC5">_2</span><span style="color:#24292E">}</span><span style="color:#D73A49">in</span><span style="color:#24292E">[b],1</span><span style="color:#6F42C1">or</span><span style="color:#24292E">($*</span><span style="color:#D73A49"><<</span><span style="color:#24292E">it</span><span style="color:#D73A49">+</span><span style="color:#005CC5">?:</span><span style="color:#D73A49">+</span><span style="color:#24292E">b;s.</span><span style="color:#6F42C1">gsub!b</span><span style="color:#24292E">,it)}</span></span> -<span class="line"><span style="color:#005CC5">puts</span><span style="color:#24292E">$*</span><span style="color:#D73A49">*</span><span style="color:#005CC5">?,</span><span style="color:#24292E">,s</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #0550ae">=</span><span style="color: #953800">gets</span> +<span style="color: #0a3069">?A</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">upto</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">?Z</span><span style="color: #24292f;background-color: #f6f8fa">){</span><span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">scan</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #116329">/(?=(.\B.))/</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">tally</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">max_by</span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #24292f;background-color: #f6f8fa">_2</span><span style="color: #24292f;background-color: #f6f8fa">}</span><span style="color: #cf222e">in</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">],</span><span style="color: #0550ae">1</span><span style="color: #0550ae">or</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$*</span><span style="color: #0550ae"><<</span><span style="color: #953800">it</span><span style="color: #0550ae">+</span><span style="color: #0a3069">?:</span><span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">gsub!</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #24292f;background-color: #f6f8fa">it</span><span style="color: #24292f;background-color: #f6f8fa">)}</span><span style="color: #0a3069"> +puts$**?,,s</span> +</code></pre> </div> <p> ここまでとは大きく異なる戦略で終了条件を判定している。使われているのはパターンマッチで、<code>in</code> がマッチの有無を <code>true</code> / <code>false</code> で返すことを利用している。<code>or</code> を用いて、最頻値の出現回数が 1 でないなら置換処理を継続する。 @@ -243,10 +250,11 @@ パターンマッチの利用については途中何度か検討したが、1 でないときに処理を実行するという方針で実装しようとしてしまい、上手く短縮できなかった。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D"># これは 106 byte</span></span> -<span class="line"><span style="color:#E36209">s</span><span style="color:#D73A49">=</span><span style="color:#005CC5">gets</span></span> -<span class="line"><span style="color:#005CC5">?A</span><span style="color:#24292E">.</span><span style="color:#6F42C1">upto</span><span style="color:#24292E">(</span><span style="color:#005CC5">?Z</span><span style="color:#24292E">){s.</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/(?=(.</span><span style="color:#22863A;font-weight:bold">\B</span><span style="color:#032F62">.))/</span><span style="color:#24292E">).</span><span style="color:#6F42C1">tally</span><span style="color:#24292E">.</span><span style="color:#6F42C1">max_by</span><span style="color:#24292E">{</span><span style="color:#005CC5">_2</span><span style="color:#24292E">}</span><span style="color:#D73A49">in</span><span style="color:#24292E">[b],</span><span style="color:#005CC5">2</span><span style="color:#24292E">..</span><span style="color:#6F42C1">and</span><span style="color:#24292E">($*</span><span style="color:#D73A49"><<</span><span style="color:#24292E">it</span><span style="color:#D73A49">+</span><span style="color:#005CC5">?:</span><span style="color:#D73A49">+</span><span style="color:#24292E">b;s.</span><span style="color:#6F42C1">gsub!b</span><span style="color:#24292E">,it)}</span></span> -<span class="line"><span style="color:#005CC5">puts</span><span style="color:#24292E">$*</span><span style="color:#D73A49">*</span><span style="color:#005CC5">?,</span><span style="color:#24292E">,s</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"># これは 106 byte</span> +<span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #0550ae">=</span><span style="color: #953800">gets</span> +<span style="color: #0a3069">?A</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">upto</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">?Z</span><span style="color: #24292f;background-color: #f6f8fa">){</span><span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">scan</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #116329">/(?=(.\B.))/</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">tally</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">max_by</span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #24292f;background-color: #f6f8fa">_2</span><span style="color: #24292f;background-color: #f6f8fa">}</span><span style="color: #cf222e">in</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">],</span><span style="color: #0550ae">2</span><span style="color: #0550ae">..</span><span style="color: #0550ae">and</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$*</span><span style="color: #0550ae"><<</span><span style="color: #953800">it</span><span style="color: #0550ae">+</span><span style="color: #0a3069">?:</span><span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #24292f;background-color: #f6f8fa">s</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">gsub!</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #24292f;background-color: #f6f8fa">it</span><span style="color: #24292f;background-color: #f6f8fa">)}</span><span style="color: #0a3069"> +puts$**?,,s</span> +</code></pre> </div> </section> <section id="section--hole-2--answer-f"> @@ -266,10 +274,11 @@ <code>ruby</code> で <code>-p</code> を付けると、以下のようなコードを書いたかのように動作する。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">while</span><span style="color:#005CC5"> gets</span></span> -<span class="line"><span style="color:#24292E"> ... </span><span style="color:#6A737D"># 記載したコードの処理</span></span> -<span class="line"><span style="color:#005CC5"> puts</span><span style="color:#24292E"> $_</span></span> -<span class="line"><span style="color:#D73A49">end</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">while</span> <span style="color: #953800">gets</span> + <span style="color: #0550ae">...</span> <span style="color: #6e7781"># 記載したコードの処理</span> + <span style="color: #953800">puts</span> <span style="color: #0550ae">$_</span> +<span style="color: #cf222e">end</span> +</code></pre> </div> <p> また、<code>Kernel#gsub</code> という <code>$_ = $_.gsub(...)</code> と同様の処理をおこなうメソッドが生えてくる。今回は <code>String#gsub!</code> も使うので、shebang の分を回収できれば短縮になりそうだ。 @@ -278,18 +287,20 @@ というわけで、実はこれまでも shebang での短縮は何度か試していた。しかし、いずれも 1 byte 増えたり変化しなかったりで成果を上げられずにいた。回答 E についても同様に、以下のようなコードを作っていた。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">#!ruby -p</span></span> -<span class="line"><span style="color:#005CC5">?A</span><span style="color:#24292E">.</span><span style="color:#6F42C1">upto</span><span style="color:#24292E">(</span><span style="color:#005CC5">?Z</span><span style="color:#24292E">){$_.</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/(?=(.</span><span style="color:#22863A;font-weight:bold">\B</span><span style="color:#032F62">.))/</span><span style="color:#24292E">).</span><span style="color:#6F42C1">tally</span><span style="color:#24292E">.</span><span style="color:#6F42C1">max_by</span><span style="color:#24292E">{</span><span style="color:#005CC5">_2</span><span style="color:#24292E">}</span><span style="color:#D73A49">in</span><span style="color:#24292E">[b],1</span><span style="color:#6F42C1">or</span><span style="color:#24292E">($*</span><span style="color:#D73A49"><<</span><span style="color:#24292E">it</span><span style="color:#D73A49">+</span><span style="color:#005CC5">?:</span><span style="color:#D73A49">+</span><span style="color:#24292E">b;</span><span style="color:#005CC5">gsub</span><span style="color:#24292E"> b,it)}</span></span> -<span class="line"><span style="color:#005CC5">puts</span><span style="color:#24292E">$*</span><span style="color:#D73A49">*</span><span style="color:#005CC5">?,</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781">#!ruby -p</span> +<span style="color: #0a3069">?A</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">upto</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">?Z</span><span style="color: #24292f;background-color: #f6f8fa">){</span><span style="color: #0550ae">$_</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">scan</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #116329">/(?=(.\B.))/</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">tally</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">max_by</span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #24292f;background-color: #f6f8fa">_2</span><span style="color: #24292f;background-color: #f6f8fa">}</span><span style="color: #cf222e">in</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">],</span><span style="color: #0550ae">1</span><span style="color: #0550ae">or</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0550ae">$*</span><span style="color: #0550ae"><<</span><span style="color: #953800">it</span><span style="color: #0550ae">+</span><span style="color: #0a3069">?:</span><span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">;</span><span style="color: #953800">gsub</span> <span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #24292f;background-color: #f6f8fa">it</span><span style="color: #24292f;background-color: #f6f8fa">)}</span><span style="color: #0a3069"> +puts$**?,</span> +</code></pre> </div> <p> しかしこれは 103 byte で縮められない。にっくきは <code>gsub</code> と <code>b</code> の間のスペースである。せっかく <code>s.gsub!</code> を <code>gsub</code> にしたのに、後ろが記号でなくなったことでスペースが生じている。といって、括弧を付けるのも上手くはいかない。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D"># これも同じく 103 byte</span></span> -<span class="line"><span style="color:#6A737D">#!ruby -p</span></span> -<span class="line"><span style="color:#005CC5">?A</span><span style="color:#24292E">.</span><span style="color:#6F42C1">upto</span><span style="color:#24292E">(</span><span style="color:#005CC5">?Z</span><span style="color:#24292E">){$_.</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/(?=(.</span><span style="color:#22863A;font-weight:bold">\B</span><span style="color:#032F62">.))/</span><span style="color:#24292E">).</span><span style="color:#6F42C1">tally</span><span style="color:#24292E">.</span><span style="color:#6F42C1">max_by</span><span style="color:#24292E">{</span><span style="color:#005CC5">_2</span><span style="color:#24292E">}</span><span style="color:#D73A49">in</span><span style="color:#24292E">[b],1or$*</span><span style="color:#D73A49"><<</span><span style="color:#24292E">it</span><span style="color:#D73A49">+</span><span style="color:#005CC5">?:</span><span style="color:#D73A49">+</span><span style="color:#24292E">b</span><span style="color:#D73A49">&&</span><span style="color:#005CC5">gsub</span><span style="color:#24292E">(b,it)}</span></span> -<span class="line"><span style="color:#005CC5">puts</span><span style="color:#24292E">$*</span><span style="color:#D73A49">*</span><span style="color:#005CC5">?,</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"># これも同じく 103 byte</span> +<span style="color: #6e7781">#!ruby -p</span> +<span style="color: #0a3069">?A</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">upto</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">?Z</span><span style="color: #24292f;background-color: #f6f8fa">){</span><span style="color: #0550ae">$_</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">scan</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #116329">/(?=(.\B.))/</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">tally</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">max_by</span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #24292f;background-color: #f6f8fa">_2</span><span style="color: #24292f;background-color: #f6f8fa">}</span><span style="color: #cf222e">in</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">],</span><span style="color: #0550ae">1</span><span style="color: #0550ae">or</span><span style="color: #0550ae">$*</span><span style="color: #0550ae"><<</span><span style="color: #953800">it</span><span style="color: #0550ae">+</span><span style="color: #0a3069">?:</span><span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #0550ae">&&</span><span style="color: #953800">gsub</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #24292f;background-color: #f6f8fa">it</span><span style="color: #24292f;background-color: #f6f8fa">)}</span><span style="color: #0a3069"> +puts$**?,</span> +</code></pre> </div> <p> 外側の括弧を移動させてくれば <code>gsub</code> と <code>b</code> の間のスペースを消せるが、<code>;</code> を <code>&&</code> にせねばならず失敗する。この問題を解決したのが最終回答の 102 byte コードである。 @@ -298,9 +309,10 @@ <section id="section--hole-2--answer-g"> <h3><a href="#section--hole-2--answer-g">最終回答 (102 byte)</a></h3> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">#!ruby -p</span></span> -<span class="line"><span style="color:#005CC5">?A</span><span style="color:#24292E">.</span><span style="color:#6F42C1">upto</span><span style="color:#24292E">(</span><span style="color:#005CC5">?Z</span><span style="color:#24292E">){$_.</span><span style="color:#6F42C1">scan</span><span style="color:#24292E">(</span><span style="color:#032F62">/(?=(.</span><span style="color:#22863A;font-weight:bold">\B</span><span style="color:#032F62">.))/</span><span style="color:#24292E">).</span><span style="color:#6F42C1">tally</span><span style="color:#24292E">.</span><span style="color:#6F42C1">max_by</span><span style="color:#24292E">{</span><span style="color:#005CC5">_2</span><span style="color:#24292E">}</span><span style="color:#D73A49">in</span><span style="color:#24292E">[b],1or$*</span><span style="color:#D73A49"><<</span><span style="color:#24292E">it</span><span style="color:#D73A49">+</span><span style="color:#005CC5">?:</span><span style="color:#D73A49">+</span><span style="color:#24292E">b</span><span style="color:#D73A49">%</span><span style="color:#005CC5">gsub</span><span style="color:#24292E">(b,it)}</span></span> -<span class="line"><span style="color:#005CC5">puts</span><span style="color:#24292E">$*</span><span style="color:#D73A49">*</span><span style="color:#005CC5">?,</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781">#!ruby -p</span> +<span style="color: #0a3069">?A</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">upto</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #0a3069">?Z</span><span style="color: #24292f;background-color: #f6f8fa">){</span><span style="color: #0550ae">$_</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">scan</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #116329">/(?=(.\B.))/</span><span style="color: #24292f;background-color: #f6f8fa">).</span><span style="color: #8250df">tally</span><span style="color: #24292f;background-color: #f6f8fa">.</span><span style="color: #8250df">max_by</span><span style="color: #24292f;background-color: #f6f8fa">{</span><span style="color: #24292f;background-color: #f6f8fa">_2</span><span style="color: #24292f;background-color: #f6f8fa">}</span><span style="color: #cf222e">in</span><span style="color: #24292f;background-color: #f6f8fa">[</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">],</span><span style="color: #0550ae">1</span><span style="color: #0550ae">or</span><span style="color: #0550ae">$*</span><span style="color: #0550ae"><<</span><span style="color: #953800">it</span><span style="color: #0550ae">+</span><span style="color: #0a3069">?:</span><span style="color: #0550ae">+</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #0550ae">%</span><span style="color: #953800">gsub</span><span style="color: #24292f;background-color: #f6f8fa">(</span><span style="color: #24292f;background-color: #f6f8fa">b</span><span style="color: #24292f;background-color: #f6f8fa">,</span><span style="color: #24292f;background-color: #f6f8fa">it</span><span style="color: #24292f;background-color: #f6f8fa">)}</span><span style="color: #0a3069"> +puts$**?,</span> +</code></pre> </div> <p> <code>String#%</code> は文字列のフォーマット処理をおこなう演算子だが、ここでは特にフォーマット目的で呼んでいるわけではない。ここで重要なのは、この演算子が特に副作用を持たず、どんな型でも右辺に取れることである。<code>b</code> の中身にフォーマット指定子はない (<code>%</code> などの記号が入力されないことが問題文から分かる) ので、誤って動作を壊してしまうおそれもない。 diff --git a/services/nuldoc/public/blog/posts/2025-12-06/archive-dynamic-site-with-wget/index.html b/services/nuldoc/public/blog/posts/2025-12-06/archive-dynamic-site-with-wget/index.html index f3c04fc0..27bf970e 100644 --- a/services/nuldoc/public/blog/posts/2025-12-06/archive-dynamic-site-with-wget/index.html +++ b/services/nuldoc/public/blog/posts/2025-12-06/archive-dynamic-site-with-wget/index.html @@ -101,41 +101,42 @@ 今回使用したスクリプトはこちら: <a class="url" href="https://github.com/nsfisis/phperkaigi-2024-albatross-archive/blob/cc837f6d2109555e2392016e8f6820fb5fd46dd6/archive.sh" rel="noreferrer" target="_blank">https://github.com/nsfisis/phperkaigi-2024-albatross-archive/blob/cc837f6d2109555e2392016e8f6820fb5fd46dd6/archive.sh</a> </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D"># 指定した URL からスタートしてリンクを辿りながら全ファイルをファイルに書き出す</span></span> -<span class="line"><span style="color:#6A737D">#</span></span> -<span class="line"><span style="color:#6A737D"># --mirror リンクを再帰的に辿ってダウンロードする</span></span> -<span class="line"><span style="color:#6A737D"># --page-requisites CSS や画像等も含めて HTML から参照されている全ファイルをダウンロードする</span></span> -<span class="line"><span style="color:#6A737D"># --convert-links リンクを相対リンクへ変換する</span></span> -<span class="line"><span style="color:#6A737D"># --adjust-extension URL に拡張子が無くてもいい感じに推測する</span></span> -<span class="line"><span style="color:#6A737D"># --no-parent 親ディレクトリは見に行かない</span></span> -<span class="line"><span style="color:#6A737D"># --no-wait=1 リクエスト間で 1 秒待機する</span></span> -<span class="line"><span style="color:#6A737D"># -P ./archive/ 指定したディレクトリに保存する</span></span> -<span class="line"><span style="color:#6F42C1">wget</span><span style="color:#005CC5"> \</span></span> -<span class="line"><span style="color:#005CC5"> --mirror</span><span style="color:#005CC5"> \</span></span> -<span class="line"><span style="color:#005CC5"> --page-requisites</span><span style="color:#005CC5"> \</span></span> -<span class="line"><span style="color:#005CC5"> --convert-links</span><span style="color:#005CC5"> \</span></span> -<span class="line"><span style="color:#005CC5"> --adjust-extension</span><span style="color:#005CC5"> \</span></span> -<span class="line"><span style="color:#005CC5"> --no-parent</span><span style="color:#005CC5"> \</span></span> -<span class="line"><span style="color:#005CC5"> --wait=1</span><span style="color:#005CC5"> \</span></span> -<span class="line"><span style="color:#005CC5"> -P</span><span style="color:#032F62"> ./archive/</span><span style="color:#005CC5"> \</span></span> -<span class="line"><span style="color:#032F62"> https://t.nil.ninja/phperkaigi/2024/golf/</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D"># ディレクトリ構造を調整する</span></span> -<span class="line"><span style="color:#6F42C1">mv</span><span style="color:#032F62"> ./archive/t.nil.ninja/phperkaigi/2024/golf/</span><span style="color:#005CC5">*</span><span style="color:#032F62"> ./archive</span></span> -<span class="line"><span style="color:#6F42C1">rmdir</span><span style="color:#032F62"> ./archive/t.nil.ninja/phperkaigi/2024/golf/</span></span> -<span class="line"><span style="color:#6F42C1">rmdir</span><span style="color:#032F62"> ./archive/t.nil.ninja/phperkaigi/2024/</span></span> -<span class="line"><span style="color:#6F42C1">rmdir</span><span style="color:#032F62"> ./archive/t.nil.ninja/phperkaigi/</span></span> -<span class="line"><span style="color:#6F42C1">rmdir</span><span style="color:#032F62"> ./archive/t.nil.ninja/</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6F42C1">mkdir</span><span style="color:#005CC5"> -p</span><span style="color:#032F62"> ./archive/api/quizzes/{1,2,3}</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D"># 動的な API エンドポイントを叩いて結果を JSON ファイルとして保存する</span></span> -<span class="line"><span style="color:#6F42C1">wget</span><span style="color:#005CC5"> -O</span><span style="color:#032F62"> ./archive/api/quizzes/1/chart.json</span><span style="color:#032F62"> https://t.nil.ninja/phperkaigi/2024/golf/api/quizzes/1/chart</span></span> -<span class="line"><span style="color:#6F42C1">wget</span><span style="color:#005CC5"> -O</span><span style="color:#032F62"> ./archive/api/quizzes/2/chart.json</span><span style="color:#032F62"> https://t.nil.ninja/phperkaigi/2024/golf/api/quizzes/2/chart</span></span> -<span class="line"><span style="color:#6F42C1">wget</span><span style="color:#005CC5"> -O</span><span style="color:#032F62"> ./archive/api/quizzes/3/chart.json</span><span style="color:#032F62"> https://t.nil.ninja/phperkaigi/2024/golf/api/quizzes/3/chart</span></span> -<span class="line"></span> -<span class="line"><span style="color:#6A737D"># 上記 API を叩いている箇所を、落としてきた静的ファイルを参照するように変更する</span></span> -<span class="line"><span style="color:#6F42C1">sed</span><span style="color:#005CC5"> -i</span><span style="color:#005CC5"> -e</span><span style="color:#032F62"> 's#/chart`#/chart.json`#'</span><span style="color:#032F62"> ./archive/assets/chart.js</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #6e7781"># 指定した URL からスタートしてリンクを辿りながら全ファイルをファイルに書き出す</span> +<span style="color: #6e7781">#</span> +<span style="color: #6e7781"># --mirror リンクを再帰的に辿ってダウンロードする</span> +<span style="color: #6e7781"># --page-requisites CSS や画像等も含めて HTML から参照されている全ファイルをダウンロードする</span> +<span style="color: #6e7781"># --convert-links リンクを相対リンクへ変換する</span> +<span style="color: #6e7781"># --adjust-extension URL に拡張子が無くてもいい感じに推測する</span> +<span style="color: #6e7781"># --no-parent 親ディレクトリは見に行かない</span> +<span style="color: #6e7781"># --no-wait=1 リクエスト間で 1 秒待機する</span> +<span style="color: #6e7781"># -P ./archive/ 指定したディレクトリに保存する</span> +wget <span style="color: #0a3069">\</span> + <span style="color: #116329">--mirror</span> <span style="color: #0a3069">\</span> + <span style="color: #116329">--page-requisites</span> <span style="color: #0a3069">\</span> + <span style="color: #116329">--convert-links</span> <span style="color: #0a3069">\</span> + <span style="color: #116329">--adjust-extension</span> <span style="color: #0a3069">\</span> + <span style="color: #116329">--no-parent</span> <span style="color: #0a3069">\</span> + <span style="color: #116329">--wait</span><span style="color: #0550ae">=</span>1 <span style="color: #0a3069">\</span> + <span style="color: #116329">-P</span> ./archive/ <span style="color: #0a3069">\</span> + https://t.nil.ninja/phperkaigi/2024/golf/ + +<span style="color: #6e7781"># ディレクトリ構造を調整する</span> +<span style="color: #953800">mv</span> ./archive/t.nil.ninja/phperkaigi/2024/golf/<span style="color: #cf222e">*</span> ./archive +<span style="color: #953800">rmdir</span> ./archive/t.nil.ninja/phperkaigi/2024/golf/ +<span style="color: #953800">rmdir</span> ./archive/t.nil.ninja/phperkaigi/2024/ +<span style="color: #953800">rmdir</span> ./archive/t.nil.ninja/phperkaigi/ +<span style="color: #953800">rmdir</span> ./archive/t.nil.ninja/ + +<span style="color: #953800">mkdir</span> <span style="color: #116329">-p</span> ./archive/api/quizzes/<span style="color: #0550ae">{</span>1,2,3<span style="color: #0550ae">}</span> + +<span style="color: #6e7781"># 動的な API エンドポイントを叩いて結果を JSON ファイルとして保存する</span> +wget <span style="color: #116329">-O</span> ./archive/api/quizzes/1/chart.json https://t.nil.ninja/phperkaigi/2024/golf/api/quizzes/1/chart +wget <span style="color: #116329">-O</span> ./archive/api/quizzes/2/chart.json https://t.nil.ninja/phperkaigi/2024/golf/api/quizzes/2/chart +wget <span style="color: #116329">-O</span> ./archive/api/quizzes/3/chart.json https://t.nil.ninja/phperkaigi/2024/golf/api/quizzes/3/chart + +<span style="color: #6e7781"># 上記 API を叩いている箇所を、落としてきた静的ファイルを参照するように変更する</span> +<span style="color: #953800">sed</span> <span style="color: #116329">-i</span> <span style="color: #116329">-e</span> <span style="color: #0a3069">'s#/chart`#/chart.json`#'</span> ./archive/assets/chart.js +</code></pre> </div> <p> このように wget に適切なオプションを渡すことで、指定したページから遷移可能なページを再帰的に辿っていき、サイト内の全ページをファイルへ落とすことができる。今回のサイトにはページ遷移では辿り着けないページがあったが (管理画面など)、運用が停止している今そういったページはアーカイブしなくてもよい。 @@ -144,16 +145,17 @@ あとはこのファイルを適当にサーブしてやればよい。 </p> <div class="codeblock"> - <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">server</span><span style="color:#24292E"> {</span></span> -<span class="line"><span style="color:#D73A49"> listen </span><span style="color:#005CC5">80</span><span style="color:#005CC5"> default</span><span style="color:#24292E">;</span></span> -<span class="line"><span style="color:#D73A49"> listen </span><span style="color:#24292E">[::]:80;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49"> charset </span><span style="color:#24292E">UTF-8;</span></span> -<span class="line"></span> -<span class="line"><span style="color:#D73A49"> location</span><span style="color:#6F42C1"> /phperkaigi/2024/golf/ </span><span style="color:#24292E">{</span></span> -<span class="line"><span style="color:#D73A49"> alias </span><span style="color:#24292E">/archive/;</span></span> -<span class="line"><span style="color:#24292E"> }</span></span> -<span class="line"><span style="color:#24292E">}</span></span></code></pre> + <pre class="highlight" style="background-color:#f5f5f5"><code><span style="color: #cf222e">server</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">listen</span> <span style="color: #0550ae">80</span> <span style="color: #0a3069">default</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #cf222e">listen</span> <span style="color: #0a3069">[::]:80</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + + <span style="color: #cf222e">charset</span> <span style="color: #0a3069">UTF-8</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + + <span style="color: #cf222e">location</span> <span style="color: #24292f;background-color: #f6f8fa">/phperkaigi/2024/golf/</span> <span style="color: #24292f;background-color: #f6f8fa">{</span> + <span style="color: #cf222e">alias</span> <span style="color: #24292f;background-color: #f6f8fa">/archive/</span><span style="color: #24292f;background-color: #f6f8fa">;</span> + <span style="color: #24292f;background-color: #f6f8fa">}</span> +<span style="color: #24292f;background-color: #f6f8fa">}</span> +</code></pre> </div> </section> <section id="section--outro"> |
