aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2022-11-19 14:23:32 +0900
committernsfisis <nsfisis@gmail.com>2022-11-19 14:25:59 +0900
commit6209453817da9922f28bac1bb1522c6d380630ab (patch)
tree19e0699e751af387d549d6720ca215c8065b3c0c
parent0cafa073914b5e0b162b735a7f8445fb2aa8a604 (diff)
downloadblog.nsfisis.dev-6209453817da9922f28bac1bb1522c6d380630ab.tar.gz
blog.nsfisis.dev-6209453817da9922f28bac1bb1522c6d380630ab.tar.zst
blog.nsfisis.dev-6209453817da9922f28bac1bb1522c6d380630ab.zip
Hugo to Asciidoctor
-rw-r--r--.gitignore1
-rw-r--r--Gemfile7
-rw-r--r--Gemfile.lock17
-rw-r--r--LICENSE (renamed from themes/mypaper/LICENSE)0
-rw-r--r--Makefile6
-rw-r--r--NOTE.md60
-rw-r--r--README.md31
-rw-r--r--archetypes/default.md11
-rw-r--r--config.toml15
-rw-r--r--content/404.html32
-rw-r--r--content/_index.md4
-rw-r--r--content/posts/2021-03-05/my-first-post.adoc13
-rw-r--r--content/posts/2021-03-05/my-first-post.md12
-rw-r--r--content/posts/2021-03-30/phperkaigi-2021.adoc532
-rw-r--r--content/posts/2021-03-30/phperkaigi-2021.md554
-rw-r--r--content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.adoc106
-rw-r--r--content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.md95
-rw-r--r--content/posts/2021-10-02/python-unbound-local-error.adoc (renamed from content/posts/2021-10-02/python-unbound-local-error.md)57
-rw-r--r--content/posts/2021-10-02/ruby-detect-running-implementation.adoc72
-rw-r--r--content/posts/2021-10-02/ruby-detect-running-implementation.md64
-rw-r--r--content/posts/2021-10-02/ruby-then-keyword-and-case-in.adoc226
-rw-r--r--content/posts/2021-10-02/ruby-then-keyword-and-case-in.md205
-rw-r--r--content/posts/2021-10-02/rust-where-are-primitive-types-from.adoc201
-rw-r--r--content/posts/2021-10-02/rust-where-are-primitive-types-from.md175
-rw-r--r--content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.adoc120
-rw-r--r--content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.md106
-rw-r--r--content/posts/2021-10-02/vim-swap-order-of-selected-lines.adoc165
-rw-r--r--content/posts/2021-10-02/vim-swap-order-of-selected-lines.md145
-rw-r--r--content/posts/2022-04-09/phperkaigi-2022-tokens.adoc (renamed from content/posts/2022-04-09/phperkaigi-2022-tokens.md)244
-rw-r--r--content/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal.adoc (renamed from content/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal.md)83
-rw-r--r--content/posts/2022-05-01/phperkaigi-2022.adoc130
-rw-r--r--content/posts/2022-05-01/phperkaigi-2022.md114
-rw-r--r--content/posts/2022-08-27/php-conference-okinawa-code-golf.adoc91
-rw-r--r--content/posts/2022-08-27/php-conference-okinawa-code-golf.md79
-rw-r--r--content/posts/2022-08-31/support-for-communty-is-employee-benefits.adoc46
-rw-r--r--content/posts/2022-08-31/support-for-communty-is-employee-benefits.md47
-rw-r--r--content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.adoc624
-rw-r--r--content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.md577
-rw-r--r--content/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1.adoc157
-rw-r--r--content/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1.md143
-rw-r--r--content/posts/2022-10-28/setup-server-for-this-site.adoc248
-rw-r--r--content/posts/2022-10-28/setup-server-for-this-site.md230
-rw-r--r--docker-compose.local.yml2
-rw-r--r--docker-compose.yml2
-rw-r--r--docs/404.html42
-rw-r--r--docs/an-old-hope.min.css1
-rw-r--r--docs/feed.xml2348
-rw-r--r--docs/highlight.min.js1122
-rw-r--r--docs/index.html170
-rw-r--r--docs/page/1/index.html10
-rw-r--r--docs/page/2/index.html131
-rw-r--r--docs/posts/2021-03-05/my-first-post/index.html58
-rw-r--r--docs/posts/2021-03-30/phperkaigi-2021/index.html532
-rw-r--r--docs/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html129
-rw-r--r--docs/posts/2021-10-02/python-unbound-local-error/index.html97
-rw-r--r--docs/posts/2021-10-02/ruby-detect-running-implementation/index.html125
-rw-r--r--docs/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html195
-rw-r--r--docs/posts/2021-10-02/rust-where-are-primitive-types-from/index.html182
-rw-r--r--docs/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html132
-rw-r--r--docs/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html148
-rw-r--r--docs/posts/2022-04-09/phperkaigi-2022-tokens/index.html375
-rw-r--r--docs/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html102
-rw-r--r--docs/posts/2022-05-01/phperkaigi-2022/index.html133
-rw-r--r--docs/posts/2022-08-27/php-conference-okinawa-code-golf/index.html102
-rw-r--r--docs/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html74
-rw-r--r--docs/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html520
-rw-r--r--docs/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html132
-rw-r--r--docs/posts/2022-10-28/setup-server-for-this-site/index.html163
-rw-r--r--docs/posts/feed.xml2348
-rw-r--r--docs/posts/index.html172
-rw-r--r--docs/posts/page/1/index.html10
-rw-r--r--docs/posts/page/2/index.html133
-rw-r--r--docs/sitemap.xml107
-rw-r--r--docs/tags/conference/feed.xml944
-rw-r--r--docs/tags/conference/index.html92
-rw-r--r--docs/tags/conference/page/1/index.html10
-rw-r--r--docs/tags/cpp/feed.xml89
-rw-r--r--docs/tags/cpp/index.html56
-rw-r--r--docs/tags/cpp/page/1/index.html10
-rw-r--r--docs/tags/cpp17/feed.xml89
-rw-r--r--docs/tags/cpp17/index.html56
-rw-r--r--docs/tags/cpp17/page/1/index.html10
-rw-r--r--docs/tags/feed.xml137
-rw-r--r--docs/tags/index.html44
-rw-r--r--docs/tags/my-programs/feed.xml62
-rw-r--r--docs/tags/my-programs/index.html56
-rw-r--r--docs/tags/my-programs/page/1/index.html10
-rw-r--r--docs/tags/note-to-self/feed.xml123
-rw-r--r--docs/tags/note-to-self/index.html57
-rw-r--r--docs/tags/note-to-self/page/1/index.html10
-rw-r--r--docs/tags/page/1/index.html10
-rw-r--r--docs/tags/php/feed.xml1493
-rw-r--r--docs/tags/php/index.html117
-rw-r--r--docs/tags/php/page/1/index.html10
-rw-r--r--docs/tags/phpcon/feed.xml61
-rw-r--r--docs/tags/phpcon/index.html56
-rw-r--r--docs/tags/phpcon/page/1/index.html10
-rw-r--r--docs/tags/phperkaigi/feed.xml974
-rw-r--r--docs/tags/phperkaigi/index.html93
-rw-r--r--docs/tags/phperkaigi/page/1/index.html10
-rw-r--r--docs/tags/python/feed.xml57
-rw-r--r--docs/tags/python/index.html56
-rw-r--r--docs/tags/python/page/1/index.html10
-rw-r--r--docs/tags/python3/feed.xml57
-rw-r--r--docs/tags/python3/index.html56
-rw-r--r--docs/tags/python3/page/1/index.html10
-rw-r--r--docs/tags/ruby/feed.xml230
-rw-r--r--docs/tags/ruby/index.html68
-rw-r--r--docs/tags/ruby/page/1/index.html10
-rw-r--r--docs/tags/ruby3/feed.xml155
-rw-r--r--docs/tags/ruby3/index.html56
-rw-r--r--docs/tags/ruby3/page/1/index.html10
-rw-r--r--docs/tags/rust/feed.xml143
-rw-r--r--docs/tags/rust/index.html56
-rw-r--r--docs/tags/rust/page/1/index.html10
-rw-r--r--docs/tags/vim/feed.xml191
-rw-r--r--docs/tags/vim/index.html68
-rw-r--r--docs/tags/vim/page/1/index.html10
-rw-r--r--lib/command.rb152
-rw-r--r--lib/extensions/document_title_processor.rb15
-rw-r--r--lib/extensions/lang_attribute_processor.rb9
-rw-r--r--lib/extensions/revision_history_processor.rb27
-rw-r--r--lib/extensions/section_id_validator.rb29
-rw-r--r--lib/extensions/source_id_processor.rb12
-rw-r--r--lib/extensions/source_id_validator.rb32
-rw-r--r--lib/extensions/tags_processor.rb20
-rw-r--r--lib/parser.rb54
-rw-r--r--lib/revision.rb3
-rw-r--r--lib/tag.rb26
-rw-r--r--nginx.conf3
-rw-r--r--nuldoc.rb24
-rw-r--r--public/custom.css (renamed from docs/custom.css)15
-rw-r--r--public/favicon.svg (renamed from docs/favicon.svg)0
-rw-r--r--public/hl.css214
-rw-r--r--public/posts/2021-03-05/my-first-post/index.html71
-rw-r--r--public/posts/2021-03-30/phperkaigi-2021/index.html1195
-rw-r--r--public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html209
-rw-r--r--public/posts/2021-10-02/python-unbound-local-error/index.html131
-rw-r--r--public/posts/2021-10-02/ruby-detect-running-implementation/index.html167
-rw-r--r--public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html392
-rw-r--r--public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html317
-rw-r--r--public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html299
-rw-r--r--public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html366
-rw-r--r--public/posts/2022-04-09/phperkaigi-2022-tokens/index.html876
-rw-r--r--public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html222
-rw-r--r--public/posts/2022-05-01/phperkaigi-2022/index.html324
-rw-r--r--public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html276
-rw-r--r--public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html140
-rw-r--r--public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html929
-rw-r--r--public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html291
-rw-r--r--public/posts/2022-10-28/setup-server-for-this-site/index.html630
-rw-r--r--public/posts/index.html315
-rw-r--r--public/style.css (renamed from docs/style.css)3
-rw-r--r--public/tags/conference/index.html107
-rw-r--r--public/tags/cpp/index.html59
-rw-r--r--public/tags/cpp17/index.html59
-rw-r--r--public/tags/note-to-self/index.html59
-rw-r--r--public/tags/php/index.html139
-rw-r--r--public/tags/phpcon/index.html59
-rw-r--r--public/tags/phperkaigi/index.html107
-rw-r--r--public/tags/python/index.html59
-rw-r--r--public/tags/python3/index.html59
-rw-r--r--public/tags/ruby/index.html75
-rw-r--r--public/tags/ruby3/index.html59
-rw-r--r--public/tags/rust/index.html59
-rw-r--r--public/tags/vim/index.html75
-rw-r--r--static/custom.css (renamed from themes/mypaper/static/custom.css)15
-rw-r--r--static/favicon.svg (renamed from themes/mypaper/static/favicon.svg)0
-rw-r--r--static/hl.css214
-rw-r--r--static/style.css (renamed from themes/mypaper/static/style.css)3
-rw-r--r--templates/document.html.erb69
-rw-r--r--templates/feed.xml.erb27
-rw-r--r--templates/posts_list.html.erb59
-rw-r--r--templates/section.html.erb19
-rw-r--r--templates/sitemap.xml.erb11
-rw-r--r--templates/tag.html.erb59
-rw-r--r--themes/mypaper/README.md1
-rw-r--r--themes/mypaper/i18n/ja.yaml5
-rw-r--r--themes/mypaper/layouts/404.html3
-rw-r--r--themes/mypaper/layouts/_default/list.html45
-rw-r--r--themes/mypaper/layouts/_default/rss.xml39
-rw-r--r--themes/mypaper/layouts/_default/single.html30
-rw-r--r--themes/mypaper/layouts/partials/footer.html12
-rw-r--r--themes/mypaper/layouts/partials/header.html54
-rw-r--r--themes/mypaper/layouts/shortcodes/collapse.html12
-rw-r--r--themes/mypaper/layouts/sitemap.xml12
-rw-r--r--themes/mypaper/static/an-old-hope.min.css1
-rw-r--r--themes/mypaper/static/highlight.min.js1122
-rw-r--r--themes/mypaper/theme.toml25
189 files changed, 12296 insertions, 19888 deletions
diff --git a/.gitignore b/.gitignore
index 2a8645f..e69de29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +0,0 @@
-.hugo_build.lock
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..1784943
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+source "https://rubygems.org"
+
+gem "asciidoctor"
+gem "concurrent-ruby"
+gem "rouge"
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..af3d42c
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,17 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ asciidoctor (2.0.18)
+ concurrent-ruby (1.1.10)
+ rouge (4.0.0)
+
+PLATFORMS
+ x86_64-darwin-19
+
+DEPENDENCIES
+ asciidoctor
+ concurrent-ruby
+ rouge
+
+BUNDLED WITH
+ 2.3.11
diff --git a/themes/mypaper/LICENSE b/LICENSE
index 415f6f2..415f6f2 100644
--- a/themes/mypaper/LICENSE
+++ b/LICENSE
diff --git a/Makefile b/Makefile
index befc090..50ef3db 100644
--- a/Makefile
+++ b/Makefile
@@ -20,10 +20,14 @@ serve:
clean:
docker-compose down
+.PHONY: gen
+gen:
+ @ruby nuldoc.rb
+
.PHONY: local_up
local_up:
docker-compose -f docker-compose.local.yml up -d
- echo http://localhost:8080
+ @echo http://localhost:8080
.PHONY: local_down
local_down:
diff --git a/NOTE.md b/NOTE.md
index 727cc36..801c62c 100644
--- a/NOTE.md
+++ b/NOTE.md
@@ -5,18 +5,70 @@
Generate the site.
```
-$ hugo -d docs
+$ make gen
```
Create a new post.
```
-$ hugo new posts/$(date +'%Y-%m-%d')/[TITLE].md
+$ mkdir -p content/posts/$(date +'%Y-%m-%d')
+$ touch content/posts/$(date +'%Y-%m-%d')/[TITLE].md
```
+## TODO
-Update `highlight.min.js`.
+* [x] Add /posts/ page
+* [x] Stylesheets
+* [x] Syntax highlight
+* [ ] Add / page
+* [ ] Add /about/ page
+* [ ] Add navigation bar
+ * Site name
+ * Posts
+ * Tags
+ * About
+* [ ] Paging
+ * /posts/
+ * /posts/?p=1 => /posts/
+* [ ] RSS feed
+ * /posts/feed.xml
+ * /tags/<tag>/feed.xml
+* [ ] Redirect
+ * [x] Old URLs
+ * [ ] /posts/?p=1
+ => /posts/
+ => /posts/_page/1.html
+ * [ ] /posts/?p=2
+ => /posts/_page/2.html
+ * [ ] /
+ => /posts/
+* [ ] Sitemap
+ * https://www.sitemaps.org/protocol.html
+ * https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap?hl=ja
+
+
+## Structure
```
-$ curl -sL https://raw.githubusercontent.com/highlightjs/cdn-release/main/build/highlight.min.js >| themes/mypaper/static/highlight.min.js
+public
+├── sitemap.xml
+├── 404.html
+├── posts
+│   ├── 2021-03-05
+│   │   └── my-first-post
+│   │   └── index.html
+│   ├── feed.xml
+│   ├── _page
+│   │   ├── 1.html
+│   │   └── 2.html
+└── tags
+ ├── index.html
+ └── vim
+ ├── feed.xml
+ └── index.html
```
+
+
+## References
+
+* https://docs.asciidoctor.org/asciidoctor/latest/
diff --git a/README.md b/README.md
index a98a85b..80ee313 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,32 @@
Site: https://blog.nsfisis.dev
+
+
+
+# License
+
+`static/style.css` is a modified version of [paper](https://github.com/nanxiaobei/hugo-paper/) theme.
+
+```
+MIT License
+
+Copyright (c) 2020 nanxiaobei
+Copyright (c) 2022 nsfisis
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+```
diff --git a/archetypes/default.md b/archetypes/default.md
deleted file mode 100644
index 1ab8ddf..0000000
--- a/archetypes/default.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-title: "{{ replace .Name "-" " " | title }}"
-date: {{ .Date }}
-draft: true
-tags: ["TODO"]
-summary: |
- TODO
-changelog:
- {{ .Date | time.Format "2006-01-02" }}: 公開
----
-
diff --git a/config.toml b/config.toml
deleted file mode 100644
index 3aaf028..0000000
--- a/config.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-baseURL = "https://blog.nsfisis.dev"
-languageCode = "ja-JP"
-hasCJKLanguage = true
-timeZone = "Asia/Tokyo"
-title = "REPL: Rest-Eat-Program Loop"
-theme = "mypaper"
-
-[author]
-name = "nsfisis"
-
-[taxonomies]
-tag = "tags"
-
-[outputFormats.rss]
-baseName = "feed"
diff --git a/content/404.html b/content/404.html
new file mode 100644
index 0000000..c0fb882
--- /dev/null
+++ b/content/404.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>Page Not Found | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article>
+ <div class="not-found">
+ 404
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/content/_index.md b/content/_index.md
deleted file mode 100644
index fb1e7ba..0000000
--- a/content/_index.md
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: ""
-date: 2021-03-31T01:36:49+09:00
----
diff --git a/content/posts/2021-03-05/my-first-post.adoc b/content/posts/2021-03-05/my-first-post.adoc
new file mode 100644
index 0000000..664dd5c
--- /dev/null
+++ b/content/posts/2021-03-05/my-first-post.adoc
@@ -0,0 +1,13 @@
+= My First Post
+:description: これはテスト投稿です。これはテスト投稿です。これはテスト投稿です。
+:revision-1: 2021-03-05 公開
+
+== Test
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
+veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
+velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
+occaecat cupidatat non proident, sunt in culpa qui officia deserunt
+mollit anim id est laborum.
diff --git a/content/posts/2021-03-05/my-first-post.md b/content/posts/2021-03-05/my-first-post.md
deleted file mode 100644
index 217db9f..0000000
--- a/content/posts/2021-03-05/my-first-post.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-title: "My First Post"
-date: 2021-03-05T23:38:21+09:00
-summary: |
- これはテスト投稿です。これはテスト投稿です。これはテスト投稿です。
-changelog:
- 2021-03-05: 公開
----
-
-# Test
-
-Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
diff --git a/content/posts/2021-03-30/phperkaigi-2021.adoc b/content/posts/2021-03-30/phperkaigi-2021.adoc
new file mode 100644
index 0000000..e843e83
--- /dev/null
+++ b/content/posts/2021-03-30/phperkaigi-2021.adoc
@@ -0,0 +1,532 @@
+= PHPerKaigi 2021
+:tags: conference, php, phperkaigi
+:description: 2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。
+:revision-1: 2021-03-30 公開
+
+== PHPerKaigi 2021 参加レポ
+
+2021-03-26 から 2021-03-28
+にかけて開催された、 https://phperkaigi.jp/2021/[PHPerKaigi 2021]
+に一般参加者として参加した。
+弊社 https://www.dgcircus.com/[デジタルサーカス株式会社]
+(今年1月から勤務)
+はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。
+
+このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。
+
+発表はトラック A、B に分かれていたのだが、今回はすべて A
+トラックを視聴している (切り替えるのが面倒だっただけ)。
+
+=== 凡例
+
+____
+発表・スライドのメモ (引用ではない)
+____
+
+感想など
+
+=== Day 0 前夜祭 (2021/03/27)
+
+==== 17:30 [A]
+
+PHP で AWS Lambda
+
+____
+Rails のプロジェクトを PHPer のメンバのみでメンテ →他のメンバもわかる
+PHP にリプレースを検討
+
+* サーバレス
+* サーバ・インフラの管理が不要
+* アプリケーションコードの知識だけで保守可能
+
+ゼロベースで作れる案件が (Railsの件とは別に)
+あるため、そちらで試験的に導入?
+
+AWSの学習 AWS のドキュメント DevelopersIO
+
+AWS Lambda のカスタムランタイムで PHP を動かす
+
+サーバのセットアップや維持管理を気にしなくて良い サーバーレスで PHP
+を動かすツールがすでにある サーバーレス構築はすんなり
+
+今は Laravel がルーティングしている Laravel Livewire を Lambda
+に載せられないか? デプロイ方法は? バッチ処理は? (Lambda は
+15分の制限)
+
+Lambda でコンテナイメージがサポートされるように
+
+抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる
+____
+
+AWS Lambda のような Function as a Service
+はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に
+web サービスを作る具体的なイメージがまだ見えない (注: すべて for me
+として書いている)。
+
+PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。
+
+勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP +
+Laravel などでは動かなさそう)
+だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。
+
+==== 18:10 [A]
+
+大規模サイトの SEO
+
+____
+大規模サイト (100万ページ以上) Google の基準
+
+クロールバジェットを意識したSEO
+
+大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト
+(10,000以上) でコンテンツが目まぐるしく変更される
+これを満たさないなら、クロールバジェットを考えなくてもいい
+
+サーチコンソール 「カバレッジ」の「除外」
+多すぎるのは問題→クロールバジェットを浪費している
+
+* クエリの順番を決める
+* 空の値のルールを決めておく
+* リダイレクトすればインデックスはうまくいく
+* リンクが存在する限りクロールはされる
+
+リニューアル前のURL
+
+インデックスは移行される
+リンクのURLが存在する限り、別のURLとしてクロールされる
+リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い
+リニューアルで無視されるようになったパラメータも注意
+
+robotes.txt で拒否しているのにクロールされる 一時的に拒否を外して 404 や
+301 を読ませる 内部リンクを確認する JS でのリンクに書き換え
+
+クエリパラメータからURLのパスに `/tokyo?area=HOGE` → `/tokyo/HOGE`
+
+URL 設計だいじ
+____
+
+SEO (Search Engine Optimization)
+は大して知らないので新鮮な話が多かった。その分語れることも少ない……。
+
+==== 18:50 [A]
+
+____
+知覚可能 操作可能 理解可能 堅牢 ちゃんとしたHTMLを書く
+(閉じタグ・入れ子構造など)
+
+* 標準の HTML を適切に使う
+* WAI-ARIA
+* キーボードフレンドリー
+* マシンフレンドリー
+* SEOフレンドリー
+
+button タグ →キーボード h1 タグ →スクリーンリーダー・クローラ a タグ
+
+WAI-ARIA HTML では表現できないセマンティクスを追加する
+
+* ロール
+** 何をするのか?
+** ユーザーアクションによって変化しない
+* プロパティ
+** 関連づけられたデータ
+* ステート
+** 現在の状態
+
+まずは標準の HTML 要素で解決する 何でもかんでも WAI-ARIA
+を使えばいいというものではない
+
+マウスホバーでツールチップが出てくるが、キーボード操作では出てこない
+
+VoiceOver
+
+全ての属性を使う必要はない
+あくまでアクセシビリティを上げるための方法の一つにすぎない
+____
+
+つい最近 WAI-ARIA
+についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが)
+いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。
+
+==== 19:30 [A]
+
+PHP で FUSE
+
+個人的に楽しみだった発表。
+
+____
+VFS (virtual filesystem) vs 具体的なファイルシステム
+
+最適な実装方法は状況により異なる
+
+アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS
+
+カーネルのプログラムを作るのは難しい
+* 権限がデカすぎる
+* システム全体がクラッシュ
+* セキュリティリスク
+* 開発サイクルを回しづらい
+* ネイティブコードにコンパイルされる言語である必要がある
+
+Filesystem in USEr space (FUSE)
+
+* 特定の C の関数を呼ぶことで filesystem が作れる
+* FFI を持つ言語なら FUSE が使える
+
+SSHFS / s3fs / Docker Desktop
+
+Linux 以外でも使える
+
+* dokany (on Windows)
+* osxfuse
+
+VFS: システムコールが呼ばれると、ファイルシステムによってコール FUSE:
+カーネル空間からユーザ空間へ通信
+
+高レベルなラッパで型をつける
+
+PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)
+
+* grep できる
+* sed できる
+* 編集できる
+____
+
+期待通りの興味深い発表だった。FUSE
+自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。
+この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ
+(ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。
+
+=== Day 1 (2021/03/27)
+
+==== 10:50 [A]
+
+ATDD
+
+____
+* ユーザーストーリー
+* ユニットテスト
+* CI/CD
+
+ユーザストーリーの受け入れ条件が曖昧になりがち
+デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている
+
+Q2の強化 アジャイルテストの4象限
+
+技術面/ビジネス面
+開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)
+
+* Q1: 技術面 & チーム支援
+** TDD
+** ユニットテストなど
+* Q2: ビジネス面 & チーム支援
+** ATDD
+** ビジネス面の受け入れテストで駆動する
+
+Agile Alliance ユーザストーリーのスキルレベルを高める
+
+テストピラミッド
+
+* UI Tests
+* Service Tests
+* Unit Tests
+* 異なる粒度のテストを書く
+* 高レベルになるほど、持つべきテストは少なくなる
+** ピラミッド型になる
+
+高レベルテストが多すぎる→アイスクリームコーン アンチパターン
+
+ATDD (Acceptance TDD) API経由・UI経由での高レベルテスト E2E test
+
+ストーリ受け入れテスト
+
+入れ子のフィードバックループ ATDD(外側) と TDD(内側)
+
+外部品質・内部品質
+
+バーティカルスライスのデリバリー
+
+* cucumber
+* gauge
+* behat
+
+ユビキタス言語 手動テストもspecに書く 自動化は可能だがコスパが悪い
+失敗することがわかっているテスト(レッドテスト)はCIから外す
+失敗時の原因究明が難しい 饒舌なエラーメッセージ 状況のスナップショット
+
+Continuous Testing
+____
+
+User Acceptance Test (UAT)
+くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。
+高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。
+
+==== 11:50 [A]
+
+型解析を用いたリファクタリング
+
+型のある世界で生きてきた身として大いに楽しみにしていた発表。
+
+____
+* PHPStan
+* Phan
+* Psalm
+
+autoload も認識できる bootstrapFiles
+
+編集箇所と利用箇所を CI でチェック ルールレベルを徐々に引き上げていく
+警告が多すぎると見落としてしまう・無視されやすくなる
+
+型がついていないことによるエラーが多い
+
+型よりも詳細な検査 `Util_Assert::min`
+
+SQL を静的解析 placeholder の型付け
+
+警告レベルを低いレベルから導入 タイプヒントを積極的に書いていく PHPStan
+の拡張を追加する
+____
+
+昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。
+今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で
+Ruby の typeprof には注目している。
+
+==== 12:30 [A]
+
+昼食をとっていた。事前に何か食料を買っておくべきだった。
+
+==== 13:10 [A]
+
+Documentation as Code
+
+この発表も以前から非常に楽しみにしていた。
+
+____
+開発開始までのオーバーヘッド 新規にチームにジョイン
+担当範囲外の機能を理解 オンボーディングのコスト
+
+PHPerKaigi 2020 で発表あり
+
+継続的にシステムの理解を助けるドキュメント
+
+継続的ドキュメンテーション システムとドキュメントの乖離
+
+書いてあることが間違っている・足りない * 徐々にずれていく *
+システムの更新タイミングとドキュメントの更新タイミングに差がある
+
+システムとドキュメントは対応関係がある * 間違ったドキュメント *
+存在しないドキュメント
+
+システムとドキュメントの乖離を定量化する 継続的に
+システムの更新に近いタイミングで ドキュメントを更新し続ける
+
+Documentation as Code
+
+コードと同じツールでドキュメントを書く * issue tracker * vcs * plain
+text markup * automation
+
+開発者 システム ドキュメント 構造化データ ソフトウェア
+
+システムから構造化データを抽出する PHPDoc OpenAPI
+
+ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する
+
+ビューの単位でドキュメントに
+
+スタックトレースからのドキュメント生成
+____
+
+ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な
+(乖離しない)
+情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。
+
+==== 14:10 [A]
+
+cookie による session 管理
+
+全体的に基本的な話だったので特に触れない。Cookie
+やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。
+
+==== 14:50 [A]
+
+PHP のエラーと例外
+
+____
+エラー PHPエンジンがエラーを通知する 例外 プログラムが投げる
+
+PHP7-8とエラー
+
+PHPエンジンのエラーの一部が に変換されるようになった → try-catch
+で捕捉できる
+
+は例外とは異なる
+
+PHP8 でエラーレベルの引き上げ
+
+* 捕捉すべきもの
+** recoverable
+* 捕捉すべきでないもの
+** unrecoverable
+** 開発時に対処できるもの
+
+例外 * 捕捉して事後処理 * 捕捉せず(or 捕捉した上で)さらに上に是非を問う
+
+開発段階で例外を把握し、ハンドリングを考えておく
+
+と
+
+はキャッチすべきでない
+
+* {blank}
++
+** 本番で起きてはいけない
+* {blank}
++
+** 本番で起きてはいけない →生じないのだから捕捉もしない
+* {blank}
++
+** 起こるかもしれないので本番環境でも考慮する
+
+捕捉して対応するのではなく、未然に防ぐ
+
+独自例外を使う を投げてしまうと、 catch ()せざるを得ない →catch
+範囲が広すぎる
+
+SPL の例外を使う
+
+例外翻訳
+上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する
+下位レイヤの知識に依存させない
+
+@throws 捕捉してほしい例外を書き連ねておく
+
+呼び出しもとに負わせたい責任
+____
+
+PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で
+PHP を書き始めてから 4ヶ月ほどになる)。
+
+個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell
+などのエラーを「値として」扱う言語だと思っている。try-catch
+は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は
+C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる
+(C のそれはまともな型付けではない。念のため)。
+
+PHP
+のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。
+
+==== 15:30 [A]
+
+Laravel のメール認証
+
+Laravel
+の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。
+
+==== 16:10 [A]
+
+gRPC
+
+____
+Unary RPCs Server streaming RPCs Client streaming RPCs Bidirectional
+streaming RPCs
+
+Protobuf
+
+実装とAPIが乖離しにくい 自動生成 複数言語でも相互に使える
+
+マイクロサービスのサービス通信 スマホアプリ ゲームサーバ
+
+PHP では?
+
+PHP ではストリーミングが難しい リクエストごとにプロセスが使い捨て
+
+PHP ではgRPCのクライアントしか対応していない
+
+gRPC-Web ブラウザで扱うためのJSライブラリ+プロトコル
+
+HTTP/1.1 でも使える Unary RPC と Server streaming RPC のみ
+
+Envoy Nginx などで相互に gRPC と gRPC-Web で変換
+
+Amp イベント駆動な並行処理のフレームワーク
+
+HTTP/2 対応
+
+C#のgRPC-Webが楽
+____
+
+(発表の中でもまさに同じことをおっしゃっていたが) PHP
+以外の方が向いているだろう、というのが第一の感想である。gRPC
+はそれ自体というよりも Protobuf
+というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。
+
+==== 16:50 [A]
+
+アーキテクチャテスト
+
+____
+Independent Core Layer Pattern
+
+開発初期のアーキテクチャが崩れる
+アーキテクチャ観点のコードレビューができない
+
+どこにクラスを置けばよいか? ドキュメントがない
+
+アーキテクチャ設計に関する知識が属人化・暗黙知化
+
+ガイドライン * 最初にルールを決めるのは簡単 *
+ルール通り作り始めるのも簡単 *
+→維持するのが難しい、人が決めたものゆえ壊れやすい
+
+PHP の特性 * クラスは public * 可視性の制御が public / protected /
+private のみ * 依存関係の制御が困難
+
+アーキテクチャテスト
+クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する
+
+* deptrac
+* phpat
+
+Independent Core Layer Pattern
+
+アーキテクチャテストの失敗 * 実装誤り * or アーキテクチャが適切でない *
+開発の過程でフィードバックしていく
+
+モジュラーモノリス→マイクロサービスへ
+____
+
+=== Day 2 (2021/03/28)
+
+冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。
+
+残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。
+
+=== 全体の感想
+
+Day 2
+にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも
+(特に初参加者として) 嬉しいポイントだった。
+
+今回、雑談/登壇者への質問等向けに Discord
+サーバもあったのだが、こちらは参加こそしたものの ROM
+のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord
+表示に
+1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった
+(さらにいうと Zoom
+でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。
+
+1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord
+しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。
+まあ初カンファレンスだし、とお茶を濁しておこう。
+
+さて、カンファレンスで一つ気になったことがある。それは、Discord
+という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord
+の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord
+があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。
+
+'''''
+
+最後になりましたが、毎年の PHPerKaigi
+開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました!
+(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)
+
+ではまた来年。
diff --git a/content/posts/2021-03-30/phperkaigi-2021.md b/content/posts/2021-03-30/phperkaigi-2021.md
deleted file mode 100644
index 8d76a36..0000000
--- a/content/posts/2021-03-30/phperkaigi-2021.md
+++ /dev/null
@@ -1,554 +0,0 @@
----
-title: "PHPerKaigi 2021"
-date: 2021-03-30T23:22:40+09:00
-tags: ["conference", "php", "phperkaigi"]
-summary: |
- 2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。
-changelog:
- 2021-03-30: 公開
----
-
-# PHPerKaigi 2021 参加レポ
-
-2021-03-26 から 2021-03-28 にかけて開催された、[PHPerKaigi 2021](https://phperkaigi.jp/2021/) に一般参加者として参加した。
-弊社[デジタルサーカス株式会社](https://www.dgcircus.com/) (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。
-
-このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。
-
-発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。
-
-
-## 凡例
-
-> 発表・スライドのメモ (引用ではない)
-
-感想など
-
-
-## Day 0 前夜祭 (2021/03/27)
-
-### 17:30 [A]
-
-PHP で AWS Lambda
-
-> Rails のプロジェクトを PHPer のメンバのみでメンテ
-> →他のメンバもわかる PHP にリプレースを検討
->
-> サーバレス
-> * サーバ・インフラの管理が不要
-> * アプリケーションコードの知識だけで保守可能
->
-> ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入?
->
-> AWSの学習
-> AWS のドキュメント
-> DevelopersIO
->
-> AWS Lambda のカスタムランタイムで PHP を動かす
->
-> サーバのセットアップや維持管理を気にしなくて良い
-> サーバーレスで PHP を動かすツールがすでにある
-> サーバーレス構築はすんなり
->
-> 今は Laravel がルーティングしている
-> Laravel Livewire を Lambda に載せられないか?
-> デプロイ方法は?
-> バッチ処理は? (Lambda は 15分の制限)
->
-> Lambda でコンテナイメージがサポートされるように
->
-> 抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる
-
-AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。
-
-PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。
-
-勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。
-
-
-
-### 18:10 [A]
-
-大規模サイトの SEO
-
-> 大規模サイト (100万ページ以上)
-> Google の基準
->
-> クロールバジェットを意識したSEO
->
-> 大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される
-> これを満たさないなら、クロールバジェットを考えなくてもいい
->
-> サーチコンソール
-> 「カバレッジ」の「除外」
-> 多すぎるのは問題→クロールバジェットを浪費している
->
-> * クエリの順番を決める
-> * 空の値のルールを決めておく
-> * リダイレクトすればインデックスはうまくいく
-> * リンクが存在する限りクロールはされる
->
-> リニューアル前のURL
->
-> インデックスは移行される
-> リンクのURLが存在する限り、別のURLとしてクロールされる
-> リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い
-> リニューアルで無視されるようになったパラメータも注意
->
-> robotes.txt で拒否しているのにクロールされる
-> 一時的に拒否を外して 404 や 301 を読ませる
-> 内部リンクを確認する
-> JS でのリンクに書き換え
->
-> クエリパラメータからURLのパスに
-> `/tokyo?area=HOGE` → `/tokyo/HOGE`
->
-> URL 設計だいじ
-
-SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。
-
-
-### 18:50 [A]
-
-> 知覚可能
-> 操作可能
-> 理解可能
-> 堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など)
->
-> * 標準の HTML を適切に使う
-> * WAI-ARIA
->
-> * キーボードフレンドリー
-> * マシンフレンドリー
-> * SEOフレンドリー
->
-> button タグ
-> →キーボード
-> h1 タグ
-> →スクリーンリーダー・クローラ
-> a タグ
->
-> WAI-ARIA
-> HTML では表現できないセマンティクスを追加する
->
-> * ロール
-> * 何をするのか?
-> * ユーザーアクションによって変化しない
-> * プロパティ
-> * 関連づけられたデータ
-> * ステート
-> * 現在の状態
->
-> まずは標準の HTML 要素で解決する
-> 何でもかんでも WAI-ARIA を使えばいいというものではない
->
-> マウスホバーでツールチップが出てくるが、キーボード操作では出てこない
->
-> VoiceOver
->
-> 全ての属性を使う必要はない
-> あくまでアクセシビリティを上げるための方法の一つにすぎない
-
-つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。
-
-
-### 19:30 [A]
-
-PHP で FUSE
-
-個人的に楽しみだった発表。
-
-> VFS (virtual filesystem) vs 具体的なファイルシステム
->
-> 最適な実装方法は状況により異なる
->
-> アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS
->
-> カーネルのプログラムを作るのは難しい
-> * 権限がデカすぎる
-> * システム全体がクラッシュ
-> * セキュリティリスク
-> * 開発サイクルを回しづらい
-> * ネイティブコードにコンパイルされる言語である必要がある
->
-> Filesystem in USEr space (FUSE)
-> * 特定の C の関数を呼ぶことで filesystem が作れる
-> * FFI を持つ言語なら FUSE が使える
->
-> SSHFS / s3fs / Docker Desktop
->
-> Linux 以外でも使える
-> * dokany (on Windows)
-> * osxfuse
->
-> VFS: システムコールが呼ばれると、ファイルシステムによってコール
-> FUSE: カーネル空間からユーザ空間へ通信
->
-> 高レベルなラッパで型をつける
->
-> PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)
->
-> * grep できる
-> * sed できる
-> * 編集できる
-
-期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。
-この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。
-
-
-
-## Day 1 (2021/03/27)
-
-### 10:50 [A]
-
-ATDD
-
-> * ユーザーストーリー
-> * ユニットテスト
-> * CI/CD
->
-> ユーザストーリーの受け入れ条件が曖昧になりがち
-> デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている
->
-> Q2の強化
-> アジャイルテストの4象限
->
-> 技術面/ビジネス面
-> 開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)
->
-> * Q1: 技術面 & チーム支援
-> * TDD
-> * ユニットテストなど
-> * Q2: ビジネス面 & チーム支援
-> * ATDD
-> * ビジネス面の受け入れテストで駆動する
->
-> Agile Alliance
-> ユーザストーリーのスキルレベルを高める
->
-> テストピラミッド
->
-> * UI Tests
-> * Service Tests
-> * Unit Tests
->
-> * 異なる粒度のテストを書く
-> * 高レベルになるほど、持つべきテストは少なくなる
-> * ピラミッド型になる
->
-> 高レベルテストが多すぎる→アイスクリームコーン アンチパターン
->
-> ATDD (Acceptance TDD)
-> API経由・UI経由での高レベルテスト E2E test
->
-> ストーリ受け入れテスト
->
-> 入れ子のフィードバックループ
-> ATDD(外側) と TDD(内側)
->
-> 外部品質・内部品質
->
-> バーティカルスライスのデリバリー
->
-> * cucumber
-> * gauge
-> * behat
->
-> ユビキタス言語
-> 手動テストもspecに書く
-> 自動化は可能だがコスパが悪い
-> 失敗することがわかっているテスト(レッドテスト)はCIから外す
-> 失敗時の原因究明が難しい
-> 饒舌なエラーメッセージ
-> 状況のスナップショット
->
-> Continuous Testing
-
-User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。
-高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。
-
-
-### 11:50 [A]
-
-型解析を用いたリファクタリング
-
-型のある世界で生きてきた身として大いに楽しみにしていた発表。
-
-> * PHPStan
-> * Phan
-> * Psalm
->
-> autoload も認識できる
-> bootstrapFiles
->
-> 編集箇所と利用箇所を CI でチェック
-> ルールレベルを徐々に引き上げていく
-> 警告が多すぎると見落としてしまう・無視されやすくなる
->
-> 型がついていないことによるエラーが多い
->
-> 型よりも詳細な検査 `Util_Assert::min`
->
-> SQL を静的解析
-> placeholder の型付け
->
-> 警告レベルを低いレベルから導入
-> タイプヒントを積極的に書いていく
-> PHPStan の拡張を追加する
-
-昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。
-今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。
-
-
-### 12:30 [A]
-
-昼食をとっていた。事前に何か食料を買っておくべきだった。
-
-
-### 13:10 [A]
-
-Documentation as Code
-
-この発表も以前から非常に楽しみにしていた。
-
-> 開発開始までのオーバーヘッド
-> 新規にチームにジョイン
-> 担当範囲外の機能を理解
-> オンボーディングのコスト
->
-> PHPerKaigi 2020 で発表あり
->
-> 継続的にシステムの理解を助けるドキュメント
->
-> 継続的ドキュメンテーション
-> システムとドキュメントの乖離
->
-> 書いてあることが間違っている・足りない
-> * 徐々にずれていく
-> * システムの更新タイミングとドキュメントの更新タイミングに差がある
->
-> システムとドキュメントは対応関係がある
-> * 間違ったドキュメント
-> * 存在しないドキュメント
->
-> システムとドキュメントの乖離を定量化する
-> 継続的に
-> システムの更新に近いタイミングで ドキュメントを更新し続ける
->
-> Documentation as Code
->
-> コードと同じツールでドキュメントを書く
-> * issue tracker
-> * vcs
-> * plain text markup
-> * automation
->
-> 開発者
-> システム
-> ドキュメント
-> 構造化データ
-> ソフトウェア
->
-> システムから構造化データを抽出する
-> PHPDoc
-> OpenAPI
->
-> ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する
->
-> ビューの単位でドキュメントに
->
-> スタックトレースからのドキュメント生成
-
-ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。
-
-
-
-### 14:10 [A]
-
-cookie による session 管理
-
-全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。
-
-
-
-### 14:50 [A]
-
-PHP のエラーと例外
-
-> エラー PHPエンジンがエラーを通知する
-> 例外 プログラムが投げる
->
-> PHP7-8とエラー
->
-> PHPエンジンのエラーの一部が \Error に変換されるようになった
-> → try-catch で捕捉できる
->
-> \Error は例外とは異なる
->
-> PHP8 でエラーレベルの引き上げ
->
-> * 捕捉すべきもの
-> * recoverable
-> * 捕捉すべきでないもの
-> * unrecoverable
-> * 開発時に対処できるもの
->
-> 例外
-> * 捕捉して事後処理
-> * 捕捉せず(or 捕捉した上で)さらに上に是非を問う
->
-> 開発段階で例外を把握し、ハンドリングを考えておく
->
-> \Throwable \Exception と \Error
->
-> \Error はキャッチすべきでない
->
-> * \Error
-> * 本番で起きてはいけない
-> * \LogicException
-> * 本番で起きてはいけない
-> →生じないのだから捕捉もしない
->
-> * \RuntimeException
-> * 起こるかもしれないので本番環境でも考慮する
->
-> 捕捉して対応するのではなく、未然に防ぐ
->
-> 独自例外を使う
-> \Exception を投げてしまうと、
-> catch (\Exception)せざるを得ない
-> →catch 範囲が広すぎる
->
-> SPL の例外を使う
->
-> 例外翻訳
-> 上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する
-> 下位レイヤの知識に依存させない
->
-> @throws
-> 捕捉してほしい例外を書き連ねておく
->
-> 呼び出しもとに負わせたい責任
-
-PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。
-
-個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。
-
-PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。
-
-
-### 15:30 [A]
-
-Laravel のメール認証
-
-Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。
-
-
-### 16:10 [A]
-
-gRPC
-
-> Unary RPCs
-> Server streaming RPCs
-> Client streaming RPCs
-> Bidirectional streaming RPCs
->
-> Protobuf
->
-> 実装とAPIが乖離しにくい
-> 自動生成
-> 複数言語でも相互に使える
->
-> マイクロサービスのサービス通信
-> スマホアプリ
-> ゲームサーバ
->
-> PHP では?
->
-> PHP ではストリーミングが難しい
-> リクエストごとにプロセスが使い捨て
->
-> PHP ではgRPCのクライアントしか対応していない
->
-> gRPC-Web
-> ブラウザで扱うためのJSライブラリ+プロトコル
->
-> HTTP/1.1 でも使える
-> Unary RPC と Server streaming RPC のみ
->
-> Envoy
-> Nginx などで相互に gRPC と gRPC-Web で変換
->
-> Amp
-> イベント駆動な並行処理のフレームワーク
->
-> HTTP/2 対応
->
-> C#のgRPC-Webが楽
-
-(発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。
-
-### 16:50 [A]
-
-アーキテクチャテスト
-
-> Independent Core Layer Pattern
->
-> 開発初期のアーキテクチャが崩れる
-> アーキテクチャ観点のコードレビューができない
->
-> どこにクラスを置けばよいか?
-> ドキュメントがない
->
-> アーキテクチャ設計に関する知識が属人化・暗黙知化
->
-> ガイドライン
-> * 最初にルールを決めるのは簡単
-> * ルール通り作り始めるのも簡単
-> * →維持するのが難しい、人が決めたものゆえ壊れやすい
->
-> PHP の特性
-> * クラスは public
-> * 可視性の制御が public / protected / private のみ
-> * 依存関係の制御が困難
->
-> アーキテクチャテスト
-> クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する
->
-> * deptrac
-> * phpat
->
-> Independent Core Layer Pattern
->
-> アーキテクチャテストの失敗
-> * 実装誤り
-> * or アーキテクチャが適切でない
-> * 開発の過程でフィードバックしていく
->
-> モジュラーモノリス→マイクロサービスへ
-
-
-## Day 2 (2021/03/28)
-
-冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。
-
-残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。
-
-
-## 全体の感想
-
-Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。
-
-今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。
-
-1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。
-まあ初カンファレンスだし、とお茶を濁しておこう。
-
-さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。
-
--------
-
-最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました!
-(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)
-
-ではまた来年。
diff --git a/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.adoc b/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.adoc
new file mode 100644
index 0000000..afa0f3f
--- /dev/null
+++ b/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.adoc
@@ -0,0 +1,106 @@
+= [C++] 属性構文の属性名にはキーワードが使える
+:tags: cpp, cpp17
+:description: C++ の属性構文の属性名には、キーワードが使える。ネタ記事。
+:revision-1: 2021-10-02 Qiita から移植
+
+この記事は Qiita から移植してきたものです。 元 URL:
+https://qiita.com/nsfisis/items/94090937bcf860cfa93b
+
+'''''
+
+タイトル落ち。まずはこのコードを見て欲しい。
+
+[source,cpp]
+----
+#include <iostream>
+
+[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]]
+[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]]
+[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]]
+[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]]
+[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]]
+[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]]
+[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]]
+[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]]
+[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]]
+[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]]
+[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]]
+[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]]
+[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]]
+// [[using]]
+int main() {
+ std::cout << "Hello, World!" << std::endl;
+}
+----
+
+____
+コンパイラのバージョン $ 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
+
+コンパイルコマンド (C++17指定) $ clang++ –std=c++17 hoge.cpp
+____
+
+この記事から得られるものはこれ以上ないので以下は蛇足になる。
+
+別件で cppreference.com の
+https://en.cppreference.com/w/cpp/language/identifiers[identifier
+のページ] を読んでいた時、次の文が目に止まった。
+
+____
+* 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)
+____
+
+キーワードでも属性として指定する場合は非キーワードとして使えるらしい。
+実際にやってみる。
+
+同サイトの https://en.cppreference.com/w/cpp/keyword[keywords のページ]
+から一覧を拝借し、上のコードが出来上がった (C++17
+においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown
+attribute `〇〇' ignored)
+がコンパイラから出力されるが、コンパイルできる。
+
+上のコードでは `[[using]]` をコメントアウトしているが、これは `using`
+キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。
+
+[source,cpp]
+----
+// using の例
+[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文
+----
+
+C++17 の仕様も見てみる (正確には標準化前のドラフト)。
+
+引用元: https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4
+
+____
+If a keyword or an alternative token that satisfies the syntactic
+requirements of an identifier is contained in an attribute-token, it is
+considered an identifier.
+____
+
+「`identifier` の構文上の要件を満たすキーワードまたは代替トークンが
+`attribute-token` に含まれている場合、`identifier`
+とみなされる」とある。どうやら間違いないようだ。
+
+ところで、代替トークン (alternative token) とは `and` (`&`) や `bitor`
+(`|`) などのことだが、`identifier`
+の構文上の要件を満たさないような代替トークンなどあるのか?
+疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい
+(参考:
+https://timsong-cpp.github.io/cppwp/n4659/lex.digraph[同ドラフト])
+
+* `<%` → `{`
+* `%>` → `}`
+* `<:` → `[`
+* `:>` → `]`
+* `%:` → `#`
+* `%:%:` → `##`
+
+「`identifier`
+の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。
+
+調べた感想: 字句解析器か構文解析器が辛そう
diff --git a/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.md b/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.md
deleted file mode 100644
index 87202cb..0000000
--- a/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.md
+++ /dev/null
@@ -1,95 +0,0 @@
----
-title: "[C++] 属性構文の属性名にはキーワードが使える [[void]] [[for]]"
-date: 2021-10-02T09:38:30+09:00
-tags: ["cpp", "cpp17"]
-summary: |
- C++ の属性構文の属性名には、キーワードが使える。ネタ記事。
-changelog:
- 2021-10-02: Qiita から移植
----
-
-
-この記事は Qiita から移植してきたものです。
-元 URL: https://qiita.com/nsfisis/items/94090937bcf860cfa93b
-
-
------------------------------------
-
-
-タイトル落ち。まずはこのコードを見て欲しい。
-
-```cpp
-#include <iostream>
-
-[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]]
-[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]]
-[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]]
-[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]]
-[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]]
-[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]]
-[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]]
-[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]]
-[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]]
-[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]]
-[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]]
-[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]]
-[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]]
-// [[using]]
-int main() {
- std::cout << "Hello, World!" << std::endl;
-}
-```
-
-> コンパイラのバージョン
-> $ 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
->
-> コンパイルコマンド (C++17指定)
-> $ 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)
-
-キーワードでも属性として指定する場合は非キーワードとして使えるらしい。
-実際にやってみる。
-
-同サイトの [keywords のページ] (https://en.cppreference.com/w/cpp/keyword) から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。
-大量の警告 (unknown attribute '〇〇' ignored) がコンパイラから出力されるが、コンパイルできる。
-
-上のコードでは `[[using]]` をコメントアウトしているが、これは `using` キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。
-
-```cpp
-// using の例
-[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文
-```
-
-C++17 の仕様も見てみる (正確には標準化前のドラフト)。
-
-引用元: https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4
-
-> If a keyword or an alternative token that satisfies the syntactic requirements of an identifier is contained in an attribute-token, it is considered an identifier.
-
-「`identifier` の構文上の要件を満たすキーワードまたは代替トークンが `attribute-token` に含まれている場合、`identifier` とみなされる」とある。どうやら間違いないようだ。
-
-ところで、代替トークン (alternative token) とは `and` (`&`) や `bitor` (`|`) などのことだが、`identifier` の構文上の要件を満たさないような代替トークンなどあるのか?
-疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい (参考: [同ドラフト](https://timsong-cpp.github.io/cppwp/n4659/lex.digraph))
-
-- `<%` → `{`
-- `%>` → `}`
-- `<:` → `[`
-- `:>` → `]`
-- `%:` → `#`
-- `%:%:` → `##`
-
-「`identifier` の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。
-
-
-調べた感想: 字句解析器か構文解析器が辛そう
-
diff --git a/content/posts/2021-10-02/python-unbound-local-error.md b/content/posts/2021-10-02/python-unbound-local-error.adoc
index 6e1b871..f68ae4d 100644
--- a/content/posts/2021-10-02/python-unbound-local-error.md
+++ b/content/posts/2021-10-02/python-unbound-local-error.adoc
@@ -1,26 +1,19 @@
----
-title: "[Python] クロージャとUnboundLocalError: local variable 'x' referenced before assignment"
-date: 2021-10-02T09:32:37+09:00
-tags: ["python", "python3"]
-summary: |
- Python における UnboundLocalError の理由と対処法。
-changelog:
- 2021-10-02: Qiita から移植
----
+= [Python] クロージャとUnboundLocalError: local variable 'x' referenced before assignment
+:tags: python, python3
+:description: Python における UnboundLocalError の理由と対処法。
+:revision-1: 2021-10-02 Qiita から移植
-この記事は Qiita から移植してきたものです。
-元 URL: https://qiita.com/nsfisis/items/5d733703afcb35bbf399
-
-
------------------------------------
+この記事は Qiita から移植してきたものです。 元 URL:
+https://qiita.com/nsfisis/items/5d733703afcb35bbf399
+'''''
本記事は Python 3.7.6 の動作結果を元にして書かれている。
-
Python でクロージャを作ろうと、次のようなコードを書いた。
-```python
+[source,python]
+----
def f():
x = 0
def g():
@@ -28,17 +21,23 @@ def f():
g()
f()
-```
+----
-関数 `g` から 関数 `f` のスコープ内で定義された変数 `x` を参照し、それに 1 を足そうとしている。
-これを実行すると `x += 1` の箇所でエラーが発生する。
+関数 `g` から 関数 `f` のスコープ内で定義された変数 `x` を参照し、それに
+1 を足そうとしている。 これを実行すると `x += 1`
+の箇所でエラーが発生する。
-> UnboundLocalError: local variable 'x' referenced before assignment
+____
+UnboundLocalError: local variable `x' referenced before assignment
+____
-local変数 `x` が代入前に参照された、とある。これは、`f` の `x` を参照するのではなく、新しく別の変数を `g` 内に作ってしまっているため。
-前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。`var` を変数宣言のための構文として擬似的に利用している。
+local変数 `x` が代入前に参照された、とある。これは、`f` の `x`
+を参照するのではなく、新しく別の変数を `g` 内に作ってしまっているため。
+前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。`var`
+を変数宣言のための構文として擬似的に利用している。
-```python
+[source,python]
+----
# 注: var は正しい Python の文法ではない。上記参照のこと
def f():
var x # f の local変数 'x' を宣言
@@ -49,19 +48,19 @@ def f():
x += 1 # x に 1 を加算 (x = x + 1 の糖衣構文)
# 加算する前の値を参照しようとするが、まだ代入されていないためエラー
g()
-```
+----
当初の意図を表現するには、次のように書けばよい。
-```python
+[source,python]
+----
def f():
x = 0
def g():
nonlocal x ## (*)
x += 1
g()
-```
-
-`(*)` のように、`nonlocal` を追加する。これにより一つ外側のスコープ (`g` の一つ外側 = `f`) で定義されている `x` を探しに行くようになる。
-
+----
+`(*)` のように、`nonlocal` を追加する。これにより一つ外側のスコープ (`g`
+の一つ外側 = `f`) で定義されている `x` を探しに行くようになる。
diff --git a/content/posts/2021-10-02/ruby-detect-running-implementation.adoc b/content/posts/2021-10-02/ruby-detect-running-implementation.adoc
new file mode 100644
index 0000000..1434891
--- /dev/null
+++ b/content/posts/2021-10-02/ruby-detect-running-implementation.adoc
@@ -0,0 +1,72 @@
+= [Ruby] 自身を実行している処理系の種類を判定する
+:tags: ruby
+:description: Ruby には複数の実装があるが、自身を実行している処理系の種類を \
+ スクリプト上からどのように判定すればよいだろうか。
+:revision-1: 2021-10-02 Qiita から移植
+
+この記事は Qiita から移植してきたものです。 元 URL:
+https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791
+
+'''''
+
+Ruby
+という言語には複数の実装があるが、それらをスクリプト上からどのようにして
+programmatically に見分ければよいだろうか。
+
+`Object` クラスに定義されている `RUBY_ENGINE`
+という定数がこの用途に使える。
+
+参考:
+https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html[Object::RUBY_ENGINE]
+
+上記ページの例から引用する:
+
+[source,shell-session]
+----
+$ ruby-1.9.1 -ve 'p RUBY_ENGINE'
+ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux]
+"ruby"
+$ jruby -ve 'p RUBY_ENGINE'
+jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
+"jruby"
+----
+
+それぞれの処理系がどのような値を返すかだが、stack overflow
+に良い質問と回答があった。
+
+https://stackoverflow.com/a/9894232[What values for RUBY_ENGINE
+correspond to which Ruby implementations?] より引用:
+
+____
+[cols="^,<",options="header",]
+|===
+|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
+|===
+____
+
+なお、この質問・回答は
+2014年になされたものであり、値は変わっている可能性がある。MRI (aka
+CRuby) については執筆時現在 (2020/12/8) も `'ruby'`
+が返ってくることを確認済み。
+
+この表にない主要な処理系として、https://mruby.org[mruby] は `'mruby'`
+を返す。
+
+https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35[mruby
+該当部分のソース] より引用:
+
+[source,c]
+----
+/*
+ * Ruby engine.
+ */
+#define MRUBY_RUBY_ENGINE "mruby"
+----
diff --git a/content/posts/2021-10-02/ruby-detect-running-implementation.md b/content/posts/2021-10-02/ruby-detect-running-implementation.md
deleted file mode 100644
index 16b918d..0000000
--- a/content/posts/2021-10-02/ruby-detect-running-implementation.md
+++ /dev/null
@@ -1,64 +0,0 @@
----
-title: "[Ruby] 自身を実行している処理系の種類を判定する"
-date: 2021-10-02T09:37:50+09:00
-tags: ["ruby"]
-summary: |
- Ruby には複数の実装があるが、自身を実行している処理系の種類をスクリプト上からどのように判定すればよいだろうか。
-changelog:
- 2021-10-02: Qiita から移植
----
-
-この記事は Qiita から移植してきたものです。
-元 URL: https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791
-
-
------------------------------------
-
-
-
-Ruby という言語には複数の実装があるが、それらをスクリプト上からどのようにして programmatically に見分ければよいだろうか。
-
-`Object` クラスに定義されている `RUBY_ENGINE` という定数がこの用途に使える。
-
-参考: [Object::RUBY_ENGINE](https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html)
-
-上記ページの例から引用する:
-
-```shell-session
-$ ruby-1.9.1 -ve 'p RUBY_ENGINE'
-ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux]
-"ruby"
-$ jruby -ve 'p RUBY_ENGINE'
-jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
-"jruby"
-```
-
-それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。
-
-[What values for RUBY_ENGINE correspond to which Ruby implementations?](https://stackoverflow.com/a/9894232) より引用:
-
-> | 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 |
-
-
-なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も `'ruby'` が返ってくることを確認済み。
-
-この表にない主要な処理系として、[mruby](https://mruby.org) は `'mruby'` を返す。
-
-[mruby 該当部分のソース](https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35) より引用:
-
-```c
-/*
- * Ruby engine.
- */
-#define MRUBY_RUBY_ENGINE "mruby"
-```
-
diff --git a/content/posts/2021-10-02/ruby-then-keyword-and-case-in.adoc b/content/posts/2021-10-02/ruby-then-keyword-and-case-in.adoc
new file mode 100644
index 0000000..94fcf48
--- /dev/null
+++ b/content/posts/2021-10-02/ruby-then-keyword-and-case-in.adoc
@@ -0,0 +1,226 @@
+= [Ruby] then キーワードと case in
+:tags: ruby, ruby3
+:description: Ruby 3.0 で追加される case in 構文と、then キーワードについて。
+:revision-1: 2021-10-02 Qiita から移植
+
+この記事は Qiita から移植してきたものです。 元 URL:
+https://qiita.com/nsfisis/items/787a8cf888a304497223
+
+'''''
+
+== TL; DR
+
+`case` - `in` によるパターンマッチング構文でも、`case` - `when`
+と同じように `then` が使える (場合によっては使う必要がある)。
+
+== `then` とは
+
+使われることは稀だが、Ruby では `then`
+がキーワードになっている。次のように使う:
+
+[source,ruby]
+----
+if cond then
+ puts "Y"
+else
+ puts "N"
+end
+----
+
+このキーワードが現れうる場所はいくつかあり、`if`、`unless`、`rescue`、`case`
+構文がそれに当たる。 上記のように、何か条件を書いた後 `then`
+を置き、式がそこで終了していることを示すマーカーとして機能する。
+
+[source,ruby]
+----
+# Example:
+
+if x then
+ a
+end
+
+unless x then
+ a
+end
+
+begin
+ a
+rescue then
+ b
+end
+
+case x
+when p then
+ a
+end
+----
+
+== なぜ普段は書かなくてもよいのか
+
+普通 Ruby のコードで `then`
+を書くことはない。なぜか。次のコードを実行してみるとわかる。
+
+[source,ruby]
+----
+if true puts 'Hello, World!' end
+----
+
+次のような構文エラーが出力される。
+
+....
+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
+....
+
+二つ目のメッセージは無視して一つ目を読むと、`then` か `;`
+か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。
+
+ポイントは改行が `then` (や `;`) の代わりとなることである。`true`
+の後に改行を入れてみる。
+
+[source,ruby]
+----
+if true
+puts 'Hello, World!' end
+----
+
+無事 Hello, World! と出力されるようになった。
+
+== なぜ `then` や `;` や改行が必要か
+
+なぜ `then` や `;` や改行 (以下 「`then` 等」)
+が必要なのだろうか。次の例を見てほしい:
+
+[source,ruby]
+----
+if a b end
+----
+
+`then` も `;`
+も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。
+この例は二通りに解釈できる。
+
+[source,ruby]
+----
+# a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価
+if a then
+ b
+end
+----
+
+[source,ruby]
+----
+# a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、
+# その結果が truthy なら何もしない
+if a(b) then
+end
+----
+
+`then` 等はこの曖昧性を排除するためにあり、条件式は `if` から `then`
+等までの間にある、ということを明確にする。 C系の `if` 後に来る `(`/`)`
+や、Python の `:`、Rust/Go/Swift などの `{` も同じ役割を持つ。
+
+Ruby の場合、プログラマーが書きやすいよう改行でもって `then`
+が代用できるので、ほとんどの場合 `then` は必要ない。
+
+== `case` - `in` における `then`
+
+ようやく本題にたどり着いた。来る Ruby 3.0 では `case` と `in`
+キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして
+`then` 等が必要になる。 (現在の) Ruby には formal
+な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc
+の説明は省略)。
+
+https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986
+
+[source,yacc]
+----
+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)) %*/
+ }
+ ;
+----
+
+簡略版:
+
+[source,yacc]
+----
+p_case_body : keyword_in p_top_expr then compstmt p_cases
+ ;
+----
+
+ここで、`keyword_in` は文字通り `in`、`p_top_expr`
+はいわゆるパターン、`then` は `then`
+キーワードのことではなく、この記事で `then` 等と呼んでいるもの、つまり
+`then` キーワード、`;`、改行のいずれかである。
+
+これにより、`case` - `when` による従来の構文と同じように、`then`
+等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:
+
+[source,ruby]
+----
+case x
+in 1 then a
+in 2 then b
+in 3 then c
+end
+
+case x
+in 1
+ a
+in 2
+ b
+in 3
+ c
+end
+
+case x
+in 1; a
+in 2; b
+in 3; c
+end
+----
+
+ところで、`p_top_expr` には `if` による guard clause
+が書けるので、その場合は `if` - `then` と似たような見た目になる。
+
+[source,ruby]
+----
+case x
+in 0 then a
+in n if n < 0 then b
+in n then c
+end
+----
+
+== まとめ
+
+* `if` や `case` の条件の後ろには `then`、`;`、改行のいずれかが必要
+** 通常は改行しておけばよい
+* 3.0 で入る予定の `case` - `in` でも `then` 等が必要になる
+* Ruby の構文を正確に知るには (現状) `parse.y` を直接読めばよい
diff --git a/content/posts/2021-10-02/ruby-then-keyword-and-case-in.md b/content/posts/2021-10-02/ruby-then-keyword-and-case-in.md
deleted file mode 100644
index 5b5c352..0000000
--- a/content/posts/2021-10-02/ruby-then-keyword-and-case-in.md
+++ /dev/null
@@ -1,205 +0,0 @@
----
-title: "[Ruby] then キーワードと case in"
-date: 2021-10-02T09:38:50+09:00
-tags: ["ruby", "ruby3"]
-summary: |
- Ruby 3.0 で追加される case in 構文と、then キーワードについて。
-changelog:
- 2021-10-02: Qiita から移植
----
-
-この記事は Qiita から移植してきたものです。
-元 URL: https://qiita.com/nsfisis/items/787a8cf888a304497223
-
-
------------------------------------
-
-
-# TL; DR
-
-`case` - `in` によるパターンマッチング構文でも、`case` - `when` と同じように `then` が使える (場合によっては使う必要がある)。
-
-# `then` とは
-
-使われることは稀だが、Ruby では `then` がキーワードになっている。次のように使う:
-
-```ruby
-if cond then
- puts "Y"
-else
- puts "N"
-end
-```
-
-このキーワードが現れうる場所はいくつかあり、`if`、`unless`、`rescue`、`case` 構文がそれに当たる。
-上記のように、何か条件を書いた後 `then` を置き、式がそこで終了していることを示すマーカーとして機能する。
-
-```ruby
-# Example:
-
-if x then
- a
-end
-
-unless x then
- a
-end
-
-begin
- a
-rescue then
- b
-end
-
-case x
-when p then
- a
-end
-```
-
-# なぜ普段は書かなくてもよいのか
-
-普通 Ruby のコードで `then` を書くことはない。なぜか。次のコードを実行してみるとわかる。
-
-```ruby
-if true puts 'Hello, World!' end
-```
-
-次のような構文エラーが出力される。
-
-```
-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
-```
-
-二つ目のメッセージは無視して一つ目を読むと、`then` か `;` か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。
-
-ポイントは改行が `then` (や `;`) の代わりとなることである。`true` の後に改行を入れてみる。
-
-```ruby
-if true
-puts 'Hello, World!' end
-```
-
-無事 Hello, World! と出力されるようになった。
-
-# なぜ `then` や `;` や改行が必要か
-
-なぜ `then` や `;` や改行 (以下 「`then` 等」) が必要なのだろうか。次の例を見てほしい:
-
-```ruby
-if a b end
-```
-
-`then` も `;` も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。
-この例は二通りに解釈できる。
-
-```ruby
-# a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価
-if a then
- b
-end
-```
-
-```ruby
-# a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、
-# その結果が truthy なら何もしない
-if a(b) then
-end
-```
-
-`then` 等はこの曖昧性を排除するためにあり、条件式は `if` から `then` 等までの間にある、ということを明確にする。
-C系の `if` 後に来る `(`/`)` や、Python の `:`、Rust/Go/Swift などの `{` も同じ役割を持つ。
-
-Ruby の場合、プログラマーが書きやすいよう改行でもって `then` が代用できるので、ほとんどの場合 `then` は必要ない。
-
-# `case` - `in` における `then`
-
-ようやく本題にたどり着いた。来る Ruby 3.0 では `case` と `in` キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして `then` 等が必要になる。
-(現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。
-
-https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986
-
-```yacc
-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)) %*/
- }
- ;
-```
-
-簡略版:
-
-```yacc
-p_case_body : keyword_in p_top_expr then compstmt p_cases
- ;
-```
-
-ここで、`keyword_in` は文字通り `in`、`p_top_expr` はいわゆるパターン、`then` は `then` キーワードのことではなく、この記事で `then` 等と呼んでいるもの、つまり `then` キーワード、`;`、改行のいずれかである。
-
-これにより、`case` - `when` による従来の構文と同じように、`then` 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:
-
-```ruby
-case x
-in 1 then a
-in 2 then b
-in 3 then c
-end
-
-case x
-in 1
- a
-in 2
- b
-in 3
- c
-end
-
-case x
-in 1; a
-in 2; b
-in 3; c
-end
-```
-
-ところで、`p_top_expr` には `if` による guard clause が書けるので、その場合は `if` - `then` と似たような見た目になる。
-
-```ruby
-case x
-in 0 then a
-in n if n < 0 then b
-in n then c
-end
-```
-
-# まとめ
-
-* `if` や `case` の条件の後ろには `then`、`;`、改行のいずれかが必要
- * 通常は改行しておけばよい
-* 3.0 で入る予定の `case` - `in` でも `then` 等が必要になる
-* Ruby の構文を正確に知るには (現状) `parse.y` を直接読めばよい
-
diff --git a/content/posts/2021-10-02/rust-where-are-primitive-types-from.adoc b/content/posts/2021-10-02/rust-where-are-primitive-types-from.adoc
new file mode 100644
index 0000000..8fc70b4
--- /dev/null
+++ b/content/posts/2021-10-02/rust-where-are-primitive-types-from.adoc
@@ -0,0 +1,201 @@
+= Rust のプリミティブ型はどこからやって来るか
+:tags: rust
+:description: Rust のプリミティブ型は予約語ではなく普通の識別子である。 \
+ どのようにこれが名前解決されるのかを調べた。
+:revision-1: 2021-10-02 Qiita から移植
+
+この記事は Qiita から移植してきたものです。 元 URL:
+https://qiita.com/nsfisis/items/9a429432258bbcd6c565
+
+'''''
+
+== 前置き
+
+Rust
+において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。
+
+[source,rust]
+----
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+
+struct bool;
+struct char;
+struct i8;
+struct i16;
+struct i32;
+struct i64;
+struct i128;
+struct isize;
+struct u8;
+struct u16;
+struct u32;
+struct u64;
+struct u128;
+struct usize;
+struct f32;
+struct f64;
+struct str;
+----
+
+では、普段単に `bool` と書いたとき、この `bool`
+は一体どこから来ているのか。rustc のソースを追ってみた。
+
+____
+前提知識: 一般的なコンパイラの構造、用語。`rustc` そのものの知識は不要
+(というよりも筆者自身がよく知らない)
+____
+
+== 調査
+
+調査に使用したソース (調査時点での最新 master)
+
+https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98
+
+どのようにして調べるか。rustc
+の構造には詳しくないため、すぐに当たりをつけるのは難しい。
+
+大雑把な構造としては、`compiler` フォルダ以下に `rustc_*`
+という名前のクレートが数十個入っている。これがどうやら `rustc`
+コマンドの実装部のようだ。
+
+`rustc` はセルフホストされている (= `rustc` 自身が Rust で書かれている)
+ので、`bool` や `char`
+などで適当に検索をかけてもノイズが多すぎて話にならない。
+しかし、お誂え向きなことに `i128`/`u128`
+というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って
+`git grep` してみる。
+
+....
+$ 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
+....
+
+165
+程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。
+
+....
+$ git grep "\bi128\b"
+...
+rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));
+...
+....
+
+`rustc_resolve`
+というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。
+
+[source,rust]
+----
+/// Interns the names of the primitive types.
+///
+/// All other types are defined somewhere and possibly imported, but the primitive ones need
+/// special handling, since they have no place of origin.
+struct PrimitiveTypeTable {
+ primitive_types: FxHashMap<Symbol, PrimTy>,
+}
+
+impl PrimitiveTypeTable {
+ fn new() -> PrimitiveTypeTable {
+ let mut table = FxHashMap::default();
+
+ table.insert(sym::bool, Bool);
+ table.insert(sym::char, Char);
+ table.insert(sym::f32, Float(FloatTy::F32));
+ table.insert(sym::f64, Float(FloatTy::F64));
+ table.insert(sym::isize, Int(IntTy::Isize));
+ table.insert(sym::i8, Int(IntTy::I8));
+ table.insert(sym::i16, Int(IntTy::I16));
+ table.insert(sym::i32, Int(IntTy::I32));
+ table.insert(sym::i64, Int(IntTy::I64));
+ table.insert(sym::i128, Int(IntTy::I128));
+ table.insert(sym::str, Str);
+ table.insert(sym::usize, Uint(UintTy::Usize));
+ table.insert(sym::u8, Uint(UintTy::U8));
+ table.insert(sym::u16, Uint(UintTy::U16));
+ table.insert(sym::u32, Uint(UintTy::U32));
+ table.insert(sym::u64, Uint(UintTy::U64));
+ table.insert(sym::u128, Uint(UintTy::U128));
+ Self { primitive_types: table }
+ }
+}
+----
+
+これは初めに列挙したプリミティブ型の一覧と一致している。doc comment
+にも、
+
+____
+All other types are defined somewhere and possibly imported, but the
+primitive ones need special handling, since they have no place of
+origin.
+____
+
+とある。次はこの struct
+の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。
+
+[source,rust]
+----
+ /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
+ /// (略)
+ fn resolve_ident_in_lexical_scope(
+ &mut self,
+ mut ident: Ident,
+ ns: Namespace,
+ // (略)
+ ) -> Option<LexicalScopeBinding<'a>> {
+ // (略)
+
+ if ns == TypeNS {
+ if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) {
+ let binding =
+ (Res::PrimTy(*prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
+ .to_name_binding(self.arenas);
+ return Some(LexicalScopeBinding::Item(binding));
+ }
+ }
+
+ None
+ }
+----
+
+関数名や doc comment が示している通り、この関数は識別子 (identifier,
+ident) を現在のレキシカルスコープ内で解決 (resolve) する。
+`if ns == TypeNS` のブロック内では、`primitive_type_table` (上記の
+`PrimitiveTypeTable::new()` で作られた変数) に含まれている識別子
+(`bool`、`i32` など)
+かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。
+
+なお、`ns` は「名前空間」を示す変数である。Rust
+における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この
+`if`
+は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。
+
+重要なのは、これが `resolve_ident_in_lexical_scope()`
+の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。
+
+動作がわかったところで、例として次のコードを考える。
+
+[source,rust]
+----
+#![allow(non_camel_case_types)]
+
+struct bool;
+
+fn main() {
+ let _: bool = bool;
+}
+----
+
+ここで `main()` の `bool` は `struct bool`
+として解決される。なぜなら、プリミティブ型の判定をする前に `bool`
+という名前の別の型が見つかるからだ。
+
+== まとめ
+
+Rust
+のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。
diff --git a/content/posts/2021-10-02/rust-where-are-primitive-types-from.md b/content/posts/2021-10-02/rust-where-are-primitive-types-from.md
deleted file mode 100644
index dc2630b..0000000
--- a/content/posts/2021-10-02/rust-where-are-primitive-types-from.md
+++ /dev/null
@@ -1,175 +0,0 @@
----
-title: "Rust のプリミティブ型はどこからやって来るか"
-date: 2021-10-02T09:39:27+09:00
-tags: ["rust"]
-summary: |
- Rust のプリミティブ型は予約語ではなく普通の識別子である。どのようにこれが名前解決されるのかを調べた。
-changelog:
- 2021-10-02: Qiita から移植
----
-
-この記事は Qiita から移植してきたものです。
-元 URL: https://qiita.com/nsfisis/items/9a429432258bbcd6c565
-
-
------------------------------------
-
-
-
-# 前置き
-
-Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。
-
-```rust
-#![allow(non_camel_case_types)]
-#![allow(dead_code)]
-
-struct bool;
-struct char;
-struct i8;
-struct i16;
-struct i32;
-struct i64;
-struct i128;
-struct isize;
-struct u8;
-struct u16;
-struct u32;
-struct u64;
-struct u128;
-struct usize;
-struct f32;
-struct f64;
-struct str;
-```
-
-では、普段単に `bool` と書いたとき、この `bool` は一体どこから来ているのか。rustc のソースを追ってみた。
-
-> 前提知識: 一般的なコンパイラの構造、用語。`rustc` そのものの知識は不要 (というよりも筆者自身がよく知らない)
-
-# 調査
-
-調査に使用したソース (調査時点での最新 master)
-
-https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98
-
-どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。
-
-大雑把な構造としては、`compiler` フォルダ以下に `rustc_*` という名前のクレートが数十個入っている。これがどうやら `rustc` コマンドの実装部のようだ。
-
-`rustc` はセルフホストされている (= `rustc` 自身が Rust で書かれている) ので、`bool` や `char` などで適当に検索をかけてもノイズが多すぎて話にならない。
-しかし、お誂え向きなことに `i128`/`u128` というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って `git grep` してみる。
-
-```
-$ 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
-```
-
-165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。
-
-```
-$ git grep "\bi128\b"
-...
-rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));
-...
-```
-
-`rustc_resolve` というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。
-
-```rust
-/// Interns the names of the primitive types.
-///
-/// All other types are defined somewhere and possibly imported, but the primitive ones need
-/// special handling, since they have no place of origin.
-struct PrimitiveTypeTable {
- primitive_types: FxHashMap<Symbol, PrimTy>,
-}
-
-impl PrimitiveTypeTable {
- fn new() -> PrimitiveTypeTable {
- let mut table = FxHashMap::default();
-
- table.insert(sym::bool, Bool);
- table.insert(sym::char, Char);
- table.insert(sym::f32, Float(FloatTy::F32));
- table.insert(sym::f64, Float(FloatTy::F64));
- table.insert(sym::isize, Int(IntTy::Isize));
- table.insert(sym::i8, Int(IntTy::I8));
- table.insert(sym::i16, Int(IntTy::I16));
- table.insert(sym::i32, Int(IntTy::I32));
- table.insert(sym::i64, Int(IntTy::I64));
- table.insert(sym::i128, Int(IntTy::I128));
- table.insert(sym::str, Str);
- table.insert(sym::usize, Uint(UintTy::Usize));
- table.insert(sym::u8, Uint(UintTy::U8));
- table.insert(sym::u16, Uint(UintTy::U16));
- table.insert(sym::u32, Uint(UintTy::U32));
- table.insert(sym::u64, Uint(UintTy::U64));
- table.insert(sym::u128, Uint(UintTy::U128));
- Self { primitive_types: table }
- }
-}
-```
-
-これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、
-
-> All other types are defined somewhere and possibly imported, but the primitive ones need special handling, since they have no place of origin.
-
-とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。
-
-```rust
- /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
- /// (略)
- fn resolve_ident_in_lexical_scope(
- &mut self,
- mut ident: Ident,
- ns: Namespace,
- // (略)
- ) -> Option<LexicalScopeBinding<'a>> {
- // (略)
-
- if ns == TypeNS {
- if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) {
- let binding =
- (Res::PrimTy(*prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
- .to_name_binding(self.arenas);
- return Some(LexicalScopeBinding::Item(binding));
- }
- }
-
- None
- }
-```
-
-関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。
-`if ns == TypeNS` のブロック内では、`primitive_type_table` (上記の `PrimitiveTypeTable::new()` で作られた変数) に含まれている識別子 (`bool`、`i32` など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。
-
-なお、`ns` は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この `if` は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。
-
-重要なのは、これが `resolve_ident_in_lexical_scope()` の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。
-
-動作がわかったところで、例として次のコードを考える。
-
-```rust
-#![allow(non_camel_case_types)]
-
-struct bool;
-
-fn main() {
- let _: bool = bool;
-}
-```
-
-ここで `main()` の `bool` は `struct bool` として解決される。なぜなら、プリミティブ型の判定をする前に `bool` という名前の別の型が見つかるからだ。
-
-
-# まとめ
-
-Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。
-
diff --git a/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.adoc b/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.adoc
new file mode 100644
index 0000000..061e764
--- /dev/null
+++ b/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.adoc
@@ -0,0 +1,120 @@
+= [Vim] autocmd events の BufWrite/BufWritePre の違い
+:tags: vim
+:description: Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、 \
+ 違いはないことがわかった。
+:revision-1: 2021-10-02 Qiita から移植
+
+この記事は Qiita から移植してきたものです。 元 URL:
+https://qiita.com/nsfisis/items/79ab4db8564032de0b25
+
+'''''
+
+== TL; DR
+
+違いはない。ただのエイリアス。
+
+== 調査記録
+
+Vim の autocmd events には似通った名前のものがいくつかある。大抵は
+`:help`
+に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。
+
+* `BufRead`/`BufReadPost`
+* `BufWrite`/`BufWritePre`
+* `BufAdd`/`BufCreate`
+
+このうち、`BufAdd`/`BufCreate` に関しては、`:help BufCreate` に
+
+____
+The BufCreate event is for historic reasons.
+____
+
+とあり、おそらくは `BufAdd`
+のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため
+vim と neovim のソースコードを調査した。
+
+____
+ソースコードへのリンク
+https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2[vim
+(調査時点での master branch)]
+https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3[neovim
+(上に同じ)]
+____
+
+=== vim のソースコード
+
+以下は、autocmd events
+の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。
+
+https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86
+
+[source,c]
+----
+ {"BufAdd", EVENT_BUFADD},
+ {"BufCreate", EVENT_BUFADD},
+----
+
+https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97
+
+[source,c]
+----
+ {"BufRead", EVENT_BUFREADPOST},
+ {"BufReadCmd", EVENT_BUFREADCMD},
+ {"BufReadPost", EVENT_BUFREADPOST},
+----
+
+https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105
+
+[source,c]
+----
+ {"BufWrite", EVENT_BUFWRITEPRE},
+ {"BufWritePost", EVENT_BUFWRITEPOST},
+ {"BufWritePre", EVENT_BUFWRITEPRE},
+----
+
+=== neovim のソースコード
+
+neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua
+で書かれている。以下にある通り、はっきり `aliases` と書かれている。
+
+https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124
+
+[source,lua]
+----
+ aliases = {
+ BufCreate = 'BufAdd',
+ BufRead = 'BufReadPost',
+ BufWrite = 'BufWritePre',
+ FileEncoding = 'EncodingChanged',
+ },
+----
+
+ところで、上では取り上げなかった `FileEncoding` だが、これは
+`:help FileEncoding` にしっかりと書いてある。
+
+....
+ *FileEncoding*
+FileEncoding Obsolete. It still works and is equivalent
+ to |EncodingChanged|.
+....
+
+=== まとめ
+
+記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。
+
+* `BufAdd`/`BufCreate`
+** → `BufCreate` は歴史的な理由により (``for historic reasons'')
+存在しているため、新しい方 (`BufAdd`) を使う
+* `BufRead`/`BufReadPost`
+** → `BufReadPre` との対称性のため、あるいは `BufWritePost`
+との対称性のため `BufReadPost` を使う
+* `BufWrite`/`BufWritePre`
+** → `BufWritePost` との対称性のため、あるいは `BufReadPre`
+との対称性のため `BufWritePre` を使う
+* `FileEncoding`/`EncodingChanged`
+** → `FileEncoding` は ``Obsolete''
+と明言されているので、`EncodingChanged` を使う
+
+ところでこの調査で知ったのだが、`BufRead` と `BufWrite`
+は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら
+`Pre`/`Post` 付きのものを使った方が分かりやすいだろう。
diff --git a/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.md b/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.md
deleted file mode 100644
index 485c304..0000000
--- a/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.md
+++ /dev/null
@@ -1,106 +0,0 @@
----
-title: "[Vim] autocmd events の BufWrite/BufWritePre の違い"
-date: 2021-10-02T09:37:12+09:00
-tags: ["vim"]
-summary: |
- Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、違いはないことがわかった。
-changelog:
- 2021-10-02: Qiita から移植
----
-
-この記事は Qiita から移植してきたものです。
-元 URL: https://qiita.com/nsfisis/items/79ab4db8564032de0b25
-
-
------------------------------------
-
-
-
-# TL; DR
-
-違いはない。ただのエイリアス。
-
-
-# 調査記録
-
-Vim の autocmd events には似通った名前のものがいくつかある。大抵は `:help` に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。
-
-* `BufRead`/`BufReadPost`
-* `BufWrite`/`BufWritePre`
-* `BufAdd`/`BufCreate`
-
-このうち、`BufAdd`/`BufCreate` に関しては、`:help BufCreate` に
-
-> The BufCreate event is for historic reasons.
-
-とあり、おそらくは `BufAdd` のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため vim と neovim のソースコードを調査した。
-
-> ソースコードへのリンク
-> [vim (調査時点での master branch)](https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2)
-> [neovim (上に同じ)](https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3)
-
-## vim のソースコード
-
-以下は、autocmd events の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。
-
-https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86
-
-```c
- {"BufAdd", EVENT_BUFADD},
- {"BufCreate", EVENT_BUFADD},
-```
-
-https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97
-
-```c
- {"BufRead", EVENT_BUFREADPOST},
- {"BufReadCmd", EVENT_BUFREADCMD},
- {"BufReadPost", EVENT_BUFREADPOST},
-```
-
-https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105
-
-```c
- {"BufWrite", EVENT_BUFWRITEPRE},
- {"BufWritePost", EVENT_BUFWRITEPOST},
- {"BufWritePre", EVENT_BUFWRITEPRE},
-```
-
-## neovim のソースコード
-
-neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua で書かれている。以下にある通り、はっきり `aliases` と書かれている。
-
-https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124
-
-```lua
- aliases = {
- BufCreate = 'BufAdd',
- BufRead = 'BufReadPost',
- BufWrite = 'BufWritePre',
- FileEncoding = 'EncodingChanged',
- },
-```
-
-ところで、上では取り上げなかった `FileEncoding` だが、これは `:help FileEncoding` にしっかりと書いてある。
-
-```
- *FileEncoding*
-FileEncoding Obsolete. It still works and is equivalent
- to |EncodingChanged|.
-```
-
-## まとめ
-
-記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。
-
-* `BufAdd`/`BufCreate`
- * → `BufCreate` は歴史的な理由により ("for historic reasons") 存在しているため、新しい方 (`BufAdd`) を使う
-* `BufRead`/`BufReadPost`
- * → `BufReadPre` との対称性のため、あるいは `BufWritePost` との対称性のため `BufReadPost` を使う
-* `BufWrite`/`BufWritePre`
- * → `BufWritePost` との対称性のため、あるいは `BufReadPre` との対称性のため `BufWritePre` を使う
-* `FileEncoding`/`EncodingChanged`
- * → `FileEncoding` は "Obsolete" と明言されているので、`EncodingChanged` を使う
-
-ところでこの調査で知ったのだが、`BufRead` と `BufWrite` は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら `Pre`/`Post` 付きのものを使った方が分かりやすいだろう。
-
diff --git a/content/posts/2021-10-02/vim-swap-order-of-selected-lines.adoc b/content/posts/2021-10-02/vim-swap-order-of-selected-lines.adoc
new file mode 100644
index 0000000..b937625
--- /dev/null
+++ b/content/posts/2021-10-02/vim-swap-order-of-selected-lines.adoc
@@ -0,0 +1,165 @@
+= Vimで選択した行の順番を入れ替える
+:tags: vim
+:description: Vim で選択した行の順番を入れ替える方法。
+:revision-1: 2021-10-02 Qiita から移植
+
+この記事は Qiita から移植してきたものです。 元 URL:
+https://qiita.com/nsfisis/items/4fefb361d9a693803520
+
+'''''
+
+== バージョン情報
+
+`:version` の一部
+
+____
+VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Jan 26 2020 11:30:30) macOS
+version Included patches: 1-148 Huge version without GUI.
+____
+
+== よく紹介されている手法
+
+=== `tac` / `tail`
+
+`tac` や `tail -r` などの外部コマンドを `!`
+を使って呼び出し、置き換える。
+
+____
+:h v_!
+____
+
+`tac` コマンドや `tail` の `-r`
+オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい
+
+=== `:g/^/m0`
+
+こちらは外部コマンドに頼らず、Vim の機能のみを使う。`g` は `:global`
+コマンドの、`m` は `:move` コマンドの略
+
+`:global` コマンドは `:[range]global/{pattern}/[command]`
+のように使い、`[range]` で指定された範囲の行のうち、`{pattern}`
+で指定された検索パターンにマッチする行に対して、順番に `[command]`
+で指定された Ex コマンドを呼び出す。
+
+____
+:h :global
+____
+
+`:move` コマンドは `[range]:move {address}` のように使い、`[range]`
+で指定された範囲の行を `{address}` で指定された位置に移動させる。
+
+____
+:h :move
+____
+
+`:g/^/m0` のように組み合わせると、「すべての行を1行ずつ
+0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。
+
+なお、`:g/^/m0` は全ての行を入れ替えるが、`:N,Mg/^/mN-1` とすることで
+N行目から
+M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。
+
+[source,vim]
+----
+command! -bar -range=%
+ \ Reverse
+ \ <line1>,<line2>g/^/m<line1>-1
+----
+
+これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。
+
+== `:g/^/m0` の問題点
+
+`:global`
+コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。`^`
+は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。`'hlsearch'`
+オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと
+`n` コマンドなどの際に不便である。
+
+____
+:h @/
+____
+
+== 解決策
+
+____
+[2020/9/28追記] より簡潔な方法を見つけたので次節に追記した
+____
+
+前述した `:Reverse` コマンドの定義を少し変えて、次のようにする:
+
+[source,vim]
+----
+function! s:reverse_lines(from, to) abort
+ execute printf("%d,%dg/^/m%d", a:from, a:to, a:from - 1)
+endfunction
+
+command! -bar -range=%
+ \ Reverse
+ \ call <SID>reverse_lines(<line1>, <line2>)
+----
+
+実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。
+
+この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが
+`^` で上書きされることがなくなる。
+
+Vim のヘルプから該当箇所を引用する (強調は筆者による)。
+
+____
+:h autocmd-searchpat
+
+*Autocommands do not change the current search patterns.* Vim saves the
+current search patterns before executing autocommands then restores them
+after the autocommands finish. This means that autocommands do not
+affect the strings highlighted with the `hlsearch' option.
+____
+
+これは autocommand
+の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは
+`:nohlsearch` のヘルプにある。同じく該当箇所を引用する
+(強調は筆者による)。
+
+____
+:h :nohlsearch
+
+(略) This command doesn’t work in an autocommand, because the
+highlighting state is saved and restored when executing autocommands
+|autocmd-searchpat|. *Same thing for when invoking a user function.*
+____
+
+この仕様により、`:g/^/m0`
+の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。
+
+== 解決策 (改訂版)
+
+____
+[2020/9/28追記] より簡潔な方法を見つけたため追記する
+____
+
+[source,vim]
+----
+command! -bar -range=%
+ \ Reverse
+ \ keeppatterns <line1>,<line2>g/^/m<line1>-1
+----
+
+まさにこのための Exコマンド、`:keeppatterns`
+が存在する。`:keeppatterns {command}`
+のように使い、読んで字の如く、後ろに続く
+Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。
+
+____
+:h :keeppatterns
+____
+
+== コピペ用再掲
+
+[source,vim]
+----
+" License: Public Domain
+
+command! -bar -range=%
+ \ Reverse
+ \ keeppatterns <line1>,<line2>g/^/m<line1>-1
+----
diff --git a/content/posts/2021-10-02/vim-swap-order-of-selected-lines.md b/content/posts/2021-10-02/vim-swap-order-of-selected-lines.md
deleted file mode 100644
index 10a6452..0000000
--- a/content/posts/2021-10-02/vim-swap-order-of-selected-lines.md
+++ /dev/null
@@ -1,145 +0,0 @@
----
-title: "Vimで選択した行の順番を入れ替える"
-date: 2021-10-02T09:37:25+09:00
-tags: ["vim"]
-summary: |
- Vim で選択した行の順番を入れ替える方法。
-changelog:
- 2021-10-02: Qiita から移植
----
-
-この記事は Qiita から移植してきたものです。
-元 URL: https://qiita.com/nsfisis/items/4fefb361d9a693803520
-
-
------------------------------------
-
-
-
-# バージョン情報
-
-`:version` の一部
-
-> VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Jan 26 2020 11:30:30)
-> macOS version
-> Included patches: 1-148
-> Huge version without GUI.
-
-
-
-# よく紹介されている手法
-
-## `tac` / `tail`
-
-`tac` や `tail -r` などの外部コマンドを `!` を使って呼び出し、置き換える。
-
-> :h v_!
-
-`tac` コマンドや `tail` の `-r` オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい
-
-
-
-
-## `:g/^/m0`
-
-こちらは外部コマンドに頼らず、Vim の機能のみを使う。`g` は `:global` コマンドの、`m` は `:move` コマンドの略
-
-`:global` コマンドは `:[range]global/{pattern}/[command]` のように使い、`[range]` で指定された範囲の行のうち、`{pattern}` で指定された検索パターンにマッチする行に対して、順番に `[command]` で指定された Ex コマンドを呼び出す。
-
-> :h :global
-
-`:move` コマンドは `[range]:move {address}` のように使い、`[range]` で指定された範囲の行を `{address}` で指定された位置に移動させる。
-
-> :h :move
-
-`:g/^/m0` のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。
-
-なお、`:g/^/m0` は全ての行を入れ替えるが、`:N,Mg/^/mN-1` とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。
-
-```vim
-command! -bar -range=%
- \ Reverse
- \ <line1>,<line2>g/^/m<line1>-1
-```
-
-これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。
-
-
-
-# `:g/^/m0` の問題点
-
-`:global` コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。`^` は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。`'hlsearch'` オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと `n` コマンドなどの際に不便である。
-
-> :h @/
-
-
-
-# 解決策
-
-> [2020/9/28追記]
-> より簡潔な方法を見つけたので次節に追記した
-
-前述した `:Reverse` コマンドの定義を少し変えて、次のようにする:
-
-```vim
-function! s:reverse_lines(from, to) abort
- execute printf("%d,%dg/^/m%d", a:from, a:to, a:from - 1)
-endfunction
-
-command! -bar -range=%
- \ Reverse
- \ call <SID>reverse_lines(<line1>, <line2>)
-```
-
-実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。
-
-この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが `^` で上書きされることがなくなる。
-
-Vim のヘルプから該当箇所を引用する (強調は筆者による)。
-
-> :h autocmd-searchpat
->
-> **Autocommands do not change the current search patterns.** Vim saves the current
-> search patterns before executing autocommands then restores them after the
-> autocommands finish. This means that autocommands do not affect the strings
-> highlighted with the 'hlsearch' option.
-
-これは autocommand の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは `:nohlsearch` のヘルプにある。同じく該当箇所を引用する (強調は筆者による)。
-
-> :h :nohlsearch
->
-> (略) This command doesn't work in an autocommand, because
-> the highlighting state is saved and restored when
-> executing autocommands |autocmd-searchpat|.
-> **Same thing for when invoking a user function.**
-
-この仕様により、`:g/^/m0` の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。
-
-
-# 解決策 (改訂版)
-
-> [2020/9/28追記]
-> より簡潔な方法を見つけたため追記する
-
-```vim
-command! -bar -range=%
- \ Reverse
- \ keeppatterns <line1>,<line2>g/^/m<line1>-1
-```
-
-まさにこのための Exコマンド、`:keeppatterns` が存在する。`:keeppatterns {command}` のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。
-
-> :h :keeppatterns
-
-
-# コピペ用再掲
-
-
-```vim
-" License: Public Domain
-
-command! -bar -range=%
- \ Reverse
- \ keeppatterns <line1>,<line2>g/^/m<line1>-1
-```
-
diff --git a/content/posts/2022-04-09/phperkaigi-2022-tokens.md b/content/posts/2022-04-09/phperkaigi-2022-tokens.adoc
index 5640b8f..51d9a36 100644
--- a/content/posts/2022-04-09/phperkaigi-2022-tokens.md
+++ b/content/posts/2022-04-09/phperkaigi-2022-tokens.adoc
@@ -1,28 +1,24 @@
----
-title: "PHPerKaigi 2022 トークン問題の解説"
-date: 2022-04-09T21:50:19+09:00
-lastmod: 2022-04-16
-tags: ["conference", "php", "phperkaigi"]
-summary: |
- PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。
-changelog:
- 2022-04-09: 公開
- 2022-04-16: 2問目、3問目の解説を追加、1問目に加筆
----
-
-# はじめに
-
-本日開始された [PHPerKaigi 2022](https://phperkaigi.jp/2022/) の PHPer チャレンジにおいて、弊社 [デジタルサーカス株式会社](https://www.dgcircus.com/) の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。
+= PHPerKaigi 2022 トークン問題の解説
+:tags: conference, php, phperkaigi
+:description: PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。
+:revision-1: 2022-04-09 公開
+:revision-2: 2022-04-16 2問目、3問目の解説を追加、1問目に加筆
-リポジトリはこちら: https://github.com/nsfisis/PHPerKaigi2022-tokens
+== はじめに
+本日開始された https://phperkaigi.jp/2022/[PHPerKaigi 2022] の PHPer
+チャレンジにおいて、弊社
+https://www.dgcircus.com/[デジタルサーカス株式会社] の問題を
+3問作成した。この記事では、これらの問題の解説をおこなう。
+リポジトリはこちら: https://github.com/nsfisis/PHPerKaigi2022-tokens
-# 第1問 brainf_ck.php
+== 第1問 brainf_ck.php
ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。
-```php
+[source,php]
+----
<?php
declare(strict_types=0O1);
@@ -92,29 +88,28 @@ $🐘([
$👉, $👎, $📝,
$👈, $📝,
]);
-```
+----
この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。
+=== 解説
-## 解説
-
-### 絵文字
+==== 絵文字
-まず目につくのは大量の絵文字だろう。
-PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。
+まず目につくのは大量の絵文字だろう。 PHP
+は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。
+==== プログラム全体
-### プログラム全体
-
-Brainf\*ck のインタプリタとプログラムになっている。
-Brainf\*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。
+Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck
+とは、難解プログラミング言語のひとつであり、ここで説明するよりも
+Wikipedia の該当ページを読んだ方がよい。
https://ja.wikipedia.org/wiki/Brainfuck
-なお、brainf\*ck プログラムを普通の書き方で書くと、次のようになる。
+なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。
-```
+....
+ + + + + + + + + +
[
> + + +
@@ -137,7 +132,7 @@ https://ja.wikipedia.org/wiki/Brainfuck
> + + .
> - .
< .
-```
+....
実行結果はこちら: https://ideone.com/22VWmb
@@ -151,48 +146,48 @@ https://ja.wikipedia.org/wiki/Brainfuck
* `$🤡`: `[`
* `$🎪`: `]`
-`,` (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。
+`,` (入力) に対応する関数はない
+(このプログラムでは使わないので用意していない)。
なお、`$🐘` はいわゆる main 関数であり、プログラムの実行部分である。
+==== 絵文字の選択
-### 絵文字の選択
-
-おおよそ意味に合致するよう選んでいるが、`$🤡` と `$🎪` は弊社デジタルサーカスにちなんでいる。
-また、`$🐘` は PHP のマスコットの象に由来する。
-
+おおよそ意味に合致するよう選んでいるが、`$🤡` と `$🎪`
+は弊社デジタルサーカスにちなんでいる。 また、`$🐘` は PHP
+のマスコットの象に由来する。
-### strict_types
+==== strict_types
-`declare` 文の `strict_types` に指定できるのは、`0` か `1` の数値リテラルだが、
-`0x0` や `0b1` のような値も受け付ける。
-今回は、PHP 8.1 から追加された、`0O` または `0o` から始まる八進数リテラルを使った。
+`declare` 文の `strict_types` に指定できるのは、`0` か `1`
+の数値リテラルだが、 `0x0` や `0b1` のような値も受け付ける。 今回は、PHP
+8.1 から追加された、`0O` または `0o` から始まる八進数リテラルを使った。
-
-### URL
+==== URL
ソースコードのライセンスを示したこの部分だが、
-```php
+[source,php]
+----
https://creativecommons.org/publicdomain/zero/1.0/
-```
-
-完全に合法な PHP のコードである。
-`https:` 部分はラベル、`//` 以降は行コメントになっている。
+----
+完全に合法な PHP のコードである。 `https:` 部分はラベル、`//`
+以降は行コメントになっている。
-### リテラルなしで数値を生成する
+==== リテラルなしで数値を生成する
ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。
PHP では、型変換を利用することで任意の整数を作り出すことができる。
-```php
+[source,php]
+----
assert(0 === +!![]);
assert(1 === +![]);
assert(2 === ![]+![]);
assert(3 === ![]+![]+![]);
assert(10 === +(![].+!![]));
-```
+----
`[]` に `!` を適用すると `true` が返ってくる。それに `+`
を適用すると、`bool` から `int` ヘの型変換が走り、`1` が生成される。`10`
@@ -201,32 +196,36 @@ assert(10 === +(![].+!![]));
への型変換が走り、`10` が生まれる (コード量に頓着しないなら、`1` を 10
個足し合わせてももちろん 10 が作れる)。
-また、`error_reporting` に指定しているのは `-1` である。
-これは、`!` によって文字列を `false` にし、`+` によって `false` を `0` にし、さらにビット反転して `-1` にしている。
-
+また、`error_reporting` に指定しているのは `-1` である。 これは、`!`
+によって文字列を `false` にし、`+` によって `false` を `0`
+にし、さらにビット反転して `-1` にしている。
-### `if` 文なしで条件分岐
+==== `if` 文なしで条件分岐
-三項演算子ないし `match` 式を使うことで、`if` を一切書かずに条件分岐ができる。
-また、`&&` / `||` も使えることがある。
-遅延評価が不要なケースでは、`[$t, $f][$cond]` のような形で分岐することもできる。
+三項演算子ないし `match` 式を使うことで、`if`
+を一切書かずに条件分岐ができる。 また、`&&` / `||` も使えることがある。
+遅延評価が不要なケースでは、`[$t, $f][$cond]`
+のような形で分岐することもできる。
-### `while`、`for` 文なしでループ
+==== `while`、`for` 文なしでループ
-不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。
-ここでは、一般に Z コンビネータとして知られるものを使った (`$z`)。
+不動点コンビネータを使って無名再帰する
+(詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に
+Z コンビネータとして知られるものを使った (`$z`)。
-実際のところ、`$🤡` や `$🎪`、`$🐘` は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。
+実際のところ、`$🤡` や `$🎪`、`$🐘` は、一度 Scheme (Lisp の一種)
+で書いてから PHP に翻訳する形で記述した。
-なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、
-あまりに長い brainf\*ck プログラムを書くとスタックオーバーフローする。
+なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは)
+ので、 あまりに長い brainf*ck
+プログラムを書くとスタックオーバーフローする。
-
-# 第2問 riddle.php
+== 第2問 riddle.php
ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。
-```php
+[source,php]
+----
<?php
/*********************************************************
@@ -261,77 +260,86 @@ foreach ($token as $x) {
$x = implode("\n", str_split($x, length: 5));
echo "{$x}\n\n";
}
-```
+----
さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。
-トークンを得るためには、ソースコードを読み、定数 `N` を特定する必要がある。
+トークンを得るためには、ソースコードを読み、定数 `N`
+を特定する必要がある。
ここでは、私の想定解を解説する。
-
-## 読解
+=== 読解
まずはソースコードを読んでいく。
-```php
+[source,php]
+----
$token = [
// 略
];
-```
+----
数値からなる `$token` があり、各要素をループしている。
-```php
+[source,php]
+----
$x = $x ^ N;
-```
+----
まずは排他的論理和 (xor) を取り、
-```php
+[source,php]
+----
$x = sprintf('%025b', $x);
-```
+----
二進数に変換して、
-```php
+[source,php]
+----
$x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);
-```
+----
0 を空白に、1 を `#` にし、
-```php
+[source,php]
+----
$x = implode("\n", str_split($x, length: 5));
-```
+----
5文字ごとに区切ったあと、改行で結合している。
-
-## ヒント
+=== ヒント
次に、ソースコードに書いてあるヒントを読んでいく。
-* `N` それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている
+* `N` それ自体は、42 や 8128
+といったような特別な意味を持たず、ランダムに決められている
* `$token` の各要素は、1文字を表す
* 1文字は 5x5 のセルからなる
* 出力されるのは、完全な PHPer トークンである
ここで、PHPer トークンは必ず `#` 記号から始まることを思いだすと、
-`$token` の最初の数字 `0x14B499C` は、変換の結果 `#` になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。
-
+`$token` の最初の数字 `0x14B499C` は、変換の結果 `#`
+になるのではないかと予想される (なお、このことは、リポジトリの README
+ファイルに追加ヒントとして書かれている)。
-## 解く
+=== 解く
-ここまでわかれば、あと一歩で解ける。すなわち、`0x14B499C` が `#` に変換されるような `N` を見つければよい。
+ここまでわかれば、あと一歩で解ける。すなわち、`0x14B499C` が `#`
+に変換されるような `N` を見つければよい。
`N` は高々
-```php
+[source,php]
+----
assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);
-```
+----
なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。
-```php
+[source,php]
+----
<?php
$x = 0x14B499C;
@@ -348,11 +356,12 @@ assert($x ===
" # # \n" .
"#####\n" .
" # # ");
-```
+----
この一連の変換に対する逆変換を考えると、次のようになる。
-```php
+[source,php]
+----
<?php
$x =
@@ -369,17 +378,16 @@ $x = bindec($x);
$n = $x ^ 0x14B499C;
echo "N = $n\n";
-```
+----
これを実行すると、`N` が得られる。
-
-
-# 第3問 toquine.php
+== 第3問 toquine.php
ソースコードはこちら。
-```php
+[source,php]
+----
<?php
// License: https://creativecommons.org/publicdomain/zero/1.0/
@@ -409,49 +417,49 @@ $t = null.false; for ($i = 0; $i <= intdiv(__LINE__-035,6); ++$i) if (!isset($xs
$t .= implode("\n", str_split(str_replace(['0','1'], [' ','##'], sprintf(chr(37) . '025b', $xs[$i])), 012)) . "\n\n";
$ws = array_map(fn($w) => implode(', ', $w), array_chunk(array_map(fn($x) => sprintf('0x' . chr(37) . '07X', $x), $xs), 10));
printf($s, $t, str_rot13("<<<'D'\n{$s}\nD"), implode(",\n", $ws));
-```
+----
コメントにもあるとおり、次のようにして実行すれば答えがでてくる。
-```shell-session
+[source,shell-session]
+----
$ php toquine.php | php | php | php | ...
-```
+----
実際にはもう少しパイプで繋げなければならない。
+=== 解説
-## 解説
-
-### プログラム全体
+==== プログラム全体
コメントにもあるとおり、これは quine (風) のプログラムになっている。
-Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。
+Quine
+とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。
このプログラムは、実行すると自身とほとんど同じプログラムを出力する。
異なるのはトークンになっている部分のみである。
+==== トークン
-### トークン
+`$xs` がトークンに対応している。変換のロジックは `riddle.php`
+とほぼ同じなので省略する。
-`$xs` がトークンに対応している。変換のロジックは `riddle.php` とほぼ同じなので省略する。
+==== 状態保持
+トークンの何文字目まで出力したかを、ソースコードを変えずに (quine
+なので) 覚えておく必要がある。
+このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、`__LINE__`
+から情報を取得している。
-### 状態保持
-
-トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。
-このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、`__LINE__` から情報を取得している。
-
-
-### ROT 13
+==== ROT 13
Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。
-これがあまり美しくないので、`toquine.php` では、ROT 13 変換を使って難読化した。
+これがあまり美しくないので、`toquine.php` では、ROT 13
+変換を使って難読化した。
それにしてもなぜこんなものが標準ライブラリに……。
-
-
-# おわりに
+== おわりに
解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。
diff --git a/content/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal.md b/content/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal.adoc
index 3e234fb..409f498 100644
--- a/content/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal.md
+++ b/content/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal.adoc
@@ -1,40 +1,34 @@
----
-title: "term-banner: ターミナルにバナーを表示するツールを書いた"
-date: 2022-04-24T13:22:52+09:00
-lastmod: 2022-04-27
-tags: ["my-programs"]
-summary: |
- ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。
-changelog:
- 2022-04-24: 公開
- 2022-04-27: -f オプションについて追記
----
+= term-banner: ターミナルにバナーを表示するツールを書いた
+:description: ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。
+:revision-1: 2022-04-24 公開
+:revision-2: 2022-04-27 -f オプションについて追記
-
-
-# はじめに
+== はじめに
こんなものを作った。
-```
+....
$ term-banner 'Hello, World!' 'こんにちは、' '世界!'
-```
+....
-![term-banner のスクリーンショット](https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png)
+image::https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png[term-banner
+のスクリーンショット]
コマンドライン引数として渡した文字列をターミナルに大きく表示する。
リポジトリはこちら: https://github.com/nsfisis/term-banner
+== Motivation
+以前、https://github.com/nsfisis/big-clock-mode[big-clock-mode]
+という似たようなプログラムを書いた。 これは tmux の `:clock-mode`
+コマンドに着想を得たもので、`:clock-mode`
+よりも大きく現在時刻を表示する。
-# Motivation
-
-以前、[big-clock-mode](https://github.com/nsfisis/big-clock-mode) という似たようなプログラムを書いた。
-これは tmux の `:clock-mode` コマンドに着想を得たもので、`:clock-mode` よりも大きく現在時刻を表示する。
-
-`big-clock-mode` を開発したのは、次のようなシチュエーションで使うためである。
-弊社では現在リモートワークが基本だが、web 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。
+`big-clock-mode`
+を開発したのは、次のようなシチュエーションで使うためである。
+弊社では現在リモートワークが基本だが、web
+会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。
こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。
それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。
@@ -45,35 +39,40 @@ $ term-banner 'Hello, World!' 'こんにちは、' '世界!'
そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。
まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。
-
-
-# プログラム
+== プログラム
全体の流れは次のようになっている。
-1. フォントファイルを読み込む
-1. コマンドライン引数を Shift-JIS に変換する (フォントが Shift-JIS 基準で並んでいるため)
-1. 1文字ずつレンダリングしていく
+[arabic]
+. フォントファイルを読み込む
+. コマンドライン引数を Shift-JIS に変換する (フォントが Shift-JIS
+基準で並んでいるため)
+. 1文字ずつレンダリングしていく
-`big-clock-mode` が Go 製なので、今回も Go で書いた。
-PNG が標準ライブラリにあったり、Shift-JIS のエンコーディングが準標準ライブラリにあったりしたのは助かった。
+`big-clock-mode` が Go 製なので、今回も Go で書いた。 PNG
+が標準ライブラリにあったり、Shift-JIS
+のエンコーディングが準標準ライブラリにあったりしたのは助かった。
-フォントファイルは `go:embed` で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。
+フォントファイルは `go:embed`
+で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。
仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。
+== フォント
-
-# フォント
-
-フリーの 8x8 ビットマップフォントである、[美咲フォント 2021-05-05a 版](https://littlelimit.net/misaki.htm) を使わせていただいた。
+フリーの 8x8
+ビットマップフォントである、https://littlelimit.net/misaki.htm[美咲フォント
+2021-05-05a 版] を使わせていただいた。
はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。
-同じく 8x8 で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。
+同じく 8x8
+で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。
-美咲フォントは、平仮名・片仮名に留まらず、JIS 第一・第二水準の漢字までサポートしている。
+美咲フォントは、平仮名・片仮名に留まらず、JIS
+第一・第二水準の漢字までサポートしている。
第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。
-さらに言うと、実のところ美咲フォントは実サイズ 7x7 で作られており、余白が設けられている。
+さらに言うと、実のところ美咲フォントは実サイズ 7x7
+で作られており、余白が設けられている。
これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。
おかげでコーディングまで楽になった。
@@ -82,8 +81,6 @@ PNG が標準ライブラリにあったり、Shift-JIS のエンコーディン
2022-04-27 追記: `-f` オプションで選べるようにした。
-
-
-# おわりに
+== おわりに
あなたもターミナルに住んでみませんか?
diff --git a/content/posts/2022-05-01/phperkaigi-2022.adoc b/content/posts/2022-05-01/phperkaigi-2022.adoc
new file mode 100644
index 0000000..863e30b
--- /dev/null
+++ b/content/posts/2022-05-01/phperkaigi-2022.adoc
@@ -0,0 +1,130 @@
+= PHPerKaigi 2022
+:tags: conference, php, phperkaigi
+:description: 2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。
+:revision-1: 2022-05-01 公開
+
+== はじめに
+
+2022-04-09 から 2022-04-11
+にかけて開催された、https://phperkaigi.jp/2022/[PHPerKaigi 2022]
+に、一般参加者として参加した。
+弊社https://www.dgcircus.com/[デジタルサーカス株式会社]
+はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。
+
+昨年のレポートはlink:/posts/2021-03-30/phperkaigi-2021[こちら]。
+
+== 感想
+
+=== 厳選おすすめトーク
+
+多くの素晴らしいトークの中から、特におすすめのものを
+5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。
+
+https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b[予防に勝る防御なし
+- 堅牢なコードを導く様々な設計のヒント]
+
+____
+PHP
+はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。
+
+本講演では PHP 8.1
+をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。
+____
+
+https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e[PHPのエラーを理解して適切なエラーハンドリングを学ぼう]
+
+____
+PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice
+理解していますか? +
+これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります! +
+またそれらを理解した上でのエラーハンドリングを学びましょう。
+____
+
+https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d[エラー監視とテスト体制への改善作戦]
+
+____
+毎日流れてくるエラーに皆さんはどう向き合ってますか? +
+エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。 +
+サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、 +
+エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。
+____
+
+https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7[ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか]
+
+____
+昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。
+
+最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には +
+・「(私の思う)良い設計」を実現するための意思決定 +
+・「ISUCONの問題」という位置付けに由来する取捨選択 +
+・移植中に遭遇したトラブルとその解決策 +
+といった文脈や葛藤が存在しています。
+
+本発表はそれらを共有することで +
+・PHPアプリケーションの設計、実装事例として役立ててもらう +
+・ISUCONの言語移植に興味を持ってもらう +
+・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう +
+ことを目的とします。
+____
+
+https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854[チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた]
+
+____
+サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。
+
+フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。
+
+このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。
+____
+
+=== トークン問題の作成
+
+今回は、PHPer チャレンジ用に弊社のトークン問題を
+3題作成した。こちらについてはlink:/posts/2022-04-09/phperkaigi-2022-tokens[別途記事にしている]ので、そちらを参照されたい。
+
+=== PHPer チャレンジ
+
+https://fortee.jp/phperkaigi-2022/challenge[1位]になった。 +
+また、賞品として https://www.amazon.co.jp/dp/B08MQNJC9Z[Echo Show 15]
+をいただいた。
+
+=== カンファレンス全体への感想
+
+link:/posts/2021-03-30/phperkaigi-2021[去年の参加レポ]
+では、こんなことを書いた。
+
+____
+1つ個人的な反省点としては、(中略) Discord
+しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。 +
+まあ初カンファレンスだし、とお茶を濁しておこう。
+____
+
+この反省を踏まえ、今年は積極的にほかの場 (公式の Discord
+サーバや、アンカンファレンス) にも参加した。 +
+これにより、参加体験の質がはるかに向上した。特に Discord
+に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる
+(ことが多い)
+ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。
+
+なお、アンカンファレンスについては、1日目の終わりにhttps://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e[トークン問題の解説放送]もおこなった。
+
+また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。
+今年は
+3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。
+
+== そして来年へ……?
+
+PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の
+4つを目標としたい。
+
+* プロポーザルを出す
+* PHPer チャレンジのトークン問題を 5題作成する
+* 現地に行く
+* PHPer チャレンジで圧勝する
+
+'''''
+
+最後になりましたが、PHPerKaigi
+のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。
+
+ではまた来年。
diff --git a/content/posts/2022-05-01/phperkaigi-2022.md b/content/posts/2022-05-01/phperkaigi-2022.md
deleted file mode 100644
index 8c9cdf2..0000000
--- a/content/posts/2022-05-01/phperkaigi-2022.md
+++ /dev/null
@@ -1,114 +0,0 @@
----
-title: "PHPerKaigi 2022"
-date: 2022-05-01T09:41:39+09:00
-tags: ["conference", "php", "phperkaigi"]
-summary: |
- 2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。
-changelog:
- 2022-05-01: 公開
----
-
-# はじめに
-
-2022-04-09 から 2022-04-11 にかけて開催された、[PHPerKaigi 2022](https://phperkaigi.jp/2022/) に、一般参加者として参加した。
-弊社[デジタルサーカス株式会社](https://www.dgcircus.com/) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。
-
-昨年のレポートは[こちら](/posts/2021-03-30/phperkaigi-2021)。
-
-
-
-# 感想
-
-## 厳選おすすめトーク
-
-多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。
-
-[予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント](https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b)
-
-> PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。
->
-> 本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。
-
-[PHPのエラーを理解して適切なエラーハンドリングを学ぼう](https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e)
-
-> PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか?
-> これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!
-> またそれらを理解した上でのエラーハンドリングを学びましょう。
-
-[エラー監視とテスト体制への改善作戦](https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d)
-
-> 毎日流れてくるエラーに皆さんはどう向き合ってますか?
-> エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。
-> サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、
-> エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。
-
-[ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか](https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7)
-
-> 昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。
->
-> 最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には
-> ・「(私の思う)良い設計」を実現するための意思決定
-> ・「ISUCONの問題」という位置付けに由来する取捨選択
-> ・移植中に遭遇したトラブルとその解決策
-> といった文脈や葛藤が存在しています。
->
-> 本発表はそれらを共有することで
-> ・PHPアプリケーションの設計、実装事例として役立ててもらう
-> ・ISUCONの言語移植に興味を持ってもらう
-> ・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう
-> ことを目的とします。
-
-[チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた](https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854)
-
-> サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。
->
-> フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。
->
-> このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。
-
-
-
-## トークン問題の作成
-
-今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては[別途記事にしている](/posts/2022-04-09/phperkaigi-2022-tokens)ので、そちらを参照されたい。
-
-
-
-## PHPer チャレンジ
-
-[1位](https://fortee.jp/phperkaigi-2022/challenge)になった。
-また、賞品として [Echo Show 15](https://www.amazon.co.jp/dp/B08MQNJC9Z) をいただいた。
-
-
-
-## カンファレンス全体への感想
-
-[去年の参加レポ](/posts/2021-03-30/phperkaigi-2021) では、こんなことを書いた。
-
-> 1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。
-> まあ初カンファレンスだし、とお茶を濁しておこう。
-
-この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。
-これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。
-
-なお、アンカンファレンスについては、1日目の終わりに[トークン問題の解説放送](https://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e)もおこなった。
-
-また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。
-今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。
-
-
-
-# そして来年へ……?
-
-PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。
-
-* プロポーザルを出す
-* PHPer チャレンジのトークン問題を 5題作成する
-* 現地に行く
-* PHPer チャレンジで圧勝する
-
---------------------------------------------------------------------------------
-
-最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。
-
-ではまた来年。
diff --git a/content/posts/2022-08-27/php-conference-okinawa-code-golf.adoc b/content/posts/2022-08-27/php-conference-okinawa-code-golf.adoc
new file mode 100644
index 0000000..86e3080
--- /dev/null
+++ b/content/posts/2022-08-27/php-conference-okinawa-code-golf.adoc
@@ -0,0 +1,91 @@
+= PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた
+:tags: conference, php, phpcon
+:description: PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。
+:revision-1: 2022-08-27 公開
+
+== はじめに
+
+本日 https://phpcon.okinawa.jp/[PHP カンファレンス沖縄 2022]
+が開催された (らしい)。
+
+カンファレンスには参加できなかったものの、懇親会の LT
+で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。
+
+ツイート: https://twitter.com/m3m0r7/status/1563397620231712772 +
+スライド:
+https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3
+
+== 解
+
+細かいレギュレーションは不明だったので、勝手に定めた。
+
+* コマンドライン引数の第1引数で受けとる
+* 結果は標準出力に出す
+* コンマの直後にはスペースを1つ置く
+* 末尾コンマは禁止
+* 数字でないものは入ってこないものとする
+* 負数は入ってこないものとする
+
+書いたものがこちら:
+
+[source,php]
+----
+[<?php $n=$argv[1];foreach([1e4,5e3,2e3,1e3,500,100,50,10,5,1]as$x)for(;$n>=$x;$n-=$x)$r[]=$x;echo implode(', ',$r??[]);?>]
+----
+
+しめて 123 バイトとなった (末尾改行を含めずにカウント)。
+
+こちらは改行とスペースを追加したバージョン:
+
+[source,php]
+----
+[<?php
+
+$n = $argv[1];
+foreach ([1e4, 5e3, 2e3, 1e3, 500, 100, 50, 10, 5, 1] as $x)
+ for (; $n >= $x; $n -= $x)
+ $r[] = $x;
+echo implode(', ', $r ?? []);
+
+?>]
+----
+
+== 使用したテクニック
+
+=== 指数表記
+
+割と多くの言語のゴルフで使えるテクニック。`e`
+を用いた指数表記で、大きな数を短く表す。このコードでは
+`10000`、`5000`、`2000`、`1000` を指数表記している。
+
+=== foreach や for の中身を1つの文に
+
+`foreach`、`for`、`if` などの後ろには、通常 `{`
+を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、`{` と `}`
+を省略できる。C言語などでも使える。
+
+=== $r に初期値を入れない
+
+PHP では、`$r[] = ...`
+のような配列の末尾に追加する式を実行したとき、`$r` が未定義だった場合は
+`$r`
+を勝手に定義して空の配列で初期化してくれる。これを利用すると、`$r = [];`
+のような初期化が不要になる。
+
+ただし、プログラムに 0 が渡されるとループを一度も回らないので、`$r`
+が未定義になってしまい、`implode()`
+に渡すところでエラーになる。それを防ぐために `$r ?? []` を使っている。
+
+もし 0 が渡されたケースを無視するなら、これが不要になるので 4
+バイト縮む。
+
+=== PHP タグの外に文字列を置く
+
+PHP では、`<?php` `?>`
+で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず
+`[` と `]` を出力するので、そのまま書いてやればよい。
+
+== おわりに
+
+最後になりましたが、https://twitter.com/m3m0r7[めもりー]
+さん、楽しい問題をありがとうございました。
diff --git a/content/posts/2022-08-27/php-conference-okinawa-code-golf.md b/content/posts/2022-08-27/php-conference-okinawa-code-golf.md
deleted file mode 100644
index 6042b65..0000000
--- a/content/posts/2022-08-27/php-conference-okinawa-code-golf.md
+++ /dev/null
@@ -1,79 +0,0 @@
----
-title: "PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた"
-date: 2022-08-27T18:55:28+09:00
-tags: ["conference", "php", "phpcon"]
-summary: |
- PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。
-changelog:
- 2022-08-27: 公開
----
-
-# はじめに
-
-本日 [PHP カンファレンス沖縄 2022](https://phpcon.okinawa.jp/) が開催された (らしい)。
-
-カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。
-
-ツイート: https://twitter.com/m3m0r7/status/1563397620231712772 \
-スライド: https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3
-
-
-# 解
-
-細かいレギュレーションは不明だったので、勝手に定めた。
-
-* コマンドライン引数の第1引数で受けとる
-* 結果は標準出力に出す
-* コンマの直後にはスペースを1つ置く
-* 末尾コンマは禁止
-* 数字でないものは入ってこないものとする
-* 負数は入ってこないものとする
-
-書いたものがこちら:
-
-```php
-[<?php $n=$argv[1];foreach([1e4,5e3,2e3,1e3,500,100,50,10,5,1]as$x)for(;$n>=$x;$n-=$x)$r[]=$x;echo implode(', ',$r??[]);?>]
-```
-
-しめて 123 バイトとなった (末尾改行を含めずにカウント)。
-
-こちらは改行とスペースを追加したバージョン:
-
-```php
-[<?php
-
-$n = $argv[1];
-foreach ([1e4, 5e3, 2e3, 1e3, 500, 100, 50, 10, 5, 1] as $x)
- for (; $n >= $x; $n -= $x)
- $r[] = $x;
-echo implode(', ', $r ?? []);
-
-?>]
-```
-
-# 使用したテクニック
-
-## 指数表記
-
-割と多くの言語のゴルフで使えるテクニック。`e` を用いた指数表記で、大きな数を短く表す。このコードでは `10000`、`5000`、`2000`、`1000` を指数表記している。
-
-## foreach や for の中身を1つの文に
-
-`foreach`、`for`、`if` などの後ろには、通常 `{` を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、`{` と `}` を省略できる。C言語などでも使える。
-
-## $r に初期値を入れない
-
-PHP では、`$r[] = ...` のような配列の末尾に追加する式を実行したとき、`$r` が未定義だった場合は `$r` を勝手に定義して空の配列で初期化してくれる。これを利用すると、`$r = [];` のような初期化が不要になる。
-
-ただし、プログラムに 0 が渡されるとループを一度も回らないので、`$r` が未定義になってしまい、`implode()` に渡すところでエラーになる。それを防ぐために `$r ?? []` を使っている。
-
-もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。
-
-## PHP タグの外に文字列を置く
-
-PHP では、`<?php` `?>` で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず `[` と `]` を出力するので、そのまま書いてやればよい。
-
-
-# おわりに
-
-最後になりましたが、[めもりー](https://twitter.com/m3m0r7) さん、楽しい問題をありがとうございました。
diff --git a/content/posts/2022-08-31/support-for-communty-is-employee-benefits.adoc b/content/posts/2022-08-31/support-for-communty-is-employee-benefits.adoc
new file mode 100644
index 0000000..ba24d8c
--- /dev/null
+++ b/content/posts/2022-08-31/support-for-communty-is-employee-benefits.adoc
@@ -0,0 +1,46 @@
+= 弊社の PHP Foundation への寄付に寄せて
+:description: 先日、私の勤めるデジタルサーカス株式会社が、PHP Foundation へ寄付をおこないました。 \
+ 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。
+:revision-1: 2022-08-31 公開
+
+== はじめに
+
+*注:
+これは私個人の意見であり、所属する組織を代表するものではありません。*
+
+先日、私の勤める https://www.dgcircus.com/[デジタルサーカス株式会社] が
+https://opencollective.com/phpfoundation[PHP Foundation] へ $2,000
+の寄付をおこないました。
+
+記事: https://www.dgcircus.com/news/581
+
+本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。
+
+== なぜ?
+
+組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。
+
+当時の考えを端的にまとめた社内チャットの投稿があったので、それを引用します:
+
+____
+結局これを通したい (私の中での)
+最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、寄付の報告が流れてきたり、OSS
+のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか
+(これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。
+
+追記: 「肩身が狭くなる」というのがより適切でした。
+____
+
+※文中の「↑にしても」は、ここに載せていない別の投稿を指しています。
+
+OSS を金銭的に支援したり、技術カンファレンスへ協賛したり (あるいは
+https://twitter.com/tomzoh[CTO] がカンファレンスを年2で主催したり:
+https://iosdc.jp[iOSDC] https://phperkaigi.jp[PHPerKaigi])
+といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう
+(知らんけど)。これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。
+
+以上が、私が社内で寄付の件を進めた (かなり私的な) 理由です。
+
+== おわりに
+
+最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。この場を借りて感謝申し上げます。
diff --git a/content/posts/2022-08-31/support-for-communty-is-employee-benefits.md b/content/posts/2022-08-31/support-for-communty-is-employee-benefits.md
deleted file mode 100644
index fe23141..0000000
--- a/content/posts/2022-08-31/support-for-communty-is-employee-benefits.md
+++ /dev/null
@@ -1,47 +0,0 @@
----
-title: "弊社の PHP Foundation への寄付に寄せて"
-date: 2022-08-31T22:25:02+09:00
-draft: false
-tags: []
-summary: |
- 先日、私の勤めるデジタルサーカス株式会社が、PHP Foundation へ寄付をおこないました。
- 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。
-changelog:
- 2022-08-31: 公開
----
-
-
-
-# はじめに
-
-**注: これは私個人の意見であり、所属する組織を代表するものではありません。**
-
-先日、私の勤める [デジタルサーカス株式会社](https://www.dgcircus.com/) が [PHP Foundation](https://opencollective.com/phpfoundation) へ $2,000 の寄付をおこないました。
-
-記事: https://www.dgcircus.com/news/581
-
-本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。
-
-
-
-# なぜ?
-
-組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。
-
-当時の考えを端的にまとめた社内チャットの投稿があったので、それを引用します:
-
-> 結局これを通したい (私の中での) 最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、寄付の報告が流れてきたり、OSS のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか (これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。
->
-> 追記: 「肩身が狭くなる」というのがより適切でした。
-
-※文中の「↑にしても」は、ここに載せていない別の投稿を指しています。
-
-OSS を金銭的に支援したり、技術カンファレンスへ協賛したり (あるいは [CTO](https://twitter.com/tomzoh) がカンファレンスを年2で主催したり: [iOSDC](https://iosdc.jp) [PHPerKaigi](https://phperkaigi.jp)) といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう (知らんけど)。これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。
-
-以上が、私が社内で寄付の件を進めた (かなり私的な) 理由です。
-
-
-
-# おわりに
-
-最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。この場を借りて感謝申し上げます。
diff --git a/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.adoc b/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.adoc
new file mode 100644
index 0000000..247f9c1
--- /dev/null
+++ b/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.adoc
@@ -0,0 +1,624 @@
+= [PHP] fizzbuzz を書く。1行あたり2文字で。
+:tags: php
+:description: PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。
+:revision-1: 2022-09-28 公開
+:revision-2: 2022-09-29 小さな文言の修正・変更
+
+== 記事の構成について
+
+この記事は、普通の fizzbuzz
+を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、
+https://gist.github.com/nsfisis/04c227d5a419867472a0b23a83ad2919#file-fizzbuzz-php-2-letters-per-line-and-supports-php-8-x-without-warnings[このページ]
+にソースコードがあるので、そちらを先に見てほしい。
+
+== レギュレーション
+
+PHP で、次のような制約の下に fizzbuzz を書いた。
+
+* 1行あたりの文字数は2文字までに収めること (ただし `<?php` タグは除く)
+** 厳密な定義: `<?php` タグ以降のソースコードが、2 byte ごとに
+ラインフィード (LF) で区切られること
+* スペースやタブを使用しないこと
+* ループのアンロールをしないこと
+** 100 回ループの代わりに 100 回コードをコピペ、というのは禁止
+* PHP 7.4〜8.1 で動作すること
+* 実行時に Notice や Warning が出ないこと
+* 標準的なインストール構成の PHP で実現できること
+(デフォルトで有効になっていない拡張等を使わないこと)
+
+備考: PHP には `short_open_tag`
+というオプションがあり、これを有効にするとファイル冒頭の `<?php`
+の代わりに `<?`
+を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト
+off になっている環境が多いようなので、今回は使わないことにした。
+
+== 主な障害
+
+1行あたりの文字数など、適当に改行を挟めばいいだけではないのか?
+
+特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。
+
+[source,c]
+----
+#\
+i\
+n\
+c\
+l\
+u\
+d\
+e\
+<\
+s\
+t\
+d\
+i\
+o\
+.\
+h\
+>\
+/*
+*/
+i\
+n\
+t\
+/*
+*/
+m\
+a\
+i\
+n(
+){
+f\
+o\
+r(
+i\
+n\
+t\
+/*
+*/
+i=
+1;
+i<
+1\
+0\
+0;
+i\
++\
++)
+if
+(i
+%\
+15
+==
+0)
+p\
+r\
+i\
+n\
+t\
+f(
+"\
+F\
+i\
+z\
+z\
+B\
+u\
+z\
+z\
+%\
+c\
+",
+10
+);
+
+/* あとは同じように普通のプログラムを変形するだけなので省略 */
+----
+
+バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。
+
+さて、PHP
+ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、`echo`
+で出力することや、`for` でループすること、`new`
+でインスタンスを生成することができない。特に、出力は fizzbuzz
+をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。
+
+当然、名前が3文字以上ある関数も使えない。なお、標準 PHP
+の範囲内において、名前が 2文字以下の関数は以下のとおりである:
+
+* `_`: `gettext` のエイリアス
+* `dl`: 拡張モジュールをロードする
+* `pi`: 円周率を返す
+
+(環境によって多少は変わるかも)
+
+2文字の関数を定義しまくった拡張モジュールを用意しておいて `dl()`
+で読み込む行為は、レギュレーションで定めた
+
+____
+* 標準的なインストール構成の PHP で実現できること
+(デフォルトで有効になっていない拡張等を使わないこと)
+____
+
+に反する
+(というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。
+
+また、2文字だと文字列がまともに書けないのも辛い。`''` だけで
+2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP
+では文字列リテラル中に生の改行が書けるので
+
+[source,php]
+----
+$a
+='
+a'
+;;
+----
+
+とすると `$a` は `"\na"` になるのだが、余計な改行が入ってしまう。
+
+これらの障害をどのように乗り越えるのか、次節から見ていく。
+
+== 解説
+
+=== 普通の (?) fizzbuzz
+
+まずは普通に書くとしよう。
+
+....
+<?php
+
+for ($i = 1; $i < 100; $i++) {
+ echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n";
+}
+....
+
+素直に書いた fizzbuzz
+とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。
+
+=== `for` の排除
+
+`for`
+は、3文字もある長いキーワードである。こんなものは使えない。`array_`
+系の関数を使って、適当に置き換えるとしよう。
+
+[source,php]
+----
+<?php
+
+$s = range(1, 100);
+array_walk(
+ $s,
+ fn($i) =>
+ printf((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"),
+);
+----
+
+`array_walk` や `range`、`printf` といった `for`
+よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、`echo`
+は文 (statement) であり式 (expression) ではないので、式である `printf`
+に置き換えた。
+
+=== 関数呼び出しの短縮
+
+`range`、`array_walk`、`printf`
+は長すぎるのでどうにかせねばならない。ここで、PHP
+の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。
+
+[source,php]
+----
+<?php
+
+$r = 'range';
+$w = 'array_walk';
+$p = 'printf';
+
+$s = $r(1, 100);
+$w(
+ $s,
+ fn($i) =>
+ $p((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"),
+);
+----
+
+これで関数を呼び出している所は短くなった。では、`$r` や `$w` や
+`$p`、また `'Fizz'` や `'Buzz'` はどうやって
+1行2文字に収めるのか。次のテクニックへ移ろう。
+
+=== 余談: PHP 8.x で動作しなくてもいいなら
+
+今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。
+
+____
+* PHP 7.4〜8.1 で動作すること
+____
+
+というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という
+PHP 7.x までの仕様が利用できる。例えば、 `Fizz`
+という文字列が欲しければ、次のようにする。
+
+[source,php]
+----
+$f
+=F
+.i
+.z
+.z
+;;
+----
+
+こうして簡単に文字列を作れる。なお、この仕様は 7.x
+時点でも警告を受けるので、`@` 演算子を使って抑制してやるとよい。
+
+[source,php]
+----
+$f
+=@
+F.
+@i
+.#
+@z
+.#
+@z
+;;
+----
+
+むしろ、このことがわかっていたからこそ PHP 8.x
+での動作を要件に課したところがある。
+
+=== 文字列リテラルの短縮
+
+実際に使った手法の説明に移る。
+
+ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算
+(`&`、`|`、`^`)
+をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。
+
+[source,php]
+----
+$a = "12345";
+$b = "world";
+
+// $a ^ $b は次のコードと同じ
+$result = '';
+for ($i = 0; $i < min(strlen($a), strlen($b)); $i++) {
+ $result .= $a[$i] ^ $b[$i];
+}
+
+echo $result;
+// => F]AXQ
+----
+
+これを踏まえ、次のコードを見てみよう。
+
+[source,php]
+----
+$x = "x\nOm\n";
+$y = "\nk!\no";
+$r = $x ^ $y;
+echo "$r\n";
+----
+
+実行すると、`range` が表示される。さて、PHP
+では文字列リテラル中に生の改行を直接書いてもよいのだった
+(「主な障害」の節を参照のこと)。書きかえてみよう。
+
+[source,php]
+----
+$x
+='x
+Om
+';
+$y
+='
+k!
+o'
+;
+
+$r = $x ^ $y;
+echo "$r\n";
+----
+
+さらに `#` を使って適当に調整すると、次のようになる。
+
+[source,php]
+----
+$x
+=#
+'x
+Om
+';
+$y
+='
+k!
+o'
+;#
+$r
+=#
+$x
+^#
+$y
+;#
+
+echo "$r\n";
+----
+
+1行あたり2文字で、`range`
+という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。
+
+備考: `Buzz` 中にある小文字の `u` は、このロジックだと non-printable
+な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。
+
+== 完成系
+
+完成したものがこちら。
+
+[source,php]
+----
+<?php
+
+$x
+=#
+'i
+S'
+;;
+$y
+='
+b!
+';
+$c
+=#
+$x
+^#
+$y
+;#
+$x
+=#
+'x
+Om
+';
+$y
+='
+k!
+o'
+;#
+$r
+=#
+$x
+^#
+$y
+;#
+$x
+=#
+'k
+Sk
+~}
+Ma
+';
+$y
+='
+x!
+s!
+k!
+';
+$w
+=#
+$x
+^#
+$y
+;#
+$x
+=#
+'z
+Hd
+G'
+;#
+$y
+='
+x!
+~!
+';
+$p
+=#
+$x
+^#
+$y
+;#
+$x
+=#
+'L
+[p
+';
+$y
+='
+c!
+';
+$f
+=#
+$x
+^#
+$y
+;#
+$x
+=#
+'H
+[p
+';
+$y
+='
+_!
+';
+$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
+)#
+.'
+')
+);
+----
+
+== 感想など
+
+PHP は、スクリプト言語の中だとシンタックスシュガーが少ない
+(体感)。この挑戦は不可能に思われたが、PHP
+マニュアルとにらめっこしていたらなんとかなった。
+
+みんなもプログラムを細長くしよう。
+
+== 余談2: 別解
+
+PHP では、バッククォートを使ってシェルを呼び出せる。これは `shell_exec`
+関数と等価である。さて、PHP
+ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える
+(当然だが、呼び出されるシェルに依存する。Bash
+なら大丈夫だろう。知らんけど)。
+
+[source,php]
+----
+<?php
+
+printf(`
+e\
+c\
+h\
+o\
+ \
+1\
+2\
+3\
+`);
+----
+
+なお、ここでは簡単のため出力に `printf` をそのまま使っているが、実際には
+`printf` という文字列を合成して可変関数で呼び出す。
+
+ただし、これでは
+
+____
+* スペースやタブを使用しないこと
+____
+
+に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。
+
+もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。
+
+[source,php]
+----
+<?php
+
+$c = 'chr';
+
+${
+'_
+'}
+=#
+$c
+(#
+32
+).
+$c
+(#
+92
+);
+
+printf(`
+e\
+c\
+h\
+o\
+${
+'_
+'}
+1\
+2\
+3\
+`);
+----
+
+先程と同じく、`chr` や `printf` を生成する部分は長くなるので省いた。
+
+....
+${
+'_
+'}
+....
+
+は変数で、中にはスペースとエスケープが入っている
+(`chr(32) . chr(92)`)。シェルに渡されている文字列は次のようになる。
+
+....
+e\
+c\
+h\
+o\
+ \
+1\
+2\
+3\
+....
+
+これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz
+のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう
+(試してないけど)。
+
+ということでこれは別解ということにしておく。
+
+ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。
+
+....
+${
+'_
+'}
+....
+
+最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。
diff --git a/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.md b/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.md
deleted file mode 100644
index 377840d..0000000
--- a/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.md
+++ /dev/null
@@ -1,577 +0,0 @@
----
-title: "[PHP] fizzbuzz を書く。1行あたり2文字で。"
-date: 2022-09-29T00:50:52+09:00
-tags: ["php"]
-summary: |
- PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。
-changelog:
- 2022-09-28: 公開
- 2022-09-29: 小さな文言の修正・変更
----
-
-# 記事の構成について
-
-この記事は、普通の fizzbuzz を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、 [このページ](https://gist.github.com/nsfisis/04c227d5a419867472a0b23a83ad2919#file-fizzbuzz-php-2-letters-per-line-and-supports-php-8-x-without-warnings) にソースコードがあるので、そちらを先に見てほしい。
-
-
-
-# レギュレーション
-
-PHP で、次のような制約の下に fizzbuzz を書いた。
-
-* 1行あたりの文字数は2文字までに収めること (ただし `<?php` タグは除く)
- * 厳密な定義: `<?php` タグ以降のソースコードが、2 byte ごとに ラインフィード (LF) で区切られること
-* スペースやタブを使用しないこと
-* ループのアンロールをしないこと
- * 100 回ループの代わりに 100 回コードをコピペ、というのは禁止
-* PHP 7.4〜8.1 で動作すること
-* 実行時に Notice や Warning が出ないこと
-* 標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)
-
-備考: PHP には `short_open_tag` というオプションがあり、これを有効にするとファイル冒頭の `<?php` の代わりに `<?` を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト off になっている環境が多いようなので、今回は使わないことにした。
-
-
-
-# 主な障害
-
-1行あたりの文字数など、適当に改行を挟めばいいだけではないのか?
-
-特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。
-
-```c
-#\
-i\
-n\
-c\
-l\
-u\
-d\
-e\
-<\
-s\
-t\
-d\
-i\
-o\
-.\
-h\
->\
-/*
-*/
-i\
-n\
-t\
-/*
-*/
-m\
-a\
-i\
-n(
-){
-f\
-o\
-r(
-i\
-n\
-t\
-/*
-*/
-i=
-1;
-i<
-1\
-0\
-0;
-i\
-+\
-+)
-if
-(i
-%\
-15
-==
-0)
-p\
-r\
-i\
-n\
-t\
-f(
-"\
-F\
-i\
-z\
-z\
-B\
-u\
-z\
-z\
-%\
-c\
-",
-10
-);
-
-/* あとは同じように普通のプログラムを変形するだけなので省略 */
-```
-
-バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。
-
-さて、PHP ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、`echo` で出力することや、`for` でループすること、`new` でインスタンスを生成することができない。特に、出力は fizzbuzz をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。
-
-当然、名前が3文字以上ある関数も使えない。なお、標準 PHP の範囲内において、名前が 2文字以下の関数は以下のとおりである:
-
-* `_`: `gettext` のエイリアス
-* `dl`: 拡張モジュールをロードする
-* `pi`: 円周率を返す
-
-(環境によって多少は変わるかも)
-
-2文字の関数を定義しまくった拡張モジュールを用意しておいて `dl()` で読み込む行為は、レギュレーションで定めた
-
-> * 標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)
-
-に反する (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。
-
-また、2文字だと文字列がまともに書けないのも辛い。`''` だけで 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので
-
-```php
-$a
-='
-a'
-;;
-```
-
-とすると `$a` は `"\na"` になるのだが、余計な改行が入ってしまう。
-
-これらの障害をどのように乗り越えるのか、次節から見ていく。
-
-
-
-# 解説
-
-## 普通の (?) fizzbuzz
-
-まずは普通に書くとしよう。
-
-```
-<?php
-
-for ($i = 1; $i < 100; $i++) {
- echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n";
-}
-```
-
-素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。
-
-
-## `for` の排除
-
-`for` は、3文字もある長いキーワードである。こんなものは使えない。`array_` 系の関数を使って、適当に置き換えるとしよう。
-
-```php
-<?php
-
-$s = range(1, 100);
-array_walk(
- $s,
- fn($i) =>
- printf((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"),
-);
-```
-
-`array_walk` や `range`、`printf` といった `for` よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、`echo` は文 (statement) であり式 (expression) ではないので、式である `printf` に置き換えた。
-
-
-## 関数呼び出しの短縮
-
-`range`、`array_walk`、`printf` は長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。
-
-```php
-<?php
-
-$r = 'range';
-$w = 'array_walk';
-$p = 'printf';
-
-$s = $r(1, 100);
-$w(
- $s,
- fn($i) =>
- $p((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"),
-);
-```
-
-これで関数を呼び出している所は短くなった。では、`$r` や `$w` や `$p`、また `'Fizz'` や `'Buzz'` はどうやって 1行2文字に収めるのか。次のテクニックへ移ろう。
-
-
-## 余談: PHP 8.x で動作しなくてもいいなら
-
-今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。
-
-> * PHP 7.4〜8.1 で動作すること
-
-というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、 `Fizz` という文字列が欲しければ、次のようにする。
-
-```php
-$f
-=F
-.i
-.z
-.z
-;;
-```
-
-こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、`@` 演算子を使って抑制してやるとよい。
-
-```php
-$f
-=@
-F.
-@i
-.#
-@z
-.#
-@z
-;;
-```
-
-むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。
-
-
-## 文字列リテラルの短縮
-
-実際に使った手法の説明に移る。
-
-ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (`&`、`|`、`^`) をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。
-
-```php
-$a = "12345";
-$b = "world";
-
-// $a ^ $b は次のコードと同じ
-$result = '';
-for ($i = 0; $i < min(strlen($a), strlen($b)); $i++) {
- $result .= $a[$i] ^ $b[$i];
-}
-
-echo $result;
-// => F]AXQ
-```
-
-これを踏まえ、次のコードを見てみよう。
-
-```php
-$x = "x\nOm\n";
-$y = "\nk!\no";
-$r = $x ^ $y;
-echo "$r\n";
-```
-
-実行すると、`range` が表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。
-
-```php
-$x
-='x
-Om
-';
-$y
-='
-k!
-o'
-;
-
-$r = $x ^ $y;
-echo "$r\n";
-```
-
-さらに `#` を使って適当に調整すると、次のようになる。
-
-```php
-$x
-=#
-'x
-Om
-';
-$y
-='
-k!
-o'
-;#
-$r
-=#
-$x
-^#
-$y
-;#
-
-echo "$r\n";
-```
-
-1行あたり2文字で、`range` という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。
-
-
-備考: `Buzz` 中にある小文字の `u` は、このロジックだと non-printable な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。
-
-
-
-# 完成系
-
-完成したものがこちら。
-
-```php
-<?php
-
-$x
-=#
-'i
-S'
-;;
-$y
-='
-b!
-';
-$c
-=#
-$x
-^#
-$y
-;#
-$x
-=#
-'x
-Om
-';
-$y
-='
-k!
-o'
-;#
-$r
-=#
-$x
-^#
-$y
-;#
-$x
-=#
-'k
-Sk
-~}
-Ma
-';
-$y
-='
-x!
-s!
-k!
-';
-$w
-=#
-$x
-^#
-$y
-;#
-$x
-=#
-'z
-Hd
-G'
-;#
-$y
-='
-x!
-~!
-';
-$p
-=#
-$x
-^#
-$y
-;#
-$x
-=#
-'L
-[p
-';
-$y
-='
-c!
-';
-$f
-=#
-$x
-^#
-$y
-;#
-$x
-=#
-'H
-[p
-';
-$y
-='
-_!
-';
-$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
-)#
-.'
-')
-);
-```
-
-
-
-# 感想など
-
-PHP は、スクリプト言語の中だとシンタックスシュガーが少ない (体感)。この挑戦は不可能に思われたが、PHP マニュアルとにらめっこしていたらなんとかなった。
-
-みんなもプログラムを細長くしよう。
-
-
-# 余談2: 別解
-
-PHP では、バッククォートを使ってシェルを呼び出せる。これは `shell_exec` 関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。
-
-```php
-<?php
-
-printf(`
-e\
-c\
-h\
-o\
- \
-1\
-2\
-3\
-`);
-```
-
-なお、ここでは簡単のため出力に `printf` をそのまま使っているが、実際には `printf` という文字列を合成して可変関数で呼び出す。
-
-ただし、これでは
-
-> * スペースやタブを使用しないこと
-
-に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。
-
-もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。
-
-```php
-<?php
-
-$c = 'chr';
-
-${
-'_
-'}
-=#
-$c
-(#
-32
-).
-$c
-(#
-92
-);
-
-printf(`
-e\
-c\
-h\
-o\
-${
-'_
-'}
-1\
-2\
-3\
-`);
-```
-
-先程と同じく、`chr` や `printf` を生成する部分は長くなるので省いた。
-
-```
-${
-'_
-'}
-```
-
-は変数で、中にはスペースとエスケープが入っている (`chr(32) . chr(92)`)。シェルに渡されている文字列は次のようになる。
-
-```
-e\
-c\
-h\
-o\
- \
-1\
-2\
-3\
-```
-
-これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。
-
-ということでこれは別解ということにしておく。
-
-ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。
-
-```
-${
-'_
-'}
-```
-
-最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。
diff --git a/content/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1.adoc b/content/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1.adoc
new file mode 100644
index 0000000..d9be116
--- /dev/null
+++ b/content/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1.adoc
@@ -0,0 +1,157 @@
+= PHPerKaigi 2023: ボツになったトークン問題 その 1
+:tags: php, phperkaigi
+:description: 来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、 \
+ ボツになった問題を公開する (その 1)。
+:revision-1: 2022-10-23 公開
+
+== はじめに
+
+2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点)
+の、 https://phperkaigi.jp/2023/[PHPerKaigi 2023]
+において、昨年と同様に、弊社 https://www.dgcircus.com/[デジタルサーカス株式会社]
+から、トークン問題を出題予定である。
+
+昨年のトークン問題の記事はこちら:
+link:/posts/2022-04-09/phperkaigi-2022-tokens[PHPerKaigi 2022
+トークン問題の解説]
+
+すでに 2023
+年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi
+開催を待つ間に紹介しようと思う。
+
+10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。
+
+== 問題
+
+注意: これはボツ問なので、得られたトークンを PHPerKaigi
+で入力してもポイントにはならない。
+
+[source,php]
+----
+<?php
+
+$π = $argv[1] ?? null;
+if ($π === null) {
+ exit('No input.');
+}
+$π = trim($π);
+if (!is_numeric($π)) {
+ exit('Invalid input.');
+}
+
+$s = implode(array_map(chr(...), str_split($π, 2)));
+
+preg_match('/(\x23.+?) /', $s, $m);
+$t = $m[1] ?? '';
+
+if (md5($t) === '056e831a4146bf123e8ea16613303d2e') {
+ echo "Token: {$t}\n";
+} else {
+ echo "Failed.\n";
+}
+----
+
+== トークン入手方法
+
+ソースを見るとわかるとおり、`$argv[1]` を参照している。それを `$π`
+なる変数に代入しているので、円周率を渡してみる。
+
+[source,shell-session]
+----
+$ php Q.php 3.14
+Failed.
+----
+
+失敗してしまった。精度を上げてみる。
+
+[source,shell-session]
+----
+$ php Q.php 3.1415
+Failed.
+----
+
+だめだった。これを成功するまで繰り返す。
+
+最初にトークンが得られるのは、小数点以下 16
+桁目まで入力したときで、こうなる。
+
+[source,shell-session]
+----
+$ php Q.php 3.1415926535897932
+Token: #YO
+----
+
+めでたくトークン「#YO」が手に入った。
+
+== 解説
+
+短いので頭から追っていく。
+
+[source,php]
+----
+$π = $argv[1] ?? null;
+if ($π === null) {
+ exit('No input.');
+}
+$π = trim($π);
+if (!is_numeric($π)) {
+ exit('Invalid input.');
+}
+----
+
+入力のバリデーション部分。数値のみ受け付ける。
+
+[source,php]
+----
+$s = implode(array_map(chr(...), str_split($π, 2)));
+----
+
+`$π` を 2 文字ごとに区切り (`str_split`)、数値を ASCII
+コードと見做して文字に変換 (`chr`) して結合 (`implode`) している。
+
+例えば、`$π` が `'656667'` だったとすると、`65`、`66`、`67` に対応した
+`'A'`、`'B'`、`'C'` へと変換され、`'ABC'` になる。
+
+[source,php]
+----
+$π = '656667';
+$s = implode(array_map(chr(...), str_split($π, 2)));
+echo $s;
+// => ABC
+----
+
+[source,php]
+----
+preg_match('/(\x23.+?) /', $s, $m);
+$t = $m[1] ?? '';
+----
+
+正規表現でマッチングしている。`\x23` は `\#`
+と同じであることに留意すると、この正規表現は「`#` から始まる 2
+以上の長さ (含 `#`)
+の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi
+におけるトークンである。
+
+なお、`\#` を直接書いていないのは、`/#.+?) /` と書くと、`#.+?)`
+という意図せぬトークンが登録されてしまうからである。
+
+[source,php]
+----
+if (md5($t) === '056e831a4146bf123e8ea16613303d2e') {
+ echo "Token: {$t}\n";
+} else {
+ echo "Failed.\n";
+}
+----
+
+最後にトークンのハッシュ値を見て、想定解かどうかを確認する。
+
+== おわりに
+
+円周率を何桁も計算して ASCII
+コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。
+
+最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた
+(ちなみに、それでも `M_PI` や `pi()`
+では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100
+万桁目くらいに埋まっていてくれたほうがよかったかもしれない。
diff --git a/content/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1.md b/content/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1.md
deleted file mode 100644
index 37f0a9a..0000000
--- a/content/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1.md
+++ /dev/null
@@ -1,143 +0,0 @@
----
-title: "PHPerKaigi 2023: ボツになったトークン問題 その 1"
-date: 2022-10-23T09:54:07+09:00
-draft: false
-tags: ["php", "phperkaigi"]
-summary: |
- 来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、
- ボツになった問題を公開する (その 1)。
-changelog:
- 2022-10-23: 公開
----
-
-
-
-# はじめに
-
-2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の、[PHPerKaigi 2023](https://phperkaigi.jp/2023/) において、昨年と同様に、弊社[デジタルサーカス株式会社](https://www.dgcircus.com/) から、トークン問題を出題予定である。
-
-昨年のトークン問題の記事はこちら: [PHPerKaigi 2022 トークン問題の解説](/posts/2022-04-09/phperkaigi-2022-tokens)
-
-すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。
-
-10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。
-
-
-
-# 問題
-
-注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。
-
-```php
-<?php
-
-$π = $argv[1] ?? null;
-if ($π === null) {
- exit('No input.');
-}
-$π = trim($π);
-if (!is_numeric($π)) {
- exit('Invalid input.');
-}
-
-$s = implode(array_map(chr(...), str_split($π, 2)));
-
-preg_match('/(\x23.+?) /', $s, $m);
-$t = $m[1] ?? '';
-
-if (md5($t) === '056e831a4146bf123e8ea16613303d2e') {
- echo "Token: {$t}\n";
-} else {
- echo "Failed.\n";
-}
-```
-
-
-
-# トークン入手方法
-
-ソースを見るとわかるとおり、`$argv[1]` を参照している。それを `$π` なる変数に代入しているので、円周率を渡してみる。
-
-```shell-session
-$ php Q.php 3.14
-Failed.
-```
-
-失敗してしまった。精度を上げてみる。
-
-```shell-session
-$ php Q.php 3.1415
-Failed.
-```
-
-だめだった。これを成功するまで繰り返す。
-
-最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。
-
-```shell-session
-$ php Q.php 3.1415926535897932
-Token: #YO
-```
-
-めでたくトークン「#YO」が手に入った。
-
-
-
-# 解説
-
-短いので頭から追っていく。
-
-```php
-$π = $argv[1] ?? null;
-if ($π === null) {
- exit('No input.');
-}
-$π = trim($π);
-if (!is_numeric($π)) {
- exit('Invalid input.');
-}
-```
-
-入力のバリデーション部分。数値のみ受け付ける。
-
-```php
-$s = implode(array_map(chr(...), str_split($π, 2)));
-```
-
-`$π` を 2 文字ごとに区切り (`str_split`)、数値を ASCII コードと見做して文字に変換 (`chr`) して結合 (`implode`) している。
-
-例えば、`$π` が `'656667'` だったとすると、`65`、`66`、`67` に対応した `'A'`、`'B'`、`'C'` へと変換され、`'ABC'` になる。
-
-```php
-$π = '656667';
-$s = implode(array_map(chr(...), str_split($π, 2)));
-echo $s;
-// => ABC
-```
-
-```php
-preg_match('/(\x23.+?) /', $s, $m);
-$t = $m[1] ?? '';
-```
-
-正規表現でマッチングしている。`\x23` は `#` と同じであることに留意すると、この正規表現は「`#` から始まる 2 以上の長さ (含 `#`) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。
-
-なお、`#` を直接書いていないのは、`/#.+?) /` と書くと、`#.+?)` という意図せぬトークンが登録されてしまうからである。
-
-```php
-if (md5($t) === '056e831a4146bf123e8ea16613303d2e') {
- echo "Token: {$t}\n";
-} else {
- echo "Failed.\n";
-}
-```
-
-最後にトークンのハッシュ値を見て、想定解かどうかを確認する。
-
-
-
-# おわりに
-
-円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。
-
-最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも `M_PI` や `pi()` では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。
diff --git a/content/posts/2022-10-28/setup-server-for-this-site.adoc b/content/posts/2022-10-28/setup-server-for-this-site.adoc
new file mode 100644
index 0000000..8d2dad3
--- /dev/null
+++ b/content/posts/2022-10-28/setup-server-for-this-site.adoc
@@ -0,0 +1,248 @@
+= [備忘録] このサイト用の VPS をセットアップしたときのメモ
+:tags: note-to-self
+:description: GitHub Pages でホストしていたこのサイトを VPS へ移行したので、 \
+ そのときにやったことのメモ。99 % 自分用。
+:revision-1: 2022-10-28 公開
+
+== はじめに
+
+これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS
+に移行した。そのときにおこなったサーバのセットアップ作業を書き残しておく。99
+% 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。
+
+未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。
+
+== VPS
+
+https://vps.sakura.ad.jp/[さくらの VPS] の 2 GB
+プラン。そこまで真面目に選定していないので、困ったら移動するかも。
+
+== 事前準備
+
+=== サーバのホスト名を決める
+
+モチベーションが上がるという効能がある。今回は藤原定家から取って
+``teika''
+にした。たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。
+
+=== SSH の鍵生成
+
+ローカルマシンで鍵を生成する。
+
+[source,shell-session]
+----
+$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key
+$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key
+----
+
+`teika.key` はローカルからサーバへの接続用、`github2teika.key`
+は、GitHub Actions からサーバへのデプロイ用。
+
+=== SSH の設定
+
+`.ssh/config` に設定しておく。
+
+[source,ssh_config]
+----
+Host teika
+ HostName **********
+ User **********
+ Port **********
+ IdentityFile ~/.ssh/teika.key
+----
+
+== 基本のセットアップ
+
+=== SSH 接続
+
+VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。
+
+=== ユーザを作成する
+
+管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。`sudo`
+グループに追加して `sudo` できるようにし、`su` で切り替え。
+
+[source,shell-session]
+----
+$ sudo adduser **********
+$ sudo adduser ********** sudo
+$ su **********
+$ cd
+----
+
+=== ホスト名を変える
+
+[source,shell-session]
+----
+$ sudo hostname teika
+----
+
+=== 公開鍵を置く
+
+[source,shell-session]
+----
+$ mkdir ~/.ssh
+$ chmod 700 ~/.ssh
+$ vi ~/.ssh/authorized_keys
+----
+
+`authorized_keys` には、ローカルで生成した `~/.ssh/teika.key.pub` と
+`~/.ssh/github2teika.key.pub` の内容をコピーする。
+
+=== SSH の設定
+
+SSH の設定を変更し、少しでも安全にしておく。
+
+[source,shell-session]
+----
+$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
+$ sudo vi /etc/ssh/sshd_config
+----
+
+* `Port` を変更
+* `PermitRootLogin` を `no` に
+* `PasswordAuthentication` を `no` に
+
+そして設定を反映。
+
+[source,shell-session]
+----
+$ sudo systemctl restart sshd
+$ sudo systemctl status sshd
+----
+
+=== SSH で接続確認
+
+今の SSH
+セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH
+の設定に不備があった場合に締め出しをくらう。
+
+[source,shell-session]
+----
+$ ssh teika
+----
+
+=== ポートの遮断
+
+デフォルトの 22 番を閉じ、設定したポートだけ空ける。
+
+[source,shell-session]
+----
+$ sudo ufw deny ssh
+$ sudo ufw allow *******
+$ sudo ufw enable
+$ sudo ufw reload
+$ sudo ufw status
+----
+
+ここでもう一度 SSH の接続確認を挟む。
+
+=== GitHub 用の SSH 鍵
+
+GitHub に置いてある private リポジトリをサーバから clone したいので、SSH
+鍵を生成して置いておく。
+
+[source,shell-session]
+----
+$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github.key
+$ cat ~/.ssh/github.key.pub
+----
+
+https://github.com/settings/ssh[GitHub の設定画面]
+から、この公開鍵を追加する。
+
+[source,shell-session]
+----
+$ vi ~/.ssh/config
+----
+
+設定はこう。
+
+[source,ssh_config]
+----
+Host github.com
+ HostName github.com
+ User git
+ IdentityFile ~/.ssh/github.key
+----
+
+最後に接続できるか確認しておく。
+
+[source,shell-session]
+----
+ssh -T github.com
+----
+
+=== パッケージの更新
+
+[source,shell-session]
+----
+$ sudo apt update
+$ sudo apt upgrade
+$ sudo apt update
+$ sudo apt upgrade
+$ sudo apt autoremove
+----
+
+== サイトホスティング用のセットアップ
+
+=== DNS に IP アドレスを登録する
+
+このサーバは固定の IP アドレスがあるので、`A`
+レコードに直接入れるだけで済んだ。
+
+=== 使うソフトウェアのインストール
+
+[source,shell-session]
+----
+$ sudo apt install docker docker-compose git make
+----
+
+=== メインユーザが Docker を使えるように
+
+[source,shell-session]
+----
+sudo adduser ********** docker
+----
+
+=== HTTP/HTTPS を通す
+
+80 番と 443 番を空ける。
+
+[source,shell-session]
+----
+$ sudo ufw allow 80/tcp
+$ sudo ufw allow 443/tcp
+$ sudo ufw reload
+$ sudo ufw status
+----
+
+=== リポジトリのクローン
+
+[source,shell-session]
+----
+$ cd
+$ git clone git@github.com:nsfisis/nsfisis.dev.git
+$ cd nsfisis.dev
+$ git submodule update --init
+----
+
+=== certbot で証明書取得
+
+[source,shell-session]
+----
+$ docker-compose up -d acme-challenge
+$ make setup
+----
+
+=== サーバを稼動させる
+
+[source,shell-session]
+----
+$ make serve
+----
+
+== 感想
+
+(業務でなく)
+個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。
diff --git a/content/posts/2022-10-28/setup-server-for-this-site.md b/content/posts/2022-10-28/setup-server-for-this-site.md
deleted file mode 100644
index c2d2f63..0000000
--- a/content/posts/2022-10-28/setup-server-for-this-site.md
+++ /dev/null
@@ -1,230 +0,0 @@
----
-title: "[備忘録] このサイト用の VPS をセットアップしたときのメモ"
-date: 2022-10-28T21:55:23+09:00
-draft: false
-tags: ["note-to-self"]
-summary: |
- GitHub Pages でホストしていたこのサイトを VPS へ移行したので、
- そのときにやったことのメモ。99 % 自分用。
-changelog:
- 2022-10-28: 公開
----
-
-
-
-# はじめに
-
-これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS に移行した。そのときにおこなったサーバのセットアップ作業を書き残しておく。99 % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。
-
-未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。
-
-
-
-# VPS
-
-[さくらの VPS](https://vps.sakura.ad.jp/) の 2 GB プラン。そこまで真面目に選定していないので、困ったら移動するかも。
-
-
-
-# 事前準備
-
-## サーバのホスト名を決める
-
-モチベーションが上がるという効能がある。今回は藤原定家から取って "teika" にした。たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。
-
-## SSH の鍵生成
-
-ローカルマシンで鍵を生成する。
-
-```shell-session
-$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key
-$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key
-```
-
-`teika.key` はローカルからサーバへの接続用、`github2teika.key` は、GitHub Actions からサーバへのデプロイ用。
-
-## SSH の設定
-
-`.ssh/config` に設定しておく。
-
-```ssh_config
-Host teika
- HostName **********
- User **********
- Port **********
- IdentityFile ~/.ssh/teika.key
-```
-
-
-# 基本のセットアップ
-
-## SSH 接続
-
-VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。
-
-## ユーザを作成する
-
-管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。`sudo` グループに追加して `sudo` できるようにし、`su` で切り替え。
-
-```shell-session
-$ sudo adduser **********
-$ sudo adduser ********** sudo
-$ su **********
-$ cd
-```
-
-## ホスト名を変える
-
-```shell-session
-$ sudo hostname teika
-```
-
-## 公開鍵を置く
-
-```shell-session
-$ mkdir ~/.ssh
-$ chmod 700 ~/.ssh
-$ vi ~/.ssh/authorized_keys
-```
-
-`authorized_keys` には、ローカルで生成した `~/.ssh/teika.key.pub` と `~/.ssh/github2teika.key.pub` の内容をコピーする。
-
-## SSH の設定
-
-SSH の設定を変更し、少しでも安全にしておく。
-
-```shell-session
-$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
-$ sudo vi /etc/ssh/sshd_config
-```
-
-* `Port` を変更
-* `PermitRootLogin` を `no` に
-* `PasswordAuthentication` を `no` に
-
-そして設定を反映。
-
-```shell-session
-$ sudo systemctl restart sshd
-$ sudo systemctl status sshd
-```
-
-## SSH で接続確認
-
-今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。
-
-```shell-session
-$ ssh teika
-```
-
-## ポートの遮断
-
-デフォルトの 22 番を閉じ、設定したポートだけ空ける。
-
-```shell-session
-$ sudo ufw deny ssh
-$ sudo ufw allow *******
-$ sudo ufw enable
-$ sudo ufw reload
-$ sudo ufw status
-```
-
-ここでもう一度 SSH の接続確認を挟む。
-
-## GitHub 用の SSH 鍵
-
-GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。
-
-```shell-session
-$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github.key
-$ cat ~/.ssh/github.key.pub
-```
-
-[GitHub の設定画面](https://github.com/settings/ssh) から、この公開鍵を追加する。
-
-```shell-session
-$ vi ~/.ssh/config
-```
-
-設定はこう。
-
-```ssh_config
-Host github.com
- HostName github.com
- User git
- IdentityFile ~/.ssh/github.key
-```
-
-最後に接続できるか確認しておく。
-
-```shell-session
-ssh -T github.com
-```
-
-## パッケージの更新
-
-```shell-session
-$ sudo apt update
-$ sudo apt upgrade
-$ sudo apt update
-$ sudo apt upgrade
-$ sudo apt autoremove
-```
-
-
-# サイトホスティング用のセットアップ
-
-## DNS に IP アドレスを登録する
-
-このサーバは固定の IP アドレスがあるので、`A` レコードに直接入れるだけで済んだ。
-
-## 使うソフトウェアのインストール
-
-```shell-session
-$ sudo apt install docker docker-compose git make
-```
-
-## メインユーザが Docker を使えるように
-
-```shell-session
-sudo adduser ********** docker
-```
-
-## HTTP/HTTPS を通す
-
-80 番と 443 番を空ける。
-
-```shell-session
-$ sudo ufw allow 80/tcp
-$ sudo ufw allow 443/tcp
-$ sudo ufw reload
-$ sudo ufw status
-```
-
-## リポジトリのクローン
-
-```shell-session
-$ cd
-$ git clone git@github.com:nsfisis/nsfisis.dev.git
-$ cd nsfisis.dev
-$ git submodule update --init
-```
-
-## certbot で証明書取得
-
-```shell-session
-$ docker-compose up -d acme-challenge
-$ make setup
-```
-
-## サーバを稼動させる
-
-```shell-session
-$ make serve
-```
-
-
-
-# 感想
-
-(業務でなく) 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。
diff --git a/docker-compose.local.yml b/docker-compose.local.yml
index d082169..ea78e67 100644
--- a/docker-compose.local.yml
+++ b/docker-compose.local.yml
@@ -5,7 +5,7 @@ services:
image: nginx
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- - ./docs:/public
+ - ./public:/public
ports:
- 80:80
environment:
diff --git a/docker-compose.yml b/docker-compose.yml
index 7151b77..f6eef3d 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -5,7 +5,7 @@ services:
image: nginx
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- - ./docs:/public
+ - ./public:/public
expose:
- 80
environment:
diff --git a/docs/404.html b/docs/404.html
deleted file mode 100644
index 7936109..0000000
--- a/docs/404.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>404 Page not found | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<div class="not-found">404</div></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/an-old-hope.min.css b/docs/an-old-hope.min.css
deleted file mode 100644
index 936fba3..0000000
--- a/docs/an-old-hope.min.css
+++ /dev/null
@@ -1 +0,0 @@
-.hljs-comment,.hljs-quote{color:#B6B18B}.hljs-variable,.hljs-template-variable,.hljs-tag,.hljs-name,.hljs-selector-id,.hljs-selector-class,.hljs-regexp,.hljs-deletion{color:#EB3C54}.hljs-number,.hljs-built_in,.hljs-builtin-name,.hljs-literal,.hljs-type,.hljs-params,.hljs-meta,.hljs-link{color:#E7CE56}.hljs-attribute{color:#EE7C2B}.hljs-string,.hljs-symbol,.hljs-bullet,.hljs-addition{color:#4FB4D7}.hljs-title,.hljs-section{color:#78BB65}.hljs-keyword,.hljs-selector-tag{color:#B45EA4}.hljs{display:block;overflow-x:auto;background:#1C1D21;color:#c0c5ce;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold} \ No newline at end of file
diff --git a/docs/feed.xml b/docs/feed.xml
deleted file mode 100644
index d39b645..0000000
--- a/docs/feed.xml
+++ /dev/null
@@ -1,2348 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/</link>
- <description>Recent content on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Wed, 31 Mar 2021 01:36:49 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>[備忘録] このサイト用の VPS をセットアップしたときのメモ</title>
- <link>https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/</link>
- <pubDate>Fri, 28 Oct 2022 21:55:23 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS に移行した。そのときにおこなったサーバのセットアップ作業を書き残しておく。99 % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。</p>
-<p>未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。</p>
-<h1 id="vps">VPS</h1>
-<p><a href="https://vps.sakura.ad.jp/">さくらの VPS</a> の 2 GB プラン。そこまで真面目に選定していないので、困ったら移動するかも。</p>
-<h1 id="事前準備">事前準備</h1>
-<h2 id="サーバのホスト名を決める">サーバのホスト名を決める</h2>
-<p>モチベーションが上がるという効能がある。今回は藤原定家から取って &ldquo;teika&rdquo; にした。たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。</p>
-<h2 id="ssh-の鍵生成">SSH の鍵生成</h2>
-<p>ローカルマシンで鍵を生成する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/teika.key
-</span></span><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/github2teika.key
-</span></span></code></pre></div><p><code>teika.key</code> はローカルからサーバへの接続用、<code>github2teika.key</code> は、GitHub Actions からサーバへのデプロイ用。</p>
-<h2 id="ssh-の設定">SSH の設定</h2>
-<p><code>.ssh/config</code> に設定しておく。</p>
-<pre tabindex="0"><code class="language-ssh_config" data-lang="ssh_config">Host teika
- HostName **********
- User **********
- Port **********
- IdentityFile ~/.ssh/teika.key
-</code></pre><h1 id="基本のセットアップ">基本のセットアップ</h1>
-<h2 id="ssh-接続">SSH 接続</h2>
-<p>VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。</p>
-<h2 id="ユーザを作成する">ユーザを作成する</h2>
-<p>管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。<code>sudo</code> グループに追加して <code>sudo</code> できるようにし、<code>su</code> で切り替え。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo adduser **********
-</span></span><span style="display:flex;"><span>$ sudo adduser ********** sudo
-</span></span><span style="display:flex;"><span>$ su **********
-</span></span><span style="display:flex;"><span>$ cd
-</span></span></code></pre></div><h2 id="ホスト名を変える">ホスト名を変える</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo hostname teika
-</span></span></code></pre></div><h2 id="公開鍵を置く">公開鍵を置く</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ mkdir ~/.ssh
-</span></span><span style="display:flex;"><span>$ chmod <span style="color:#ae81ff">700</span> ~/.ssh
-</span></span><span style="display:flex;"><span>$ vi ~/.ssh/authorized_keys
-</span></span></code></pre></div><p><code>authorized_keys</code> には、ローカルで生成した <code>~/.ssh/teika.key.pub</code> と <code>~/.ssh/github2teika.key.pub</code> の内容をコピーする。</p>
-<h2 id="ssh-の設定-1">SSH の設定</h2>
-<p>SSH の設定を変更し、少しでも安全にしておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
-</span></span><span style="display:flex;"><span>$ sudo vi /etc/ssh/sshd_config
-</span></span></code></pre></div><ul>
-<li><code>Port</code> を変更</li>
-<li><code>PermitRootLogin</code> を <code>no</code> に</li>
-<li><code>PasswordAuthentication</code> を <code>no</code> に</li>
-</ul>
-<p>そして設定を反映。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo systemctl restart sshd
-</span></span><span style="display:flex;"><span>$ sudo systemctl status sshd
-</span></span></code></pre></div><h2 id="ssh-で接続確認">SSH で接続確認</h2>
-<p>今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh teika
-</span></span></code></pre></div><h2 id="ポートの遮断">ポートの遮断</h2>
-<p>デフォルトの 22 番を閉じ、設定したポートだけ空ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo ufw deny ssh
-</span></span><span style="display:flex;"><span>$ sudo ufw allow *******
-</span></span><span style="display:flex;"><span>$ sudo ufw enable
-</span></span><span style="display:flex;"><span>$ sudo ufw reload
-</span></span><span style="display:flex;"><span>$ sudo ufw status
-</span></span></code></pre></div><p>ここでもう一度 SSH の接続確認を挟む。</p>
-<h2 id="github-用の-ssh-鍵">GitHub 用の SSH 鍵</h2>
-<p>GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/github.key
-</span></span><span style="display:flex;"><span>$ cat ~/.ssh/github.key.pub
-</span></span></code></pre></div><p><a href="https://github.com/settings/ssh">GitHub の設定画面</a> から、この公開鍵を追加する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ vi ~/.ssh/config
-</span></span></code></pre></div><p>設定はこう。</p>
-<pre tabindex="0"><code class="language-ssh_config" data-lang="ssh_config">Host github.com
- HostName github.com
- User git
- IdentityFile ~/.ssh/github.key
-</code></pre><p>最後に接続できるか確認しておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>ssh -T github.com
-</span></span></code></pre></div><h2 id="パッケージの更新">パッケージの更新</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo apt update
-</span></span><span style="display:flex;"><span>$ sudo apt upgrade
-</span></span><span style="display:flex;"><span>$ sudo apt update
-</span></span><span style="display:flex;"><span>$ sudo apt upgrade
-</span></span><span style="display:flex;"><span>$ sudo apt autoremove
-</span></span></code></pre></div><h1 id="サイトホスティング用のセットアップ">サイトホスティング用のセットアップ</h1>
-<h2 id="dns-に-ip-アドレスを登録する">DNS に IP アドレスを登録する</h2>
-<p>このサーバは固定の IP アドレスがあるので、<code>A</code> レコードに直接入れるだけで済んだ。</p>
-<h2 id="使うソフトウェアのインストール">使うソフトウェアのインストール</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo apt install docker docker-compose git make
-</span></span></code></pre></div><h2 id="メインユーザが-docker-を使えるように">メインユーザが Docker を使えるように</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>sudo adduser ********** docker
-</span></span></code></pre></div><h2 id="httphttps-を通す">HTTP/HTTPS を通す</h2>
-<p>80 番と 443 番を空ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo ufw allow 80/tcp
-</span></span><span style="display:flex;"><span>$ sudo ufw allow 443/tcp
-</span></span><span style="display:flex;"><span>$ sudo ufw reload
-</span></span><span style="display:flex;"><span>$ sudo ufw status
-</span></span></code></pre></div><h2 id="リポジトリのクローン">リポジトリのクローン</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ cd
-</span></span><span style="display:flex;"><span>$ git clone git@github.com:nsfisis/nsfisis.dev.git
-</span></span><span style="display:flex;"><span>$ cd nsfisis.dev
-</span></span><span style="display:flex;"><span>$ git submodule update --init
-</span></span></code></pre></div><h2 id="certbot-で証明書取得">certbot で証明書取得</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ docker-compose up -d acme-challenge
-</span></span><span style="display:flex;"><span>$ make setup
-</span></span></code></pre></div><h2 id="サーバを稼動させる">サーバを稼動させる</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ make serve
-</span></span></code></pre></div><h1 id="感想">感想</h1>
-<p>(業務でなく) 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2023: ボツになったトークン問題 その 1</title>
- <link>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</link>
- <pubDate>Sun, 23 Oct 2022 09:54:07 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の、<a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a> において、昨年と同様に、弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> から、トークン問題を出題予定である。</p>
-<p>昨年のトークン問題の記事はこちら: <a href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022 トークン問題の解説</a></p>
-<p>すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。</p>
-<p>10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。</p>
-<h1 id="問題">問題</h1>
-<p>注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;No input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π);
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;Invalid input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">&#39;/(\x23.+?) /&#39;</span>, $s, $m);
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;056e831a4146bf123e8ea16613303d2e&#39;</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><h1 id="トークン入手方法">トークン入手方法</h1>
-<p>ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。それを <code>$π</code> なる変数に代入しているので、円周率を渡してみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.14
-</span></span><span style="display:flex;"><span>Failed.
-</span></span></code></pre></div><p>失敗してしまった。精度を上げてみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415
-</span></span><span style="display:flex;"><span>Failed.
-</span></span></code></pre></div><p>だめだった。これを成功するまで繰り返す。</p>
-<p>最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415926535897932
-</span></span><span style="display:flex;"><span>Token: #YO
-</span></span></code></pre></div><p>めでたくトークン「#YO」が手に入った。</p>
-<h1 id="解説">解説</h1>
-<p>短いので頭から追っていく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;No input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π);
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;Invalid input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>入力のバリデーション部分。数値のみ受け付ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span></code></pre></div><p><code>$π</code> を 2 文字ごとに区切り (<code>str_split</code>)、数値を ASCII コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。</p>
-<p>例えば、<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="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;656667&#39;</span>;
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $s;
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// =&gt; ABC
-</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">&#39;/(\x23.+?) /&#39;</span>, $s, $m);
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span></code></pre></div><p>正規表現でマッチングしている。<code>\x23</code> は <code>#</code> と同じであることに留意すると、この正規表現は「<code>#</code> から始まる 2 以上の長さ (含 <code>#</code>) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。</p>
-<p>なお、<code>#</code> を直接書いていないのは、<code>/#.+?) /</code> と書くと、<code>#.+?)</code> という意図せぬトークンが登録されてしまうからである。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;056e831a4146bf123e8ea16613303d2e&#39;</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>最後にトークンのハッシュ値を見て、想定解かどうかを確認する。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。</p>
-<p>最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも <code>M_PI</code> や <code>pi()</code> では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。</p>
-]]></description>
- </item>
-
- <item>
- <title>[PHP] fizzbuzz を書く。1行あたり2文字で。</title>
- <link>https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/</link>
- <pubDate>Thu, 29 Sep 2022 00:50:52 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/</guid>
- <description><![CDATA[ <h1 id="記事の構成について">記事の構成について</h1>
-<p>この記事は、普通の fizzbuzz を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、 <a href="https://gist.github.com/nsfisis/04c227d5a419867472a0b23a83ad2919#file-fizzbuzz-php-2-letters-per-line-and-supports-php-8-x-without-warnings">このページ</a> にソースコードがあるので、そちらを先に見てほしい。</p>
-<h1 id="レギュレーション">レギュレーション</h1>
-<p>PHP で、次のような制約の下に fizzbuzz を書いた。</p>
-<ul>
-<li>1行あたりの文字数は2文字までに収めること (ただし <code>&lt;?php</code> タグは除く)
-<ul>
-<li>厳密な定義: <code>&lt;?php</code> タグ以降のソースコードが、2 byte ごとに ラインフィード (LF) で区切られること</li>
-</ul>
-</li>
-<li>スペースやタブを使用しないこと</li>
-<li>ループのアンロールをしないこと
-<ul>
-<li>100 回ループの代わりに 100 回コードをコピペ、というのは禁止</li>
-</ul>
-</li>
-<li>PHP 7.4〜8.1 で動作すること</li>
-<li>実行時に Notice や Warning が出ないこと</li>
-<li>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)</li>
-</ul>
-<p>備考: PHP には <code>short_open_tag</code> というオプションがあり、これを有効にするとファイル冒頭の <code>&lt;?php</code> の代わりに <code>&lt;?</code> を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト off になっている環境が多いようなので、今回は使わないことにした。</p>
-<h1 id="主な障害">主な障害</h1>
-<p>1行あたりの文字数など、適当に改行を挟めばいいだけではないのか?</p>
-<p>特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">i\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">n\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">l\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">u\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">d\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">e\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">&lt;\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">s\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">t\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">d\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">i\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">o\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">.\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">h\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">&gt;\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span><span style="color:#75715e">
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>i\
-</span></span><span style="display:flex;"><span>n\
-</span></span><span style="display:flex;"><span>t\
-</span></span><span style="display:flex;"><span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span>
-</span></span><span style="display:flex;"><span>m\
-</span></span><span style="display:flex;"><span>a\
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span>n(
-</span></span><span style="display:flex;"><span>){
-</span></span><span style="display:flex;"><span>f\
-</span></span><span style="display:flex;"><span>o\
-</span></span><span style="display:flex;"><span>r(
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span>n\
-</span></span><span style="display:flex;"><span>t\
-</span></span><span style="display:flex;"><span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span>
-</span></span><span style="display:flex;"><span>i<span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>;
-</span></span><span style="display:flex;"><span>i<span style="color:#f92672">&lt;</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>\
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>\
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>;
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span>\
-</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span>)
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span>
-</span></span><span style="display:flex;"><span>(i
-</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span>\
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">15</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">==</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>)
-</span></span><span style="display:flex;"><span>p\
-</span></span><span style="display:flex;"><span>r\
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span>n\
-</span></span><span style="display:flex;"><span>t\
-</span></span><span style="display:flex;"><span>f(
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">F\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">i\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">B\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">u\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">10</span>
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">/* あとは同じように普通のプログラムを変形するだけなので省略 */</span>
-</span></span></code></pre></div><p>バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。</p>
-<p>さて、PHP ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、<code>echo</code> で出力することや、<code>for</code> でループすること、<code>new</code> でインスタンスを生成することができない。特に、出力は fizzbuzz をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。</p>
-<p>当然、名前が3文字以上ある関数も使えない。なお、標準 PHP の範囲内において、名前が 2文字以下の関数は以下のとおりである:</p>
-<ul>
-<li><code>_</code>: <code>gettext</code> のエイリアス</li>
-<li><code>dl</code>: 拡張モジュールをロードする</li>
-<li><code>pi</code>: 円周率を返す</li>
-</ul>
-<p>(環境によって多少は変わるかも)</p>
-<p>2文字の関数を定義しまくった拡張モジュールを用意しておいて <code>dl()</code> で読み込む行為は、レギュレーションで定めた</p>
-<blockquote>
-<ul>
-<li>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)</li>
-</ul>
-</blockquote>
-<p>に反する (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。</p>
-<p>また、2文字だと文字列がまともに書けないのも辛い。<code>''</code> だけで 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$a
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">a&#39;</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span></code></pre></div><p>とすると <code>$a</code> は <code>&quot;\na&quot;</code> になるのだが、余計な改行が入ってしまう。</p>
-<p>これらの障害をどのように乗り越えるのか、次節から見ていく。</p>
-<h1 id="解説">解説</h1>
-<h2 id="普通の--fizzbuzz">普通の (?) fizzbuzz</h2>
-<p>まずは普通に書くとしよう。</p>
-<pre tabindex="0"><code>&lt;?php
-
-for ($i = 1; $i &lt; 100; $i++) {
- echo (($i % 3 ? &#39;&#39; : &#39;Fizz&#39;) . ($i % 5 ? &#39;&#39; : &#39;Buzz&#39;) ?: $i) . &#34;\n&#34;;
-}
-</code></pre><p>素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。</p>
-<h2 id="for-の排除"><code>for</code> の排除</h2>
-<p><code>for</code> は、3文字もある長いキーワードである。こんなものは使えない。<code>array_</code> 系の関数を使って、適当に置き換えるとしよう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">range</span>(<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">100</span>);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">array_walk</span>(
-</span></span><span style="display:flex;"><span> $s,
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fn</span>($i) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">printf</span>((($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Fizz&#39;</span>) <span style="color:#f92672">.</span> ($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">5</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Buzz&#39;</span>) <span style="color:#f92672">?:</span> $i) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>),
-</span></span><span style="display:flex;"><span>);
-</span></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> に置き換えた。</p>
-<h2 id="関数呼び出しの短縮">関数呼び出しの短縮</h2>
-<p><code>range</code>、<code>array_walk</code>、<code>printf</code> は長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;range&#39;</span>;
-</span></span><span style="display:flex;"><span>$w <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;array_walk&#39;</span>;
-</span></span><span style="display:flex;"><span>$p <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;printf&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> $r(<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">100</span>);
-</span></span><span style="display:flex;"><span>$w(
-</span></span><span style="display:flex;"><span> $s,
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fn</span>($i) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> $p((($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Fizz&#39;</span>) <span style="color:#f92672">.</span> ($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">5</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Buzz&#39;</span>) <span style="color:#f92672">?:</span> $i) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>),
-</span></span><span style="display:flex;"><span>);
-</span></span></code></pre></div><p>これで関数を呼び出している所は短くなった。では、<code>$r</code> や <code>$w</code> や <code>$p</code>、また <code>'Fizz'</code> や <code>'Buzz'</code> はどうやって 1行2文字に収めるのか。次のテクニックへ移ろう。</p>
-<h2 id="余談-php-8x-で動作しなくてもいいなら">余談: PHP 8.x で動作しなくてもいいなら</h2>
-<p>今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。</p>
-<blockquote>
-<ul>
-<li>PHP 7.4〜8.1 で動作すること</li>
-</ul>
-</blockquote>
-<p>というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、 <code>Fizz</code> という文字列が欲しければ、次のようにする。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$f
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#a6e22e">F</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">i</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span></code></pre></div><p>こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、<code>@</code> 演算子を使って抑制してやるとよい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$f
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=@</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">F</span><span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">@</span><span style="color:#a6e22e">i</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">@</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">@</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span></code></pre></div><p>むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。</p>
-<h2 id="文字列リテラルの短縮">文字列リテラルの短縮</h2>
-<p>実際に使った手法の説明に移る。</p>
-<p>ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (<code>&amp;</code>、<code>|</code>、<code>^</code>) をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$a <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;12345&#34;</span>;
-</span></span><span style="display:flex;"><span>$b <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;world&#34;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// $a ^ $b は次のコードと同じ
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$result <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672">&lt;</span> <span style="color:#a6e22e">min</span>(<span style="color:#a6e22e">strlen</span>($a), <span style="color:#a6e22e">strlen</span>($b)); $i<span style="color:#f92672">++</span>) {
-</span></span><span style="display:flex;"><span> $result <span style="color:#f92672">.=</span> $a[$i] <span style="color:#f92672">^</span> $b[$i];
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $result;
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// =&gt; F]AXQ
-</span></span></span></code></pre></div><p>これを踏まえ、次のコードを見てみよう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;x</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">Om</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>$y <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">k!</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">o&#34;</span>;
-</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> $y;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>実行すると、<code>range</code> が表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;x
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o&#39;</span>
-</span></span><span style="display:flex;"><span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> $y;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>さらに <code>#</code> を使って適当に調整すると、次のようになる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;x
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o&#39;</span>
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>1行あたり2文字で、<code>range</code> という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。</p>
-<p>備考: <code>Buzz</code> 中にある小文字の <code>u</code> は、このロジックだと non-printable な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。</p>
-<h1 id="完成系">完成系</h1>
-<p>完成したものがこちら。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;i
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">S&#39;</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">b!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$c
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;x
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o&#39;</span>
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;k
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Sk
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">~}
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Ma
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">x!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">s!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$w
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;z
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Hd
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">G&#39;</span>
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">x!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">~!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$p
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;L
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[p
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$f
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;H
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[p
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">_!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$b
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$b
-</span></span><span style="display:flex;"><span>[<span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span>]<span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span>$c
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">13</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">*</span><span style="color:#ae81ff">9</span>
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>$s
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r
-</span></span><span style="display:flex;"><span>(<span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span>,(
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">10</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">**</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span>)
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>$w
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$s
-</span></span><span style="display:flex;"><span>,<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">fn</span>
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span>)<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span>$p
-</span></span><span style="display:flex;"><span>((
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span><span style="color:#ae81ff">3</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">?</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;&#39;</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$f
-</span></span><span style="display:flex;"><span>)<span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span><span style="color:#ae81ff">5</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">?</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;&#39;</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$b
-</span></span><span style="display:flex;"><span>)<span style="color:#f92672">?</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span>)<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">.</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>)
-</span></span><span style="display:flex;"><span>);
-</span></span></code></pre></div><h1 id="感想など">感想など</h1>
-<p>PHP は、スクリプト言語の中だとシンタックスシュガーが少ない (体感)。この挑戦は不可能に思われたが、PHP マニュアルとにらめっこしていたらなんとかなった。</p>
-<p>みんなもプログラムを細長くしよう。</p>
-<h1 id="余談2-別解">余談2: 別解</h1>
-<p>PHP では、バッククォートを使ってシェルを呼び出せる。これは <code>shell_exec</code> 関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">`
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">e\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">h\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> \
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">1\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">2\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">3\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">`</span>);
-</span></span></code></pre></div><p>なお、ここでは簡単のため出力に <code>printf</code> をそのまま使っているが、実際には <code>printf</code> という文字列を合成して可変関数で呼び出す。</p>
-<p>ただし、これでは</p>
-<blockquote>
-<ul>
-<li>スペースやタブを使用しないこと</li>
-</ul>
-</blockquote>
-<p>に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。</p>
-<p>もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$c <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;chr&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">$</span>{
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;_
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>}
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$c
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">32</span>
-</span></span><span style="display:flex;"><span>)<span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span>$c
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">92</span>
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">`
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">e\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">h\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">${
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;_
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;}
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">1\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">2\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">3\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">`</span>);
-</span></span></code></pre></div><p>先程と同じく、<code>chr</code> や <code>printf</code> を生成する部分は長くなるので省いた。</p>
-<pre tabindex="0"><code>${
-&#39;_
-&#39;}
-</code></pre><p>は変数で、中にはスペースとエスケープが入っている (<code>chr(32) . chr(92)</code>)。シェルに渡されている文字列は次のようになる。</p>
-<pre tabindex="0"><code>e\
-c\
-h\
-o\
- \
-1\
-2\
-3\
-</code></pre><p>これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。</p>
-<p>ということでこれは別解ということにしておく。</p>
-<p>ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。</p>
-<pre tabindex="0"><code>${
-&#39;_
-&#39;}
-</code></pre><p>最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。</p>
-]]></description>
- </item>
-
- <item>
- <title>弊社の PHP Foundation への寄付に寄せて</title>
- <link>https://blog.nsfisis.dev/posts/2022-08-31/support-for-communty-is-employee-benefits/</link>
- <pubDate>Wed, 31 Aug 2022 22:25:02 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-08-31/support-for-communty-is-employee-benefits/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p><strong>注: これは私個人の意見であり、所属する組織を代表するものではありません。</strong></p>
-<p>先日、私の勤める <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> が <a href="https://opencollective.com/phpfoundation">PHP Foundation</a> へ $2,000 の寄付をおこないました。</p>
-<p>記事: <a href="https://www.dgcircus.com/news/581">https://www.dgcircus.com/news/581</a></p>
-<p>本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。</p>
-<h1 id="なぜ">なぜ?</h1>
-<p>組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。</p>
-<p>当時の考えを端的にまとめた社内チャットの投稿があったので、それを引用します:</p>
-<blockquote>
-<p>結局これを通したい (私の中での) 最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、寄付の報告が流れてきたり、OSS のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか (これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。</p>
-<p>追記: 「肩身が狭くなる」というのがより適切でした。</p>
-</blockquote>
-<p>※文中の「↑にしても」は、ここに載せていない別の投稿を指しています。</p>
-<p>OSS を金銭的に支援したり、技術カンファレンスへ協賛したり (あるいは <a href="https://twitter.com/tomzoh">CTO</a> がカンファレンスを年2で主催したり: <a href="https://iosdc.jp">iOSDC</a> <a href="https://phperkaigi.jp">PHPerKaigi</a>) といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう (知らんけど)。これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。</p>
-<p>以上が、私が社内で寄付の件を進めた (かなり私的な) 理由です。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。この場を借りて感謝申し上げます。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</title>
- <link>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</link>
- <pubDate>Sat, 27 Aug 2022 18:55:28 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> が開催された (らしい)。</p>
-<p>カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。</p>
-<p>ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</a> <br>
-スライド: <a href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</a></p>
-<h1 id="解">解</h1>
-<p>細かいレギュレーションは不明だったので、勝手に定めた。</p>
-<ul>
-<li>コマンドライン引数の第1引数で受けとる</li>
-<li>結果は標準出力に出す</li>
-<li>コンマの直後にはスペースを1つ置く</li>
-<li>末尾コンマは禁止</li>
-<li>数字でないものは入ってこないものとする</li>
-<li>負数は入ってこないものとする</li>
-</ul>
-<p>書いたものがこちら:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span> $n<span style="color:#f92672">=</span>$argv[<span style="color:#ae81ff">1</span>];<span style="color:#66d9ef">foreach</span>([<span style="color:#ae81ff">1e4</span>,<span style="color:#ae81ff">5e3</span>,<span style="color:#ae81ff">2e3</span>,<span style="color:#ae81ff">1e3</span>,<span style="color:#ae81ff">500</span>,<span style="color:#ae81ff">100</span>,<span style="color:#ae81ff">50</span>,<span style="color:#ae81ff">10</span>,<span style="color:#ae81ff">5</span>,<span style="color:#ae81ff">1</span>]<span style="color:#66d9ef">as</span>$x)<span style="color:#66d9ef">for</span>(;$n<span style="color:#f92672">&gt;=</span>$x;$n<span style="color:#f92672">-=</span>$x)$r[]<span style="color:#f92672">=</span>$x;<span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>,$r<span style="color:#f92672">??</span>[]);<span style="color:#75715e">?&gt;</span><span style="color:#960050;background-color:#1e0010">]
-</span></span></span></code></pre></div><p>しめて 123 バイトとなった (末尾改行を含めずにカウント)。</p>
-<p>こちらは改行とスペースを追加したバージョン:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>];
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ([<span style="color:#ae81ff">1e4</span>, <span style="color:#ae81ff">5e3</span>, <span style="color:#ae81ff">2e3</span>, <span style="color:#ae81ff">1e3</span>, <span style="color:#ae81ff">500</span>, <span style="color:#ae81ff">100</span>, <span style="color:#ae81ff">50</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">1</span>] <span style="color:#66d9ef">as</span> $x)
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> (; $n <span style="color:#f92672">&gt;=</span> $x; $n <span style="color:#f92672">-=</span> $x)
-</span></span><span style="display:flex;"><span> $r[] <span style="color:#f92672">=</span> $x;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>, $r <span style="color:#f92672">??</span> []);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">?&gt;</span><span style="color:#960050;background-color:#1e0010">]
-</span></span></span></code></pre></div><h1 id="使用したテクニック">使用したテクニック</h1>
-<h2 id="指数表記">指数表記</h2>
-<p>割と多くの言語のゴルフで使えるテクニック。<code>e</code> を用いた指数表記で、大きな数を短く表す。このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。</p>
-<h2 id="foreach-や-for-の中身を1つの文に">foreach や for の中身を1つの文に</h2>
-<p><code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code> を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> を省略できる。C言語などでも使える。</p>
-<h2 id="r-に初期値を入れない">$r に初期値を入れない</h2>
-<p>PHP では、<code>$r[] = ...</code> のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は <code>$r</code> を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code> のような初期化が不要になる。</p>
-<p>ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> が未定義になってしまい、<code>implode()</code> に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。</p>
-<p>もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。</p>
-<h2 id="php-タグの外に文字列を置く">PHP タグの外に文字列を置く</h2>
-<p>PHP では、<code>&lt;?php</code> <code>?&gt;</code> で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず <code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>最後になりましたが、<a href="https://twitter.com/m3m0r7">めもりー</a> さん、楽しい問題をありがとうございました。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2022</title>
- <link>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</link>
- <pubDate>Sun, 01 May 2022 09:41:39 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>2022-04-09 から 2022-04-11 にかけて開催された、<a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> に、一般参加者として参加した。
-弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
-<p>昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。</p>
-<h1 id="感想">感想</h1>
-<h2 id="厳選おすすめトーク">厳選おすすめトーク</h2>
-<p>多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。</p>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント</a></p>
-<blockquote>
-<p>PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。</p>
-<p>本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</a></p>
-<blockquote>
-<p>PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか?<br>
-これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br>
-またそれらを理解した上でのエラーハンドリングを学びましょう。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</a></p>
-<blockquote>
-<p>毎日流れてくるエラーに皆さんはどう向き合ってますか?<br>
-エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br>
-サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br>
-エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</a></p>
-<blockquote>
-<p>昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。</p>
-<p>最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br>
-・「(私の思う)良い設計」を実現するための意思決定<br>
-・「ISUCONの問題」という位置付けに由来する取捨選択<br>
-・移植中に遭遇したトラブルとその解決策<br>
-といった文脈や葛藤が存在しています。</p>
-<p>本発表はそれらを共有することで<br>
-・PHPアプリケーションの設計、実装事例として役立ててもらう<br>
-・ISUCONの言語移植に興味を持ってもらう<br>
-・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br>
-ことを目的とします。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</a></p>
-<blockquote>
-<p>サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。</p>
-<p>フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。</p>
-<p>このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。</p>
-</blockquote>
-<h2 id="トークン問題の作成">トークン問題の作成</h2>
-<p>今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。</p>
-<h2 id="phper-チャレンジ">PHPer チャレンジ</h2>
-<p><a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。<br>
-また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> をいただいた。</p>
-<h2 id="カンファレンス全体への感想">カンファレンス全体への感想</h2>
-<p><a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。</p>
-<blockquote>
-<p>1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br>
-まあ初カンファレンスだし、とお茶を濁しておこう。</p>
-</blockquote>
-<p>この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。<br>
-これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。</p>
-<p>なお、アンカンファレンスについては、1日目の終わりに<a href="https://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e">トークン問題の解説放送</a>もおこなった。</p>
-<p>また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。
-今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。</p>
-<h1 id="そして来年へ">そして来年へ……?</h1>
-<p>PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。</p>
-<ul>
-<li>プロポーザルを出す</li>
-<li>PHPer チャレンジのトークン問題を 5題作成する</li>
-<li>現地に行く</li>
-<li>PHPer チャレンジで圧勝する</li>
-</ul>
-<hr>
-<p>最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。</p>
-<p>ではまた来年。</p>
-]]></description>
- </item>
-
- <item>
- <title>term-banner: ターミナルにバナーを表示するツールを書いた</title>
- <link>https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/</link>
- <pubDate>Sun, 24 Apr 2022 13:22:52 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>こんなものを作った。</p>
-<pre tabindex="0"><code>$ term-banner &#39;Hello, World!&#39; &#39;こんにちは、&#39; &#39;世界!&#39;
-</code></pre><p><img src="https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png" alt="term-banner のスクリーンショット"></p>
-<p>コマンドライン引数として渡した文字列をターミナルに大きく表示する。</p>
-<p>リポジトリはこちら: <a href="https://github.com/nsfisis/term-banner">https://github.com/nsfisis/term-banner</a></p>
-<h1 id="motivation">Motivation</h1>
-<p>以前、<a href="https://github.com/nsfisis/big-clock-mode">big-clock-mode</a> という似たようなプログラムを書いた。
-これは tmux の <code>:clock-mode</code> コマンドに着想を得たもので、<code>:clock-mode</code> よりも大きく現在時刻を表示する。</p>
-<p><code>big-clock-mode</code> を開発したのは、次のようなシチュエーションで使うためである。
-弊社では現在リモートワークが基本だが、web 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。
-こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。</p>
-<p>それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。</p>
-<p>しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。
-どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。</p>
-<p>そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。
-まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。</p>
-<h1 id="プログラム">プログラム</h1>
-<p>全体の流れは次のようになっている。</p>
-<ol>
-<li>フォントファイルを読み込む</li>
-<li>コマンドライン引数を Shift-JIS に変換する (フォントが Shift-JIS 基準で並んでいるため)</li>
-<li>1文字ずつレンダリングしていく</li>
-</ol>
-<p><code>big-clock-mode</code> が Go 製なので、今回も Go で書いた。
-PNG が標準ライブラリにあったり、Shift-JIS のエンコーディングが準標準ライブラリにあったりしたのは助かった。</p>
-<p>フォントファイルは <code>go:embed</code> で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。
-仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。</p>
-<h1 id="フォント">フォント</h1>
-<p>フリーの 8x8 ビットマップフォントである、<a href="https://littlelimit.net/misaki.htm">美咲フォント 2021-05-05a 版</a> を使わせていただいた。</p>
-<p>はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。
-同じく 8x8 で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。</p>
-<p>美咲フォントは、平仮名・片仮名に留まらず、JIS 第一・第二水準の漢字までサポートしている。
-第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。</p>
-<p>さらに言うと、実のところ美咲フォントは実サイズ 7x7 で作られており、余白が設けられている。
-これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。
-おかげでコーディングまで楽になった。</p>
-<p>ゴシック体と明朝体があったが、私の好みで明朝体の方にした。
-ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。</p>
-<p>2022-04-27 追記: <code>-f</code> オプションで選べるようにした。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>あなたもターミナルに住んでみませんか?</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2022 トークン問題の解説</title>
- <link>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</link>
- <pubDate>Sat, 09 Apr 2022 21:50:19 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>本日開始された <a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> の PHPer チャレンジにおいて、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。</p>
-<p>リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</a></p>
-<h1 id="第1問-brainf_ckphp">第1問 brainf_ck.php</h1>
-<p>ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">declare</span>(<span style="color:#a6e22e">strict_types</span><span style="color:#f92672">=</span><span style="color:#ae81ff">0</span><span style="color:#a6e22e">O1</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> <span style="color:#a6e22e">Dgcircus\PHPerKaigi\Y2022</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">/**
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * @todo
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Run this program to acquire a PHPer token.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> */</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">\error_reporting</span>(<span style="color:#f92672">~+!</span><span style="color:#e6db74">&#39;We are hiring!&#39;</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$z <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($f) <span style="color:#f92672">=&gt;</span> (<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=&gt;</span> $x($x)(<span style="color:#f92672">...</span>$xs)))(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=&gt;</span> $x($x)(<span style="color:#f92672">...</span>$xs)));
-</span></span><span style="display:flex;"><span>$id <span style="color:#f92672">=</span> <span style="color:#a6e22e">\spl_object_id</span>(<span style="color:#f92672">...</span>);
-</span></span><span style="display:flex;"><span>$put <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($c) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">\printf</span>(<span style="color:#e6db74">&#39;%c&#39;</span>, $c);
-</span></span><span style="display:flex;"><span>$mm <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\ArrayObject</span>(<span style="color:#a6e22e">\array_fill</span>(<span style="color:#f92672">+!!</span>[], $n, $p));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$👉 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [<span style="color:#f92672">++</span>$mp, <span style="color:#f92672">++</span>$pc];
-</span></span><span style="display:flex;"><span>$👈 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [<span style="color:#f92672">--</span>$mp, <span style="color:#f92672">++</span>$pc];
-</span></span><span style="display:flex;"><span>$👍 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$m[$mp]];
-</span></span><span style="display:flex;"><span>$👎 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$m[$mp]];
-</span></span><span style="display:flex;"><span>$📝 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, $put($m[$mp])];
-</span></span><span style="display:flex;"><span>$🤡 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($m[$mp]) {
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=&gt;</span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) {
-</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$n),
-</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=&gt;</span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> <span style="color:#f92672">++</span>$pc <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$n),
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">++</span>$pc, $n),
-</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])],
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc],
-</span></span><span style="display:flex;"><span>};
-</span></span><span style="display:flex;"><span>$🎪 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($m[$mp]) {
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc],
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) {
-</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">++</span>$n),
-</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=&gt;</span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> $pc<span style="color:#f92672">+!</span>[] <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">--</span>$n),
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">--</span>$pc, $n),
-</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])],
-</span></span><span style="display:flex;"><span>};
-</span></span><span style="display:flex;"><span>$🐘 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p) <span style="color:#f92672">=&gt;</span> $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">isset</span>($p[$pc]) <span style="color:#f92672">&amp;&amp;</span> $loop($m, $p, $b, $e, <span style="color:#f92672">...</span>($p[$pc]($m, $p, $b, $e, $mp, $pc)))
-</span></span><span style="display:flex;"><span>)($mm(<span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.!</span>[])), $p, $id($🤡), $id($🎪), <span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+!!</span>[]);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$🐘([
-</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $🤡,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👈, $👈, $👈, $👈, $👎,
-</span></span><span style="display:flex;"><span> $🎪,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👉, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👈, $👎, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span>]);
-</span></span></code></pre></div><p>この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。</p>
-<h2 id="解説">解説</h2>
-<h3 id="絵文字">絵文字</h3>
-<p>まず目につくのは大量の絵文字だろう。
-PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。</p>
-<h3 id="プログラム全体">プログラム全体</h3>
-<p>Brainf*ck のインタプリタとプログラムになっている。
-Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。</p>
-<p><a href="https://ja.wikipedia.org/wiki/Brainfuck">https://ja.wikipedia.org/wiki/Brainfuck</a></p>
-<p>なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。</p>
-<pre tabindex="0"><code>+ + + + + + + + + +
-[
- &gt; + + +
- &gt; + + + + +
- &gt; + + + + + + + + + + + +
- &gt; + + + + + + + + + +
- &lt; &lt; &lt; &lt; -
-]
-&gt; + + + + + .
-- - .
-&gt; - - - .
-&gt; - - - .
-- - .
-- .
-&lt; .
-&gt; &gt; - - .
-+ + + + + + + .
-&lt; - - - - .
-&lt; .
-&gt; + + .
-&gt; - .
-&lt; .
-</code></pre><p>実行結果はこちら: <a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a></p>
-<p>それぞれの絵文字で表された関数が、各命令に対応している。</p>
-<ul>
-<li><code>$👉</code>: <code>&gt;</code></li>
-<li><code>$👈</code>: <code>&lt;</code></li>
-<li><code>$👍</code>: <code>+</code></li>
-<li><code>$👎</code>: <code>-</code></li>
-<li><code>$📝</code>: <code>.</code></li>
-<li><code>$🤡</code>: <code>[</code></li>
-<li><code>$🎪</code>: <code>]</code></li>
-</ul>
-<p><code>,</code> (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。</p>
-<p>なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。</p>
-<h3 id="絵文字の選択">絵文字の選択</h3>
-<p>おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> は弊社デジタルサーカスにちなんでいる。
-また、<code>$🐘</code> は PHP のマスコットの象に由来する。</p>
-<h3 id="strict_types">strict_types</h3>
-<p><code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code> の数値リテラルだが、
-<code>0x0</code> や <code>0b1</code> のような値も受け付ける。
-今回は、PHP 8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。</p>
-<h3 id="url">URL</h3>
-<p>ソースコードのライセンスを示したこの部分だが、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span>
-</span></span></code></pre></div><p>完全に合法な PHP のコードである。
-<code>https:</code> 部分はラベル、<code>//</code> 以降は行コメントになっている。</p>
-<h3 id="リテラルなしで数値を生成する">リテラルなしで数値を生成する</h3>
-<p>ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。
-PHP では、型変換を利用することで任意の整数を作り出すことができる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">1</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">2</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">3</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]<span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">10</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.+!!</span>[]));
-</span></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 が作れる)。</p>
-<p>また、<code>error_reporting</code> に指定しているのは <code>-1</code> である。
-これは、<code>!</code> によって文字列を <code>false</code> にし、<code>+</code> によって <code>false</code> を <code>0</code> にし、さらにビット反転して <code>-1</code> にしている。</p>
-<h3 id="if-文なしで条件分岐"><code>if</code> 文なしで条件分岐</h3>
-<p>三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> を一切書かずに条件分岐ができる。
-また、<code>&amp;&amp;</code> / <code>||</code> も使えることがある。
-遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> のような形で分岐することもできる。</p>
-<h3 id="whilefor-文なしでループ"><code>while</code>、<code>for</code> 文なしでループ</h3>
-<p>不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。
-ここでは、一般に Z コンビネータとして知られるものを使った (<code>$z</code>)。</p>
-<p>実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。</p>
-<p>なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、
-あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。</p>
-<h1 id="第2問-riddlephp">第2問 riddle.php</h1>
-<p>ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">/*********************************************************
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * This program displays a PHPer token. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Guess &#39;N&#39;. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Hints: *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - N itself has no special meaning, e.g., 42, 8128, *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * it is selected at random. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Each element of $token represents a single letter. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - One letter consists of 5x5 cells. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Remember, the output is a complete PHPer token. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * License: *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * https://creativecommons.org/publicdomain/zero/1.0/ *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> *********************************************************/</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">N</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e">/* Change it to your answer. */</span>;
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x14B499C</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0BE34CC</span>, <span style="color:#ae81ff">0x01C9C69</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0ECA069</span>, <span style="color:#ae81ff">0x01C2449</span>, <span style="color:#ae81ff">0x0FDB166</span>, <span style="color:#ae81ff">0x01C9C69</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x01C1C66</span>, <span style="color:#ae81ff">0x0FC1C47</span>, <span style="color:#ae81ff">0x01C1C66</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x10C5858</span>, <span style="color:#ae81ff">0x1E4E3B8</span>, <span style="color:#ae81ff">0x1A2F2F8</span>,
-</span></span><span style="display:flex;"><span>];
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($token <span style="color:#66d9ef">as</span> $x) {
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{</span>$x<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。
-トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。</p>
-<p>ここでは、私の想定解を解説する。</p>
-<h2 id="読解">読解</h2>
-<p>まずはソースコードを読んでいく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 略
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>];
-</span></span></code></pre></div><p>数値からなる <code>$token</code> があり、各要素をループしている。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span></code></pre></div><p>まずは排他的論理和 (xor) を取り、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span></code></pre></div><p>二進数に変換して、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span></code></pre></div><p>0 を空白に、1 を <code>#</code> にし、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span></code></pre></div><p>5文字ごとに区切ったあと、改行で結合している。</p>
-<h2 id="ヒント">ヒント</h2>
-<p>次に、ソースコードに書いてあるヒントを読んでいく。</p>
-<ul>
-<li><code>N</code> それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている</li>
-<li><code>$token</code> の各要素は、1文字を表す</li>
-<li>1文字は 5x5 のセルからなる</li>
-<li>出力されるのは、完全な PHPer トークンである</li>
-</ul>
-<p>ここで、PHPer トークンは必ず <code>#</code> 記号から始まることを思いだすと、
-<code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code>#</code> になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。</p>
-<h2 id="解く">解く</h2>
-<p>ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> に変換されるような <code>N</code> を見つければよい。</p>
-<p><code>N</code> は高々</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>);
-</span></span></code></pre></div><p>なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0x14B499C</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>($x <span style="color:#f92672">===</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # &#34;</span>);
-</span></span></code></pre></div><p>この一連の変換に対する逆変換を考えると、次のようになる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # &#34;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;&#39;</span>, <span style="color:#a6e22e">explode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, $x));
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">bindec</span>($x);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#ae81ff">0x14B499C</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;N = </span><span style="color:#e6db74">$n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>これを実行すると、<code>N</code> が得られる。</p>
-<h1 id="第3問-toquinephp">第3問 toquine.php</h1>
-<p>ソースコードはこちら。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// License: https://creativecommons.org/publicdomain/zero/1.0/
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// This is a quine-like program to generate a PHPer token.
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Execute it like this: php toquine.php | php | php | php | ...
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#e6db74">&lt;&lt;&lt;&#39;</span><span style="color:#e6db74">Q</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&lt;?cuc
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ...
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f$f = %f;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$f = fge_ebg13($f); $kf = [
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f,
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">];
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g = ahyy.snyfr; sbe ($v = 0; $v &lt;= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g .= vzcybqr(&#34;\a&#34;, fge_fcyvg(fge_ercynpr([&#39;0&#39;,&#39;1&#39;], [&#39; &#39;,&#39;##&#39;], fcevags(pue(37) . &#39;025o&#39;, $kf[$v])), 012)) . &#34;\a\a&#34;;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$jf = neenl_znc(sa($j) =&gt; vzcybqr(&#39;, &#39;, $j), neenl_puhax(neenl_znc(sa($k) =&gt; fcevags(&#39;0k&#39; . pue(37) . &#39;07K&#39;, $k), $kf), 10));
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">cevags($f, $g, fge_ebg13(&#34;&lt;&lt;&lt;&#39;Q&#39;\a{$f}\aQ&#34;), vzcybqr(&#34;,\a&#34;, $jf));
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#e6db74">Q</span>;
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_rot13</span>($s); $xs <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x0AFABEA</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x0002800</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x0117041</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F295B7</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1151151</span>, <span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1F8C63F</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x1F8C631</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x1F8C63F</span>, <span style="color:#ae81ff">0x1F295B7</span>,
-</span></span><span style="display:flex;"><span>];
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">.</span><span style="color:#66d9ef">false</span>; <span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">intdiv</span>(<span style="color:#66d9ef">__LINE__</span><span style="color:#f92672">-</span><span style="color:#ae81ff">035</span>,<span style="color:#ae81ff">6</span>); <span style="color:#f92672">++</span>$i) <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">isset</span>($xs[$i])) <span style="color:#66d9ef">break</span>; <span style="color:#66d9ef">else</span>
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">.=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>(<span style="color:#a6e22e">str_replace</span>([<span style="color:#e6db74">&#39;0&#39;</span>,<span style="color:#e6db74">&#39;1&#39;</span>], [<span style="color:#e6db74">&#39; &#39;</span>,<span style="color:#e6db74">&#39;##&#39;</span>], <span style="color:#a6e22e">sprintf</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;025b&#39;</span>, $xs[$i])), <span style="color:#ae81ff">012</span>)) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>$ws <span style="color:#f92672">=</span> <span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($w) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>, $w), <span style="color:#a6e22e">array_chunk</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;0x&#39;</span> <span style="color:#f92672">.</span> <span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;07X&#39;</span>, $x), $xs), <span style="color:#ae81ff">10</span>));
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>($s, $t, <span style="color:#a6e22e">str_rot13</span>(<span style="color:#e6db74">&#34;&lt;&lt;&lt;&#39;D&#39;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">{</span>$s<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">D&#34;</span>), <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;,</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, $ws));
-</span></span></code></pre></div><p>コメントにもあるとおり、次のようにして実行すれば答えがでてくる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php toquine.php | php | php | php | ...
-</span></span></code></pre></div><p>実際にはもう少しパイプで繋げなければならない。</p>
-<h2 id="解説-1">解説</h2>
-<h3 id="プログラム全体-1">プログラム全体</h3>
-<p>コメントにもあるとおり、これは quine (風) のプログラムになっている。
-Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。</p>
-<p>このプログラムは、実行すると自身とほとんど同じプログラムを出力する。
-異なるのはトークンになっている部分のみである。</p>
-<h3 id="トークン">トークン</h3>
-<p><code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。</p>
-<h3 id="状態保持">状態保持</h3>
-<p>トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。
-このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code>__LINE__</code> から情報を取得している。</p>
-<h3 id="rot-13">ROT 13</h3>
-<p>Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。
-これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 変換を使って難読化した。</p>
-<p>それにしてもなぜこんなものが標準ライブラリに……。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。</p>
-<p>今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、
-来年は 5問、より面白い問題を持っていきます。</p>
-<p>実はもう作りはじめているので、どうか来年もありますように……。</p>
-]]></description>
- </item>
-
- <item>
- <title>Rust のプリミティブ型はどこからやって来るか</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/</link>
- <pubDate>Sat, 02 Oct 2021 09:39:27 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</a></p>
-<hr>
-<h1 id="前置き">前置き</h1>
-<p>Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">#![allow(non_camel_case_types)]</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">#![allow(dead_code)]</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">char</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i8</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i16</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i32</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i64</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i128</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">isize</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u8</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u16</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u32</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u64</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u128</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">usize</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f32</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f64</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">str</span>;
-</span></span></code></pre></div><p>では、普段単に <code>bool</code> と書いたとき、この <code>bool</code> は一体どこから来ているのか。rustc のソースを追ってみた。</p>
-<blockquote>
-<p>前提知識: 一般的なコンパイラの構造、用語。<code>rustc</code> そのものの知識は不要 (というよりも筆者自身がよく知らない)</p>
-</blockquote>
-<h1 id="調査">調査</h1>
-<p>調査に使用したソース (調査時点での最新 master)</p>
-<p><a href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</a></p>
-<p>どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。</p>
-<p>大雑把な構造としては、<code>compiler</code> フォルダ以下に <code>rustc_*</code> という名前のクレートが数十個入っている。これがどうやら <code>rustc</code> コマンドの実装部のようだ。</p>
-<p><code>rustc</code> はセルフホストされている (= <code>rustc</code> 自身が Rust で書かれている) ので、<code>bool</code> や <code>char</code> などで適当に検索をかけてもノイズが多すぎて話にならない。
-しかし、お誂え向きなことに <code>i128</code>/<code>u128</code> というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って <code>git grep</code> してみる。</p>
-<pre tabindex="0"><code>$ git grep &#34;\bi128\b&#34; | wc # i128
- 165 1069 15790
-
-$ git grep &#34;\bu128\b&#34; | wc # u128
- 293 2127 26667
-
-$ git grep &#34;\bbool\b&#34; | wc # cf. bool の結果
- 3563 23577 294659
-</code></pre><p>165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。</p>
-<pre tabindex="0"><code>$ git grep &#34;\bi128\b&#34;
-...
-rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));
-...
-</code></pre><p><code>rustc_resolve</code> というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#e6db74">/// Interns the names of the primitive types.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">///
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// All other types are defined somewhere and possibly imported, but the primitive ones need
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// special handling, since they have no place of origin.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">PrimitiveTypeTable</span> {
-</span></span><span style="display:flex;"><span> primitive_types: <span style="color:#a6e22e">FxHashMap</span><span style="color:#f92672">&lt;</span>Symbol, PrimTy<span style="color:#f92672">&gt;</span>,
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> PrimitiveTypeTable {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">new</span>() -&gt; <span style="color:#a6e22e">PrimitiveTypeTable</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> table <span style="color:#f92672">=</span> FxHashMap::default();
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">bool</span>, Bool);
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">char</span>, Char);
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">f32</span>, Float(FloatTy::F32));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">f64</span>, Float(FloatTy::F64));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">isize</span>, Int(IntTy::Isize));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i8</span>, Int(IntTy::I8));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i16</span>, Int(IntTy::I16));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i32</span>, Int(IntTy::I32));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i64</span>, Int(IntTy::I64));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i128</span>, Int(IntTy::I128));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">str</span>, Str);
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">usize</span>, Uint(UintTy::Usize));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u8</span>, Uint(UintTy::U8));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u16</span>, Uint(UintTy::U16));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u32</span>, Uint(UintTy::U32));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u64</span>, Uint(UintTy::U64));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u128</span>, Uint(UintTy::U128));
-</span></span><span style="display:flex;"><span> Self { primitive_types: <span style="color:#a6e22e">table</span> }
-</span></span><span style="display:flex;"><span> }
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、</p>
-<blockquote>
-<p>All other types are defined somewhere and possibly imported, but the primitive ones need special handling, since they have no place of origin.</p>
-</blockquote>
-<p>とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span> <span style="color:#e6db74">/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span> <span style="color:#e6db74">/// (略)
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">resolve_ident_in_lexical_scope</span>(
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">&amp;</span><span style="color:#66d9ef">mut</span> self,
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">mut</span> ident: <span style="color:#a6e22e">Ident</span>,
-</span></span><span style="display:flex;"><span> ns: <span style="color:#a6e22e">Namespace</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// (略)
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> ) -&gt; Option<span style="color:#f92672">&lt;</span>LexicalScopeBinding<span style="color:#f92672">&lt;&#39;</span><span style="color:#a6e22e">a</span><span style="color:#f92672">&gt;&gt;</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// (略)
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> ns <span style="color:#f92672">==</span> TypeNS {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">let</span> Some(prim_ty) <span style="color:#f92672">=</span> self.primitive_type_table.primitive_types.get(<span style="color:#f92672">&amp;</span>ident.name) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> binding <span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span> (Res::PrimTy(<span style="color:#f92672">*</span>prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
-</span></span><span style="display:flex;"><span> .to_name_binding(self.arenas);
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> Some(LexicalScopeBinding::Item(binding));
-</span></span><span style="display:flex;"><span> }
-</span></span><span style="display:flex;"><span> }
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> None
-</span></span><span style="display:flex;"><span> }
-</span></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> など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。</p>
-<p>なお、<code>ns</code> は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この <code>if</code> は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。</p>
-<p>重要なのは、これが <code>resolve_ident_in_lexical_scope()</code> の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。</p>
-<p>動作がわかったところで、例として次のコードを考える。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">#![allow(non_camel_case_types)]</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">main</span>() {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> _: <span style="color:#66d9ef">bool</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">bool</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>ここで <code>main()</code> の <code>bool</code> は <code>struct bool</code> として解決される。なぜなら、プリミティブ型の判定をする前に <code>bool</code> という名前の別の型が見つかるからだ。</p>
-<h1 id="まとめ">まとめ</h1>
-<p>Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。</p>
-]]></description>
- </item>
-
- <item>
- <title>[Ruby] then キーワードと case in</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</link>
- <pubDate>Sat, 02 Oct 2021 09:38:50 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</a></p>
-<hr>
-<h1 id="tl-dr">TL; DR</h1>
-<p><code>case</code> - <code>in</code> によるパターンマッチング構文でも、<code>case</code> - <code>when</code> と同じように <code>then</code> が使える (場合によっては使う必要がある)。</p>
-<h1 id="then-とは"><code>then</code> とは</h1>
-<p>使われることは稀だが、Ruby では <code>then</code> がキーワードになっている。次のように使う:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> cond <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">&#34;Y&#34;</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
-</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">&#34;N&#34;</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code> 構文がそれに当たる。
-上記のように、何か条件を書いた後 <code>then</code> を置き、式がそこで終了していることを示すマーカーとして機能する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># Example:</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> x <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">unless</span> x <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">begin</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">rescue</span> <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">when</span> p <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><h1 id="なぜ普段は書かなくてもよいのか">なぜ普段は書かなくてもよいのか</h1>
-<p>普通 Ruby のコードで <code>then</code> を書くことはない。なぜか。次のコードを実行してみるとわかる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span> puts <span style="color:#e6db74">&#39;Hello, World!&#39;</span> <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>次のような構文エラーが出力される。</p>
-<pre tabindex="0"><code>20:1: syntax error, unexpected local variable or method, expecting `then&#39; or &#39;;&#39; or &#39;\n&#39;
-if true puts &#39;Hello, World!&#39; end
- ^~~~
-20:1: syntax error, unexpected `end&#39;, expecting end-of-input
-...f true puts &#39;Hello, World!&#39; end
-</code></pre><p>二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code> か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。</p>
-<p>ポイントは改行が <code>then</code> (や <code>;</code>) の代わりとなることである。<code>true</code> の後に改行を入れてみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span>
-</span></span><span style="display:flex;"><span>puts <span style="color:#e6db74">&#39;Hello, World!&#39;</span> <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>無事 Hello, World! と出力されるようになった。</p>
-<h1 id="なぜ-then-や--や改行が必要か">なぜ <code>then</code> や <code>;</code> や改行が必要か</h1>
-<p>なぜ <code>then</code> や <code>;</code> や改行 (以下 「<code>then</code> 等」) が必要なのだろうか。次の例を見てほしい:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a b <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p><code>then</code> も <code>;</code> も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。
-この例は二通りに解釈できる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e"># その結果が truthy なら何もしない</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a(b) <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></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> も同じ役割を持つ。</p>
-<p>Ruby の場合、プログラマーが書きやすいよう改行でもって <code>then</code> が代用できるので、ほとんどの場合 <code>then</code> は必要ない。</p>
-<h1 id="case---in-における-then"><code>case</code> - <code>in</code> における <code>then</code></h1>
-<p>ようやく本題にたどり着いた。来る Ruby 3.0 では <code>case</code> と <code>in</code> キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして <code>then</code> 等が必要になる。
-(現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。</p>
-<p><a href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</a></p>
-<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in
- {
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- p-&gt;command_start = FALSE;
- $&lt;ctxt&gt;1 = p-&gt;ctxt;
- p-&gt;ctxt.in_kwarg = 1;
- $&lt;tbl&gt;$ = push_pvtbl(p);
- }
- {
- $&lt;tbl&gt;$ = push_pktbl(p);
- }
- p_top_expr then
- {
- pop_pktbl(p, $&lt;tbl&gt;3);
- pop_pvtbl(p, $&lt;tbl&gt;2);
- p-&gt;ctxt.in_kwarg = $&lt;ctxt&gt;1.in_kwarg;
- }
- compstmt
- p_cases
- {
- /*%%%*/
- $$ = NEW_IN($4, $7, $8, &amp;@$);
- /*% %*/
- /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
- }
- ;
-</code></pre><p>簡略版:</p>
-<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in p_top_expr then compstmt p_cases
- ;
-</code></pre><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>、改行のいずれかである。</p>
-<p>これにより、<code>case</code> - <code>when</code> による従来の構文と同じように、<code>then</code> 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span> <span style="color:#66d9ef">then</span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span> <span style="color:#66d9ef">then</span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span> <span style="color:#66d9ef">then</span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span>
-</span></span><span style="display:flex;"><span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span>; a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span>; b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span>; c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>ところで、<code>p_top_expr</code> には <code>if</code> による guard clause が書けるので、その場合は <code>if</code> - <code>then</code> と似たような見た目になる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">if</span> n <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">then</span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><h1 id="まとめ">まとめ</h1>
-<ul>
-<li><code>if</code> や <code>case</code> の条件の後ろには <code>then</code>、<code>;</code>、改行のいずれかが必要
-<ul>
-<li>通常は改行しておけばよい</li>
-</ul>
-</li>
-<li>3.0 で入る予定の <code>case</code> - <code>in</code> でも <code>then</code> 等が必要になる</li>
-<li>Ruby の構文を正確に知るには (現状) <code>parse.y</code> を直接読めばよい</li>
-</ul>
-]]></description>
- </item>
-
- <item>
- <title>[C&#43;&#43;] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</link>
- <pubDate>Sat, 02 Oct 2021 09:38:30 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</a></p>
-<hr>
-<p>タイトル落ち。まずはこのコードを見て欲しい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;iostream&gt;</span><span style="color:#75715e">
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// [[using]]
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">int</span> main() {
-</span></span><span style="display:flex;"><span> std<span style="color:#f92672">::</span>cout <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#34;Hello, World!&#34;</span> <span style="color:#f92672">&lt;&lt;</span> std<span style="color:#f92672">::</span>endl;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><blockquote>
-<p>コンパイラのバージョン
-$ clang++ &ndash;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</p>
-<p>コンパイルコマンド (C++17指定)
-$ clang++ &ndash;std=c++17 hoge.cpp</p>
-</blockquote>
-<p>この記事から得られるものはこれ以上ないので以下は蛇足になる。</p>
-<p>別件で cppreference.com の <a href="https://en.cppreference.com/w/cpp/language/identifiers">identifier のページ</a> を読んでいた時、次の文が目に止まった。</p>
-<blockquote>
-<ul>
-<li>the identifiers that are keywords cannot be used for other purposes;
-<ul>
-<li>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)</li>
-</ul>
-</li>
-</ul>
-</blockquote>
-<p>キーワードでも属性として指定する場合は非キーワードとして使えるらしい。
-実際にやってみる。</p>
-<p>同サイトの [keywords のページ] (<a href="https://en.cppreference.com/w/cpp/keyword">https://en.cppreference.com/w/cpp/keyword</a>) から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。
-大量の警告 (unknown attribute &lsquo;〇〇&rsquo; ignored) がコンパイラから出力されるが、コンパイルできる。</p>
-<p>上のコードでは <code>[[using]]</code> をコメントアウトしているが、これは <code>using</code> キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">// using の例
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]]</span> <span style="color:#960050;background-color:#1e0010">の糖衣構文</span>
-</span></span></code></pre></div><p>C++17 の仕様も見てみる (正確には標準化前のドラフト)。</p>
-<p>引用元: <a href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</a></p>
-<blockquote>
-<p>If a keyword or an alternative token that satisfies the syntactic requirements of an identifier is contained in an attribute-token, it is considered an identifier.</p>
-</blockquote>
-<p>「<code>identifier</code> の構文上の要件を満たすキーワードまたは代替トークンが <code>attribute-token</code> に含まれている場合、<code>identifier</code> とみなされる」とある。どうやら間違いないようだ。</p>
-<p>ところで、代替トークン (alternative token) とは <code>and</code> (<code>&amp;</code>) や <code>bitor</code> (<code>|</code>) などのことだが、<code>identifier</code> の構文上の要件を満たさないような代替トークンなどあるのか?
-疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい (参考: <a href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</a>)</p>
-<ul>
-<li><code>&lt;%</code> → <code>{</code></li>
-<li><code>%&gt;</code> → <code>}</code></li>
-<li><code>&lt;:</code> → <code>[</code></li>
-<li><code>:&gt;</code> → <code>]</code></li>
-<li><code>%:</code> → <code>#</code></li>
-<li><code>%:%:</code> → <code>##</code></li>
-</ul>
-<p>「<code>identifier</code> の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。</p>
-<p>調べた感想: 字句解析器か構文解析器が辛そう</p>
-]]></description>
- </item>
-
- <item>
- <title>[Ruby] 自身を実行している処理系の種類を判定する</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/</link>
- <pubDate>Sat, 02 Oct 2021 09:37:50 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</a></p>
-<hr>
-<p>Ruby という言語には複数の実装があるが、それらをスクリプト上からどのようにして programmatically に見分ければよいだろうか。</p>
-<p><code>Object</code> クラスに定義されている <code>RUBY_ENGINE</code> という定数がこの用途に使える。</p>
-<p>参考: <a href="https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html">Object::RUBY_ENGINE</a></p>
-<p>上記ページの例から引用する:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ruby-1.9.1 -ve <span style="color:#e6db74">&#39;p RUBY_ENGINE&#39;</span>
-</span></span><span style="display:flex;"><span>ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux]
-</span></span><span style="display:flex;"><span>&#34;ruby&#34;
-</span></span><span style="display:flex;"><span>$ jruby -ve <span style="color:#e6db74">&#39;p RUBY_ENGINE&#39;</span>
-</span></span><span style="display:flex;"><span>jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
-</span></span><span style="display:flex;"><span>&#34;jruby&#34;
-</span></span></code></pre></div><p>それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。</p>
-<p><a href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE correspond to which Ruby implementations?</a> より引用:</p>
-<blockquote>
-<table>
-<thead>
-<tr>
-<th style="text-align:center">RUBY_ENGINE</th>
-<th style="text-align:left">Implementation</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td style="text-align:center">&lt;undefined&gt;</td>
-<td style="text-align:left">MRI &lt; 1.9</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;ruby&rsquo;</td>
-<td style="text-align:left">MRI &gt;= 1.9 or REE</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;jruby&rsquo;</td>
-<td style="text-align:left">JRuby</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;macruby&rsquo;</td>
-<td style="text-align:left">MacRuby</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;rbx&rsquo;</td>
-<td style="text-align:left">Rubinius</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;maglev&rsquo;</td>
-<td style="text-align:left">MagLev</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;ironruby&rsquo;</td>
-<td style="text-align:left">IronRuby</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;cardinal&rsquo;</td>
-<td style="text-align:left">Cardinal</td>
-</tr>
-</tbody>
-</table>
-</blockquote>
-<p>なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も <code>'ruby'</code> が返ってくることを確認済み。</p>
-<p>この表にない主要な処理系として、<a href="https://mruby.org">mruby</a> は <code>'mruby'</code> を返す。</p>
-<p><a href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby 該当部分のソース</a> より引用:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * Ruby engine.
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">#define MRUBY_RUBY_ENGINE &#34;mruby&#34;
-</span></span></span></code></pre></div>]]></description>
- </item>
-
- <item>
- <title>Vimで選択した行の順番を入れ替える</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/</link>
- <pubDate>Sat, 02 Oct 2021 09:37:25 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/4fefb361d9a693803520">https://qiita.com/nsfisis/items/4fefb361d9a693803520</a></p>
-<hr>
-<h1 id="バージョン情報">バージョン情報</h1>
-<p><code>:version</code> の一部</p>
-<blockquote>
-<p>VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Jan 26 2020 11:30:30)
-macOS version
-Included patches: 1-148
-Huge version without GUI.</p>
-</blockquote>
-<h1 id="よく紹介されている手法">よく紹介されている手法</h1>
-<h2 id="tac--tail"><code>tac</code> / <code>tail</code></h2>
-<p><code>tac</code> や <code>tail -r</code> などの外部コマンドを <code>!</code> を使って呼び出し、置き換える。</p>
-<blockquote>
-<p>:h v_!</p>
-</blockquote>
-<p><code>tac</code> コマンドや <code>tail</code> の <code>-r</code> オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい</p>
-<h2 id="gm0"><code>:g/^/m0</code></h2>
-<p>こちらは外部コマンドに頼らず、Vim の機能のみを使う。<code>g</code> は <code>:global</code> コマンドの、<code>m</code> は <code>:move</code> コマンドの略</p>
-<p><code>:global</code> コマンドは <code>:[range]global/{pattern}/[command]</code> のように使い、<code>[range]</code> で指定された範囲の行のうち、<code>{pattern}</code> で指定された検索パターンにマッチする行に対して、順番に <code>[command]</code> で指定された Ex コマンドを呼び出す。</p>
-<blockquote>
-<p>:h :global</p>
-</blockquote>
-<p><code>:move</code> コマンドは <code>[range]:move {address}</code> のように使い、<code>[range]</code> で指定された範囲の行を <code>{address}</code> で指定された位置に移動させる。</p>
-<blockquote>
-<p>:h :move</p>
-</blockquote>
-<p><code>:g/^/m0</code> のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。</p>
-<p>なお、<code>:g/^/m0</code> は全ての行を入れ替えるが、<code>:N,Mg/^/mN-1</code> とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ &lt;<span style="color:#a6e22e">line1</span>&gt;,&lt;<span style="color:#a6e22e">line2</span>&gt;<span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span>&lt;<span style="color:#a6e22e">line1</span>&gt;<span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div><p>これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。</p>
-<h1 id="gm0-の問題点"><code>:g/^/m0</code> の問題点</h1>
-<p><code>:global</code> コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<code>^</code> は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<code>'hlsearch'</code> オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと <code>n</code> コマンドなどの際に不便である。</p>
-<blockquote>
-<p>:h @/</p>
-</blockquote>
-<h1 id="解決策">解決策</h1>
-<blockquote>
-<p>[2020/9/28追記]
-より簡潔な方法を見つけたので次節に追記した</p>
-</blockquote>
-<p>前述した <code>:Reverse</code> コマンドの定義を少し変えて、次のようにする:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#66d9ef">function</span>! <span style="color:#a6e22e">s</span>:<span style="color:#a6e22e">reverse_lines</span>(<span style="color:#a6e22e">from</span>, <span style="color:#a6e22e">to</span>) <span style="color:#a6e22e">abort</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#a6e22e">execute</span> <span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">&#34;%d,%dg/^/m%d&#34;</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">from</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">to</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">from</span> - <span style="color:#ae81ff">1</span>)<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">endfunction</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">call</span> &lt;<span style="color:#a6e22e">SID</span>&gt;<span style="color:#a6e22e">reverse_lines</span>(&lt;<span style="color:#a6e22e">line1</span>&gt;, &lt;<span style="color:#a6e22e">line2</span>&gt;)<span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div><p>実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。</p>
-<p>この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが <code>^</code> で上書きされることがなくなる。</p>
-<p>Vim のヘルプから該当箇所を引用する (強調は筆者による)。</p>
-<blockquote>
-<p>:h autocmd-searchpat</p>
-<p><strong>Autocommands do not change the current search patterns.</strong> Vim saves the current
-search patterns before executing autocommands then restores them after the
-autocommands finish. This means that autocommands do not affect the strings
-highlighted with the &lsquo;hlsearch&rsquo; option.</p>
-</blockquote>
-<p>これは autocommand の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは <code>:nohlsearch</code> のヘルプにある。同じく該当箇所を引用する (強調は筆者による)。</p>
-<blockquote>
-<p>:h :nohlsearch</p>
-<p>(略) This command doesn&rsquo;t work in an autocommand, because
-the highlighting state is saved and restored when
-executing autocommands |autocmd-searchpat|.
-<strong>Same thing for when invoking a user function.</strong></p>
-</blockquote>
-<p>この仕様により、<code>:g/^/m0</code> の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。</p>
-<h1 id="解決策-改訂版">解決策 (改訂版)</h1>
-<blockquote>
-<p>[2020/9/28追記]
-より簡潔な方法を見つけたため追記する</p>
-</blockquote>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">keeppatterns</span> &lt;<span style="color:#a6e22e">line1</span>&gt;,&lt;<span style="color:#a6e22e">line2</span>&gt;<span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span>&lt;<span style="color:#a6e22e">line1</span>&gt;<span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div><p>まさにこのための Exコマンド、<code>:keeppatterns</code> が存在する。<code>:keeppatterns {command}</code> のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。</p>
-<blockquote>
-<p>:h :keeppatterns</p>
-</blockquote>
-<h1 id="コピペ用再掲">コピペ用再掲</h1>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#75715e">&#34; License: Public Domain</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">keeppatterns</span> &lt;<span style="color:#a6e22e">line1</span>&gt;,&lt;<span style="color:#a6e22e">line2</span>&gt;<span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span>&lt;<span style="color:#a6e22e">line1</span>&gt;<span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div>]]></description>
- </item>
-
- <item>
- <title>[Vim] autocmd events の BufWrite/BufWritePre の違い</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/</link>
- <pubDate>Sat, 02 Oct 2021 09:37:12 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</a></p>
-<hr>
-<h1 id="tl-dr">TL; DR</h1>
-<p>違いはない。ただのエイリアス。</p>
-<h1 id="調査記録">調査記録</h1>
-<p>Vim の autocmd events には似通った名前のものがいくつかある。大抵は <code>:help</code> に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。</p>
-<ul>
-<li><code>BufRead</code>/<code>BufReadPost</code></li>
-<li><code>BufWrite</code>/<code>BufWritePre</code></li>
-<li><code>BufAdd</code>/<code>BufCreate</code></li>
-</ul>
-<p>このうち、<code>BufAdd</code>/<code>BufCreate</code> に関しては、<code>:help BufCreate</code> に</p>
-<blockquote>
-<p>The BufCreate event is for historic reasons.</p>
-</blockquote>
-<p>とあり、おそらくは <code>BufAdd</code> のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため vim と neovim のソースコードを調査した。</p>
-<blockquote>
-<p>ソースコードへのリンク
-<a href="https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2">vim (調査時点での master branch)</a>
-<a href="https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3">neovim (上に同じ)</a></p>
-</blockquote>
-<h2 id="vim-のソースコード">vim のソースコード</h2>
-<p>以下は、autocmd events の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。</p>
-<p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufAdd&#34;</span>, EVENT_BUFADD},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufCreate&#34;</span>, EVENT_BUFADD},
-</span></span></code></pre></div><p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufRead&#34;</span>, EVENT_BUFREADPOST},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufReadCmd&#34;</span>, EVENT_BUFREADCMD},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufReadPost&#34;</span>, EVENT_BUFREADPOST},
-</span></span></code></pre></div><p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufWrite&#34;</span>, EVENT_BUFWRITEPRE},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufWritePost&#34;</span>, EVENT_BUFWRITEPOST},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufWritePre&#34;</span>, EVENT_BUFWRITEPRE},
-</span></span></code></pre></div><h2 id="neovim-のソースコード">neovim のソースコード</h2>
-<p>neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua で書かれている。以下にある通り、はっきり <code>aliases</code> と書かれている。</p>
-<p><a href="https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124">https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span> aliases <span style="color:#f92672">=</span> {
-</span></span><span style="display:flex;"><span> BufCreate <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;BufAdd&#39;</span>,
-</span></span><span style="display:flex;"><span> BufRead <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;BufReadPost&#39;</span>,
-</span></span><span style="display:flex;"><span> BufWrite <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;BufWritePre&#39;</span>,
-</span></span><span style="display:flex;"><span> FileEncoding <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;EncodingChanged&#39;</span>,
-</span></span><span style="display:flex;"><span> },
-</span></span></code></pre></div><p>ところで、上では取り上げなかった <code>FileEncoding</code> だが、これは <code>:help FileEncoding</code> にしっかりと書いてある。</p>
-<pre tabindex="0"><code> *FileEncoding*
-FileEncoding Obsolete. It still works and is equivalent
- to |EncodingChanged|.
-</code></pre><h2 id="まとめ">まとめ</h2>
-<p>記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。</p>
-<ul>
-<li><code>BufAdd</code>/<code>BufCreate</code>
-<ul>
-<li>→ <code>BufCreate</code> は歴史的な理由により (&ldquo;for historic reasons&rdquo;) 存在しているため、新しい方 (<code>BufAdd</code>) を使う</li>
-</ul>
-</li>
-<li><code>BufRead</code>/<code>BufReadPost</code>
-<ul>
-<li>→ <code>BufReadPre</code> との対称性のため、あるいは <code>BufWritePost</code> との対称性のため <code>BufReadPost</code> を使う</li>
-</ul>
-</li>
-<li><code>BufWrite</code>/<code>BufWritePre</code>
-<ul>
-<li>→ <code>BufWritePost</code> との対称性のため、あるいは <code>BufReadPre</code> との対称性のため <code>BufWritePre</code> を使う</li>
-</ul>
-</li>
-<li><code>FileEncoding</code>/<code>EncodingChanged</code>
-<ul>
-<li>→ <code>FileEncoding</code> は &ldquo;Obsolete&rdquo; と明言されているので、<code>EncodingChanged</code> を使う</li>
-</ul>
-</li>
-</ul>
-<p>ところでこの調査で知ったのだが、<code>BufRead</code> と <code>BufWrite</code> は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら <code>Pre</code>/<code>Post</code> 付きのものを使った方が分かりやすいだろう。</p>
-]]></description>
- </item>
-
- <item>
- <title>[Python] クロージャとUnboundLocalError: local variable &#39;x&#39; referenced before assignment</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</link>
- <pubDate>Sat, 02 Oct 2021 09:32:37 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</a></p>
-<hr>
-<p>本記事は Python 3.7.6 の動作結果を元にして書かれている。</p>
-<p>Python でクロージャを作ろうと、次のようなコードを書いた。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>f()
-</span></span></code></pre></div><p>関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに 1 を足そうとしている。
-これを実行すると <code>x += 1</code> の箇所でエラーが発生する。</p>
-<blockquote>
-<p>UnboundLocalError: local variable &lsquo;x&rsquo; referenced before assignment</p>
-</blockquote>
-<p>local変数 <code>x</code> が代入前に参照された、とある。これは、<code>f</code> の <code>x</code> を参照するのではなく、新しく別の変数を <code>g</code> 内に作ってしまっているため。
-前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code> を変数宣言のための構文として擬似的に利用している。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># 注: var は正しい Python の文法ではない。上記参照のこと</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># f の local変数 &#39;x&#39; を宣言</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e"># x に 0 を代入</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>(): <span style="color:#75715e"># f の内部関数 g を定義</span>
-</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># g の local変数 &#39;x&#39; を宣言</span>
-</span></span><span style="display:flex;"><span> <span style="color:#75715e"># たまたま f にも同じ名前の変数があるが、それとは別の変数</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span> <span style="color:#75715e"># x に 1 を加算 (x = x + 1 の糖衣構文)</span>
-</span></span><span style="display:flex;"><span> <span style="color:#75715e"># 加算する前の値を参照しようとするが、まだ代入されていないためエラー</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span></code></pre></div><p>当初の意図を表現するには、次のように書けばよい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>():
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">nonlocal</span> x <span style="color:#75715e">## (*)</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span></code></pre></div><p><code>(*)</code> のように、<code>nonlocal</code> を追加する。これにより一つ外側のスコープ (<code>g</code> の一つ外側 = <code>f</code>) で定義されている <code>x</code> を探しに行くようになる。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2021</title>
- <link>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</link>
- <pubDate>Tue, 30 Mar 2021 23:22:40 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</guid>
- <description><![CDATA[ <h1 id="phperkaigi-2021-参加レポ">PHPerKaigi 2021 参加レポ</h1>
-<p>2021-03-26 から 2021-03-28 にかけて開催された、<a href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</a> に一般参加者として参加した。
-弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
-<p>このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。</p>
-<p>発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。</p>
-<h2 id="凡例">凡例</h2>
-<blockquote>
-<p>発表・スライドのメモ (引用ではない)</p>
-</blockquote>
-<p>感想など</p>
-<h2 id="day-0-前夜祭-20210327">Day 0 前夜祭 (2021/03/27)</h2>
-<h3 id="1730-a">17:30 [A]</h3>
-<p>PHP で AWS Lambda</p>
-<blockquote>
-<p>Rails のプロジェクトを PHPer のメンバのみでメンテ
-→他のメンバもわかる PHP にリプレースを検討</p>
-<p>サーバレス</p>
-<ul>
-<li>サーバ・インフラの管理が不要</li>
-<li>アプリケーションコードの知識だけで保守可能</li>
-</ul>
-<p>ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入?</p>
-<p>AWSの学習
-AWS のドキュメント
-DevelopersIO</p>
-<p>AWS Lambda のカスタムランタイムで PHP を動かす</p>
-<p>サーバのセットアップや維持管理を気にしなくて良い
-サーバーレスで PHP を動かすツールがすでにある
-サーバーレス構築はすんなり</p>
-<p>今は Laravel がルーティングしている
-Laravel Livewire を Lambda に載せられないか?
-デプロイ方法は?
-バッチ処理は? (Lambda は 15分の制限)</p>
-<p>Lambda でコンテナイメージがサポートされるように</p>
-<p>抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる</p>
-</blockquote>
-<p>AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。</p>
-<p>PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。</p>
-<p>勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。</p>
-<h3 id="1810-a">18:10 [A]</h3>
-<p>大規模サイトの SEO</p>
-<blockquote>
-<p>大規模サイト (100万ページ以上)
-Google の基準</p>
-<p>クロールバジェットを意識したSEO</p>
-<p>大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される
-これを満たさないなら、クロールバジェットを考えなくてもいい</p>
-<p>サーチコンソール
-「カバレッジ」の「除外」
-多すぎるのは問題→クロールバジェットを浪費している</p>
-<ul>
-<li>クエリの順番を決める</li>
-<li>空の値のルールを決めておく</li>
-<li>リダイレクトすればインデックスはうまくいく</li>
-<li>リンクが存在する限りクロールはされる</li>
-</ul>
-<p>リニューアル前のURL</p>
-<p>インデックスは移行される
-リンクのURLが存在する限り、別のURLとしてクロールされる
-リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い
-リニューアルで無視されるようになったパラメータも注意</p>
-<p>robotes.txt で拒否しているのにクロールされる
-一時的に拒否を外して 404 や 301 を読ませる
-内部リンクを確認する
-JS でのリンクに書き換え</p>
-<p>クエリパラメータからURLのパスに
-<code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code></p>
-<p>URL 設計だいじ</p>
-</blockquote>
-<p>SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。</p>
-<h3 id="1850-a">18:50 [A]</h3>
-<blockquote>
-<p>知覚可能
-操作可能
-理解可能
-堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など)</p>
-<ul>
-<li>
-<p>標準の HTML を適切に使う</p>
-</li>
-<li>
-<p>WAI-ARIA</p>
-</li>
-<li>
-<p>キーボードフレンドリー</p>
-</li>
-<li>
-<p>マシンフレンドリー</p>
-</li>
-<li>
-<p>SEOフレンドリー</p>
-</li>
-</ul>
-<p>button タグ
-→キーボード
-h1 タグ
-→スクリーンリーダー・クローラ
-a タグ</p>
-<p>WAI-ARIA
-HTML では表現できないセマンティクスを追加する</p>
-<ul>
-<li>ロール
-<ul>
-<li>何をするのか?</li>
-<li>ユーザーアクションによって変化しない</li>
-</ul>
-</li>
-<li>プロパティ
-<ul>
-<li>関連づけられたデータ</li>
-</ul>
-</li>
-<li>ステート
-<ul>
-<li>現在の状態</li>
-</ul>
-</li>
-</ul>
-<p>まずは標準の HTML 要素で解決する
-何でもかんでも WAI-ARIA を使えばいいというものではない</p>
-<p>マウスホバーでツールチップが出てくるが、キーボード操作では出てこない</p>
-<p>VoiceOver</p>
-<p>全ての属性を使う必要はない
-あくまでアクセシビリティを上げるための方法の一つにすぎない</p>
-</blockquote>
-<p>つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。</p>
-<h3 id="1930-a">19:30 [A]</h3>
-<p>PHP で FUSE</p>
-<p>個人的に楽しみだった発表。</p>
-<blockquote>
-<p>VFS (virtual filesystem) vs 具体的なファイルシステム</p>
-<p>最適な実装方法は状況により異なる</p>
-<p>アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS</p>
-<p>カーネルのプログラムを作るのは難しい</p>
-<ul>
-<li>権限がデカすぎる</li>
-<li>システム全体がクラッシュ</li>
-<li>セキュリティリスク</li>
-<li>開発サイクルを回しづらい</li>
-<li>ネイティブコードにコンパイルされる言語である必要がある</li>
-</ul>
-<p>Filesystem in USEr space (FUSE)</p>
-<ul>
-<li>特定の C の関数を呼ぶことで filesystem が作れる</li>
-<li>FFI を持つ言語なら FUSE が使える</li>
-</ul>
-<p>SSHFS / s3fs / Docker Desktop</p>
-<p>Linux 以外でも使える</p>
-<ul>
-<li>dokany (on Windows)</li>
-<li>osxfuse</li>
-</ul>
-<p>VFS: システムコールが呼ばれると、ファイルシステムによってコール
-FUSE: カーネル空間からユーザ空間へ通信</p>
-<p>高レベルなラッパで型をつける</p>
-<p>PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)</p>
-<ul>
-<li>grep できる</li>
-<li>sed できる</li>
-<li>編集できる</li>
-</ul>
-</blockquote>
-<p>期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。
-この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。</p>
-<h2 id="day-1-20210327">Day 1 (2021/03/27)</h2>
-<h3 id="1050-a">10:50 [A]</h3>
-<p>ATDD</p>
-<blockquote>
-<ul>
-<li>ユーザーストーリー</li>
-<li>ユニットテスト</li>
-<li>CI/CD</li>
-</ul>
-<p>ユーザストーリーの受け入れ条件が曖昧になりがち
-デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている</p>
-<p>Q2の強化
-アジャイルテストの4象限</p>
-<p>技術面/ビジネス面
-開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)</p>
-<ul>
-<li>Q1: 技術面 &amp; チーム支援
-<ul>
-<li>TDD</li>
-<li>ユニットテストなど</li>
-</ul>
-</li>
-<li>Q2: ビジネス面 &amp; チーム支援
-<ul>
-<li>ATDD</li>
-<li>ビジネス面の受け入れテストで駆動する</li>
-</ul>
-</li>
-</ul>
-<p>Agile Alliance
-ユーザストーリーのスキルレベルを高める</p>
-<p>テストピラミッド</p>
-<ul>
-<li>
-<p>UI Tests</p>
-</li>
-<li>
-<p>Service Tests</p>
-</li>
-<li>
-<p>Unit Tests</p>
-</li>
-<li>
-<p>異なる粒度のテストを書く</p>
-</li>
-<li>
-<p>高レベルになるほど、持つべきテストは少なくなる</p>
-<ul>
-<li>ピラミッド型になる</li>
-</ul>
-</li>
-</ul>
-<p>高レベルテストが多すぎる→アイスクリームコーン アンチパターン</p>
-<p>ATDD (Acceptance TDD)
-API経由・UI経由での高レベルテスト E2E test</p>
-<p>ストーリ受け入れテスト</p>
-<p>入れ子のフィードバックループ
-ATDD(外側) と TDD(内側)</p>
-<p>外部品質・内部品質</p>
-<p>バーティカルスライスのデリバリー</p>
-<ul>
-<li>cucumber</li>
-<li>gauge</li>
-<li>behat</li>
-</ul>
-<p>ユビキタス言語
-手動テストもspecに書く
-自動化は可能だがコスパが悪い
-失敗することがわかっているテスト(レッドテスト)はCIから外す
-失敗時の原因究明が難しい
-饒舌なエラーメッセージ
-状況のスナップショット</p>
-<p>Continuous Testing</p>
-</blockquote>
-<p>User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。
-高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。</p>
-<h3 id="1150-a">11:50 [A]</h3>
-<p>型解析を用いたリファクタリング</p>
-<p>型のある世界で生きてきた身として大いに楽しみにしていた発表。</p>
-<blockquote>
-<ul>
-<li>PHPStan</li>
-<li>Phan</li>
-<li>Psalm</li>
-</ul>
-<p>autoload も認識できる
-bootstrapFiles</p>
-<p>編集箇所と利用箇所を CI でチェック
-ルールレベルを徐々に引き上げていく
-警告が多すぎると見落としてしまう・無視されやすくなる</p>
-<p>型がついていないことによるエラーが多い</p>
-<p>型よりも詳細な検査 <code>Util_Assert::min</code></p>
-<p>SQL を静的解析
-placeholder の型付け</p>
-<p>警告レベルを低いレベルから導入
-タイプヒントを積極的に書いていく
-PHPStan の拡張を追加する</p>
-</blockquote>
-<p>昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。
-今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。</p>
-<h3 id="1230-a">12:30 [A]</h3>
-<p>昼食をとっていた。事前に何か食料を買っておくべきだった。</p>
-<h3 id="1310-a">13:10 [A]</h3>
-<p>Documentation as Code</p>
-<p>この発表も以前から非常に楽しみにしていた。</p>
-<blockquote>
-<p>開発開始までのオーバーヘッド
-新規にチームにジョイン
-担当範囲外の機能を理解
-オンボーディングのコスト</p>
-<p>PHPerKaigi 2020 で発表あり</p>
-<p>継続的にシステムの理解を助けるドキュメント</p>
-<p>継続的ドキュメンテーション
-システムとドキュメントの乖離</p>
-<p>書いてあることが間違っている・足りない</p>
-<ul>
-<li>徐々にずれていく</li>
-<li>システムの更新タイミングとドキュメントの更新タイミングに差がある</li>
-</ul>
-<p>システムとドキュメントは対応関係がある</p>
-<ul>
-<li>間違ったドキュメント</li>
-<li>存在しないドキュメント</li>
-</ul>
-<p>システムとドキュメントの乖離を定量化する
-継続的に
-システムの更新に近いタイミングで ドキュメントを更新し続ける</p>
-<p>Documentation as Code</p>
-<p>コードと同じツールでドキュメントを書く</p>
-<ul>
-<li>issue tracker</li>
-<li>vcs</li>
-<li>plain text markup</li>
-<li>automation</li>
-</ul>
-<p>開発者
-システム
-ドキュメント
-構造化データ
-ソフトウェア</p>
-<p>システムから構造化データを抽出する
-PHPDoc
-OpenAPI</p>
-<p>ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する</p>
-<p>ビューの単位でドキュメントに</p>
-<p>スタックトレースからのドキュメント生成</p>
-</blockquote>
-<p>ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。</p>
-<h3 id="1410-a">14:10 [A]</h3>
-<p>cookie による session 管理</p>
-<p>全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。</p>
-<h3 id="1450-a">14:50 [A]</h3>
-<p>PHP のエラーと例外</p>
-<blockquote>
-<p>エラー PHPエンジンがエラーを通知する
-例外 プログラムが投げる</p>
-<p>PHP7-8とエラー</p>
-<p>PHPエンジンのエラーの一部が \Error に変換されるようになった
-→ try-catch で捕捉できる</p>
-<p>\Error は例外とは異なる</p>
-<p>PHP8 でエラーレベルの引き上げ</p>
-<ul>
-<li>捕捉すべきもの
-<ul>
-<li>recoverable</li>
-</ul>
-</li>
-<li>捕捉すべきでないもの
-<ul>
-<li>unrecoverable</li>
-<li>開発時に対処できるもの</li>
-</ul>
-</li>
-</ul>
-<p>例外</p>
-<ul>
-<li>捕捉して事後処理</li>
-<li>捕捉せず(or 捕捉した上で)さらに上に是非を問う</li>
-</ul>
-<p>開発段階で例外を把握し、ハンドリングを考えておく</p>
-<p>\Throwable \Exception と \Error</p>
-<p>\Error はキャッチすべきでない</p>
-<ul>
-<li>
-<p>\Error</p>
-<ul>
-<li>本番で起きてはいけない</li>
-</ul>
-</li>
-<li>
-<p>\LogicException</p>
-<ul>
-<li>本番で起きてはいけない
-→生じないのだから捕捉もしない</li>
-</ul>
-</li>
-<li>
-<p>\RuntimeException</p>
-<ul>
-<li>起こるかもしれないので本番環境でも考慮する</li>
-</ul>
-</li>
-</ul>
-<p>捕捉して対応するのではなく、未然に防ぐ</p>
-<p>独自例外を使う
-\Exception を投げてしまうと、
-catch (\Exception)せざるを得ない
-→catch 範囲が広すぎる</p>
-<p>SPL の例外を使う</p>
-<p>例外翻訳
-上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する
-下位レイヤの知識に依存させない</p>
-<p>@throws
-捕捉してほしい例外を書き連ねておく</p>
-<p>呼び出しもとに負わせたい責任</p>
-</blockquote>
-<p>PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。</p>
-<p>個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。</p>
-<p>PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。</p>
-<h3 id="1530-a">15:30 [A]</h3>
-<p>Laravel のメール認証</p>
-<p>Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。</p>
-<h3 id="1610-a">16:10 [A]</h3>
-<p>gRPC</p>
-<blockquote>
-<p>Unary RPCs
-Server streaming RPCs
-Client streaming RPCs
-Bidirectional streaming RPCs</p>
-<p>Protobuf</p>
-<p>実装とAPIが乖離しにくい
-自動生成
-複数言語でも相互に使える</p>
-<p>マイクロサービスのサービス通信
-スマホアプリ
-ゲームサーバ</p>
-<p>PHP では?</p>
-<p>PHP ではストリーミングが難しい
-リクエストごとにプロセスが使い捨て</p>
-<p>PHP ではgRPCのクライアントしか対応していない</p>
-<p>gRPC-Web
-ブラウザで扱うためのJSライブラリ+プロトコル</p>
-<p>HTTP/1.1 でも使える
-Unary RPC と Server streaming RPC のみ</p>
-<p>Envoy
-Nginx などで相互に gRPC と gRPC-Web で変換</p>
-<p>Amp
-イベント駆動な並行処理のフレームワーク</p>
-<p>HTTP/2 対応</p>
-<p>C#のgRPC-Webが楽</p>
-</blockquote>
-<p>(発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。</p>
-<h3 id="1650-a">16:50 [A]</h3>
-<p>アーキテクチャテスト</p>
-<blockquote>
-<p>Independent Core Layer Pattern</p>
-<p>開発初期のアーキテクチャが崩れる
-アーキテクチャ観点のコードレビューができない</p>
-<p>どこにクラスを置けばよいか?
-ドキュメントがない</p>
-<p>アーキテクチャ設計に関する知識が属人化・暗黙知化</p>
-<p>ガイドライン</p>
-<ul>
-<li>最初にルールを決めるのは簡単</li>
-<li>ルール通り作り始めるのも簡単
-<ul>
-<li>→維持するのが難しい、人が決めたものゆえ壊れやすい</li>
-</ul>
-</li>
-</ul>
-<p>PHP の特性</p>
-<ul>
-<li>クラスは public</li>
-<li>可視性の制御が public / protected / private のみ</li>
-<li>依存関係の制御が困難</li>
-</ul>
-<p>アーキテクチャテスト
-クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する</p>
-<ul>
-<li>deptrac</li>
-<li>phpat</li>
-</ul>
-<p>Independent Core Layer Pattern</p>
-<p>アーキテクチャテストの失敗</p>
-<ul>
-<li>実装誤り</li>
-<li>or アーキテクチャが適切でない
-<ul>
-<li>開発の過程でフィードバックしていく</li>
-</ul>
-</li>
-</ul>
-<p>モジュラーモノリス→マイクロサービスへ</p>
-</blockquote>
-<h2 id="day-2-20210328">Day 2 (2021/03/28)</h2>
-<p>冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。</p>
-<p>残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。</p>
-<h2 id="全体の感想">全体の感想</h2>
-<p>Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。</p>
-<p>今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。</p>
-<p>1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。
-まあ初カンファレンスだし、とお茶を濁しておこう。</p>
-<p>さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。</p>
-<hr>
-<p>最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました!
-(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)</p>
-<p>ではまた来年。</p>
-]]></description>
- </item>
-
- <item>
- <title>My First Post</title>
- <link>https://blog.nsfisis.dev/posts/2021-03-05/my-first-post/</link>
- <pubDate>Fri, 05 Mar 2021 23:38:21 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-03-05/my-first-post/</guid>
- <description><![CDATA[ <h1 id="test">Test</h1>
-<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/highlight.min.js b/docs/highlight.min.js
deleted file mode 100644
index ce50ad7..0000000
--- a/docs/highlight.min.js
+++ /dev/null
@@ -1,1122 +0,0 @@
-/*!
- Highlight.js v11.0.0-beta1 (git: bc7ef3d912)
- (c) 2006-2021 Ivan Sagalaev and other contributors
- License: BSD-3-Clause
- */
-var hljs=function(){"use strict";var e={exports:{}};function n(e){
-return e instanceof Map?e.clear=e.delete=e.set=()=>{
-throw Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=()=>{
-throw Error("set is read-only")
-}),Object.freeze(e),Object.getOwnPropertyNames(e).forEach((t=>{var a=e[t]
-;"object"!=typeof a||Object.isFrozen(a)||n(a)})),e}
-e.exports=n,e.exports.default=n;var t=e.exports;class a{constructor(e){
-void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}
-ignoreMatch(){this.isMatchIgnored=!0}}function i(e){
-return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")
-}function s(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n]
-;return n.forEach((e=>{for(const n in e)t[n]=e[n]})),t}const r=e=>!!e.kind
-;class o{constructor(e,n){
-this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){
-this.buffer+=i(e)}openNode(e){if(!r(e))return;let n=e.kind
-;n=e.sublanguage?"language-"+n:((e,{prefix:n})=>{if(e.includes(".")){
-const t=e.split(".")
-;return[`${n}${t.shift()}`,...t.map(((e,n)=>`${e}${"_".repeat(n+1)}`))].join(" ")
-}return`${n}${e}`})(n,{prefix:this.classPrefix}),this.span(n)}closeNode(e){
-r(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){
-this.buffer+=`<span class="${e}">`}}class l{constructor(){this.rootNode={
-children:[]},this.stack=[this.rootNode]}get top(){
-return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
-this.top.children.push(e)}openNode(e){const n={kind:e,children:[]}
-;this.add(n),this.stack.push(n)}closeNode(){
-if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){
-for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}
-walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){
-return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),
-n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){
-"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
-l._collapse(e)})))}}class c extends l{constructor(e){super(),this.options=e}
-addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}
-addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root
-;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){
-return new o(this,this.options).value()}finalize(){return!0}}function d(e){
-return e?"string"==typeof e?e:e.source:null}function g(e){return b("(?=",e,")")}
-function u(e){return b("(?:",e,")?")}function b(...e){
-return e.map((e=>d(e))).join("")}function m(...e){return"("+((e=>{
-const n=e[e.length-1]
-;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{}
-})(e).capture?"":"?:")+e.map((e=>d(e))).join("|")+")"}function p(e){
-return RegExp(e.toString()+"|").exec("").length-1}
-const _=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./
-;function f(e,{joinWith:n}){let t=0;return e.map((e=>{t+=1;const n=t
-;let a=d(e),i="";for(;a.length>0;){const e=_.exec(a);if(!e){i+=a;break}
-i+=a.substring(0,e.index),
-a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+(Number(e[1])+n):(i+=e[0],
-"("===e[0]&&t++)}return i})).map((e=>`(${e})`)).join(n)}
-const h="[a-zA-Z]\\w*",E="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",N="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",v={
-begin:"\\\\[\\s\\S]",relevance:0},O={scope:"string",begin:"'",end:"'",
-illegal:"\\n",contains:[v]},M={scope:"string",begin:'"',end:'"',illegal:"\\n",
-contains:[v]},x=(e,n,t={})=>{const a=s({scope:"comment",begin:e,end:n,
-contains:[]},t);a.contains.push({scope:"doctag",
-begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",
-end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0})
-;const i=m("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/)
-;return a.contains.push({begin:b(/[ ]+/,"(",i,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),a
-},S=x("//","$"),k=x("/\\*","\\*/"),A=x("#","$");var C=Object.freeze({
-__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:h,UNDERSCORE_IDENT_RE:E,
-NUMBER_RE:y,C_NUMBER_RE:N,BINARY_NUMBER_RE:w,
-RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
-SHEBANG:(e={})=>{const n=/^#![ ]*\//
-;return e.binary&&(e.begin=b(n,/.*\b/,e.binary,/\b.*/)),s({scope:"meta",begin:n,
-end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},
-BACKSLASH_ESCAPE:v,APOS_STRING_MODE:O,QUOTE_STRING_MODE:M,PHRASAL_WORDS_MODE:{
-begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
-},COMMENT:x,C_LINE_COMMENT_MODE:S,C_BLOCK_COMMENT_MODE:k,HASH_COMMENT_MODE:A,
-NUMBER_MODE:{scope:"number",begin:y,relevance:0},C_NUMBER_MODE:{scope:"number",
-begin:N,relevance:0},BINARY_NUMBER_MODE:{scope:"number",begin:w,relevance:0},
-REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{scope:"regexp",begin:/\//,
-end:/\/[gimuy]*/,illegal:/\n/,contains:[v,{begin:/\[/,end:/\]/,relevance:0,
-contains:[v]}]}]},TITLE_MODE:{scope:"title",begin:h,relevance:0},
-UNDERSCORE_TITLE_MODE:{scope:"title",begin:E,relevance:0},METHOD_GUARD:{
-begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:e=>Object.assign(e,{
-"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{
-n.data._beginMatch!==e[1]&&n.ignoreMatch()}})});function T(e,n){
-"."===e.input[e.index-1]&&n.ignoreMatch()}function R(e,n){
-void 0!==e.className&&(e.scope=e.className,delete e.className)}function D(e,n){
-n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
-e.__beforeBegin=T,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
-void 0===e.relevance&&(e.relevance=0))}function I(e,n){
-Array.isArray(e.illegal)&&(e.illegal=m(...e.illegal))}function B(e,n){
-if(e.match){
-if(e.begin||e.end)throw Error("begin & end are not supported with match")
-;e.begin=e.match,delete e.match}}function L(e,n){
-void 0===e.relevance&&(e.relevance=1)}const $=(e,n)=>{if(!e.beforeMatch)return
-;if(e.starts)throw Error("beforeMatch cannot be used with starts")
-;const t=Object.assign({},e);Object.keys(e).forEach((n=>{delete e[n]
-})),e.keywords=t.keywords,e.begin=b(t.beforeMatch,g(t.begin)),e.starts={
-relevance:0,contains:[Object.assign(t,{endsParent:!0})]
-},e.relevance=0,delete t.beforeMatch
-},z=["of","and","for","in","not","or","if","then","parent","list","value"]
-;function F(e,n,t="keyword"){const a=Object.create(null)
-;return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach((t=>{
-Object.assign(a,F(e[t],n,t))})),a;function i(e,t){
-n&&(t=t.map((e=>e.toLowerCase()))),t.forEach((n=>{const t=n.split("|")
-;a[t[0]]=[e,j(t[0],t[1])]}))}}function j(e,n){
-return n?Number(n):(e=>z.includes(e.toLowerCase()))(e)?0:1}const U={},P=e=>{
-console.error(e)},K=(e,...n)=>{console.log("WARN: "+e,...n)},q=(e,n)=>{
-U[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),U[`${e}/${n}`]=!0)
-},H=Error();function Z(e,n,{key:t}){let a=0;const i=e[t],s={},r={}
-;for(let e=1;e<=n.length;e++)r[e+a]=i[e],s[e+a]=!0,a+=p(n[e-1])
-;e[t]=r,e[t]._emit=s,e[t]._multi=!0}function G(e){(e=>{
-e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,
-delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={
-_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope
-}),(e=>{if(Array.isArray(e.begin)){
-if(e.skip||e.excludeBegin||e.returnBegin)throw P("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),
-H
-;if("object"!=typeof e.beginScope||null===e.beginScope)throw P("beginScope must be object"),
-H;Z(e,e.begin,{key:"beginScope"}),e.begin=f(e.begin,{joinWith:""})}})(e),(e=>{
-if(Array.isArray(e.end)){
-if(e.skip||e.excludeEnd||e.returnEnd)throw P("skip, excludeEnd, returnEnd not compatible with endScope: {}"),
-H
-;if("object"!=typeof e.endScope||null===e.endScope)throw P("endScope must be object"),
-H;Z(e,e.end,{key:"endScope"}),e.end=f(e.end,{joinWith:""})}})(e)}function W(e){
-function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}
-class t{constructor(){
-this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
-addRule(e,n){
-n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),
-this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null)
-;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(f(e,{joinWith:"|"
-}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex
-;const n=this.matcherRe.exec(e);if(!n)return null
-;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),a=this.matchIndexes[t]
-;return n.splice(0,t),Object.assign(n,a)}}class a{constructor(){
-this.rules=[],this.multiRegexes=[],
-this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
-if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t
-;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))),
-n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){
-return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){
-this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){
-const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex
-;let t=n.exec(e)
-;if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{
-const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)}
-return t&&(this.regexIndex+=t.position+1,
-this.regexIndex===this.count&&this.considerAll()),t}}
-if(e.compilerExtensions||(e.compilerExtensions=[]),
-e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.")
-;return e.classNameAliases=s(e.classNameAliases||{}),function t(i,r){const o=i
-;if(i.isCompiled)return o
-;[R,B,G,$].forEach((e=>e(i,r))),e.compilerExtensions.forEach((e=>e(i,r))),
-i.__beforeBegin=null,[D,I,L].forEach((e=>e(i,r))),i.isCompiled=!0;let l=null
-;return"object"==typeof i.keywords&&i.keywords.$pattern&&(i.keywords=Object.assign({},i.keywords),
-l=i.keywords.$pattern,
-delete i.keywords.$pattern),l=l||/\w+/,i.keywords&&(i.keywords=F(i.keywords,e.case_insensitive)),
-o.keywordPatternRe=n(l,!0),
-r&&(i.begin||(i.begin=/\B|\b/),o.beginRe=n(i.begin),i.end||i.endsWithParent||(i.end=/\B|\b/),
-i.end&&(o.endRe=n(i.end)),
-o.terminatorEnd=d(i.end)||"",i.endsWithParent&&r.terminatorEnd&&(o.terminatorEnd+=(i.end?"|":"")+r.terminatorEnd)),
-i.illegal&&(o.illegalRe=n(i.illegal)),
-i.contains||(i.contains=[]),i.contains=[].concat(...i.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((n=>s(e,{
-variants:null},n)))),e.cachedVariants?e.cachedVariants:Q(e)?s(e,{
-starts:e.starts?s(e.starts):null
-}):Object.isFrozen(e)?s(e):e))("self"===e?i:e)))),i.contains.forEach((e=>{t(e,o)
-})),i.starts&&t(i.starts,r),o.matcher=(e=>{const n=new a
-;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin"
-}))),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end"
-}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n})(o),o}(e)}function Q(e){
-return!!e&&(e.endsWithParent||Q(e.starts))}const X=i,V=s,J=Symbol("nomatch")
-;var Y=(e=>{const n=Object.create(null),i=Object.create(null),s=[];let r=!0
-;const o="Could not find the language '{}', did you forget to load/include a language module?",l={
-disableAutodetect:!0,name:"Plain text",contains:[]};let d={
-ignoreUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,
-languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
-cssSelector:"pre code",languages:null,__emitter:c};function g(e){
-return d.noHighlightRe.test(e)}function u(e,n,t,a){let i="",s=""
-;"object"==typeof n?(i=e,
-t=n.ignoreIllegals,s=n.language,a=void 0):(q("10.7.0","highlight(lang, code, ...args) has been deprecated."),
-q("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),
-s=e,i=n),void 0===t&&(t=!0);const r={code:i,language:s};N("before:highlight",r)
-;const o=r.result?r.result:b(r.language,r.code,t,a)
-;return o.code=r.code,N("after:highlight",o),o}function b(e,t,i,s){
-const l=Object.create(null);function c(){if(!M.keywords)return void S.addText(k)
-;let e=0;M.keywordPatternRe.lastIndex=0;let n=M.keywordPatternRe.exec(k),t=""
-;for(;n;){t+=k.substring(e,n.index)
-;const i=w.case_insensitive?n[0].toLowerCase():n[0],s=(a=i,M.keywords[a]);if(s){
-const[e,a]=s
-;if(S.addText(t),t="",l[i]=(l[i]||0)+1,l[i]<=7&&(A+=a),e.startsWith("_"))t+=n[0];else{
-const t=w.classNameAliases[e]||e;S.addKeyword(n[0],t)}}else t+=n[0]
-;e=M.keywordPatternRe.lastIndex,n=M.keywordPatternRe.exec(k)}var a
-;t+=k.substr(e),S.addText(t)}function g(){null!=M.subLanguage?(()=>{
-if(""===k)return;let e=null;if("string"==typeof M.subLanguage){
-if(!n[M.subLanguage])return void S.addText(k)
-;e=b(M.subLanguage,k,!0,x[M.subLanguage]),x[M.subLanguage]=e._top
-}else e=m(k,M.subLanguage.length?M.subLanguage:null)
-;M.relevance>0&&(A+=e.relevance),S.addSublanguage(e._emitter,e.language)
-})():c(),k=""}function u(e,n){let t=1;for(;void 0!==n[t];){if(!e._emit[t]){t++
-;continue}const a=w.classNameAliases[e[t]]||e[t],i=n[t]
-;a?S.addKeyword(i,a):(k=i,c(),k=""),t++}}function p(e,n){
-return e.scope&&"string"==typeof e.scope&&S.openNode(w.classNameAliases[e.scope]||e.scope),
-e.beginScope&&(e.beginScope._wrap?(S.addKeyword(k,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),
-k=""):e.beginScope._multi&&(u(e.beginScope,n),k="")),M=Object.create(e,{parent:{
-value:M}}),M}function _(e,n,t){let i=((e,n)=>{const t=e&&e.exec(n)
-;return t&&0===t.index})(e.endRe,t);if(i){if(e["on:end"]){const t=new a(e)
-;e["on:end"](n,t),t.isMatchIgnored&&(i=!1)}if(i){
-for(;e.endsParent&&e.parent;)e=e.parent;return e}}
-if(e.endsWithParent)return _(e.parent,n,t)}function f(e){
-return 0===M.matcher.regexIndex?(k+=e[0],1):(R=!0,0)}function E(e){
-const n=e[0],a=t.substr(e.index),i=_(M,e,a);if(!i)return J;const s=M
-;M.endScope&&M.endScope._wrap?(g(),
-S.addKeyword(n,M.endScope._wrap)):M.endScope&&M.endScope._multi?(g(),
-u(M.endScope,e)):s.skip?k+=n:(s.returnEnd||s.excludeEnd||(k+=n),
-g(),s.excludeEnd&&(k=n));do{
-M.scope&&!M.isMultiClass&&S.closeNode(),M.skip||M.subLanguage||(A+=M.relevance),
-M=M.parent}while(M!==i.parent)
-;return i.starts&&p(i.starts,e),s.returnEnd?0:n.length}let y={};function N(n,s){
-const o=s&&s[0];if(k+=n,null==o)return g(),0
-;if("begin"===y.type&&"end"===s.type&&y.index===s.index&&""===o){
-if(k+=t.slice(s.index,s.index+1),!r){const n=Error(`0 width match regex (${e})`)
-;throw n.languageName=e,n.badRule=y.rule,n}return 1}
-if(y=s,"begin"===s.type)return(e=>{
-const n=e[0],t=e.rule,i=new a(t),s=[t.__beforeBegin,t["on:begin"]]
-;for(const t of s)if(t&&(t(e,i),i.isMatchIgnored))return f(n)
-;return t.skip?k+=n:(t.excludeBegin&&(k+=n),
-g(),t.returnBegin||t.excludeBegin||(k=n)),p(t,e),t.returnBegin?0:n.length})(s)
-;if("illegal"===s.type&&!i){
-const e=Error('Illegal lexeme "'+o+'" for mode "'+(M.scope||"<unnamed>")+'"')
-;throw e.mode=M,e}if("end"===s.type){const e=E(s);if(e!==J)return e}
-if("illegal"===s.type&&""===o)return 1
-;if(T>1e5&&T>3*s.index)throw Error("potential infinite loop, way more iterations than matches")
-;return k+=o,o.length}const w=h(e)
-;if(!w)throw P(o.replace("{}",e)),Error('Unknown language: "'+e+'"')
-;const v=W(w);let O="",M=s||v;const x={},S=new d.__emitter(d);(()=>{const e=[]
-;for(let n=M;n!==w;n=n.parent)n.scope&&e.unshift(n.scope)
-;e.forEach((e=>S.openNode(e)))})();let k="",A=0,C=0,T=0,R=!1;try{
-for(M.matcher.considerAll();;){
-T++,R?R=!1:M.matcher.considerAll(),M.matcher.lastIndex=C
-;const e=M.matcher.exec(t);if(!e)break;const n=N(t.substring(C,e.index),e)
-;C=e.index+n}return N(t.substr(C)),S.closeAllNodes(),S.finalize(),O=S.toHTML(),{
-language:e,value:O,relevance:A,illegal:!1,_emitter:S,_top:M}}catch(n){
-if(n.message&&n.message.includes("Illegal"))return{language:e,value:X(t),
-illegal:!0,relevance:0,_illegalBy:{message:n.message,index:C,
-context:t.slice(C-100,C+100),mode:n.mode,resultSoFar:O},_emitter:S};if(r)return{
-language:e,value:X(t),illegal:!1,relevance:0,errorRaised:n,_emitter:S,_top:M}
-;throw n}}function m(e,t){t=t||d.languages||Object.keys(n);const a=(e=>{
-const n={value:X(e),illegal:!1,relevance:0,_top:l,_emitter:new d.__emitter(d)}
-;return n._emitter.addText(e),n})(e),i=t.filter(h).filter(y).map((n=>b(n,e,!1)))
-;i.unshift(a);const s=i.sort(((e,n)=>{
-if(e.relevance!==n.relevance)return n.relevance-e.relevance
-;if(e.language&&n.language){if(h(e.language).supersetOf===n.language)return 1
-;if(h(n.language).supersetOf===e.language)return-1}return 0})),[r,o]=s,c=r
-;return c.secondBest=o,c}function p(e){let n=null;const t=(e=>{
-let n=e.className+" ";n+=e.parentNode?e.parentNode.className:""
-;const t=d.languageDetectRe.exec(n);if(t){const n=h(t[1])
-;return n||(K(o.replace("{}",t[1])),
-K("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"}
-return n.split(/\s+/).find((e=>g(e)||h(e)))})(e);if(g(t))return
-;N("before:highlightElement",{el:e,language:t
-}),!d.ignoreUnescapedHTML&&e.children.length>0&&(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),
-console.warn("https://github.com/highlightjs/highlight.js/issues/2886"),
-console.warn(e)),n=e;const a=n.textContent,s=t?u(a,{language:t,ignoreIllegals:!0
-}):m(a);N("after:highlightElement",{el:e,result:s,text:a
-}),e.innerHTML=s.value,((e,n,t)=>{const a=n&&i[n]||t
-;e.classList.add("hljs"),e.classList.add("language-"+a)
-})(e,t,s.language),e.result={language:s.language,re:s.relevance,
-relevance:s.relevance},s.secondBest&&(e.secondBest={
-language:s.secondBest.language,relevance:s.secondBest.relevance})}let _=!1
-;function f(){
-"loading"!==document.readyState?document.querySelectorAll(d.cssSelector).forEach(p):_=!0
-}function h(e){return e=(e||"").toLowerCase(),n[e]||n[i[e]]}
-function E(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{
-i[e.toLowerCase()]=n}))}function y(e){const n=h(e)
-;return n&&!n.disableAutodetect}function N(e,n){const t=e;s.forEach((e=>{
-e[t]&&e[t](n)}))}
-"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{
-_&&f()}),!1),Object.assign(e,{highlight:u,highlightAuto:m,highlightAll:f,
-highlightElement:p,
-highlightBlock:e=>(q("10.7.0","highlightBlock will be removed entirely in v12.0"),
-q("10.7.0","Please use highlightElement now."),p(e)),configure:e=>{d=V(d,e)},
-initHighlighting:()=>{
-f(),q("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")},
-initHighlightingOnLoad:()=>{
-f(),q("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")
-},registerLanguage:(t,a)=>{let i=null;try{i=a(e)}catch(e){
-if(P("Language definition for '{}' could not be registered.".replace("{}",t)),
-!r)throw e;P(e),i=l}
-i.name||(i.name=t),n[t]=i,i.rawDefinition=a.bind(null,e),i.aliases&&E(i.aliases,{
-languageName:t})},unregisterLanguage:e=>{delete n[e]
-;for(const n of Object.keys(i))i[n]===e&&delete i[n]},
-listLanguages:()=>Object.keys(n),getLanguage:h,registerAliases:E,
-autoDetection:y,inherit:V,addPlugin:e=>{(e=>{
-e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{
-e["before:highlightBlock"](Object.assign({block:n.el},n))
-}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{
-e["after:highlightBlock"](Object.assign({block:n.el},n))})})(e),s.push(e)}
-}),e.debugMode=()=>{r=!1},e.safeMode=()=>{r=!0},e.versionString="11.0.0-beta1"
-;for(const e in C)"object"==typeof C[e]&&t(C[e]);return Object.assign(e,C),e
-})({});const ee=e=>({IMPORTANT:{scope:"meta",begin:"!important"},HEXCOLOR:{
-scope:"number",begin:"#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})"},
-ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",
-contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{
-scope:"number",
-begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",
-relevance:0}
-}),ne=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],te=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],ae=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],ie=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],se=["align-content","align-items","align-self","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","auto","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","clip-path","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-variant","font-variant-ligatures","font-variation-settings","font-weight","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inherit","initial","justify-content","left","letter-spacing","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","mask","max-height","max-width","min-height","min-width","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","perspective","perspective-origin","pointer-events","position","quotes","resize","right","src","tab-size","table-layout","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-indent","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","white-space","widows","width","word-break","word-spacing","word-wrap","z-index"].reverse(),re=ae.concat(ie)
-;var oe="\\.([0-9](_*[0-9])*)",le="[0-9a-fA-F](_*[0-9a-fA-F])*",ce={
-className:"number",variants:[{
-begin:`(\\b([0-9](_*[0-9])*)((${oe})|\\.)?|(${oe}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`
-},{begin:`\\b([0-9](_*[0-9])*)((${oe})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{
-begin:`(${oe})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{
-begin:`\\b0[xX]((${le})\\.?|(${le})?\\.(${le}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`
-},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${le})[lL]?\\b`},{
-begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],
-relevance:0};function de(e,n,t){return-1===t?"":e.replace(n,(a=>de(e,n,t-1)))}
-const ge="[A-Za-z$_][0-9A-Za-z$_]*",ue=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],be=["true","false","null","undefined","NaN","Infinity"],me=["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer","BigInt64Array","BigUint64Array","BigInt"],pe=["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],_e=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],fe=["arguments","this","super","console","window","document","localStorage","module","global"],he=[].concat(_e,me,pe)
-;function Ee(e){const n=ge,t={begin:/<[A-Za-z0-9\\._:-]+/,
-end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{
-const t=e[0].length+e.index,a=e.input[t];"<"!==a?">"===a&&(((e,{after:n})=>{
-const t="</"+e[0].slice(1);return-1!==e.input.indexOf(t,n)})(e,{after:t
-})||n.ignoreMatch()):n.ignoreMatch()}},a={$pattern:ge,keyword:ue,literal:be,
-built_in:he,"variable.language":fe
-},i="\\.([0-9](_?[0-9])*)",s="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",r={
-className:"number",variants:[{
-begin:`(\\b(${s})((${i})|\\.)?|(${i}))[eE][+-]?([0-9](_?[0-9])*)\\b`},{
-begin:`\\b(${s})\\b((${i})\\b|\\.)?|(${i})\\b`},{
-begin:"\\b(0|[1-9](_?[0-9])*)n\\b"},{
-begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b"},{
-begin:"\\b0[bB][0-1](_?[0-1])*n?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*n?\\b"},{
-begin:"\\b0[0-7]+n?\\b"}],relevance:0},o={className:"subst",begin:"\\$\\{",
-end:"\\}",keywords:a,contains:[]},l={begin:"html`",end:"",starts:{end:"`",
-returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,o],subLanguage:"xml"}},c={
-begin:"css`",end:"",starts:{end:"`",returnEnd:!1,
-contains:[e.BACKSLASH_ESCAPE,o],subLanguage:"css"}},d={className:"string",
-begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE,o]},u={className:"comment",
-variants:[e.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{
-begin:"(?=@[A-Za-z]+)",relevance:0,contains:[{className:"doctag",
-begin:"@[A-Za-z]+"},{className:"type",begin:"\\{",end:"\\}",excludeEnd:!0,
-excludeBegin:!0,relevance:0},{className:"variable",begin:n+"(?=\\s*(-)|$)",
-endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]
-}),e.C_BLOCK_COMMENT_MODE,e.C_LINE_COMMENT_MODE]
-},m=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,l,c,d,r,e.REGEXP_MODE]
-;o.contains=m.concat({begin:/\{/,end:/\}/,keywords:a,contains:["self"].concat(m)
-});const p=[].concat(u,o.contains),_=p.concat([{begin:/\(/,end:/\)/,keywords:a,
-contains:["self"].concat(p)}]),f={className:"params",begin:/\(/,end:/\)/,
-excludeBegin:!0,excludeEnd:!0,keywords:a,contains:_},h={variants:[{
-match:[/class/,/\s+/,n],scope:{1:"keyword",3:"title.class"}},{
-match:[/extends/,/\s+/,b(n,"(",b(/\./,n),")*")],scope:{1:"keyword",
-3:"title.class.inherited"}}]},E={relevance:0,
-match:/\b[A-Z][a-z]+([A-Z][a-z]+)*/,className:"title.class",keywords:{
-_:[...me,...pe]}},y={variants:[{match:[/function/,/\s+/,n,/(?=\s*\()/]},{
-match:[/function/,/\s*(?=\()/]}],className:{1:"keyword",3:"title.function"},
-label:"func.def",contains:[f],illegal:/%/},N={
-match:b(/\b/,(w=[..._e,"super"],b("(?!",w.join("|"),")")),n,g(/\(/)),
-className:"title.function",relevance:0};var w;const v={
-begin:b(/\./,g(b(n,/(?![0-9A-Za-z$_(])/))),end:n,excludeBegin:!0,
-keywords:"prototype",className:"property",relevance:0},O={
-match:[/get|set/,/\s+/,n,/(?=\()/],className:{1:"keyword",3:"title.function"},
-contains:[{begin:/\(\)/},f]
-},M="(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+e.UNDERSCORE_IDENT_RE+")\\s*=>",x={
-match:[/const|var|let/,/\s+/,n,/\s*/,/=\s*/,g(M)],className:{1:"keyword",
-3:"title.function"},contains:[f]};return{name:"Javascript",
-aliases:["js","jsx","mjs","cjs"],keywords:a,exports:{PARAMS_CONTAINS:_},
-illegal:/#(?![$_A-z])/,contains:[e.SHEBANG({label:"shebang",binary:"node",
-relevance:5}),{label:"use_strict",className:"meta",relevance:10,
-begin:/^\s*['"]use (strict|asm)['"]/
-},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,l,c,d,u,r,E,{className:"attr",
-begin:n+g(":"),relevance:0},x,{
-begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",
-keywords:"return throw case",relevance:0,contains:[u,e.REGEXP_MODE,{
-className:"function",begin:M,returnBegin:!0,end:"\\s*=>",contains:[{
-className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{
-className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,
-excludeEnd:!0,keywords:a,contains:_}]}]},{begin:/,/,relevance:0},{match:/\s+/,
-relevance:0},{variants:[{begin:"<>",end:"</>"},{begin:t.begin,
-"on:begin":t.isTrulyOpeningTag,end:t.end}],subLanguage:"xml",contains:[{
-begin:t.begin,end:t.end,skip:!0,contains:["self"]}]}]},y,{
-beginKeywords:"while if switch catch for"},{
-begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",
-returnBegin:!0,label:"func.def",contains:[f,e.inherit(e.TITLE_MODE,{begin:n,
-className:"title.function"})]},{match:/\.\.\./,relevance:0},v,{match:"\\$"+n,
-relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"},
-contains:[f]},N,{relevance:0,match:/\b[A-Z][A-Z_]+\b/,
-className:"variable.constant"},h,O,{match:/\$[(.]/}]}}
-const ye=e=>b(/\b/,e,/\w$/.test(e)?/\b/:/\B/),Ne=["Protocol","Type"].map(ye),we=["init","self"].map(ye),ve=["Any","Self"],Oe=["actor","associatedtype","async","await",/as\?/,/as!/,"as","break","case","catch","class","continue","convenience","default","defer","deinit","didSet","do","dynamic","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","lazy","let","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],Me=["false","nil","true"],xe=["assignment","associativity","higherThan","left","lowerThan","none","right"],Se=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warn_unqualified_access","#warning"],ke=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],Ae=m(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),Ce=m(Ae,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),Te=b(Ae,Ce,"*"),Re=m(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),De=m(Re,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Ie=b(Re,De,"*"),Be=b(/[A-Z]/,De,"*"),Le=["autoclosure",b(/convention\(/,m("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",b(/objc\(/,Ie,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","testable","UIApplicationMain","unknown","usableFromInline"],$e=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"]
-;var ze=Object.freeze({__proto__:null,grmr_bash:e=>{const n={},t={begin:/\$\{/,
-end:/\}/,contains:["self",{begin:/:-/,contains:[n]}]};Object.assign(n,{
-className:"variable",variants:[{
-begin:b(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},t]});const a={
-className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},i={
-begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,
-end:/(\w+)/,className:"string"})]}},s={className:"string",begin:/"/,end:/"/,
-contains:[e.BACKSLASH_ESCAPE,n,a]};a.contains.push(s);const r={begin:/\$\(\(/,
-end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,n]
-},o=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10
-}),l={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,
-contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{
-name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z._-]+\b/,
-keyword:["if","then","else","elif","fi","for","while","in","do","done","case","esac","function"],
-literal:["true","false"],
-built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp"
-},contains:[o,e.SHEBANG(),l,r,e.HASH_COMMENT_MODE,i,s,{className:"",begin:/\\"/
-},{className:"string",begin:/'/,end:/'/},n]}},grmr_c:e=>{
-const n=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]
-}),t="[a-zA-Z_]\\w*::",a="(decltype\\(auto\\)|"+u(t)+"[a-zA-Z_]\\w*"+u("<[^<>]+>")+")",i={
-className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{
-match:/\batomic_[a-z]{3,6}\b/}]},s={className:"string",variants:[{
-begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{
-begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",
-end:"'",illegal:"."},e.END_SAME_AS_BEGIN({
-begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},r={
-className:"number",variants:[{begin:"\\b(0b[01']+)"},{
-begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)"
-},{
-begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"
-}],relevance:0},o={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{
-keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"
-},contains:[{begin:/\\\n/,relevance:0},e.inherit(s,{className:"string"}),{
-className:"string",begin:/<.*?>/},n,e.C_BLOCK_COMMENT_MODE]},l={
-className:"title",begin:u(t)+e.IDENT_RE,relevance:0
-},c=u(t)+e.IDENT_RE+"\\s*\\(",d={
-keyword:["asm","auto","break","case","const","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","static","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"],
-type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","complex","bool","imaginary"],
-literal:"true false NULL",
-built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr"
-},g=[o,i,n,e.C_BLOCK_COMMENT_MODE,r,s],b={variants:[{begin:/=/,end:/;/},{
-begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],
-keywords:d,contains:g.concat([{begin:/\(/,end:/\)/,keywords:d,
-contains:g.concat(["self"]),relevance:0}]),relevance:0},m={
-begin:"("+a+"[\\*&\\s]+)+"+c,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,
-keywords:d,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:"decltype\\(auto\\)",
-keywords:d,relevance:0},{begin:c,returnBegin:!0,contains:[e.inherit(l,{
-className:"title.function"})],relevance:0},{relevance:0,match:/,/},{
-className:"params",begin:/\(/,end:/\)/,keywords:d,relevance:0,
-contains:[n,e.C_BLOCK_COMMENT_MODE,s,r,i,{begin:/\(/,end:/\)/,keywords:d,
-relevance:0,contains:["self",n,e.C_BLOCK_COMMENT_MODE,s,r,i]}]
-},i,n,e.C_BLOCK_COMMENT_MODE,o]};return{name:"C",aliases:["h"],keywords:d,
-disableAutodetect:!0,illegal:"</",contains:[].concat(b,m,g,[o,{
-begin:e.IDENT_RE+"::",keywords:d},{className:"class",
-beginKeywords:"enum class struct union",end:/[{;:<>=]/,contains:[{
-beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:o,
-strings:s,keywords:d}}},grmr_cpp:e=>{const n=e.COMMENT("//","$",{contains:[{
-begin:/\\\n/}]
-}),t="[a-zA-Z_]\\w*::",a="(?!struct)(decltype\\(auto\\)|"+u(t)+"[a-zA-Z_]\\w*"+u("<[^<>]+>")+")",i={
-className:"type",begin:"\\b[a-z\\d_]*_t\\b"},s={className:"string",variants:[{
-begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{
-begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",
-end:"'",illegal:"."},e.END_SAME_AS_BEGIN({
-begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},r={
-className:"number",variants:[{begin:"\\b(0b[01']+)"},{
-begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)"
-},{
-begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"
-}],relevance:0},o={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{
-keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"
-},contains:[{begin:/\\\n/,relevance:0},e.inherit(s,{className:"string"}),{
-className:"string",begin:/<.*?>/},n,e.C_BLOCK_COMMENT_MODE]},l={
-className:"title",begin:u(t)+e.IDENT_RE,relevance:0
-},c=u(t)+e.IDENT_RE+"\\s*\\(",d={
-type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","any","array","async","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","function","future","imaginary","initializer_list","istringstream","jthread","latch","list","lock_guard","map","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"],
-keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","signed","sizeof","static","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","unsigned","using","virtual","volatile","while","xor","xor_eq,"],
-built_in:["_Bool","_Complex","_Imaginary"],
-literal:["NULL","false","nullopt","nullptr","true"]},m={
-className:"function.dispatch",relevance:0,keywords:{
-_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"]
-},
-begin:b(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!while)/,e.IDENT_RE,g(/(<[^<>]+>|)\s*\(/))
-},p=[m,o,i,n,e.C_BLOCK_COMMENT_MODE,r,s],_={variants:[{begin:/=/,end:/;/},{
-begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],
-keywords:d,contains:p.concat([{begin:/\(/,end:/\)/,keywords:d,
-contains:p.concat(["self"]),relevance:0}]),relevance:0},f={className:"function",
-begin:"("+a+"[\\*&\\s]+)+"+c,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,
-keywords:d,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:"decltype\\(auto\\)",
-keywords:d,relevance:0},{begin:c,returnBegin:!0,contains:[l],relevance:0},{
-begin:/::/,relevance:0},{begin:/:/,endsWithParent:!0,contains:[s,r]},{
-relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,keywords:d,
-relevance:0,contains:[n,e.C_BLOCK_COMMENT_MODE,s,r,i,{begin:/\(/,end:/\)/,
-keywords:d,relevance:0,contains:["self",n,e.C_BLOCK_COMMENT_MODE,s,r,i]}]
-},i,n,e.C_BLOCK_COMMENT_MODE,o]};return{name:"C++",
-aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:d,illegal:"</",
-classNameAliases:{"function.dispatch":"built_in"},
-contains:[].concat(_,f,m,p,[o,{
-begin:"\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array|tuple|optional|variant|function)\\s*<",
-end:">",keywords:d,contains:["self",i]},{begin:e.IDENT_RE+"::",keywords:d},{
-match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/],
-className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={
-keyword:["abstract","as","base","break","case","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]),
-built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"],
-literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{
-begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{
-begin:"\\b(0b[01']+)"},{
-begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{
-begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"
-}],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]
-},s=e.inherit(i,{illegal:/\n/}),r={className:"subst",begin:/\{/,end:/\}/,
-keywords:n},o=e.inherit(r,{illegal:/\n/}),l={className:"string",begin:/\$"/,
-end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/
-},e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{
-begin:/\{\{/},{begin:/\}\}/},{begin:'""'},r]},d=e.inherit(c,{illegal:/\n/,
-contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]})
-;r.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE],
-o.contains=[d,l,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{
-illegal:/\n/})];const g={variants:[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]
-},u={begin:"<",end:">",contains:[{beginKeywords:"in out"},t]
-},b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={
-begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],
-keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,
-contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{
-begin:"\x3c!--|--\x3e"},{begin:"</?",end:">"}]}]
-}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",
-end:"$",keywords:{
-keyword:"if else elif endif define undef warning error line region endregion pragma checksum"
-}},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/,
-illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"
-},t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",
-relevance:0,end:/[{;=]/,illegal:/[^\s:]/,
-contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{
-beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/,
-contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",
-begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{
-className:"string",begin:/"/,end:/"/}]},{
-beginKeywords:"new return throw await else",relevance:0},{className:"function",
-begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<.+>\\s*)?\\(",returnBegin:!0,
-end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{
-beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial",
-relevance:0},{begin:e.IDENT_RE+"\\s*(<.+>\\s*)?\\(",returnBegin:!0,
-contains:[e.TITLE_MODE,u],relevance:0},{className:"params",begin:/\(/,end:/\)/,
-excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,
-contains:[g,a,e.C_BLOCK_COMMENT_MODE]
-},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{
-const n=ee(e),t=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{name:"CSS",
-case_insensitive:!0,illegal:/[=|'\$]/,keywords:{keyframePosition:"from to"},
-classNameAliases:{keyframePosition:"selector-tag"},
-contains:[e.C_BLOCK_COMMENT_MODE,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/
-},n.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0
-},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0
-},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{
-begin:":("+ae.join("|")+")"},{begin:"::("+ie.join("|")+")"}]},{
-className:"attribute",begin:"\\b("+se.join("|")+")\\b"},{begin:":",end:"[;}]",
-contains:[n.HEXCOLOR,n.IMPORTANT,n.CSS_NUMBER_MODE,...t,{
-begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri"
-},contains:[{className:"string",begin:/[^)]/,endsWithParent:!0,excludeEnd:!0}]
-},{className:"built_in",begin:/[\w-]+(?=\()/}]},{begin:g(/@/),end:"[{;]",
-relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/
-},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{
-$pattern:/[a-z-]+/,keyword:"and or not only",attribute:te.join(" ")},contains:[{
-begin:/[a-z-]+(?=:)/,className:"attribute"},...t,n.CSS_NUMBER_MODE]}]},{
-className:"selector-tag",begin:"\\b("+ne.join("|")+")\\b"}]}},grmr_diff:e=>({
-name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,
-match:m(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)
-},{className:"comment",variants:[{
-begin:m(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),
-end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{
-className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,
-end:/$/}]}),grmr_go:e=>{const n={
-keyword:["break","default","func","interface","select","case","map","struct","chan","else","goto","package","switch","const","fallthrough","if","range","type","continue","for","import","return","var","go","defer","bool","byte","complex64","complex128","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"],
-literal:["true","false","iota","nil"],
-built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"]
-};return{name:"Go",aliases:["golang"],keywords:n,illegal:"</",
-contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"string",
-variants:[e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{begin:"`",end:"`"}]},{
-className:"number",variants:[{begin:e.C_NUMBER_RE+"[i]",relevance:1
-},e.C_NUMBER_MODE]},{begin:/:=/},{className:"function",beginKeywords:"func",
-end:"\\s*(\\{|$)",excludeEnd:!0,contains:[e.TITLE_MODE,{className:"params",
-begin:/\(/,end:/\)/,keywords:n,illegal:/["']/}]}]}},grmr_ini:e=>{const n={
-className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{
-begin:e.NUMBER_RE}]},t=e.COMMENT();t.variants=[{begin:/;/,end:/$/},{begin:/#/,
-end:/$/}];const a={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{
-begin:/\$\{(.*?)\}/}]},i={className:"literal",
-begin:/\bon|off|true|false|yes|no\b/},s={className:"string",
-contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{
-begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]
-},r={begin:/\[/,end:/\]/,contains:[t,i,a,s,n,"self"],relevance:0
-},o=m(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{name:"TOML, also INI",
-aliases:["toml"],case_insensitive:!0,illegal:/\S/,contains:[t,{
-className:"section",begin:/\[+/,end:/\]+/},{
-begin:b(o,"(\\s*\\.\\s*",o,")*",g(/\s*=\s*[^#\s]/)),className:"attr",starts:{
-end:/$/,contains:[t,r,i,a,s,n]}}]}},grmr_java:e=>{
-const n="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",t=n+de("(?:<"+n+"~~~(?:\\s*,\\s*"+n+"~~~)*>)?",/~~~/g,2),a={
-keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do"],
-literal:["false","true","null"],
-type:["char","boolean","long","float","int","byte","short","double"],
-built_in:["super","this"]},i={className:"meta",begin:"@"+n,contains:[{
-begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/,
-end:/\)/,keywords:a,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0}
-;return{name:"Java",aliases:["jsp"],keywords:a,illegal:/<\/|#/,
-contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,
-relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{
-begin:/import java\.[a-z]+\./,keywords:"import",relevance:2
-},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{
-match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,n],className:{
-1:"keyword",3:"title.class"}},{begin:[n,/\s+/,n,/\s+/,/=/],className:{1:"type",
-3:"variable",5:"operator"}},{begin:[/record/,/\s+/,n],className:{1:"keyword",
-3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{
-beginKeywords:"new throw return else",relevance:0},{
-begin:["(?:"+t+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{
-2:"title.function"},keywords:a,contains:[{className:"params",begin:/\(/,
-end:/\)/,keywords:a,relevance:0,
-contains:[i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,ce,e.C_BLOCK_COMMENT_MODE]
-},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},ce,i]}},grmr_javascript:Ee,
-grmr_json:e=>({name:"JSON",contains:[{className:"attr",
-begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{match:/[{}[\],:]/,
-className:"punctuation",relevance:0},e.QUOTE_STRING_MODE,{
-beginKeywords:"true false null"
-},e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],illegal:"\\S"}),
-grmr_kotlin:e=>{const n={
-keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual",
-built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",
-literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"
-},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={
-className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},s={className:"string",
-variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'",
-illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,
-contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(s);const r={
-className:"meta",
-begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"
-},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,
-end:/\)/,contains:[e.inherit(s,{className:"string"})]}]
-},l=ce,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={
-variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,
-contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g],
-{name:"Kotlin",aliases:["kt","kts"],keywords:n,
-contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",
-begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",
-begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",
-begin:/@\w+/}]}},t,r,o,{className:"function",beginKeywords:"fun",end:"[(]|$",
-returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{
-begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,
-contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin:/</,end:/>/,
-keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,
-endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,
-endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0
-},e.C_LINE_COMMENT_MODE,c,r,o,s,e.C_NUMBER_MODE]},c]},{className:"class",
-beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,
-illegal:"extends implements",contains:[{
-beginKeywords:"public protected internal private constructor"
-},e.UNDERSCORE_TITLE_MODE,{className:"type",begin:/</,end:/>/,excludeBegin:!0,
-excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,
-excludeBegin:!0,returnEnd:!0},r,o]},s,{className:"meta",begin:"^#!/usr/bin/env",
-end:"$",illegal:"\n"},l]}},grmr_less:e=>{
-const n=ee(e),t=re,a="([\\w-]+|@\\{[\\w-]+\\})",i=[],s=[],r=e=>({
-className:"string",begin:"~?"+e+".*?"+e}),o=(e,n,t)=>({className:e,begin:n,
-relevance:t}),l={$pattern:/[a-z-]+/,keyword:"and or not only",
-attribute:te.join(" ")},c={begin:"\\(",end:"\\)",contains:s,keywords:l,
-relevance:0}
-;s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,r("'"),r('"'),n.CSS_NUMBER_MODE,{
-begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",
-excludeEnd:!0}
-},n.HEXCOLOR,c,o("variable","@@?[\\w-]+",10),o("variable","@\\{[\\w-]+\\}"),o("built_in","~?`[^`]*?`"),{
-className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0
-},n.IMPORTANT);const d=s.concat({begin:/\{/,end:/\}/,contains:i}),g={
-beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"
-}].concat(s)},u={begin:a+"\\s*:",returnBegin:!0,end:/[;}]/,relevance:0,
-contains:[{begin:/-(webkit|moz|ms|o)-/},{className:"attribute",
-begin:"\\b("+se.join("|")+")\\b",end:/(?=:)/,starts:{endsWithParent:!0,
-illegal:"[<=$]",relevance:0,contains:s}}]},b={className:"keyword",
-begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",
-starts:{end:"[;{}]",keywords:l,returnEnd:!0,contains:s,relevance:0}},m={
-className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{
-begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:d}},p={variants:[{
-begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:a,end:/\{/}],returnBegin:!0,
-returnEnd:!0,illegal:"[<='$\"]",relevance:0,
-contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,o("keyword","all\\b"),o("variable","@\\{[\\w-]+\\}"),{
-begin:"\\b("+ne.join("|")+")\\b",className:"selector-tag"
-},o("selector-tag",a+"%?",0),o("selector-id","#"+a),o("selector-class","\\."+a,0),o("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{
-className:"selector-pseudo",begin:":("+ae.join("|")+")"},{
-className:"selector-pseudo",begin:"::("+ie.join("|")+")"},{begin:/\(/,end:/\)/,
-relevance:0,contains:d},{begin:"!important"}]},_={
-begin:`[\\w-]+:(:)?(${t.join("|")})`,returnBegin:!0,contains:[p]}
-;return i.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,b,m,_,u,p),{
-name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:i}},grmr_lua:e=>{
-const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"]
-},i=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[",t,{contains:[a],
-relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE,
-literal:"true false nil",
-keyword:"and break do else elseif end for goto if in local not or repeat return then until while",
-built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"
-},contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)",
-contains:[e.inherit(e.TITLE_MODE,{
-begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",
-begin:"\\(",endsWithParent:!0,contains:i}].concat(i)
-},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",
-begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={
-className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",
-contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%<?\^\+\*]/}]},t={className:"string",
-begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,n]},a={className:"variable",
-begin:/\$\([\w-]+\s/,end:/\)/,keywords:{
-built_in:"subst patsubst strip findstring filter filter-out sort word wordlist firstword lastword dir notdir suffix basename addsuffix addprefix join wildcard realpath abspath error warning shell origin flavor foreach if or and call eval file value"
-},contains:[n]},i={begin:"^"+e.UNDERSCORE_IDENT_RE+"\\s*(?=[:+?]?=)"},s={
-className:"section",begin:/^[^\s]+:/,end:/$/,contains:[n]};return{
-name:"Makefile",aliases:["mk","mak","make"],keywords:{$pattern:/[\w-]+/,
-keyword:"define endef undefine ifdef ifndef ifeq ifneq else endif include -include sinclude override export unexport private vpath"
-},contains:[e.HASH_COMMENT_MODE,n,t,a,i,{className:"meta",begin:/^\.PHONY:/,
-end:/$/,keywords:{$pattern:/[\.\w]+/,keyword:".PHONY"}},s]}},grmr_xml:e=>{
-const n=b(/[A-Z_]/,u(/[A-Z0-9_.-]*:/),/[A-Z0-9_.-]*/),t={className:"symbol",
-begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},a={begin:/\s/,contains:[{
-className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},i=e.inherit(a,{
-begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{className:"string"
-}),r=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),o={endsWithParent:!0,
-illegal:/</,relevance:0,contains:[{className:"attr",begin:/[A-Za-z0-9._:-]+/,
-relevance:0},{begin:/=\s*/,relevance:0,contains:[{className:"string",
-endsParent:!0,variants:[{begin:/"/,end:/"/,contains:[t]},{begin:/'/,end:/'/,
-contains:[t]},{begin:/[^\s"'=<>`]+/}]}]}]};return{name:"HTML, XML",
-aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],
-case_insensitive:!0,contains:[{className:"meta",begin:/<![a-z]/,end:/>/,
-relevance:10,contains:[a,r,s,i,{begin:/\[/,end:/\]/,contains:[{className:"meta",
-begin:/<![a-z]/,end:/>/,contains:[a,i,r,s]}]}]},e.COMMENT(/<!--/,/-->/,{
-relevance:10}),{begin:/<!\[CDATA\[/,end:/\]\]>/,relevance:10},t,{
-className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",
-begin:/<style(?=\s|>)/,end:/>/,keywords:{name:"style"},contains:[o],starts:{
-end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",
-begin:/<script(?=\s|>)/,end:/>/,keywords:{name:"script"},contains:[o],starts:{
-end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{
-className:"tag",begin:/<>|<\/>/},{className:"tag",
-begin:b(/</,g(b(n,m(/\/>/,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name",
-begin:n,relevance:0,starts:o}]},{className:"tag",begin:b(/<\//,g(b(n,/>/))),
-contains:[{className:"name",begin:n,relevance:0},{begin:/>/,relevance:0,
-endsParent:!0}]}]}},grmr_markdown:e=>{const n={begin:/<\/?[A-Za-z_]/,end:">",
-subLanguage:"xml",relevance:0},t={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0
-},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,
-relevance:2},{begin:b(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/),
-relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{
-begin:/\[.+?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{
-className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,
-returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",
-excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",
-end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[],
-variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},i={
-className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{
-begin:/_(?!_)/,end:/_/,relevance:0}]};a.contains.push(i),i.contains.push(a)
-;let s=[n,t]
-;return a.contains=a.contains.concat(s),i.contains=i.contains.concat(s),
-s=s.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{
-className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:s},{
-begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",
-contains:s}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",
-end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:s,
-end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{
-begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{
-begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",
-contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{
-begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{
-className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{
-className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}},grmr_objectivec:e=>{
-const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n,
-keyword:["@interface","@class","@protocol","@implementation"]};return{
-name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"],
-keywords:{$pattern:n,
-keyword:["int","float","while","char","export","sizeof","typedef","const","struct","for","union","unsigned","long","volatile","static","bool","mutable","if","do","return","goto","void","enum","else","break","extern","asm","case","short","default","double","register","explicit","signed","typename","this","switch","continue","wchar_t","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","super","unichar","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"],
-literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"],
-built_in:["BOOL","dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"]
-},illegal:"</",contains:[{className:"built_in",
-begin:"\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\w+"
-},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.C_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{
-className:"string",variants:[{begin:'@"',end:'"',illegal:"\\n",
-contains:[e.BACKSLASH_ESCAPE]}]},{className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,
-keywords:{
-keyword:"if else elif endif define undef warning error line pragma ifdef ifndef include"
-},contains:[{begin:/\\\n/,relevance:0},e.inherit(e.QUOTE_STRING_MODE,{
-className:"string"}),{className:"string",begin:/<.*?>/,end:/$/,illegal:"\\n"
-},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",
-begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t,
-contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,
-relevance:0}]}},grmr_perl:e=>{const n=/[dualxmsipngr]{0,12}/,t={
-$pattern:/[\w.]+/,
-keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0"
-},a={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:t},i={begin:/->\{/,
-end:/\}/},s={variants:[{begin:/\$\d/},{
-begin:b(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])")
-},{begin:/[$%@][^\s\w{]/,relevance:0}]
-},r=[e.BACKSLASH_ESCAPE,a,s],o=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],l=(e,t,a="\\1")=>{
-const i="\\1"===a?a:b(a,t)
-;return b(b("(?:",e,")"),t,/(?:\\.|[^\\\/])*?/,i,/(?:\\.|[^\\\/])*?/,a,n)
-},c=(e,t,a)=>b(b("(?:",e,")"),t,/(?:\\.|[^\\\/])*?/,a,n),d=[s,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{
-endsWithParent:!0}),i,{className:"string",contains:r,variants:[{
-begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",
-end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{
-begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">",
-relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",
-contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",
-contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{
-begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number",
-begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",
-relevance:0},{
-begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",
-keywords:"split return print reverse grep",relevance:0,
-contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{
-begin:l("s|tr|y",m(...o,{capture:!0}))},{begin:l("s|tr|y","\\(","\\)")},{
-begin:l("s|tr|y","\\[","\\]")},{begin:l("s|tr|y","\\{","\\}")}],relevance:2},{
-className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{
-begin:c("(?:m|qr)?",/\//,/\//)},{begin:c("m|qr",m(...o,{capture:!0}),/\1/)},{
-begin:c("m|qr",/\(/,/\)/)},{begin:c("m|qr",/\[/,/\]/)},{
-begin:c("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub",
-end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{
-begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",
-subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]
-}];return a.contains=d,i.contains=d,{name:"Perl",aliases:["pl","pm"],keywords:t,
-contains:d}},grmr_php:e=>{const n={className:"variable",
-begin:"\\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?![A-Za-z0-9])(?![$])"},t={
-className:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{
-begin:/\?>/}]},a={className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,
-end:/\}/}]},i=e.inherit(e.APOS_STRING_MODE,{illegal:null
-}),s=e.inherit(e.QUOTE_STRING_MODE,{illegal:null,
-contains:e.QUOTE_STRING_MODE.contains.concat(a)}),r=e.END_SAME_AS_BEGIN({
-begin:/<<<[ \t]*(\w+)\n/,end:/[ \t]*(\w+)\b/,
-contains:e.QUOTE_STRING_MODE.contains.concat(a)}),o={className:"string",
-contains:[e.BACKSLASH_ESCAPE,t],variants:[e.inherit(i,{begin:"b'",end:"'"
-}),e.inherit(s,{begin:'b"',end:'"'}),s,i,r]},l={className:"number",variants:[{
-begin:"\\b0b[01]+(?:_[01]+)*\\b"},{begin:"\\b0o[0-7]+(?:_[0-7]+)*\\b"},{
-begin:"\\b0x[\\da-f]+(?:_[\\da-f]+)*\\b"},{
-begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:e[+-]?\\d+)?"
-}],relevance:0},c={
-keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile enum eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list match|0 mixed new object or private protected public real return string switch throw trait try unset use var void while xor yield",
-literal:"false null true",
-built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException UnhandledMatchError ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Stringable Throwable Traversable WeakReference WeakMap Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"
-};return{case_insensitive:!0,keywords:c,
-contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t]
-}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]
-}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,
-keywords:"__halt_compiler"}),t,{className:"keyword",begin:/\$this\b/},n,{
-begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",
-relevance:0,beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,
-illegal:"[$%\\[]",contains:[{beginKeywords:"use"},e.UNDERSCORE_TITLE_MODE,{
-begin:"=>",endsParent:!0},{className:"params",begin:"\\(",end:"\\)",
-excludeBegin:!0,excludeEnd:!0,keywords:c,
-contains:["self",n,e.C_BLOCK_COMMENT_MODE,o,l]}]},{className:"class",variants:[{
-beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait",
-illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{
-beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{
-beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/,
-contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",relevance:0,end:";",
-contains:[e.UNDERSCORE_TITLE_MODE]},o,l]}},grmr_php_template:e=>({
-name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,
-subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',
-end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},e.inherit(e.APOS_STRING_MODE,{
-illegal:null,className:null,contains:null,skip:!0
-}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,
-skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text",aliases:["text","txt"],
-disableAutodetect:!0}),grmr_python:e=>{const n={$pattern:/[A-Za-z]\w+|__\w+__/,
-keyword:["and","as","assert","async","await","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],
-built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"],
-literal:["__debug__","Ellipsis","False","None","NotImplemented","True"],
-type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"]
-},t={className:"meta",begin:/^(>>>|\.\.\.) /},a={className:"subst",begin:/\{/,
-end:/\}/,keywords:n,illegal:/#/},i={begin:/\{\{/,relevance:0},s={
-className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{
-begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/,
-contains:[e.BACKSLASH_ESCAPE,t],relevance:10},{
-begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/,
-contains:[e.BACKSLASH_ESCAPE,t],relevance:10},{
-begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/,
-contains:[e.BACKSLASH_ESCAPE,t,i,a]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/,
-end:/"""/,contains:[e.BACKSLASH_ESCAPE,t,i,a]},{begin:/([uU]|[rR])'/,end:/'/,
-relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{
-begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/,
-end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/,
-contains:[e.BACKSLASH_ESCAPE,i,a]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/,
-contains:[e.BACKSLASH_ESCAPE,i,a]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]
-},r="[0-9](_?[0-9])*",o=`(\\b(${r}))?\\.(${r})|\\b(${r})\\.`,l={
-className:"number",relevance:0,variants:[{
-begin:`(\\b(${r})|(${o}))[eE][+-]?(${r})[jJ]?\\b`},{begin:`(${o})[jJ]?`},{
-begin:"\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?\\b"},{
-begin:"\\b0[bB](_?[01])+[lL]?\\b"},{begin:"\\b0[oO](_?[0-7])+[lL]?\\b"},{
-begin:"\\b0[xX](_?[0-9a-fA-F])+[lL]?\\b"},{begin:`\\b(${r})[jJ]\\b`}]},c={
-className:"comment",begin:g(/# type:/),end:/$/,keywords:n,contains:[{
-begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},d={
-className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/,
-end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,
-contains:["self",t,l,s,e.HASH_COMMENT_MODE]}]};return a.contains=[s,l,t],{
-name:"Python",aliases:["py","gyp","ipython"],keywords:n,
-illegal:/(<\/|->|\?)|=>/,contains:[t,l,{begin:/\bself\b/},{beginKeywords:"if",
-relevance:0},s,c,e.HASH_COMMENT_MODE,{match:[/def/,/\s+/,h],scope:{1:"keyword",
-3:"title.function"},contains:[d]},{variants:[{
-match:[/class/,/\s+/,h,/\s*/,/\(\s*/,h,/\s*\)/]},{match:[/class/,/\s+/,h]}],
-scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{
-className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[l,d,s]}]}},
-grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta",starts:{
-end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{
-begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{
-const n=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/;return{name:"R",
-illegal:/->/,keywords:{$pattern:n,
-keyword:"function if in break next repeat else for while",
-literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10",
-built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm"
-},contains:[e.COMMENT(/#'/,/$/,{contains:[{className:"doctag",begin:"@examples",
-starts:{contains:[{begin:/\n/},{begin:/#'\s*(?=@[a-zA-Z]+)/,endsParent:!0},{
-begin:/#'/,end:/$/,excludeBegin:!0}]}},{className:"doctag",begin:"@param",
-end:/$/,contains:[{className:"variable",variants:[{begin:n},{
-begin:/`(?:\\.|[^`\\])+`/}],endsParent:!0}]},{className:"doctag",
-begin:/@[a-zA-Z]+/},{className:"keyword",begin:/\\[a-zA-Z]+/}]
-}),e.HASH_COMMENT_MODE,{className:"string",contains:[e.BACKSLASH_ESCAPE],
-variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/
-}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/
-}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/
-}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/
-}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/
-}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"',
-relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,className:{
-2:"number"},variants:[{
-match:[/[^a-zA-Z0-9._]/,/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/]},{
-match:[/[^a-zA-Z0-9._]/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/]},{
-match:[/[^a-zA-Z0-9._]/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/]}]},{
-begin:"%",end:"%"},{begin:b(/[a-zA-Z][a-zA-Z_0-9]*/,"\\s+<-\\s+")},{begin:"`",
-end:"`",contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{
-const n="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",t={
-keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor __FILE__",
-built_in:"proc lambda",literal:"true false nil"},a={className:"doctag",
-begin:"@[A-Za-z]+"},i={begin:"#<",end:">"},s=[e.COMMENT("#","$",{contains:[a]
-}),e.COMMENT("^=begin","^=end",{contains:[a],relevance:10
-}),e.COMMENT("^__END__","\\n$")],r={className:"subst",begin:/#\{/,end:/\}/,
-keywords:t},o={className:"string",contains:[e.BACKSLASH_ESCAPE,r],variants:[{
-begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/,
-end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{
-begin:/%[qQwWx]?</,end:/>/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/,
-end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{
-begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{
-begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{
-begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{
-begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{
-begin:b(/<<[-~]?'?/,g(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)),
-contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,
-contains:[e.BACKSLASH_ESCAPE,r]})]}]},l="[0-9](_?[0-9])*",c={className:"number",
-relevance:0,variants:[{
-begin:`\\b([1-9](_?[0-9])*|0)(\\.(${l}))?([eE][+-]?(${l})|r)?i?\\b`},{
-begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b"
-},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{
-begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{
-begin:"\\b0(_?[0-7])+r?i?\\b"}]},d={className:"params",begin:"\\(",end:"\\)",
-endsParent:!0,keywords:t},u=[o,{className:"class",beginKeywords:"class module",
-end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{
-begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|!)?"}),{begin:"<\\s*",contains:[{
-begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE,relevance:0}]}].concat(s)},{
-className:"function",begin:b(/def\s+/,g(n+"\\s*(\\(|;|$)")),relevance:0,
-keywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:n
-}),d].concat(s)},{begin:e.IDENT_RE+"::"},{className:"symbol",
-begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",
-begin:":(?!\\s)",contains:[o,{begin:n}],relevance:0},c,{className:"variable",
-begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{
-className:"params",begin:/\|/,end:/\|/,relevance:0,keywords:t},{
-begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{
-className:"regexp",contains:[e.BACKSLASH_ESCAPE,r],illegal:/\n/,variants:[{
-begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(",
-end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]
-}].concat(i,s),relevance:0}].concat(i,s);r.contains=u,d.contains=u;const m=[{
-begin:/^\s*=>/,starts:{end:"$",contains:u}},{className:"meta",
-begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])",
-starts:{end:"$",contains:u}}];return s.unshift(i),{name:"Ruby",
-aliases:["rb","gemspec","podspec","thor","irb"],keywords:t,illegal:/\/\*/,
-contains:[e.SHEBANG({binary:"ruby"})].concat(m).concat(s).concat(u)}},
-grmr_rust:e=>{const n={className:"title.function.invoke",relevance:0,
-begin:b(/\b/,/(?!let\b)/,e.IDENT_RE,g(/\s*\(/))
-},t="([ui](8|16|32|64|128|size)|f(32|64))?",a=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","panic!","file!","format!","format_args!","include_bin!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"]
-;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",
-type:["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"],
-keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","unsafe","unsized","use","virtual","where","while","yield"],
-literal:["true","false","Some","None","Ok","Err"],built_in:a},illegal:"</",
-contains:[e.C_LINE_COMMENT_MODE,e.COMMENT("/\\*","\\*/",{contains:["self"]
-}),e.inherit(e.QUOTE_STRING_MODE,{begin:/b?"/,illegal:null}),{
-className:"string",variants:[{begin:/b?r(#*)"(.|\n)*?"\1(?!#)/},{
-begin:/b?'\\?(x\w{2}|u\w{4}|U\w{8}|.)'/}]},{className:"symbol",
-begin:/'[a-zA-Z_][a-zA-Z0-9_]*/},{className:"number",variants:[{
-begin:"\\b0b([01_]+)"+t},{begin:"\\b0o([0-7_]+)"+t},{
-begin:"\\b0x([A-Fa-f0-9_]+)"+t},{
-begin:"\\b(\\d[\\d_]*(\\.[0-9_]+)?([eE][+-]?[0-9_]+)?)"+t}],relevance:0},{
-begin:[/fn/,/\s+/,e.UNDERSCORE_IDENT_RE],className:{1:"keyword",
-3:"title.function"}},{className:"meta",begin:"#!?\\[",end:"\\]",contains:[{
-className:"string",begin:/"/,end:/"/}]},{
-begin:[/let/,/\s+/,/(?:mut\s+)?/,e.UNDERSCORE_IDENT_RE],className:{1:"keyword",
-3:"keyword",4:"variable"}},{
-begin:[/for/,/\s+/,e.UNDERSCORE_IDENT_RE,/\s+/,/in/],className:{1:"keyword",
-3:"variable",5:"keyword"}},{begin:[/type/,/\s+/,e.UNDERSCORE_IDENT_RE],
-className:{1:"keyword",3:"title.class"}},{
-begin:[/(?:trait|enum|struct|union|impl|for)/,/\s+/,e.UNDERSCORE_IDENT_RE],
-className:{1:"keyword",3:"title.class"}},{begin:e.IDENT_RE+"::",keywords:{
-keyword:"Self",built_in:a}},{className:"punctuation",begin:"->"},n]}},
-grmr_scss:e=>{const n=ee(e),t=ie,a=ae,i="@[a-z-]+",s={className:"variable",
-begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b"};return{name:"SCSS",case_insensitive:!0,
-illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{
-className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{
-className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0
-},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag",
-begin:"\\b("+ne.join("|")+")\\b",relevance:0},{className:"selector-pseudo",
-begin:":("+a.join("|")+")"},{className:"selector-pseudo",
-begin:"::("+t.join("|")+")"},s,{begin:/\(/,end:/\)/,contains:[n.CSS_NUMBER_MODE]
-},{className:"attribute",begin:"\\b("+se.join("|")+")\\b"},{
-begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"
-},{begin:":",end:";",
-contains:[s,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT]
-},{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{
-begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/,
-keyword:"and or not only",attribute:te.join(" ")},contains:[{begin:i,
-className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute"
-},s,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE]}]}},
-grmr_shell:e=>({name:"Shell Session",aliases:["console","shellsession"],
-contains:[{className:"meta",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{
-end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]}),grmr_sql:e=>{
-const n=e.COMMENT("--","$"),t=["true","false","unknown"],a=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],i=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],r=i,o=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!i.includes(e))),l={
-begin:b(/\b/,m(...r),/\s*\(/),relevance:0,keywords:{built_in:r}};return{
-name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{
-$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t
-;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e))
-})(o,{when:e=>e.length<3}),literal:t,type:a,
-built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"]
-},contains:[{begin:m(...s),relevance:0,keywords:{$pattern:/[\w\.]+/,
-keyword:o.concat(s),literal:t,type:a}},{className:"type",
-begin:m("double precision","large object","with timezone","without timezone")
-},l,{className:"variable",begin:/@[a-z0-9]+/},{className:"string",variants:[{
-begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/,contains:[{
-begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,n,{className:"operator",
-begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/,relevance:0}]}},
-grmr_swift:e=>{const n={match:/\s+/,relevance:0},t=e.COMMENT("/\\*","\\*/",{
-contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={match:[/\./,m(...Ne,...we)],
-className:{2:"keyword"}},s={match:b(/\./,m(...Oe)),relevance:0
-},r=Oe.filter((e=>"string"==typeof e)).concat(["_|0"]),o={variants:[{
-className:"keyword",
-match:m(...Oe.filter((e=>"string"!=typeof e)).concat(ve).map(ye),...we)}]},l={
-$pattern:m(/\b\w+/,/#\w+/),keyword:r.concat(Se),literal:Me},c=[i,s,o],d=[{
-match:b(/\./,m(...ke)),relevance:0},{className:"built_in",
-match:b(/\b/,m(...ke),/(?=\()/)}],u={match:/->/,relevance:0},p=[u,{
-className:"operator",relevance:0,variants:[{match:Te},{match:`\\.(\\.|${Ce})+`}]
-}],_="([0-9a-fA-F]_*)+",f={className:"number",relevance:0,variants:[{
-match:"\\b(([0-9]_*)+)(\\.(([0-9]_*)+))?([eE][+-]?(([0-9]_*)+))?\\b"},{
-match:`\\b0x(${_})(\\.(${_}))?([pP][+-]?(([0-9]_*)+))?\\b`},{
-match:/\b0o([0-7]_*)+\b/},{match:/\b0b([01]_*)+\b/}]},h=(e="")=>({
-className:"subst",variants:[{match:b(/\\/,e,/[0\\tnr"']/)},{
-match:b(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}]}),E=(e="")=>({className:"subst",
-match:b(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/)}),y=(e="")=>({className:"subst",
-label:"interpol",begin:b(/\\/,e,/\(/),end:/\)/}),N=(e="")=>({begin:b(e,/"""/),
-end:b(/"""/,e),contains:[h(e),E(e),y(e)]}),w=(e="")=>({begin:b(e,/"/),
-end:b(/"/,e),contains:[h(e),y(e)]}),v={className:"string",
-variants:[N(),N("#"),N("##"),N("###"),w(),w("#"),w("##"),w("###")]},O={
-match:b(/`/,Ie,/`/)},M=[O,{className:"variable",match:/\$\d+/},{
-className:"variable",match:`\\$${De}+`}],x=[{match:/(@|#)available/,
-className:"keyword",starts:{contains:[{begin:/\(/,end:/\)/,keywords:$e,
-contains:[...p,f,v]}]}},{className:"keyword",match:b(/@/,m(...Le))},{
-className:"meta",match:b(/@/,Ie)}],S={match:g(/\b[A-Z]/),relevance:0,contains:[{
-className:"type",
-match:b(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,De,"+")
-},{className:"type",match:Be,relevance:0},{match:/[?!]+/,relevance:0},{
-match:/\.\.\./,relevance:0},{match:b(/\s+&\s+/,g(Be)),relevance:0}]},k={
-begin:/</,end:/>/,keywords:l,contains:[...a,...c,...x,u,S]};S.contains.push(k)
-;const A={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{
-match:b(Ie,/\s*:/),keywords:"_|0",relevance:0
-},...a,...c,...d,...p,f,v,...M,...x,S]},C={begin:/</,end:/>/,contains:[...a,S]
-},T={begin:/\(/,end:/\)/,keywords:l,contains:[{
-begin:m(g(b(Ie,/\s*:/)),g(b(Ie,/\s+/,Ie,/\s*:/))),end:/:/,relevance:0,
-contains:[{className:"keyword",match:/\b_\b/},{className:"params",match:Ie}]
-},...a,...c,...p,f,v,...x,S,A],endsParent:!0,illegal:/["']/},R={
-match:[/func/,/\s+/,m(O.match,Ie,Te)],className:{1:"keyword",3:"title.function"
-},contains:[C,T,n],illegal:[/\[/,/%/]},D={
-match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"},
-contains:[C,T,n],illegal:/\[|%/},I={match:[/operator/,/\s+/,Te],className:{
-1:"keyword",3:"title"}},B={begin:[/precedencegroup/,/\s+/,Be],className:{
-1:"keyword",3:"title"},contains:[S],keywords:[...xe,...Me],end:/}/}
-;for(const e of v.variants){const n=e.contains.find((e=>"interpol"===e.label))
-;n.keywords=l;const t=[...c,...d,...p,f,v,...M];n.contains=[...t,{begin:/\(/,
-end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:l,
-contains:[...a,R,D,{beginKeywords:"struct protocol class extension enum actor",
-end:"\\{",excludeEnd:!0,keywords:l,contains:[e.inherit(e.TITLE_MODE,{
-className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...c]
-},I,B,{beginKeywords:"import",end:/$/,contains:[...a],relevance:0
-},...c,...d,...p,f,v,...M,...x,S,A]}},grmr_typescript:e=>{const n={$pattern:ge,
-keyword:ue.concat(["type","namespace","typedef","interface","public","private","protected","implements","declare","abstract","readonly"]),
-literal:be,
-built_in:he.concat(["any","void","number","boolean","string","object","never","enum"]),
-"variable.language":fe},t={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"
-},a=(e,n,t)=>{const a=e.contains.findIndex((e=>e.label===n))
-;if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)
-},i=Ee(e)
-;return Object.assign(i.keywords,n),i.exports.PARAMS_CONTAINS.push(t),i.contains=i.contains.concat([t,{
-beginKeywords:"namespace",end:/\{/,excludeEnd:!0},{beginKeywords:"interface",
-end:/\{/,excludeEnd:!0,keywords:"interface extends"
-}]),a(i,"shebang",e.SHEBANG()),a(i,"use_strict",{className:"meta",relevance:10,
-begin:/^\s*['"]use strict['"]/
-}),i.contains.find((e=>"func.def"===e.label)).relevance=0,Object.assign(i,{
-name:"TypeScript",aliases:["ts","tsx"]}),i},grmr_vbnet:e=>{
-const n=/\d{1,2}\/\d{1,2}\/\d{4}/,t=/\d{4}-\d{1,2}-\d{1,2}/,a=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,i=/\d{1,2}(:\d{1,2}){1,2}/,s={
-className:"literal",variants:[{begin:b(/# */,m(t,n),/ *#/)},{
-begin:b(/# */,i,/ *#/)},{begin:b(/# */,a,/ *#/)},{
-begin:b(/# */,m(t,n),/ +/,m(a,i),/ *#/)}]},r=e.COMMENT(/'''/,/$/,{contains:[{
-className:"doctag",begin:/<\/?/,end:/>/}]}),o=e.COMMENT(null,/$/,{variants:[{
-begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]});return{name:"Visual Basic .NET",
-aliases:["vb"],case_insensitive:!0,classNameAliases:{label:"symbol"},keywords:{
-keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield",
-built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort",
-type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort",
-literal:"true false nothing"},
-illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{
-className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/,
-end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0,
-variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/
-},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{
-begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{
-className:"label",begin:/^\w+:/},r,o,{className:"meta",
-begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/,
-end:/$/,keywords:{
-keyword:"const disable else elseif enable end externalsource if region then"},
-contains:[o]}]}},grmr_yaml:e=>{
-const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={
-className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/
-},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",
-variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{
-variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),s={
-end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},r={begin:/\{/,
-end:/\}/,contains:[s],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]",
-contains:[s],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{
-begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{
-begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$",
-relevance:10},{className:"string",
-begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{
-begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,
-relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type",
-begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t
-},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",
-begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)",
-relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{
-className:"number",
-begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"
-},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},r,o,a],c=[...l]
-;return c.pop(),c.push(i),s.contains=c,{name:"YAML",case_insensitive:!0,
-aliases:["yml"],contains:l}}});const Fe=Y;for(const e of Object.keys(ze)){
-const n=e.replace("grmr_","");Fe.registerLanguage(n,ze[e])}return Fe}()
-;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); \ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
deleted file mode 100644
index 95e2382..0000000
--- a/docs/index.html
+++ /dev/null
@@ -1,170 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list home">
- <header class="header">
- <nav class="nav">
- <h1 class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></h1>
- </nav>
- </header>
- <main class="main">
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>[備忘録] このサイト用の VPS をセットアップしたときのメモ</h2>
- </header>
- <section class="entry-content">
- <p>GitHub Pages でホストしていたこのサイトを VPS へ移行したので、
-そのときにやったことのメモ。99 % 自分用。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-10-28</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2023: ボツになったトークン問題 その 1</h2>
- </header>
- <section class="entry-content">
- <p>来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、
-ボツになった問題を公開する (その 1)。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-10-23</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[PHP] fizzbuzz を書く。1行あたり2文字で。</h2>
- </header>
- <section class="entry-content">
- <p>PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-09-29</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>弊社の PHP Foundation への寄付に寄せて</h2>
- </header>
- <section class="entry-content">
- <p>先日、私の勤めるデジタルサーカス株式会社が、PHP Foundation へ寄付をおこないました。
-本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-08-31</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-08-31/support-for-communty-is-employee-benefits/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2>
- </header>
- <section class="entry-content">
- <p>PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-08-27</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2022</h2>
- </header>
- <section class="entry-content">
- <p>2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-05-01</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>term-banner: ターミナルにバナーを表示するツールを書いた</h2>
- </header>
- <section class="entry-content">
- <p>ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-04-24</time>, updated on <time>2022-04-27</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2022 トークン問題の解説</h2>
- </header>
- <section class="entry-content">
- <p>PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-04-09</time>, updated on <time>2022-04-16</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>Rust のプリミティブ型はどこからやって来るか</h2>
- </header>
- <section class="entry-content">
- <p>Rust のプリミティブ型は予約語ではなく普通の識別子である。どのようにこれが名前解決されるのかを調べた。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Ruby] then キーワードと case in</h2>
- </header>
- <section class="entry-content">
- <p>Ruby 3.0 で追加される case in 構文と、then キーワードについて。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/"></a>
-</article>
-<footer class="page-footer">
- <nav class="pagination">
- <a class="next" href="/page/2/"> →</a>
- </nav>
-</footer></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/page/1/index.html b/docs/page/1/index.html
deleted file mode 100644
index 81da958..0000000
--- a/docs/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/">
- </head>
-</html>
diff --git a/docs/page/2/index.html b/docs/page/2/index.html
deleted file mode 100644
index 5d6af1b..0000000
--- a/docs/page/2/index.html
+++ /dev/null
@@ -1,131 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list home">
- <header class="header">
- <nav class="nav">
- <h1 class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></h1>
- </nav>
- </header>
- <main class="main">
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>[C&#43;&#43;] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</h2>
- </header>
- <section class="entry-content">
- <p>C&#43;&#43; の属性構文の属性名には、キーワードが使える。ネタ記事。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Ruby] 自身を実行している処理系の種類を判定する</h2>
- </header>
- <section class="entry-content">
- <p>Ruby には複数の実装があるが、自身を実行している処理系の種類をスクリプト上からどのように判定すればよいだろうか。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>Vimで選択した行の順番を入れ替える</h2>
- </header>
- <section class="entry-content">
- <p>Vim で選択した行の順番を入れ替える方法。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Vim] autocmd events の BufWrite/BufWritePre の違い</h2>
- </header>
- <section class="entry-content">
- <p>Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、違いはないことがわかった。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Python] クロージャとUnboundLocalError: local variable &#39;x&#39; referenced before assignment</h2>
- </header>
- <section class="entry-content">
- <p>Python における UnboundLocalError の理由と対処法。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2021</h2>
- </header>
- <section class="entry-content">
- <p>2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-03-30</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>My First Post</h2>
- </header>
- <section class="entry-content">
- <p>これはテスト投稿です。これはテスト投稿です。これはテスト投稿です。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-03-05</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-03-05/my-first-post/"></a>
-</article>
-<footer class="page-footer">
- <nav class="pagination">
- <a class="prev" href="/">← </a>
- </nav>
-</footer></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2021-03-05/my-first-post/index.html b/docs/posts/2021-03-05/my-first-post/index.html
deleted file mode 100644
index cd1bbe8..0000000
--- a/docs/posts/2021-03-05/my-first-post/index.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>My First Post | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="これはテスト投稿です。これはテスト投稿です。これはテスト投稿です。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">My First Post</h1>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2021-03-05: 公開</li>
- </ul>
- </section>
- <h1 id="test">Test</h1>
-<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2021-03-30/phperkaigi-2021/index.html b/docs/posts/2021-03-30/phperkaigi-2021/index.html
deleted file mode 100644
index a10cc08..0000000
--- a/docs/posts/2021-03-30/phperkaigi-2021/index.html
+++ /dev/null
@@ -1,532 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>PHPerKaigi 2021 | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">PHPerKaigi 2021</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/conference">conference</a></li>
- <li><a href="https://blog.nsfisis.dev/tags/php">php</a></li>
- <li><a href="https://blog.nsfisis.dev/tags/phperkaigi">phperkaigi</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2021-03-30: 公開</li>
- </ul>
- </section>
- <h1 id="phperkaigi-2021-参加レポ">PHPerKaigi 2021 参加レポ</h1>
-<p>2021-03-26 から 2021-03-28 にかけて開催された、<a href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</a> に一般参加者として参加した。
-弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
-<p>このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。</p>
-<p>発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。</p>
-<h2 id="凡例">凡例</h2>
-<blockquote>
-<p>発表・スライドのメモ (引用ではない)</p>
-</blockquote>
-<p>感想など</p>
-<h2 id="day-0-前夜祭-20210327">Day 0 前夜祭 (2021/03/27)</h2>
-<h3 id="1730-a">17:30 [A]</h3>
-<p>PHP で AWS Lambda</p>
-<blockquote>
-<p>Rails のプロジェクトを PHPer のメンバのみでメンテ
-→他のメンバもわかる PHP にリプレースを検討</p>
-<p>サーバレス</p>
-<ul>
-<li>サーバ・インフラの管理が不要</li>
-<li>アプリケーションコードの知識だけで保守可能</li>
-</ul>
-<p>ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入?</p>
-<p>AWSの学習
-AWS のドキュメント
-DevelopersIO</p>
-<p>AWS Lambda のカスタムランタイムで PHP を動かす</p>
-<p>サーバのセットアップや維持管理を気にしなくて良い
-サーバーレスで PHP を動かすツールがすでにある
-サーバーレス構築はすんなり</p>
-<p>今は Laravel がルーティングしている
-Laravel Livewire を Lambda に載せられないか?
-デプロイ方法は?
-バッチ処理は? (Lambda は 15分の制限)</p>
-<p>Lambda でコンテナイメージがサポートされるように</p>
-<p>抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる</p>
-</blockquote>
-<p>AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。</p>
-<p>PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。</p>
-<p>勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。</p>
-<h3 id="1810-a">18:10 [A]</h3>
-<p>大規模サイトの SEO</p>
-<blockquote>
-<p>大規模サイト (100万ページ以上)
-Google の基準</p>
-<p>クロールバジェットを意識したSEO</p>
-<p>大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される
-これを満たさないなら、クロールバジェットを考えなくてもいい</p>
-<p>サーチコンソール
-「カバレッジ」の「除外」
-多すぎるのは問題→クロールバジェットを浪費している</p>
-<ul>
-<li>クエリの順番を決める</li>
-<li>空の値のルールを決めておく</li>
-<li>リダイレクトすればインデックスはうまくいく</li>
-<li>リンクが存在する限りクロールはされる</li>
-</ul>
-<p>リニューアル前のURL</p>
-<p>インデックスは移行される
-リンクのURLが存在する限り、別のURLとしてクロールされる
-リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い
-リニューアルで無視されるようになったパラメータも注意</p>
-<p>robotes.txt で拒否しているのにクロールされる
-一時的に拒否を外して 404 や 301 を読ませる
-内部リンクを確認する
-JS でのリンクに書き換え</p>
-<p>クエリパラメータからURLのパスに
-<code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code></p>
-<p>URL 設計だいじ</p>
-</blockquote>
-<p>SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。</p>
-<h3 id="1850-a">18:50 [A]</h3>
-<blockquote>
-<p>知覚可能
-操作可能
-理解可能
-堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など)</p>
-<ul>
-<li>
-<p>標準の HTML を適切に使う</p>
-</li>
-<li>
-<p>WAI-ARIA</p>
-</li>
-<li>
-<p>キーボードフレンドリー</p>
-</li>
-<li>
-<p>マシンフレンドリー</p>
-</li>
-<li>
-<p>SEOフレンドリー</p>
-</li>
-</ul>
-<p>button タグ
-→キーボード
-h1 タグ
-→スクリーンリーダー・クローラ
-a タグ</p>
-<p>WAI-ARIA
-HTML では表現できないセマンティクスを追加する</p>
-<ul>
-<li>ロール
-<ul>
-<li>何をするのか?</li>
-<li>ユーザーアクションによって変化しない</li>
-</ul>
-</li>
-<li>プロパティ
-<ul>
-<li>関連づけられたデータ</li>
-</ul>
-</li>
-<li>ステート
-<ul>
-<li>現在の状態</li>
-</ul>
-</li>
-</ul>
-<p>まずは標準の HTML 要素で解決する
-何でもかんでも WAI-ARIA を使えばいいというものではない</p>
-<p>マウスホバーでツールチップが出てくるが、キーボード操作では出てこない</p>
-<p>VoiceOver</p>
-<p>全ての属性を使う必要はない
-あくまでアクセシビリティを上げるための方法の一つにすぎない</p>
-</blockquote>
-<p>つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。</p>
-<h3 id="1930-a">19:30 [A]</h3>
-<p>PHP で FUSE</p>
-<p>個人的に楽しみだった発表。</p>
-<blockquote>
-<p>VFS (virtual filesystem) vs 具体的なファイルシステム</p>
-<p>最適な実装方法は状況により異なる</p>
-<p>アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS</p>
-<p>カーネルのプログラムを作るのは難しい</p>
-<ul>
-<li>権限がデカすぎる</li>
-<li>システム全体がクラッシュ</li>
-<li>セキュリティリスク</li>
-<li>開発サイクルを回しづらい</li>
-<li>ネイティブコードにコンパイルされる言語である必要がある</li>
-</ul>
-<p>Filesystem in USEr space (FUSE)</p>
-<ul>
-<li>特定の C の関数を呼ぶことで filesystem が作れる</li>
-<li>FFI を持つ言語なら FUSE が使える</li>
-</ul>
-<p>SSHFS / s3fs / Docker Desktop</p>
-<p>Linux 以外でも使える</p>
-<ul>
-<li>dokany (on Windows)</li>
-<li>osxfuse</li>
-</ul>
-<p>VFS: システムコールが呼ばれると、ファイルシステムによってコール
-FUSE: カーネル空間からユーザ空間へ通信</p>
-<p>高レベルなラッパで型をつける</p>
-<p>PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)</p>
-<ul>
-<li>grep できる</li>
-<li>sed できる</li>
-<li>編集できる</li>
-</ul>
-</blockquote>
-<p>期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。
-この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。</p>
-<h2 id="day-1-20210327">Day 1 (2021/03/27)</h2>
-<h3 id="1050-a">10:50 [A]</h3>
-<p>ATDD</p>
-<blockquote>
-<ul>
-<li>ユーザーストーリー</li>
-<li>ユニットテスト</li>
-<li>CI/CD</li>
-</ul>
-<p>ユーザストーリーの受け入れ条件が曖昧になりがち
-デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている</p>
-<p>Q2の強化
-アジャイルテストの4象限</p>
-<p>技術面/ビジネス面
-開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)</p>
-<ul>
-<li>Q1: 技術面 &amp; チーム支援
-<ul>
-<li>TDD</li>
-<li>ユニットテストなど</li>
-</ul>
-</li>
-<li>Q2: ビジネス面 &amp; チーム支援
-<ul>
-<li>ATDD</li>
-<li>ビジネス面の受け入れテストで駆動する</li>
-</ul>
-</li>
-</ul>
-<p>Agile Alliance
-ユーザストーリーのスキルレベルを高める</p>
-<p>テストピラミッド</p>
-<ul>
-<li>
-<p>UI Tests</p>
-</li>
-<li>
-<p>Service Tests</p>
-</li>
-<li>
-<p>Unit Tests</p>
-</li>
-<li>
-<p>異なる粒度のテストを書く</p>
-</li>
-<li>
-<p>高レベルになるほど、持つべきテストは少なくなる</p>
-<ul>
-<li>ピラミッド型になる</li>
-</ul>
-</li>
-</ul>
-<p>高レベルテストが多すぎる→アイスクリームコーン アンチパターン</p>
-<p>ATDD (Acceptance TDD)
-API経由・UI経由での高レベルテスト E2E test</p>
-<p>ストーリ受け入れテスト</p>
-<p>入れ子のフィードバックループ
-ATDD(外側) と TDD(内側)</p>
-<p>外部品質・内部品質</p>
-<p>バーティカルスライスのデリバリー</p>
-<ul>
-<li>cucumber</li>
-<li>gauge</li>
-<li>behat</li>
-</ul>
-<p>ユビキタス言語
-手動テストもspecに書く
-自動化は可能だがコスパが悪い
-失敗することがわかっているテスト(レッドテスト)はCIから外す
-失敗時の原因究明が難しい
-饒舌なエラーメッセージ
-状況のスナップショット</p>
-<p>Continuous Testing</p>
-</blockquote>
-<p>User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。
-高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。</p>
-<h3 id="1150-a">11:50 [A]</h3>
-<p>型解析を用いたリファクタリング</p>
-<p>型のある世界で生きてきた身として大いに楽しみにしていた発表。</p>
-<blockquote>
-<ul>
-<li>PHPStan</li>
-<li>Phan</li>
-<li>Psalm</li>
-</ul>
-<p>autoload も認識できる
-bootstrapFiles</p>
-<p>編集箇所と利用箇所を CI でチェック
-ルールレベルを徐々に引き上げていく
-警告が多すぎると見落としてしまう・無視されやすくなる</p>
-<p>型がついていないことによるエラーが多い</p>
-<p>型よりも詳細な検査 <code>Util_Assert::min</code></p>
-<p>SQL を静的解析
-placeholder の型付け</p>
-<p>警告レベルを低いレベルから導入
-タイプヒントを積極的に書いていく
-PHPStan の拡張を追加する</p>
-</blockquote>
-<p>昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。
-今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。</p>
-<h3 id="1230-a">12:30 [A]</h3>
-<p>昼食をとっていた。事前に何か食料を買っておくべきだった。</p>
-<h3 id="1310-a">13:10 [A]</h3>
-<p>Documentation as Code</p>
-<p>この発表も以前から非常に楽しみにしていた。</p>
-<blockquote>
-<p>開発開始までのオーバーヘッド
-新規にチームにジョイン
-担当範囲外の機能を理解
-オンボーディングのコスト</p>
-<p>PHPerKaigi 2020 で発表あり</p>
-<p>継続的にシステムの理解を助けるドキュメント</p>
-<p>継続的ドキュメンテーション
-システムとドキュメントの乖離</p>
-<p>書いてあることが間違っている・足りない</p>
-<ul>
-<li>徐々にずれていく</li>
-<li>システムの更新タイミングとドキュメントの更新タイミングに差がある</li>
-</ul>
-<p>システムとドキュメントは対応関係がある</p>
-<ul>
-<li>間違ったドキュメント</li>
-<li>存在しないドキュメント</li>
-</ul>
-<p>システムとドキュメントの乖離を定量化する
-継続的に
-システムの更新に近いタイミングで ドキュメントを更新し続ける</p>
-<p>Documentation as Code</p>
-<p>コードと同じツールでドキュメントを書く</p>
-<ul>
-<li>issue tracker</li>
-<li>vcs</li>
-<li>plain text markup</li>
-<li>automation</li>
-</ul>
-<p>開発者
-システム
-ドキュメント
-構造化データ
-ソフトウェア</p>
-<p>システムから構造化データを抽出する
-PHPDoc
-OpenAPI</p>
-<p>ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する</p>
-<p>ビューの単位でドキュメントに</p>
-<p>スタックトレースからのドキュメント生成</p>
-</blockquote>
-<p>ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。</p>
-<h3 id="1410-a">14:10 [A]</h3>
-<p>cookie による session 管理</p>
-<p>全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。</p>
-<h3 id="1450-a">14:50 [A]</h3>
-<p>PHP のエラーと例外</p>
-<blockquote>
-<p>エラー PHPエンジンがエラーを通知する
-例外 プログラムが投げる</p>
-<p>PHP7-8とエラー</p>
-<p>PHPエンジンのエラーの一部が \Error に変換されるようになった
-→ try-catch で捕捉できる</p>
-<p>\Error は例外とは異なる</p>
-<p>PHP8 でエラーレベルの引き上げ</p>
-<ul>
-<li>捕捉すべきもの
-<ul>
-<li>recoverable</li>
-</ul>
-</li>
-<li>捕捉すべきでないもの
-<ul>
-<li>unrecoverable</li>
-<li>開発時に対処できるもの</li>
-</ul>
-</li>
-</ul>
-<p>例外</p>
-<ul>
-<li>捕捉して事後処理</li>
-<li>捕捉せず(or 捕捉した上で)さらに上に是非を問う</li>
-</ul>
-<p>開発段階で例外を把握し、ハンドリングを考えておく</p>
-<p>\Throwable \Exception と \Error</p>
-<p>\Error はキャッチすべきでない</p>
-<ul>
-<li>
-<p>\Error</p>
-<ul>
-<li>本番で起きてはいけない</li>
-</ul>
-</li>
-<li>
-<p>\LogicException</p>
-<ul>
-<li>本番で起きてはいけない
-→生じないのだから捕捉もしない</li>
-</ul>
-</li>
-<li>
-<p>\RuntimeException</p>
-<ul>
-<li>起こるかもしれないので本番環境でも考慮する</li>
-</ul>
-</li>
-</ul>
-<p>捕捉して対応するのではなく、未然に防ぐ</p>
-<p>独自例外を使う
-\Exception を投げてしまうと、
-catch (\Exception)せざるを得ない
-→catch 範囲が広すぎる</p>
-<p>SPL の例外を使う</p>
-<p>例外翻訳
-上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する
-下位レイヤの知識に依存させない</p>
-<p>@throws
-捕捉してほしい例外を書き連ねておく</p>
-<p>呼び出しもとに負わせたい責任</p>
-</blockquote>
-<p>PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。</p>
-<p>個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。</p>
-<p>PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。</p>
-<h3 id="1530-a">15:30 [A]</h3>
-<p>Laravel のメール認証</p>
-<p>Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。</p>
-<h3 id="1610-a">16:10 [A]</h3>
-<p>gRPC</p>
-<blockquote>
-<p>Unary RPCs
-Server streaming RPCs
-Client streaming RPCs
-Bidirectional streaming RPCs</p>
-<p>Protobuf</p>
-<p>実装とAPIが乖離しにくい
-自動生成
-複数言語でも相互に使える</p>
-<p>マイクロサービスのサービス通信
-スマホアプリ
-ゲームサーバ</p>
-<p>PHP では?</p>
-<p>PHP ではストリーミングが難しい
-リクエストごとにプロセスが使い捨て</p>
-<p>PHP ではgRPCのクライアントしか対応していない</p>
-<p>gRPC-Web
-ブラウザで扱うためのJSライブラリ+プロトコル</p>
-<p>HTTP/1.1 でも使える
-Unary RPC と Server streaming RPC のみ</p>
-<p>Envoy
-Nginx などで相互に gRPC と gRPC-Web で変換</p>
-<p>Amp
-イベント駆動な並行処理のフレームワーク</p>
-<p>HTTP/2 対応</p>
-<p>C#のgRPC-Webが楽</p>
-</blockquote>
-<p>(発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。</p>
-<h3 id="1650-a">16:50 [A]</h3>
-<p>アーキテクチャテスト</p>
-<blockquote>
-<p>Independent Core Layer Pattern</p>
-<p>開発初期のアーキテクチャが崩れる
-アーキテクチャ観点のコードレビューができない</p>
-<p>どこにクラスを置けばよいか?
-ドキュメントがない</p>
-<p>アーキテクチャ設計に関する知識が属人化・暗黙知化</p>
-<p>ガイドライン</p>
-<ul>
-<li>最初にルールを決めるのは簡単</li>
-<li>ルール通り作り始めるのも簡単
-<ul>
-<li>→維持するのが難しい、人が決めたものゆえ壊れやすい</li>
-</ul>
-</li>
-</ul>
-<p>PHP の特性</p>
-<ul>
-<li>クラスは public</li>
-<li>可視性の制御が public / protected / private のみ</li>
-<li>依存関係の制御が困難</li>
-</ul>
-<p>アーキテクチャテスト
-クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する</p>
-<ul>
-<li>deptrac</li>
-<li>phpat</li>
-</ul>
-<p>Independent Core Layer Pattern</p>
-<p>アーキテクチャテストの失敗</p>
-<ul>
-<li>実装誤り</li>
-<li>or アーキテクチャが適切でない
-<ul>
-<li>開発の過程でフィードバックしていく</li>
-</ul>
-</li>
-</ul>
-<p>モジュラーモノリス→マイクロサービスへ</p>
-</blockquote>
-<h2 id="day-2-20210328">Day 2 (2021/03/28)</h2>
-<p>冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。</p>
-<p>残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。</p>
-<h2 id="全体の感想">全体の感想</h2>
-<p>Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。</p>
-<p>今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。</p>
-<p>1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。
-まあ初カンファレンスだし、とお茶を濁しておこう。</p>
-<p>さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。</p>
-<hr>
-<p>最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました!
-(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)</p>
-<p>ではまた来年。</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html b/docs/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html
deleted file mode 100644
index 38c34aa..0000000
--- a/docs/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html
+++ /dev/null
@@ -1,129 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>[C&#43;&#43;] 属性構文の属性名にはキーワードが使える [[void]] [[for]] | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="C&#43;&#43; の属性構文の属性名には、キーワードが使える。ネタ記事。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">[C&#43;&#43;] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/cpp">cpp</a></li>
- <li><a href="https://blog.nsfisis.dev/tags/cpp17">cpp17</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2021-10-02: Qiita から移植</li>
- </ul>
- </section>
- <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</a></p>
-<hr>
-<p>タイトル落ち。まずはこのコードを見て欲しい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;iostream&gt;</span><span style="color:#75715e">
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// [[using]]
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">int</span> main() {
-</span></span><span style="display:flex;"><span> std<span style="color:#f92672">::</span>cout <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#34;Hello, World!&#34;</span> <span style="color:#f92672">&lt;&lt;</span> std<span style="color:#f92672">::</span>endl;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><blockquote>
-<p>コンパイラのバージョン
-$ clang++ &ndash;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</p>
-<p>コンパイルコマンド (C++17指定)
-$ clang++ &ndash;std=c++17 hoge.cpp</p>
-</blockquote>
-<p>この記事から得られるものはこれ以上ないので以下は蛇足になる。</p>
-<p>別件で cppreference.com の <a href="https://en.cppreference.com/w/cpp/language/identifiers">identifier のページ</a> を読んでいた時、次の文が目に止まった。</p>
-<blockquote>
-<ul>
-<li>the identifiers that are keywords cannot be used for other purposes;
-<ul>
-<li>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)</li>
-</ul>
-</li>
-</ul>
-</blockquote>
-<p>キーワードでも属性として指定する場合は非キーワードとして使えるらしい。
-実際にやってみる。</p>
-<p>同サイトの [keywords のページ] (<a href="https://en.cppreference.com/w/cpp/keyword">https://en.cppreference.com/w/cpp/keyword</a>) から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。
-大量の警告 (unknown attribute &lsquo;〇〇&rsquo; ignored) がコンパイラから出力されるが、コンパイルできる。</p>
-<p>上のコードでは <code>[[using]]</code> をコメントアウトしているが、これは <code>using</code> キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">// using の例
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]]</span> <span style="color:#960050;background-color:#1e0010">の糖衣構文</span>
-</span></span></code></pre></div><p>C++17 の仕様も見てみる (正確には標準化前のドラフト)。</p>
-<p>引用元: <a href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</a></p>
-<blockquote>
-<p>If a keyword or an alternative token that satisfies the syntactic requirements of an identifier is contained in an attribute-token, it is considered an identifier.</p>
-</blockquote>
-<p>「<code>identifier</code> の構文上の要件を満たすキーワードまたは代替トークンが <code>attribute-token</code> に含まれている場合、<code>identifier</code> とみなされる」とある。どうやら間違いないようだ。</p>
-<p>ところで、代替トークン (alternative token) とは <code>and</code> (<code>&amp;</code>) や <code>bitor</code> (<code>|</code>) などのことだが、<code>identifier</code> の構文上の要件を満たさないような代替トークンなどあるのか?
-疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい (参考: <a href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</a>)</p>
-<ul>
-<li><code>&lt;%</code> → <code>{</code></li>
-<li><code>%&gt;</code> → <code>}</code></li>
-<li><code>&lt;:</code> → <code>[</code></li>
-<li><code>:&gt;</code> → <code>]</code></li>
-<li><code>%:</code> → <code>#</code></li>
-<li><code>%:%:</code> → <code>##</code></li>
-</ul>
-<p>「<code>identifier</code> の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。</p>
-<p>調べた感想: 字句解析器か構文解析器が辛そう</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2021-10-02/python-unbound-local-error/index.html b/docs/posts/2021-10-02/python-unbound-local-error/index.html
deleted file mode 100644
index 35a880d..0000000
--- a/docs/posts/2021-10-02/python-unbound-local-error/index.html
+++ /dev/null
@@ -1,97 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>[Python] クロージャとUnboundLocalError: local variable &#39;x&#39; referenced before assignment | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="Python における UnboundLocalError の理由と対処法。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">[Python] クロージャとUnboundLocalError: local variable &#39;x&#39; referenced before assignment</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/python">python</a></li>
- <li><a href="https://blog.nsfisis.dev/tags/python3">python3</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2021-10-02: Qiita から移植</li>
- </ul>
- </section>
- <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</a></p>
-<hr>
-<p>本記事は Python 3.7.6 の動作結果を元にして書かれている。</p>
-<p>Python でクロージャを作ろうと、次のようなコードを書いた。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>f()
-</span></span></code></pre></div><p>関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに 1 を足そうとしている。
-これを実行すると <code>x += 1</code> の箇所でエラーが発生する。</p>
-<blockquote>
-<p>UnboundLocalError: local variable &lsquo;x&rsquo; referenced before assignment</p>
-</blockquote>
-<p>local変数 <code>x</code> が代入前に参照された、とある。これは、<code>f</code> の <code>x</code> を参照するのではなく、新しく別の変数を <code>g</code> 内に作ってしまっているため。
-前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code> を変数宣言のための構文として擬似的に利用している。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># 注: var は正しい Python の文法ではない。上記参照のこと</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># f の local変数 &#39;x&#39; を宣言</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e"># x に 0 を代入</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>(): <span style="color:#75715e"># f の内部関数 g を定義</span>
-</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># g の local変数 &#39;x&#39; を宣言</span>
-</span></span><span style="display:flex;"><span> <span style="color:#75715e"># たまたま f にも同じ名前の変数があるが、それとは別の変数</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span> <span style="color:#75715e"># x に 1 を加算 (x = x + 1 の糖衣構文)</span>
-</span></span><span style="display:flex;"><span> <span style="color:#75715e"># 加算する前の値を参照しようとするが、まだ代入されていないためエラー</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span></code></pre></div><p>当初の意図を表現するには、次のように書けばよい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>():
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">nonlocal</span> x <span style="color:#75715e">## (*)</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span></code></pre></div><p><code>(*)</code> のように、<code>nonlocal</code> を追加する。これにより一つ外側のスコープ (<code>g</code> の一つ外側 = <code>f</code>) で定義されている <code>x</code> を探しに行くようになる。</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2021-10-02/ruby-detect-running-implementation/index.html b/docs/posts/2021-10-02/ruby-detect-running-implementation/index.html
deleted file mode 100644
index 71eadba..0000000
--- a/docs/posts/2021-10-02/ruby-detect-running-implementation/index.html
+++ /dev/null
@@ -1,125 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>[Ruby] 自身を実行している処理系の種類を判定する | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="Ruby には複数の実装があるが、自身を実行している処理系の種類をスクリプト上からどのように判定すればよいだろうか。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">[Ruby] 自身を実行している処理系の種類を判定する</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/ruby">ruby</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2021-10-02: Qiita から移植</li>
- </ul>
- </section>
- <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</a></p>
-<hr>
-<p>Ruby という言語には複数の実装があるが、それらをスクリプト上からどのようにして programmatically に見分ければよいだろうか。</p>
-<p><code>Object</code> クラスに定義されている <code>RUBY_ENGINE</code> という定数がこの用途に使える。</p>
-<p>参考: <a href="https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html">Object::RUBY_ENGINE</a></p>
-<p>上記ページの例から引用する:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ruby-1.9.1 -ve <span style="color:#e6db74">&#39;p RUBY_ENGINE&#39;</span>
-</span></span><span style="display:flex;"><span>ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux]
-</span></span><span style="display:flex;"><span>&#34;ruby&#34;
-</span></span><span style="display:flex;"><span>$ jruby -ve <span style="color:#e6db74">&#39;p RUBY_ENGINE&#39;</span>
-</span></span><span style="display:flex;"><span>jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
-</span></span><span style="display:flex;"><span>&#34;jruby&#34;
-</span></span></code></pre></div><p>それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。</p>
-<p><a href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE correspond to which Ruby implementations?</a> より引用:</p>
-<blockquote>
-<table>
-<thead>
-<tr>
-<th style="text-align:center">RUBY_ENGINE</th>
-<th style="text-align:left">Implementation</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td style="text-align:center">&lt;undefined&gt;</td>
-<td style="text-align:left">MRI &lt; 1.9</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;ruby&rsquo;</td>
-<td style="text-align:left">MRI &gt;= 1.9 or REE</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;jruby&rsquo;</td>
-<td style="text-align:left">JRuby</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;macruby&rsquo;</td>
-<td style="text-align:left">MacRuby</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;rbx&rsquo;</td>
-<td style="text-align:left">Rubinius</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;maglev&rsquo;</td>
-<td style="text-align:left">MagLev</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;ironruby&rsquo;</td>
-<td style="text-align:left">IronRuby</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;cardinal&rsquo;</td>
-<td style="text-align:left">Cardinal</td>
-</tr>
-</tbody>
-</table>
-</blockquote>
-<p>なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も <code>'ruby'</code> が返ってくることを確認済み。</p>
-<p>この表にない主要な処理系として、<a href="https://mruby.org">mruby</a> は <code>'mruby'</code> を返す。</p>
-<p><a href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby 該当部分のソース</a> より引用:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * Ruby engine.
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">#define MRUBY_RUBY_ENGINE &#34;mruby&#34;
-</span></span></span></code></pre></div>
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html b/docs/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html
deleted file mode 100644
index 7d62273..0000000
--- a/docs/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html
+++ /dev/null
@@ -1,195 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>[Ruby] then キーワードと case in | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="Ruby 3.0 で追加される case in 構文と、then キーワードについて。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">[Ruby] then キーワードと case in</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/ruby">ruby</a></li>
- <li><a href="https://blog.nsfisis.dev/tags/ruby3">ruby3</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2021-10-02: Qiita から移植</li>
- </ul>
- </section>
- <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</a></p>
-<hr>
-<h1 id="tl-dr">TL; DR</h1>
-<p><code>case</code> - <code>in</code> によるパターンマッチング構文でも、<code>case</code> - <code>when</code> と同じように <code>then</code> が使える (場合によっては使う必要がある)。</p>
-<h1 id="then-とは"><code>then</code> とは</h1>
-<p>使われることは稀だが、Ruby では <code>then</code> がキーワードになっている。次のように使う:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> cond <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">&#34;Y&#34;</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
-</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">&#34;N&#34;</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code> 構文がそれに当たる。
-上記のように、何か条件を書いた後 <code>then</code> を置き、式がそこで終了していることを示すマーカーとして機能する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># Example:</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> x <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">unless</span> x <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">begin</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">rescue</span> <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">when</span> p <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><h1 id="なぜ普段は書かなくてもよいのか">なぜ普段は書かなくてもよいのか</h1>
-<p>普通 Ruby のコードで <code>then</code> を書くことはない。なぜか。次のコードを実行してみるとわかる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span> puts <span style="color:#e6db74">&#39;Hello, World!&#39;</span> <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>次のような構文エラーが出力される。</p>
-<pre tabindex="0"><code>20:1: syntax error, unexpected local variable or method, expecting `then&#39; or &#39;;&#39; or &#39;\n&#39;
-if true puts &#39;Hello, World!&#39; end
- ^~~~
-20:1: syntax error, unexpected `end&#39;, expecting end-of-input
-...f true puts &#39;Hello, World!&#39; end
-</code></pre><p>二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code> か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。</p>
-<p>ポイントは改行が <code>then</code> (や <code>;</code>) の代わりとなることである。<code>true</code> の後に改行を入れてみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span>
-</span></span><span style="display:flex;"><span>puts <span style="color:#e6db74">&#39;Hello, World!&#39;</span> <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>無事 Hello, World! と出力されるようになった。</p>
-<h1 id="なぜ-then-や--や改行が必要か">なぜ <code>then</code> や <code>;</code> や改行が必要か</h1>
-<p>なぜ <code>then</code> や <code>;</code> や改行 (以下 「<code>then</code> 等」) が必要なのだろうか。次の例を見てほしい:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a b <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p><code>then</code> も <code>;</code> も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。
-この例は二通りに解釈できる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e"># その結果が truthy なら何もしない</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a(b) <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></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> も同じ役割を持つ。</p>
-<p>Ruby の場合、プログラマーが書きやすいよう改行でもって <code>then</code> が代用できるので、ほとんどの場合 <code>then</code> は必要ない。</p>
-<h1 id="case---in-における-then"><code>case</code> - <code>in</code> における <code>then</code></h1>
-<p>ようやく本題にたどり着いた。来る Ruby 3.0 では <code>case</code> と <code>in</code> キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして <code>then</code> 等が必要になる。
-(現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。</p>
-<p><a href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</a></p>
-<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in
- {
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- p-&gt;command_start = FALSE;
- $&lt;ctxt&gt;1 = p-&gt;ctxt;
- p-&gt;ctxt.in_kwarg = 1;
- $&lt;tbl&gt;$ = push_pvtbl(p);
- }
- {
- $&lt;tbl&gt;$ = push_pktbl(p);
- }
- p_top_expr then
- {
- pop_pktbl(p, $&lt;tbl&gt;3);
- pop_pvtbl(p, $&lt;tbl&gt;2);
- p-&gt;ctxt.in_kwarg = $&lt;ctxt&gt;1.in_kwarg;
- }
- compstmt
- p_cases
- {
- /*%%%*/
- $$ = NEW_IN($4, $7, $8, &amp;@$);
- /*% %*/
- /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
- }
- ;
-</code></pre><p>簡略版:</p>
-<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in p_top_expr then compstmt p_cases
- ;
-</code></pre><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>、改行のいずれかである。</p>
-<p>これにより、<code>case</code> - <code>when</code> による従来の構文と同じように、<code>then</code> 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span> <span style="color:#66d9ef">then</span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span> <span style="color:#66d9ef">then</span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span> <span style="color:#66d9ef">then</span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span>
-</span></span><span style="display:flex;"><span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span>; a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span>; b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span>; c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>ところで、<code>p_top_expr</code> には <code>if</code> による guard clause が書けるので、その場合は <code>if</code> - <code>then</code> と似たような見た目になる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">if</span> n <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">then</span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><h1 id="まとめ">まとめ</h1>
-<ul>
-<li><code>if</code> や <code>case</code> の条件の後ろには <code>then</code>、<code>;</code>、改行のいずれかが必要
-<ul>
-<li>通常は改行しておけばよい</li>
-</ul>
-</li>
-<li>3.0 で入る予定の <code>case</code> - <code>in</code> でも <code>then</code> 等が必要になる</li>
-<li>Ruby の構文を正確に知るには (現状) <code>parse.y</code> を直接読めばよい</li>
-</ul>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2021-10-02/rust-where-are-primitive-types-from/index.html b/docs/posts/2021-10-02/rust-where-are-primitive-types-from/index.html
deleted file mode 100644
index 3aba89f..0000000
--- a/docs/posts/2021-10-02/rust-where-are-primitive-types-from/index.html
+++ /dev/null
@@ -1,182 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>Rust のプリミティブ型はどこからやって来るか | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="Rust のプリミティブ型は予約語ではなく普通の識別子である。どのようにこれが名前解決されるのかを調べた。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">Rust のプリミティブ型はどこからやって来るか</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/rust">rust</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2021-10-02: Qiita から移植</li>
- </ul>
- </section>
- <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</a></p>
-<hr>
-<h1 id="前置き">前置き</h1>
-<p>Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">#![allow(non_camel_case_types)]</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">#![allow(dead_code)]</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">char</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i8</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i16</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i32</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i64</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i128</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">isize</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u8</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u16</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u32</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u64</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u128</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">usize</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f32</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f64</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">str</span>;
-</span></span></code></pre></div><p>では、普段単に <code>bool</code> と書いたとき、この <code>bool</code> は一体どこから来ているのか。rustc のソースを追ってみた。</p>
-<blockquote>
-<p>前提知識: 一般的なコンパイラの構造、用語。<code>rustc</code> そのものの知識は不要 (というよりも筆者自身がよく知らない)</p>
-</blockquote>
-<h1 id="調査">調査</h1>
-<p>調査に使用したソース (調査時点での最新 master)</p>
-<p><a href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</a></p>
-<p>どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。</p>
-<p>大雑把な構造としては、<code>compiler</code> フォルダ以下に <code>rustc_*</code> という名前のクレートが数十個入っている。これがどうやら <code>rustc</code> コマンドの実装部のようだ。</p>
-<p><code>rustc</code> はセルフホストされている (= <code>rustc</code> 自身が Rust で書かれている) ので、<code>bool</code> や <code>char</code> などで適当に検索をかけてもノイズが多すぎて話にならない。
-しかし、お誂え向きなことに <code>i128</code>/<code>u128</code> というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って <code>git grep</code> してみる。</p>
-<pre tabindex="0"><code>$ git grep &#34;\bi128\b&#34; | wc # i128
- 165 1069 15790
-
-$ git grep &#34;\bu128\b&#34; | wc # u128
- 293 2127 26667
-
-$ git grep &#34;\bbool\b&#34; | wc # cf. bool の結果
- 3563 23577 294659
-</code></pre><p>165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。</p>
-<pre tabindex="0"><code>$ git grep &#34;\bi128\b&#34;
-...
-rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));
-...
-</code></pre><p><code>rustc_resolve</code> というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#e6db74">/// Interns the names of the primitive types.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">///
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// All other types are defined somewhere and possibly imported, but the primitive ones need
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// special handling, since they have no place of origin.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">PrimitiveTypeTable</span> {
-</span></span><span style="display:flex;"><span> primitive_types: <span style="color:#a6e22e">FxHashMap</span><span style="color:#f92672">&lt;</span>Symbol, PrimTy<span style="color:#f92672">&gt;</span>,
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> PrimitiveTypeTable {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">new</span>() -&gt; <span style="color:#a6e22e">PrimitiveTypeTable</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> table <span style="color:#f92672">=</span> FxHashMap::default();
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">bool</span>, Bool);
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">char</span>, Char);
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">f32</span>, Float(FloatTy::F32));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">f64</span>, Float(FloatTy::F64));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">isize</span>, Int(IntTy::Isize));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i8</span>, Int(IntTy::I8));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i16</span>, Int(IntTy::I16));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i32</span>, Int(IntTy::I32));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i64</span>, Int(IntTy::I64));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i128</span>, Int(IntTy::I128));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">str</span>, Str);
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">usize</span>, Uint(UintTy::Usize));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u8</span>, Uint(UintTy::U8));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u16</span>, Uint(UintTy::U16));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u32</span>, Uint(UintTy::U32));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u64</span>, Uint(UintTy::U64));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u128</span>, Uint(UintTy::U128));
-</span></span><span style="display:flex;"><span> Self { primitive_types: <span style="color:#a6e22e">table</span> }
-</span></span><span style="display:flex;"><span> }
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、</p>
-<blockquote>
-<p>All other types are defined somewhere and possibly imported, but the primitive ones need special handling, since they have no place of origin.</p>
-</blockquote>
-<p>とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span> <span style="color:#e6db74">/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span> <span style="color:#e6db74">/// (略)
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">resolve_ident_in_lexical_scope</span>(
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">&amp;</span><span style="color:#66d9ef">mut</span> self,
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">mut</span> ident: <span style="color:#a6e22e">Ident</span>,
-</span></span><span style="display:flex;"><span> ns: <span style="color:#a6e22e">Namespace</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// (略)
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> ) -&gt; Option<span style="color:#f92672">&lt;</span>LexicalScopeBinding<span style="color:#f92672">&lt;&#39;</span><span style="color:#a6e22e">a</span><span style="color:#f92672">&gt;&gt;</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// (略)
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> ns <span style="color:#f92672">==</span> TypeNS {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">let</span> Some(prim_ty) <span style="color:#f92672">=</span> self.primitive_type_table.primitive_types.get(<span style="color:#f92672">&amp;</span>ident.name) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> binding <span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span> (Res::PrimTy(<span style="color:#f92672">*</span>prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
-</span></span><span style="display:flex;"><span> .to_name_binding(self.arenas);
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> Some(LexicalScopeBinding::Item(binding));
-</span></span><span style="display:flex;"><span> }
-</span></span><span style="display:flex;"><span> }
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> None
-</span></span><span style="display:flex;"><span> }
-</span></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> など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。</p>
-<p>なお、<code>ns</code> は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この <code>if</code> は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。</p>
-<p>重要なのは、これが <code>resolve_ident_in_lexical_scope()</code> の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。</p>
-<p>動作がわかったところで、例として次のコードを考える。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">#![allow(non_camel_case_types)]</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">main</span>() {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> _: <span style="color:#66d9ef">bool</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">bool</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>ここで <code>main()</code> の <code>bool</code> は <code>struct bool</code> として解決される。なぜなら、プリミティブ型の判定をする前に <code>bool</code> という名前の別の型が見つかるからだ。</p>
-<h1 id="まとめ">まとめ</h1>
-<p>Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html b/docs/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html
deleted file mode 100644
index 91708ad..0000000
--- a/docs/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html
+++ /dev/null
@@ -1,132 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>[Vim] autocmd events の BufWrite/BufWritePre の違い | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、違いはないことがわかった。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">[Vim] autocmd events の BufWrite/BufWritePre の違い</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/vim">vim</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2021-10-02: Qiita から移植</li>
- </ul>
- </section>
- <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</a></p>
-<hr>
-<h1 id="tl-dr">TL; DR</h1>
-<p>違いはない。ただのエイリアス。</p>
-<h1 id="調査記録">調査記録</h1>
-<p>Vim の autocmd events には似通った名前のものがいくつかある。大抵は <code>:help</code> に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。</p>
-<ul>
-<li><code>BufRead</code>/<code>BufReadPost</code></li>
-<li><code>BufWrite</code>/<code>BufWritePre</code></li>
-<li><code>BufAdd</code>/<code>BufCreate</code></li>
-</ul>
-<p>このうち、<code>BufAdd</code>/<code>BufCreate</code> に関しては、<code>:help BufCreate</code> に</p>
-<blockquote>
-<p>The BufCreate event is for historic reasons.</p>
-</blockquote>
-<p>とあり、おそらくは <code>BufAdd</code> のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため vim と neovim のソースコードを調査した。</p>
-<blockquote>
-<p>ソースコードへのリンク
-<a href="https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2">vim (調査時点での master branch)</a>
-<a href="https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3">neovim (上に同じ)</a></p>
-</blockquote>
-<h2 id="vim-のソースコード">vim のソースコード</h2>
-<p>以下は、autocmd events の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。</p>
-<p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufAdd&#34;</span>, EVENT_BUFADD},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufCreate&#34;</span>, EVENT_BUFADD},
-</span></span></code></pre></div><p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufRead&#34;</span>, EVENT_BUFREADPOST},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufReadCmd&#34;</span>, EVENT_BUFREADCMD},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufReadPost&#34;</span>, EVENT_BUFREADPOST},
-</span></span></code></pre></div><p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufWrite&#34;</span>, EVENT_BUFWRITEPRE},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufWritePost&#34;</span>, EVENT_BUFWRITEPOST},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufWritePre&#34;</span>, EVENT_BUFWRITEPRE},
-</span></span></code></pre></div><h2 id="neovim-のソースコード">neovim のソースコード</h2>
-<p>neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua で書かれている。以下にある通り、はっきり <code>aliases</code> と書かれている。</p>
-<p><a href="https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124">https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span> aliases <span style="color:#f92672">=</span> {
-</span></span><span style="display:flex;"><span> BufCreate <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;BufAdd&#39;</span>,
-</span></span><span style="display:flex;"><span> BufRead <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;BufReadPost&#39;</span>,
-</span></span><span style="display:flex;"><span> BufWrite <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;BufWritePre&#39;</span>,
-</span></span><span style="display:flex;"><span> FileEncoding <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;EncodingChanged&#39;</span>,
-</span></span><span style="display:flex;"><span> },
-</span></span></code></pre></div><p>ところで、上では取り上げなかった <code>FileEncoding</code> だが、これは <code>:help FileEncoding</code> にしっかりと書いてある。</p>
-<pre tabindex="0"><code> *FileEncoding*
-FileEncoding Obsolete. It still works and is equivalent
- to |EncodingChanged|.
-</code></pre><h2 id="まとめ">まとめ</h2>
-<p>記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。</p>
-<ul>
-<li><code>BufAdd</code>/<code>BufCreate</code>
-<ul>
-<li>→ <code>BufCreate</code> は歴史的な理由により (&ldquo;for historic reasons&rdquo;) 存在しているため、新しい方 (<code>BufAdd</code>) を使う</li>
-</ul>
-</li>
-<li><code>BufRead</code>/<code>BufReadPost</code>
-<ul>
-<li>→ <code>BufReadPre</code> との対称性のため、あるいは <code>BufWritePost</code> との対称性のため <code>BufReadPost</code> を使う</li>
-</ul>
-</li>
-<li><code>BufWrite</code>/<code>BufWritePre</code>
-<ul>
-<li>→ <code>BufWritePost</code> との対称性のため、あるいは <code>BufReadPre</code> との対称性のため <code>BufWritePre</code> を使う</li>
-</ul>
-</li>
-<li><code>FileEncoding</code>/<code>EncodingChanged</code>
-<ul>
-<li>→ <code>FileEncoding</code> は &ldquo;Obsolete&rdquo; と明言されているので、<code>EncodingChanged</code> を使う</li>
-</ul>
-</li>
-</ul>
-<p>ところでこの調査で知ったのだが、<code>BufRead</code> と <code>BufWrite</code> は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら <code>Pre</code>/<code>Post</code> 付きのものを使った方が分かりやすいだろう。</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html b/docs/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html
deleted file mode 100644
index eac828f..0000000
--- a/docs/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html
+++ /dev/null
@@ -1,148 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>Vimで選択した行の順番を入れ替える | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="Vim で選択した行の順番を入れ替える方法。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">Vimで選択した行の順番を入れ替える</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/vim">vim</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2021-10-02: Qiita から移植</li>
- </ul>
- </section>
- <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/4fefb361d9a693803520">https://qiita.com/nsfisis/items/4fefb361d9a693803520</a></p>
-<hr>
-<h1 id="バージョン情報">バージョン情報</h1>
-<p><code>:version</code> の一部</p>
-<blockquote>
-<p>VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Jan 26 2020 11:30:30)
-macOS version
-Included patches: 1-148
-Huge version without GUI.</p>
-</blockquote>
-<h1 id="よく紹介されている手法">よく紹介されている手法</h1>
-<h2 id="tac--tail"><code>tac</code> / <code>tail</code></h2>
-<p><code>tac</code> や <code>tail -r</code> などの外部コマンドを <code>!</code> を使って呼び出し、置き換える。</p>
-<blockquote>
-<p>:h v_!</p>
-</blockquote>
-<p><code>tac</code> コマンドや <code>tail</code> の <code>-r</code> オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい</p>
-<h2 id="gm0"><code>:g/^/m0</code></h2>
-<p>こちらは外部コマンドに頼らず、Vim の機能のみを使う。<code>g</code> は <code>:global</code> コマンドの、<code>m</code> は <code>:move</code> コマンドの略</p>
-<p><code>:global</code> コマンドは <code>:[range]global/{pattern}/[command]</code> のように使い、<code>[range]</code> で指定された範囲の行のうち、<code>{pattern}</code> で指定された検索パターンにマッチする行に対して、順番に <code>[command]</code> で指定された Ex コマンドを呼び出す。</p>
-<blockquote>
-<p>:h :global</p>
-</blockquote>
-<p><code>:move</code> コマンドは <code>[range]:move {address}</code> のように使い、<code>[range]</code> で指定された範囲の行を <code>{address}</code> で指定された位置に移動させる。</p>
-<blockquote>
-<p>:h :move</p>
-</blockquote>
-<p><code>:g/^/m0</code> のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。</p>
-<p>なお、<code>:g/^/m0</code> は全ての行を入れ替えるが、<code>:N,Mg/^/mN-1</code> とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ &lt;<span style="color:#a6e22e">line1</span>&gt;,&lt;<span style="color:#a6e22e">line2</span>&gt;<span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span>&lt;<span style="color:#a6e22e">line1</span>&gt;<span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div><p>これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。</p>
-<h1 id="gm0-の問題点"><code>:g/^/m0</code> の問題点</h1>
-<p><code>:global</code> コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<code>^</code> は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<code>'hlsearch'</code> オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと <code>n</code> コマンドなどの際に不便である。</p>
-<blockquote>
-<p>:h @/</p>
-</blockquote>
-<h1 id="解決策">解決策</h1>
-<blockquote>
-<p>[2020/9/28追記]
-より簡潔な方法を見つけたので次節に追記した</p>
-</blockquote>
-<p>前述した <code>:Reverse</code> コマンドの定義を少し変えて、次のようにする:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#66d9ef">function</span>! <span style="color:#a6e22e">s</span>:<span style="color:#a6e22e">reverse_lines</span>(<span style="color:#a6e22e">from</span>, <span style="color:#a6e22e">to</span>) <span style="color:#a6e22e">abort</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#a6e22e">execute</span> <span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">&#34;%d,%dg/^/m%d&#34;</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">from</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">to</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">from</span> - <span style="color:#ae81ff">1</span>)<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">endfunction</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">call</span> &lt;<span style="color:#a6e22e">SID</span>&gt;<span style="color:#a6e22e">reverse_lines</span>(&lt;<span style="color:#a6e22e">line1</span>&gt;, &lt;<span style="color:#a6e22e">line2</span>&gt;)<span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div><p>実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。</p>
-<p>この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが <code>^</code> で上書きされることがなくなる。</p>
-<p>Vim のヘルプから該当箇所を引用する (強調は筆者による)。</p>
-<blockquote>
-<p>:h autocmd-searchpat</p>
-<p><strong>Autocommands do not change the current search patterns.</strong> Vim saves the current
-search patterns before executing autocommands then restores them after the
-autocommands finish. This means that autocommands do not affect the strings
-highlighted with the &lsquo;hlsearch&rsquo; option.</p>
-</blockquote>
-<p>これは autocommand の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは <code>:nohlsearch</code> のヘルプにある。同じく該当箇所を引用する (強調は筆者による)。</p>
-<blockquote>
-<p>:h :nohlsearch</p>
-<p>(略) This command doesn&rsquo;t work in an autocommand, because
-the highlighting state is saved and restored when
-executing autocommands |autocmd-searchpat|.
-<strong>Same thing for when invoking a user function.</strong></p>
-</blockquote>
-<p>この仕様により、<code>:g/^/m0</code> の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。</p>
-<h1 id="解決策-改訂版">解決策 (改訂版)</h1>
-<blockquote>
-<p>[2020/9/28追記]
-より簡潔な方法を見つけたため追記する</p>
-</blockquote>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">keeppatterns</span> &lt;<span style="color:#a6e22e">line1</span>&gt;,&lt;<span style="color:#a6e22e">line2</span>&gt;<span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span>&lt;<span style="color:#a6e22e">line1</span>&gt;<span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div><p>まさにこのための Exコマンド、<code>:keeppatterns</code> が存在する。<code>:keeppatterns {command}</code> のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。</p>
-<blockquote>
-<p>:h :keeppatterns</p>
-</blockquote>
-<h1 id="コピペ用再掲">コピペ用再掲</h1>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#75715e">&#34; License: Public Domain</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">keeppatterns</span> &lt;<span style="color:#a6e22e">line1</span>&gt;,&lt;<span style="color:#a6e22e">line2</span>&gt;<span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span>&lt;<span style="color:#a6e22e">line1</span>&gt;<span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div>
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2022-04-09/phperkaigi-2022-tokens/index.html b/docs/posts/2022-04-09/phperkaigi-2022-tokens/index.html
deleted file mode 100644
index 4d4918e..0000000
--- a/docs/posts/2022-04-09/phperkaigi-2022-tokens/index.html
+++ /dev/null
@@ -1,375 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>PHPerKaigi 2022 トークン問題の解説 | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">PHPerKaigi 2022 トークン問題の解説</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/conference">conference</a></li>
- <li><a href="https://blog.nsfisis.dev/tags/php">php</a></li>
- <li><a href="https://blog.nsfisis.dev/tags/phperkaigi">phperkaigi</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2022-04-09: 公開</li>
- <li>2022-04-16: 2問目、3問目の解説を追加、1問目に加筆</li>
- </ul>
- </section>
- <h1 id="はじめに">はじめに</h1>
-<p>本日開始された <a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> の PHPer チャレンジにおいて、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。</p>
-<p>リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</a></p>
-<h1 id="第1問-brainf_ckphp">第1問 brainf_ck.php</h1>
-<p>ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">declare</span>(<span style="color:#a6e22e">strict_types</span><span style="color:#f92672">=</span><span style="color:#ae81ff">0</span><span style="color:#a6e22e">O1</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> <span style="color:#a6e22e">Dgcircus\PHPerKaigi\Y2022</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">/**
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * @todo
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Run this program to acquire a PHPer token.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> */</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">\error_reporting</span>(<span style="color:#f92672">~+!</span><span style="color:#e6db74">&#39;We are hiring!&#39;</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$z <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($f) <span style="color:#f92672">=&gt;</span> (<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=&gt;</span> $x($x)(<span style="color:#f92672">...</span>$xs)))(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=&gt;</span> $x($x)(<span style="color:#f92672">...</span>$xs)));
-</span></span><span style="display:flex;"><span>$id <span style="color:#f92672">=</span> <span style="color:#a6e22e">\spl_object_id</span>(<span style="color:#f92672">...</span>);
-</span></span><span style="display:flex;"><span>$put <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($c) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">\printf</span>(<span style="color:#e6db74">&#39;%c&#39;</span>, $c);
-</span></span><span style="display:flex;"><span>$mm <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\ArrayObject</span>(<span style="color:#a6e22e">\array_fill</span>(<span style="color:#f92672">+!!</span>[], $n, $p));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$👉 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [<span style="color:#f92672">++</span>$mp, <span style="color:#f92672">++</span>$pc];
-</span></span><span style="display:flex;"><span>$👈 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [<span style="color:#f92672">--</span>$mp, <span style="color:#f92672">++</span>$pc];
-</span></span><span style="display:flex;"><span>$👍 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$m[$mp]];
-</span></span><span style="display:flex;"><span>$👎 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$m[$mp]];
-</span></span><span style="display:flex;"><span>$📝 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, $put($m[$mp])];
-</span></span><span style="display:flex;"><span>$🤡 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($m[$mp]) {
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=&gt;</span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) {
-</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$n),
-</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=&gt;</span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> <span style="color:#f92672">++</span>$pc <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$n),
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">++</span>$pc, $n),
-</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])],
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc],
-</span></span><span style="display:flex;"><span>};
-</span></span><span style="display:flex;"><span>$🎪 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($m[$mp]) {
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc],
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) {
-</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">++</span>$n),
-</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=&gt;</span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> $pc<span style="color:#f92672">+!</span>[] <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">--</span>$n),
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">--</span>$pc, $n),
-</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])],
-</span></span><span style="display:flex;"><span>};
-</span></span><span style="display:flex;"><span>$🐘 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p) <span style="color:#f92672">=&gt;</span> $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">isset</span>($p[$pc]) <span style="color:#f92672">&amp;&amp;</span> $loop($m, $p, $b, $e, <span style="color:#f92672">...</span>($p[$pc]($m, $p, $b, $e, $mp, $pc)))
-</span></span><span style="display:flex;"><span>)($mm(<span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.!</span>[])), $p, $id($🤡), $id($🎪), <span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+!!</span>[]);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$🐘([
-</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $🤡,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👈, $👈, $👈, $👈, $👎,
-</span></span><span style="display:flex;"><span> $🎪,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👉, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👈, $👎, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span>]);
-</span></span></code></pre></div><p>この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。</p>
-<h2 id="解説">解説</h2>
-<h3 id="絵文字">絵文字</h3>
-<p>まず目につくのは大量の絵文字だろう。
-PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。</p>
-<h3 id="プログラム全体">プログラム全体</h3>
-<p>Brainf*ck のインタプリタとプログラムになっている。
-Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。</p>
-<p><a href="https://ja.wikipedia.org/wiki/Brainfuck">https://ja.wikipedia.org/wiki/Brainfuck</a></p>
-<p>なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。</p>
-<pre tabindex="0"><code>+ + + + + + + + + +
-[
- &gt; + + +
- &gt; + + + + +
- &gt; + + + + + + + + + + + +
- &gt; + + + + + + + + + +
- &lt; &lt; &lt; &lt; -
-]
-&gt; + + + + + .
-- - .
-&gt; - - - .
-&gt; - - - .
-- - .
-- .
-&lt; .
-&gt; &gt; - - .
-+ + + + + + + .
-&lt; - - - - .
-&lt; .
-&gt; + + .
-&gt; - .
-&lt; .
-</code></pre><p>実行結果はこちら: <a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a></p>
-<p>それぞれの絵文字で表された関数が、各命令に対応している。</p>
-<ul>
-<li><code>$👉</code>: <code>&gt;</code></li>
-<li><code>$👈</code>: <code>&lt;</code></li>
-<li><code>$👍</code>: <code>+</code></li>
-<li><code>$👎</code>: <code>-</code></li>
-<li><code>$📝</code>: <code>.</code></li>
-<li><code>$🤡</code>: <code>[</code></li>
-<li><code>$🎪</code>: <code>]</code></li>
-</ul>
-<p><code>,</code> (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。</p>
-<p>なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。</p>
-<h3 id="絵文字の選択">絵文字の選択</h3>
-<p>おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> は弊社デジタルサーカスにちなんでいる。
-また、<code>$🐘</code> は PHP のマスコットの象に由来する。</p>
-<h3 id="strict_types">strict_types</h3>
-<p><code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code> の数値リテラルだが、
-<code>0x0</code> や <code>0b1</code> のような値も受け付ける。
-今回は、PHP 8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。</p>
-<h3 id="url">URL</h3>
-<p>ソースコードのライセンスを示したこの部分だが、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span>
-</span></span></code></pre></div><p>完全に合法な PHP のコードである。
-<code>https:</code> 部分はラベル、<code>//</code> 以降は行コメントになっている。</p>
-<h3 id="リテラルなしで数値を生成する">リテラルなしで数値を生成する</h3>
-<p>ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。
-PHP では、型変換を利用することで任意の整数を作り出すことができる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">1</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">2</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">3</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]<span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">10</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.+!!</span>[]));
-</span></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 が作れる)。</p>
-<p>また、<code>error_reporting</code> に指定しているのは <code>-1</code> である。
-これは、<code>!</code> によって文字列を <code>false</code> にし、<code>+</code> によって <code>false</code> を <code>0</code> にし、さらにビット反転して <code>-1</code> にしている。</p>
-<h3 id="if-文なしで条件分岐"><code>if</code> 文なしで条件分岐</h3>
-<p>三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> を一切書かずに条件分岐ができる。
-また、<code>&amp;&amp;</code> / <code>||</code> も使えることがある。
-遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> のような形で分岐することもできる。</p>
-<h3 id="whilefor-文なしでループ"><code>while</code>、<code>for</code> 文なしでループ</h3>
-<p>不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。
-ここでは、一般に Z コンビネータとして知られるものを使った (<code>$z</code>)。</p>
-<p>実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。</p>
-<p>なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、
-あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。</p>
-<h1 id="第2問-riddlephp">第2問 riddle.php</h1>
-<p>ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">/*********************************************************
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * This program displays a PHPer token. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Guess &#39;N&#39;. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Hints: *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - N itself has no special meaning, e.g., 42, 8128, *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * it is selected at random. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Each element of $token represents a single letter. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - One letter consists of 5x5 cells. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Remember, the output is a complete PHPer token. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * License: *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * https://creativecommons.org/publicdomain/zero/1.0/ *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> *********************************************************/</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">N</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e">/* Change it to your answer. */</span>;
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x14B499C</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0BE34CC</span>, <span style="color:#ae81ff">0x01C9C69</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0ECA069</span>, <span style="color:#ae81ff">0x01C2449</span>, <span style="color:#ae81ff">0x0FDB166</span>, <span style="color:#ae81ff">0x01C9C69</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x01C1C66</span>, <span style="color:#ae81ff">0x0FC1C47</span>, <span style="color:#ae81ff">0x01C1C66</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x10C5858</span>, <span style="color:#ae81ff">0x1E4E3B8</span>, <span style="color:#ae81ff">0x1A2F2F8</span>,
-</span></span><span style="display:flex;"><span>];
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($token <span style="color:#66d9ef">as</span> $x) {
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{</span>$x<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。
-トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。</p>
-<p>ここでは、私の想定解を解説する。</p>
-<h2 id="読解">読解</h2>
-<p>まずはソースコードを読んでいく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 略
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>];
-</span></span></code></pre></div><p>数値からなる <code>$token</code> があり、各要素をループしている。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span></code></pre></div><p>まずは排他的論理和 (xor) を取り、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span></code></pre></div><p>二進数に変換して、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span></code></pre></div><p>0 を空白に、1 を <code>#</code> にし、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span></code></pre></div><p>5文字ごとに区切ったあと、改行で結合している。</p>
-<h2 id="ヒント">ヒント</h2>
-<p>次に、ソースコードに書いてあるヒントを読んでいく。</p>
-<ul>
-<li><code>N</code> それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている</li>
-<li><code>$token</code> の各要素は、1文字を表す</li>
-<li>1文字は 5x5 のセルからなる</li>
-<li>出力されるのは、完全な PHPer トークンである</li>
-</ul>
-<p>ここで、PHPer トークンは必ず <code>#</code> 記号から始まることを思いだすと、
-<code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code>#</code> になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。</p>
-<h2 id="解く">解く</h2>
-<p>ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> に変換されるような <code>N</code> を見つければよい。</p>
-<p><code>N</code> は高々</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>);
-</span></span></code></pre></div><p>なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0x14B499C</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>($x <span style="color:#f92672">===</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # &#34;</span>);
-</span></span></code></pre></div><p>この一連の変換に対する逆変換を考えると、次のようになる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # &#34;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;&#39;</span>, <span style="color:#a6e22e">explode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, $x));
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">bindec</span>($x);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#ae81ff">0x14B499C</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;N = </span><span style="color:#e6db74">$n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>これを実行すると、<code>N</code> が得られる。</p>
-<h1 id="第3問-toquinephp">第3問 toquine.php</h1>
-<p>ソースコードはこちら。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// License: https://creativecommons.org/publicdomain/zero/1.0/
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// This is a quine-like program to generate a PHPer token.
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Execute it like this: php toquine.php | php | php | php | ...
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#e6db74">&lt;&lt;&lt;&#39;</span><span style="color:#e6db74">Q</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&lt;?cuc
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ...
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f$f = %f;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$f = fge_ebg13($f); $kf = [
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f,
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">];
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g = ahyy.snyfr; sbe ($v = 0; $v &lt;= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g .= vzcybqr(&#34;\a&#34;, fge_fcyvg(fge_ercynpr([&#39;0&#39;,&#39;1&#39;], [&#39; &#39;,&#39;##&#39;], fcevags(pue(37) . &#39;025o&#39;, $kf[$v])), 012)) . &#34;\a\a&#34;;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$jf = neenl_znc(sa($j) =&gt; vzcybqr(&#39;, &#39;, $j), neenl_puhax(neenl_znc(sa($k) =&gt; fcevags(&#39;0k&#39; . pue(37) . &#39;07K&#39;, $k), $kf), 10));
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">cevags($f, $g, fge_ebg13(&#34;&lt;&lt;&lt;&#39;Q&#39;\a{$f}\aQ&#34;), vzcybqr(&#34;,\a&#34;, $jf));
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#e6db74">Q</span>;
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_rot13</span>($s); $xs <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x0AFABEA</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x0002800</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x0117041</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F295B7</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1151151</span>, <span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1F8C63F</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x1F8C631</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x1F8C63F</span>, <span style="color:#ae81ff">0x1F295B7</span>,
-</span></span><span style="display:flex;"><span>];
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">.</span><span style="color:#66d9ef">false</span>; <span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">intdiv</span>(<span style="color:#66d9ef">__LINE__</span><span style="color:#f92672">-</span><span style="color:#ae81ff">035</span>,<span style="color:#ae81ff">6</span>); <span style="color:#f92672">++</span>$i) <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">isset</span>($xs[$i])) <span style="color:#66d9ef">break</span>; <span style="color:#66d9ef">else</span>
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">.=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>(<span style="color:#a6e22e">str_replace</span>([<span style="color:#e6db74">&#39;0&#39;</span>,<span style="color:#e6db74">&#39;1&#39;</span>], [<span style="color:#e6db74">&#39; &#39;</span>,<span style="color:#e6db74">&#39;##&#39;</span>], <span style="color:#a6e22e">sprintf</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;025b&#39;</span>, $xs[$i])), <span style="color:#ae81ff">012</span>)) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>$ws <span style="color:#f92672">=</span> <span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($w) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>, $w), <span style="color:#a6e22e">array_chunk</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;0x&#39;</span> <span style="color:#f92672">.</span> <span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;07X&#39;</span>, $x), $xs), <span style="color:#ae81ff">10</span>));
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>($s, $t, <span style="color:#a6e22e">str_rot13</span>(<span style="color:#e6db74">&#34;&lt;&lt;&lt;&#39;D&#39;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">{</span>$s<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">D&#34;</span>), <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;,</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, $ws));
-</span></span></code></pre></div><p>コメントにもあるとおり、次のようにして実行すれば答えがでてくる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php toquine.php | php | php | php | ...
-</span></span></code></pre></div><p>実際にはもう少しパイプで繋げなければならない。</p>
-<h2 id="解説-1">解説</h2>
-<h3 id="プログラム全体-1">プログラム全体</h3>
-<p>コメントにもあるとおり、これは quine (風) のプログラムになっている。
-Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。</p>
-<p>このプログラムは、実行すると自身とほとんど同じプログラムを出力する。
-異なるのはトークンになっている部分のみである。</p>
-<h3 id="トークン">トークン</h3>
-<p><code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。</p>
-<h3 id="状態保持">状態保持</h3>
-<p>トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。
-このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code>__LINE__</code> から情報を取得している。</p>
-<h3 id="rot-13">ROT 13</h3>
-<p>Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。
-これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 変換を使って難読化した。</p>
-<p>それにしてもなぜこんなものが標準ライブラリに……。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。</p>
-<p>今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、
-来年は 5問、より面白い問題を持っていきます。</p>
-<p>実はもう作りはじめているので、どうか来年もありますように……。</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html b/docs/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html
deleted file mode 100644
index a1e9ca7..0000000
--- a/docs/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html
+++ /dev/null
@@ -1,102 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>term-banner: ターミナルにバナーを表示するツールを書いた | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">term-banner: ターミナルにバナーを表示するツールを書いた</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/my-programs">my-programs</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2022-04-24: 公開</li>
- <li>2022-04-27: -f オプションについて追記</li>
- </ul>
- </section>
- <h1 id="はじめに">はじめに</h1>
-<p>こんなものを作った。</p>
-<pre tabindex="0"><code>$ term-banner &#39;Hello, World!&#39; &#39;こんにちは、&#39; &#39;世界!&#39;
-</code></pre><p><img src="https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png" alt="term-banner のスクリーンショット"></p>
-<p>コマンドライン引数として渡した文字列をターミナルに大きく表示する。</p>
-<p>リポジトリはこちら: <a href="https://github.com/nsfisis/term-banner">https://github.com/nsfisis/term-banner</a></p>
-<h1 id="motivation">Motivation</h1>
-<p>以前、<a href="https://github.com/nsfisis/big-clock-mode">big-clock-mode</a> という似たようなプログラムを書いた。
-これは tmux の <code>:clock-mode</code> コマンドに着想を得たもので、<code>:clock-mode</code> よりも大きく現在時刻を表示する。</p>
-<p><code>big-clock-mode</code> を開発したのは、次のようなシチュエーションで使うためである。
-弊社では現在リモートワークが基本だが、web 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。
-こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。</p>
-<p>それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。</p>
-<p>しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。
-どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。</p>
-<p>そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。
-まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。</p>
-<h1 id="プログラム">プログラム</h1>
-<p>全体の流れは次のようになっている。</p>
-<ol>
-<li>フォントファイルを読み込む</li>
-<li>コマンドライン引数を Shift-JIS に変換する (フォントが Shift-JIS 基準で並んでいるため)</li>
-<li>1文字ずつレンダリングしていく</li>
-</ol>
-<p><code>big-clock-mode</code> が Go 製なので、今回も Go で書いた。
-PNG が標準ライブラリにあったり、Shift-JIS のエンコーディングが準標準ライブラリにあったりしたのは助かった。</p>
-<p>フォントファイルは <code>go:embed</code> で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。
-仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。</p>
-<h1 id="フォント">フォント</h1>
-<p>フリーの 8x8 ビットマップフォントである、<a href="https://littlelimit.net/misaki.htm">美咲フォント 2021-05-05a 版</a> を使わせていただいた。</p>
-<p>はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。
-同じく 8x8 で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。</p>
-<p>美咲フォントは、平仮名・片仮名に留まらず、JIS 第一・第二水準の漢字までサポートしている。
-第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。</p>
-<p>さらに言うと、実のところ美咲フォントは実サイズ 7x7 で作られており、余白が設けられている。
-これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。
-おかげでコーディングまで楽になった。</p>
-<p>ゴシック体と明朝体があったが、私の好みで明朝体の方にした。
-ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。</p>
-<p>2022-04-27 追記: <code>-f</code> オプションで選べるようにした。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>あなたもターミナルに住んでみませんか?</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2022-05-01/phperkaigi-2022/index.html b/docs/posts/2022-05-01/phperkaigi-2022/index.html
deleted file mode 100644
index b56c70a..0000000
--- a/docs/posts/2022-05-01/phperkaigi-2022/index.html
+++ /dev/null
@@ -1,133 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>PHPerKaigi 2022 | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">PHPerKaigi 2022</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/conference">conference</a></li>
- <li><a href="https://blog.nsfisis.dev/tags/php">php</a></li>
- <li><a href="https://blog.nsfisis.dev/tags/phperkaigi">phperkaigi</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2022-05-01: 公開</li>
- </ul>
- </section>
- <h1 id="はじめに">はじめに</h1>
-<p>2022-04-09 から 2022-04-11 にかけて開催された、<a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> に、一般参加者として参加した。
-弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
-<p>昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。</p>
-<h1 id="感想">感想</h1>
-<h2 id="厳選おすすめトーク">厳選おすすめトーク</h2>
-<p>多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。</p>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント</a></p>
-<blockquote>
-<p>PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。</p>
-<p>本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</a></p>
-<blockquote>
-<p>PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか?<br>
-これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br>
-またそれらを理解した上でのエラーハンドリングを学びましょう。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</a></p>
-<blockquote>
-<p>毎日流れてくるエラーに皆さんはどう向き合ってますか?<br>
-エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br>
-サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br>
-エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</a></p>
-<blockquote>
-<p>昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。</p>
-<p>最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br>
-・「(私の思う)良い設計」を実現するための意思決定<br>
-・「ISUCONの問題」という位置付けに由来する取捨選択<br>
-・移植中に遭遇したトラブルとその解決策<br>
-といった文脈や葛藤が存在しています。</p>
-<p>本発表はそれらを共有することで<br>
-・PHPアプリケーションの設計、実装事例として役立ててもらう<br>
-・ISUCONの言語移植に興味を持ってもらう<br>
-・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br>
-ことを目的とします。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</a></p>
-<blockquote>
-<p>サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。</p>
-<p>フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。</p>
-<p>このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。</p>
-</blockquote>
-<h2 id="トークン問題の作成">トークン問題の作成</h2>
-<p>今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。</p>
-<h2 id="phper-チャレンジ">PHPer チャレンジ</h2>
-<p><a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。<br>
-また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> をいただいた。</p>
-<h2 id="カンファレンス全体への感想">カンファレンス全体への感想</h2>
-<p><a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。</p>
-<blockquote>
-<p>1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br>
-まあ初カンファレンスだし、とお茶を濁しておこう。</p>
-</blockquote>
-<p>この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。<br>
-これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。</p>
-<p>なお、アンカンファレンスについては、1日目の終わりに<a href="https://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e">トークン問題の解説放送</a>もおこなった。</p>
-<p>また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。
-今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。</p>
-<h1 id="そして来年へ">そして来年へ……?</h1>
-<p>PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。</p>
-<ul>
-<li>プロポーザルを出す</li>
-<li>PHPer チャレンジのトークン問題を 5題作成する</li>
-<li>現地に行く</li>
-<li>PHPer チャレンジで圧勝する</li>
-</ul>
-<hr>
-<p>最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。</p>
-<p>ではまた来年。</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2022-08-27/php-conference-okinawa-code-golf/index.html b/docs/posts/2022-08-27/php-conference-okinawa-code-golf/index.html
deleted file mode 100644
index b9c337e..0000000
--- a/docs/posts/2022-08-27/php-conference-okinawa-code-golf/index.html
+++ /dev/null
@@ -1,102 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/conference">conference</a></li>
- <li><a href="https://blog.nsfisis.dev/tags/php">php</a></li>
- <li><a href="https://blog.nsfisis.dev/tags/phpcon">phpcon</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2022-08-27: 公開</li>
- </ul>
- </section>
- <h1 id="はじめに">はじめに</h1>
-<p>本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> が開催された (らしい)。</p>
-<p>カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。</p>
-<p>ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</a> <br>
-スライド: <a href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</a></p>
-<h1 id="解">解</h1>
-<p>細かいレギュレーションは不明だったので、勝手に定めた。</p>
-<ul>
-<li>コマンドライン引数の第1引数で受けとる</li>
-<li>結果は標準出力に出す</li>
-<li>コンマの直後にはスペースを1つ置く</li>
-<li>末尾コンマは禁止</li>
-<li>数字でないものは入ってこないものとする</li>
-<li>負数は入ってこないものとする</li>
-</ul>
-<p>書いたものがこちら:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span> $n<span style="color:#f92672">=</span>$argv[<span style="color:#ae81ff">1</span>];<span style="color:#66d9ef">foreach</span>([<span style="color:#ae81ff">1e4</span>,<span style="color:#ae81ff">5e3</span>,<span style="color:#ae81ff">2e3</span>,<span style="color:#ae81ff">1e3</span>,<span style="color:#ae81ff">500</span>,<span style="color:#ae81ff">100</span>,<span style="color:#ae81ff">50</span>,<span style="color:#ae81ff">10</span>,<span style="color:#ae81ff">5</span>,<span style="color:#ae81ff">1</span>]<span style="color:#66d9ef">as</span>$x)<span style="color:#66d9ef">for</span>(;$n<span style="color:#f92672">&gt;=</span>$x;$n<span style="color:#f92672">-=</span>$x)$r[]<span style="color:#f92672">=</span>$x;<span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>,$r<span style="color:#f92672">??</span>[]);<span style="color:#75715e">?&gt;</span><span style="color:#960050;background-color:#1e0010">]
-</span></span></span></code></pre></div><p>しめて 123 バイトとなった (末尾改行を含めずにカウント)。</p>
-<p>こちらは改行とスペースを追加したバージョン:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>];
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ([<span style="color:#ae81ff">1e4</span>, <span style="color:#ae81ff">5e3</span>, <span style="color:#ae81ff">2e3</span>, <span style="color:#ae81ff">1e3</span>, <span style="color:#ae81ff">500</span>, <span style="color:#ae81ff">100</span>, <span style="color:#ae81ff">50</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">1</span>] <span style="color:#66d9ef">as</span> $x)
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> (; $n <span style="color:#f92672">&gt;=</span> $x; $n <span style="color:#f92672">-=</span> $x)
-</span></span><span style="display:flex;"><span> $r[] <span style="color:#f92672">=</span> $x;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>, $r <span style="color:#f92672">??</span> []);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">?&gt;</span><span style="color:#960050;background-color:#1e0010">]
-</span></span></span></code></pre></div><h1 id="使用したテクニック">使用したテクニック</h1>
-<h2 id="指数表記">指数表記</h2>
-<p>割と多くの言語のゴルフで使えるテクニック。<code>e</code> を用いた指数表記で、大きな数を短く表す。このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。</p>
-<h2 id="foreach-や-for-の中身を1つの文に">foreach や for の中身を1つの文に</h2>
-<p><code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code> を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> を省略できる。C言語などでも使える。</p>
-<h2 id="r-に初期値を入れない">$r に初期値を入れない</h2>
-<p>PHP では、<code>$r[] = ...</code> のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は <code>$r</code> を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code> のような初期化が不要になる。</p>
-<p>ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> が未定義になってしまい、<code>implode()</code> に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。</p>
-<p>もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。</p>
-<h2 id="php-タグの外に文字列を置く">PHP タグの外に文字列を置く</h2>
-<p>PHP では、<code>&lt;?php</code> <code>?&gt;</code> で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず <code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>最後になりましたが、<a href="https://twitter.com/m3m0r7">めもりー</a> さん、楽しい問題をありがとうございました。</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html b/docs/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html
deleted file mode 100644
index bf217ca..0000000
--- a/docs/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html
+++ /dev/null
@@ -1,74 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>弊社の PHP Foundation への寄付に寄せて | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="先日、私の勤めるデジタルサーカス株式会社が、PHP Foundation へ寄付をおこないました。
-本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">弊社の PHP Foundation への寄付に寄せて</h1>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2022-08-31: 公開</li>
- </ul>
- </section>
- <h1 id="はじめに">はじめに</h1>
-<p><strong>注: これは私個人の意見であり、所属する組織を代表するものではありません。</strong></p>
-<p>先日、私の勤める <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> が <a href="https://opencollective.com/phpfoundation">PHP Foundation</a> へ $2,000 の寄付をおこないました。</p>
-<p>記事: <a href="https://www.dgcircus.com/news/581">https://www.dgcircus.com/news/581</a></p>
-<p>本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。</p>
-<h1 id="なぜ">なぜ?</h1>
-<p>組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。</p>
-<p>当時の考えを端的にまとめた社内チャットの投稿があったので、それを引用します:</p>
-<blockquote>
-<p>結局これを通したい (私の中での) 最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、寄付の報告が流れてきたり、OSS のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか (これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。</p>
-<p>追記: 「肩身が狭くなる」というのがより適切でした。</p>
-</blockquote>
-<p>※文中の「↑にしても」は、ここに載せていない別の投稿を指しています。</p>
-<p>OSS を金銭的に支援したり、技術カンファレンスへ協賛したり (あるいは <a href="https://twitter.com/tomzoh">CTO</a> がカンファレンスを年2で主催したり: <a href="https://iosdc.jp">iOSDC</a> <a href="https://phperkaigi.jp">PHPerKaigi</a>) といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう (知らんけど)。これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。</p>
-<p>以上が、私が社内で寄付の件を進めた (かなり私的な) 理由です。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。この場を借りて感謝申し上げます。</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html b/docs/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html
deleted file mode 100644
index 921a607..0000000
--- a/docs/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html
+++ /dev/null
@@ -1,520 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>[PHP] fizzbuzz を書く。1行あたり2文字で。 | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">[PHP] fizzbuzz を書く。1行あたり2文字で。</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/php">php</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2022-09-28: 公開</li>
- <li>2022-09-29: 小さな文言の修正・変更</li>
- </ul>
- </section>
- <h1 id="記事の構成について">記事の構成について</h1>
-<p>この記事は、普通の fizzbuzz を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、 <a href="https://gist.github.com/nsfisis/04c227d5a419867472a0b23a83ad2919#file-fizzbuzz-php-2-letters-per-line-and-supports-php-8-x-without-warnings">このページ</a> にソースコードがあるので、そちらを先に見てほしい。</p>
-<h1 id="レギュレーション">レギュレーション</h1>
-<p>PHP で、次のような制約の下に fizzbuzz を書いた。</p>
-<ul>
-<li>1行あたりの文字数は2文字までに収めること (ただし <code>&lt;?php</code> タグは除く)
-<ul>
-<li>厳密な定義: <code>&lt;?php</code> タグ以降のソースコードが、2 byte ごとに ラインフィード (LF) で区切られること</li>
-</ul>
-</li>
-<li>スペースやタブを使用しないこと</li>
-<li>ループのアンロールをしないこと
-<ul>
-<li>100 回ループの代わりに 100 回コードをコピペ、というのは禁止</li>
-</ul>
-</li>
-<li>PHP 7.4〜8.1 で動作すること</li>
-<li>実行時に Notice や Warning が出ないこと</li>
-<li>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)</li>
-</ul>
-<p>備考: PHP には <code>short_open_tag</code> というオプションがあり、これを有効にするとファイル冒頭の <code>&lt;?php</code> の代わりに <code>&lt;?</code> を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト off になっている環境が多いようなので、今回は使わないことにした。</p>
-<h1 id="主な障害">主な障害</h1>
-<p>1行あたりの文字数など、適当に改行を挟めばいいだけではないのか?</p>
-<p>特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">i\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">n\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">l\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">u\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">d\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">e\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">&lt;\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">s\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">t\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">d\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">i\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">o\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">.\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">h\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">&gt;\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span><span style="color:#75715e">
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>i\
-</span></span><span style="display:flex;"><span>n\
-</span></span><span style="display:flex;"><span>t\
-</span></span><span style="display:flex;"><span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span>
-</span></span><span style="display:flex;"><span>m\
-</span></span><span style="display:flex;"><span>a\
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span>n(
-</span></span><span style="display:flex;"><span>){
-</span></span><span style="display:flex;"><span>f\
-</span></span><span style="display:flex;"><span>o\
-</span></span><span style="display:flex;"><span>r(
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span>n\
-</span></span><span style="display:flex;"><span>t\
-</span></span><span style="display:flex;"><span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span>
-</span></span><span style="display:flex;"><span>i<span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>;
-</span></span><span style="display:flex;"><span>i<span style="color:#f92672">&lt;</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>\
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>\
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>;
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span>\
-</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span>)
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span>
-</span></span><span style="display:flex;"><span>(i
-</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span>\
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">15</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">==</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>)
-</span></span><span style="display:flex;"><span>p\
-</span></span><span style="display:flex;"><span>r\
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span>n\
-</span></span><span style="display:flex;"><span>t\
-</span></span><span style="display:flex;"><span>f(
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">F\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">i\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">B\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">u\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">10</span>
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">/* あとは同じように普通のプログラムを変形するだけなので省略 */</span>
-</span></span></code></pre></div><p>バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。</p>
-<p>さて、PHP ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、<code>echo</code> で出力することや、<code>for</code> でループすること、<code>new</code> でインスタンスを生成することができない。特に、出力は fizzbuzz をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。</p>
-<p>当然、名前が3文字以上ある関数も使えない。なお、標準 PHP の範囲内において、名前が 2文字以下の関数は以下のとおりである:</p>
-<ul>
-<li><code>_</code>: <code>gettext</code> のエイリアス</li>
-<li><code>dl</code>: 拡張モジュールをロードする</li>
-<li><code>pi</code>: 円周率を返す</li>
-</ul>
-<p>(環境によって多少は変わるかも)</p>
-<p>2文字の関数を定義しまくった拡張モジュールを用意しておいて <code>dl()</code> で読み込む行為は、レギュレーションで定めた</p>
-<blockquote>
-<ul>
-<li>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)</li>
-</ul>
-</blockquote>
-<p>に反する (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。</p>
-<p>また、2文字だと文字列がまともに書けないのも辛い。<code>''</code> だけで 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$a
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">a&#39;</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span></code></pre></div><p>とすると <code>$a</code> は <code>&quot;\na&quot;</code> になるのだが、余計な改行が入ってしまう。</p>
-<p>これらの障害をどのように乗り越えるのか、次節から見ていく。</p>
-<h1 id="解説">解説</h1>
-<h2 id="普通の--fizzbuzz">普通の (?) fizzbuzz</h2>
-<p>まずは普通に書くとしよう。</p>
-<pre tabindex="0"><code>&lt;?php
-
-for ($i = 1; $i &lt; 100; $i++) {
- echo (($i % 3 ? &#39;&#39; : &#39;Fizz&#39;) . ($i % 5 ? &#39;&#39; : &#39;Buzz&#39;) ?: $i) . &#34;\n&#34;;
-}
-</code></pre><p>素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。</p>
-<h2 id="for-の排除"><code>for</code> の排除</h2>
-<p><code>for</code> は、3文字もある長いキーワードである。こんなものは使えない。<code>array_</code> 系の関数を使って、適当に置き換えるとしよう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">range</span>(<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">100</span>);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">array_walk</span>(
-</span></span><span style="display:flex;"><span> $s,
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fn</span>($i) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">printf</span>((($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Fizz&#39;</span>) <span style="color:#f92672">.</span> ($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">5</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Buzz&#39;</span>) <span style="color:#f92672">?:</span> $i) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>),
-</span></span><span style="display:flex;"><span>);
-</span></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> に置き換えた。</p>
-<h2 id="関数呼び出しの短縮">関数呼び出しの短縮</h2>
-<p><code>range</code>、<code>array_walk</code>、<code>printf</code> は長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;range&#39;</span>;
-</span></span><span style="display:flex;"><span>$w <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;array_walk&#39;</span>;
-</span></span><span style="display:flex;"><span>$p <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;printf&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> $r(<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">100</span>);
-</span></span><span style="display:flex;"><span>$w(
-</span></span><span style="display:flex;"><span> $s,
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fn</span>($i) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> $p((($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Fizz&#39;</span>) <span style="color:#f92672">.</span> ($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">5</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Buzz&#39;</span>) <span style="color:#f92672">?:</span> $i) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>),
-</span></span><span style="display:flex;"><span>);
-</span></span></code></pre></div><p>これで関数を呼び出している所は短くなった。では、<code>$r</code> や <code>$w</code> や <code>$p</code>、また <code>'Fizz'</code> や <code>'Buzz'</code> はどうやって 1行2文字に収めるのか。次のテクニックへ移ろう。</p>
-<h2 id="余談-php-8x-で動作しなくてもいいなら">余談: PHP 8.x で動作しなくてもいいなら</h2>
-<p>今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。</p>
-<blockquote>
-<ul>
-<li>PHP 7.4〜8.1 で動作すること</li>
-</ul>
-</blockquote>
-<p>というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、 <code>Fizz</code> という文字列が欲しければ、次のようにする。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$f
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#a6e22e">F</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">i</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span></code></pre></div><p>こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、<code>@</code> 演算子を使って抑制してやるとよい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$f
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=@</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">F</span><span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">@</span><span style="color:#a6e22e">i</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">@</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">@</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span></code></pre></div><p>むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。</p>
-<h2 id="文字列リテラルの短縮">文字列リテラルの短縮</h2>
-<p>実際に使った手法の説明に移る。</p>
-<p>ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (<code>&amp;</code>、<code>|</code>、<code>^</code>) をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$a <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;12345&#34;</span>;
-</span></span><span style="display:flex;"><span>$b <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;world&#34;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// $a ^ $b は次のコードと同じ
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$result <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672">&lt;</span> <span style="color:#a6e22e">min</span>(<span style="color:#a6e22e">strlen</span>($a), <span style="color:#a6e22e">strlen</span>($b)); $i<span style="color:#f92672">++</span>) {
-</span></span><span style="display:flex;"><span> $result <span style="color:#f92672">.=</span> $a[$i] <span style="color:#f92672">^</span> $b[$i];
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $result;
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// =&gt; F]AXQ
-</span></span></span></code></pre></div><p>これを踏まえ、次のコードを見てみよう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;x</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">Om</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>$y <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">k!</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">o&#34;</span>;
-</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> $y;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>実行すると、<code>range</code> が表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;x
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o&#39;</span>
-</span></span><span style="display:flex;"><span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> $y;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>さらに <code>#</code> を使って適当に調整すると、次のようになる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;x
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o&#39;</span>
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>1行あたり2文字で、<code>range</code> という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。</p>
-<p>備考: <code>Buzz</code> 中にある小文字の <code>u</code> は、このロジックだと non-printable な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。</p>
-<h1 id="完成系">完成系</h1>
-<p>完成したものがこちら。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;i
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">S&#39;</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">b!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$c
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;x
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o&#39;</span>
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;k
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Sk
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">~}
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Ma
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">x!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">s!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$w
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;z
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Hd
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">G&#39;</span>
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">x!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">~!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$p
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;L
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[p
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$f
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;H
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[p
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">_!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$b
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$b
-</span></span><span style="display:flex;"><span>[<span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span>]<span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span>$c
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">13</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">*</span><span style="color:#ae81ff">9</span>
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>$s
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r
-</span></span><span style="display:flex;"><span>(<span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span>,(
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">10</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">**</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span>)
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>$w
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$s
-</span></span><span style="display:flex;"><span>,<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">fn</span>
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span>)<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span>$p
-</span></span><span style="display:flex;"><span>((
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span><span style="color:#ae81ff">3</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">?</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;&#39;</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$f
-</span></span><span style="display:flex;"><span>)<span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span><span style="color:#ae81ff">5</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">?</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;&#39;</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$b
-</span></span><span style="display:flex;"><span>)<span style="color:#f92672">?</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span>)<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">.</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>)
-</span></span><span style="display:flex;"><span>);
-</span></span></code></pre></div><h1 id="感想など">感想など</h1>
-<p>PHP は、スクリプト言語の中だとシンタックスシュガーが少ない (体感)。この挑戦は不可能に思われたが、PHP マニュアルとにらめっこしていたらなんとかなった。</p>
-<p>みんなもプログラムを細長くしよう。</p>
-<h1 id="余談2-別解">余談2: 別解</h1>
-<p>PHP では、バッククォートを使ってシェルを呼び出せる。これは <code>shell_exec</code> 関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">`
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">e\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">h\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> \
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">1\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">2\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">3\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">`</span>);
-</span></span></code></pre></div><p>なお、ここでは簡単のため出力に <code>printf</code> をそのまま使っているが、実際には <code>printf</code> という文字列を合成して可変関数で呼び出す。</p>
-<p>ただし、これでは</p>
-<blockquote>
-<ul>
-<li>スペースやタブを使用しないこと</li>
-</ul>
-</blockquote>
-<p>に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。</p>
-<p>もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$c <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;chr&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">$</span>{
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;_
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>}
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$c
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">32</span>
-</span></span><span style="display:flex;"><span>)<span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span>$c
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">92</span>
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">`
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">e\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">h\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">${
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;_
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;}
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">1\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">2\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">3\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">`</span>);
-</span></span></code></pre></div><p>先程と同じく、<code>chr</code> や <code>printf</code> を生成する部分は長くなるので省いた。</p>
-<pre tabindex="0"><code>${
-&#39;_
-&#39;}
-</code></pre><p>は変数で、中にはスペースとエスケープが入っている (<code>chr(32) . chr(92)</code>)。シェルに渡されている文字列は次のようになる。</p>
-<pre tabindex="0"><code>e\
-c\
-h\
-o\
- \
-1\
-2\
-3\
-</code></pre><p>これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。</p>
-<p>ということでこれは別解ということにしておく。</p>
-<p>ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。</p>
-<pre tabindex="0"><code>${
-&#39;_
-&#39;}
-</code></pre><p>最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html b/docs/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html
deleted file mode 100644
index b785a95..0000000
--- a/docs/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html
+++ /dev/null
@@ -1,132 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>PHPerKaigi 2023: ボツになったトークン問題 その 1 | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、
-ボツになった問題を公開する (その 1)。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">PHPerKaigi 2023: ボツになったトークン問題 その 1</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/php">php</a></li>
- <li><a href="https://blog.nsfisis.dev/tags/phperkaigi">phperkaigi</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2022-10-23: 公開</li>
- </ul>
- </section>
- <h1 id="はじめに">はじめに</h1>
-<p>2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の、<a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a> において、昨年と同様に、弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> から、トークン問題を出題予定である。</p>
-<p>昨年のトークン問題の記事はこちら: <a href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022 トークン問題の解説</a></p>
-<p>すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。</p>
-<p>10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。</p>
-<h1 id="問題">問題</h1>
-<p>注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;No input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π);
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;Invalid input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">&#39;/(\x23.+?) /&#39;</span>, $s, $m);
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;056e831a4146bf123e8ea16613303d2e&#39;</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><h1 id="トークン入手方法">トークン入手方法</h1>
-<p>ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。それを <code>$π</code> なる変数に代入しているので、円周率を渡してみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.14
-</span></span><span style="display:flex;"><span>Failed.
-</span></span></code></pre></div><p>失敗してしまった。精度を上げてみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415
-</span></span><span style="display:flex;"><span>Failed.
-</span></span></code></pre></div><p>だめだった。これを成功するまで繰り返す。</p>
-<p>最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415926535897932
-</span></span><span style="display:flex;"><span>Token: #YO
-</span></span></code></pre></div><p>めでたくトークン「#YO」が手に入った。</p>
-<h1 id="解説">解説</h1>
-<p>短いので頭から追っていく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;No input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π);
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;Invalid input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>入力のバリデーション部分。数値のみ受け付ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span></code></pre></div><p><code>$π</code> を 2 文字ごとに区切り (<code>str_split</code>)、数値を ASCII コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。</p>
-<p>例えば、<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="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;656667&#39;</span>;
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $s;
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// =&gt; ABC
-</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">&#39;/(\x23.+?) /&#39;</span>, $s, $m);
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span></code></pre></div><p>正規表現でマッチングしている。<code>\x23</code> は <code>#</code> と同じであることに留意すると、この正規表現は「<code>#</code> から始まる 2 以上の長さ (含 <code>#</code>) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。</p>
-<p>なお、<code>#</code> を直接書いていないのは、<code>/#.+?) /</code> と書くと、<code>#.+?)</code> という意図せぬトークンが登録されてしまうからである。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;056e831a4146bf123e8ea16613303d2e&#39;</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>最後にトークンのハッシュ値を見て、想定解かどうかを確認する。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。</p>
-<p>最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも <code>M_PI</code> や <code>pi()</code> では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/2022-10-28/setup-server-for-this-site/index.html b/docs/posts/2022-10-28/setup-server-for-this-site/index.html
deleted file mode 100644
index e886a29..0000000
--- a/docs/posts/2022-10-28/setup-server-for-this-site/index.html
+++ /dev/null
@@ -1,163 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>[備忘録] このサイト用の VPS をセットアップしたときのメモ | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="GitHub Pages でホストしていたこのサイトを VPS へ移行したので、
-そのときにやったことのメモ。99 % 自分用。">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
-
- </head>
- <body class="single">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">[備忘録] このサイト用の VPS をセットアップしたときのメモ</h1>
- <ul class="post-tags">
- <li><a href="https://blog.nsfisis.dev/tags/note-to-self">note-to-self</a></li>
- </ul>
- </header>
- <div class="post-content">
- <section>
- <h1>更新履歴</h1>
- <ul>
- <li>2022-10-28: 公開</li>
- </ul>
- </section>
- <h1 id="はじめに">はじめに</h1>
-<p>これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS に移行した。そのときにおこなったサーバのセットアップ作業を書き残しておく。99 % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。</p>
-<p>未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。</p>
-<h1 id="vps">VPS</h1>
-<p><a href="https://vps.sakura.ad.jp/">さくらの VPS</a> の 2 GB プラン。そこまで真面目に選定していないので、困ったら移動するかも。</p>
-<h1 id="事前準備">事前準備</h1>
-<h2 id="サーバのホスト名を決める">サーバのホスト名を決める</h2>
-<p>モチベーションが上がるという効能がある。今回は藤原定家から取って &ldquo;teika&rdquo; にした。たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。</p>
-<h2 id="ssh-の鍵生成">SSH の鍵生成</h2>
-<p>ローカルマシンで鍵を生成する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/teika.key
-</span></span><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/github2teika.key
-</span></span></code></pre></div><p><code>teika.key</code> はローカルからサーバへの接続用、<code>github2teika.key</code> は、GitHub Actions からサーバへのデプロイ用。</p>
-<h2 id="ssh-の設定">SSH の設定</h2>
-<p><code>.ssh/config</code> に設定しておく。</p>
-<pre tabindex="0"><code class="language-ssh_config" data-lang="ssh_config">Host teika
- HostName **********
- User **********
- Port **********
- IdentityFile ~/.ssh/teika.key
-</code></pre><h1 id="基本のセットアップ">基本のセットアップ</h1>
-<h2 id="ssh-接続">SSH 接続</h2>
-<p>VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。</p>
-<h2 id="ユーザを作成する">ユーザを作成する</h2>
-<p>管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。<code>sudo</code> グループに追加して <code>sudo</code> できるようにし、<code>su</code> で切り替え。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo adduser **********
-</span></span><span style="display:flex;"><span>$ sudo adduser ********** sudo
-</span></span><span style="display:flex;"><span>$ su **********
-</span></span><span style="display:flex;"><span>$ cd
-</span></span></code></pre></div><h2 id="ホスト名を変える">ホスト名を変える</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo hostname teika
-</span></span></code></pre></div><h2 id="公開鍵を置く">公開鍵を置く</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ mkdir ~/.ssh
-</span></span><span style="display:flex;"><span>$ chmod <span style="color:#ae81ff">700</span> ~/.ssh
-</span></span><span style="display:flex;"><span>$ vi ~/.ssh/authorized_keys
-</span></span></code></pre></div><p><code>authorized_keys</code> には、ローカルで生成した <code>~/.ssh/teika.key.pub</code> と <code>~/.ssh/github2teika.key.pub</code> の内容をコピーする。</p>
-<h2 id="ssh-の設定-1">SSH の設定</h2>
-<p>SSH の設定を変更し、少しでも安全にしておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
-</span></span><span style="display:flex;"><span>$ sudo vi /etc/ssh/sshd_config
-</span></span></code></pre></div><ul>
-<li><code>Port</code> を変更</li>
-<li><code>PermitRootLogin</code> を <code>no</code> に</li>
-<li><code>PasswordAuthentication</code> を <code>no</code> に</li>
-</ul>
-<p>そして設定を反映。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo systemctl restart sshd
-</span></span><span style="display:flex;"><span>$ sudo systemctl status sshd
-</span></span></code></pre></div><h2 id="ssh-で接続確認">SSH で接続確認</h2>
-<p>今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh teika
-</span></span></code></pre></div><h2 id="ポートの遮断">ポートの遮断</h2>
-<p>デフォルトの 22 番を閉じ、設定したポートだけ空ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo ufw deny ssh
-</span></span><span style="display:flex;"><span>$ sudo ufw allow *******
-</span></span><span style="display:flex;"><span>$ sudo ufw enable
-</span></span><span style="display:flex;"><span>$ sudo ufw reload
-</span></span><span style="display:flex;"><span>$ sudo ufw status
-</span></span></code></pre></div><p>ここでもう一度 SSH の接続確認を挟む。</p>
-<h2 id="github-用の-ssh-鍵">GitHub 用の SSH 鍵</h2>
-<p>GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/github.key
-</span></span><span style="display:flex;"><span>$ cat ~/.ssh/github.key.pub
-</span></span></code></pre></div><p><a href="https://github.com/settings/ssh">GitHub の設定画面</a> から、この公開鍵を追加する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ vi ~/.ssh/config
-</span></span></code></pre></div><p>設定はこう。</p>
-<pre tabindex="0"><code class="language-ssh_config" data-lang="ssh_config">Host github.com
- HostName github.com
- User git
- IdentityFile ~/.ssh/github.key
-</code></pre><p>最後に接続できるか確認しておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>ssh -T github.com
-</span></span></code></pre></div><h2 id="パッケージの更新">パッケージの更新</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo apt update
-</span></span><span style="display:flex;"><span>$ sudo apt upgrade
-</span></span><span style="display:flex;"><span>$ sudo apt update
-</span></span><span style="display:flex;"><span>$ sudo apt upgrade
-</span></span><span style="display:flex;"><span>$ sudo apt autoremove
-</span></span></code></pre></div><h1 id="サイトホスティング用のセットアップ">サイトホスティング用のセットアップ</h1>
-<h2 id="dns-に-ip-アドレスを登録する">DNS に IP アドレスを登録する</h2>
-<p>このサーバは固定の IP アドレスがあるので、<code>A</code> レコードに直接入れるだけで済んだ。</p>
-<h2 id="使うソフトウェアのインストール">使うソフトウェアのインストール</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo apt install docker docker-compose git make
-</span></span></code></pre></div><h2 id="メインユーザが-docker-を使えるように">メインユーザが Docker を使えるように</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>sudo adduser ********** docker
-</span></span></code></pre></div><h2 id="httphttps-を通す">HTTP/HTTPS を通す</h2>
-<p>80 番と 443 番を空ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo ufw allow 80/tcp
-</span></span><span style="display:flex;"><span>$ sudo ufw allow 443/tcp
-</span></span><span style="display:flex;"><span>$ sudo ufw reload
-</span></span><span style="display:flex;"><span>$ sudo ufw status
-</span></span></code></pre></div><h2 id="リポジトリのクローン">リポジトリのクローン</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ cd
-</span></span><span style="display:flex;"><span>$ git clone git@github.com:nsfisis/nsfisis.dev.git
-</span></span><span style="display:flex;"><span>$ cd nsfisis.dev
-</span></span><span style="display:flex;"><span>$ git submodule update --init
-</span></span></code></pre></div><h2 id="certbot-で証明書取得">certbot で証明書取得</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ docker-compose up -d acme-challenge
-</span></span><span style="display:flex;"><span>$ make setup
-</span></span></code></pre></div><h2 id="サーバを稼動させる">サーバを稼動させる</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ make serve
-</span></span></code></pre></div><h1 id="感想">感想</h1>
-<p>(業務でなく) 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。</p>
-
- </div>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/feed.xml b/docs/posts/feed.xml
deleted file mode 100644
index ab1cbfc..0000000
--- a/docs/posts/feed.xml
+++ /dev/null
@@ -1,2348 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>Posts on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/posts/</link>
- <description>Recent content in Posts on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Fri, 28 Oct 2022 21:55:23 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/posts/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>[備忘録] このサイト用の VPS をセットアップしたときのメモ</title>
- <link>https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/</link>
- <pubDate>Fri, 28 Oct 2022 21:55:23 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS に移行した。そのときにおこなったサーバのセットアップ作業を書き残しておく。99 % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。</p>
-<p>未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。</p>
-<h1 id="vps">VPS</h1>
-<p><a href="https://vps.sakura.ad.jp/">さくらの VPS</a> の 2 GB プラン。そこまで真面目に選定していないので、困ったら移動するかも。</p>
-<h1 id="事前準備">事前準備</h1>
-<h2 id="サーバのホスト名を決める">サーバのホスト名を決める</h2>
-<p>モチベーションが上がるという効能がある。今回は藤原定家から取って &ldquo;teika&rdquo; にした。たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。</p>
-<h2 id="ssh-の鍵生成">SSH の鍵生成</h2>
-<p>ローカルマシンで鍵を生成する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/teika.key
-</span></span><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/github2teika.key
-</span></span></code></pre></div><p><code>teika.key</code> はローカルからサーバへの接続用、<code>github2teika.key</code> は、GitHub Actions からサーバへのデプロイ用。</p>
-<h2 id="ssh-の設定">SSH の設定</h2>
-<p><code>.ssh/config</code> に設定しておく。</p>
-<pre tabindex="0"><code class="language-ssh_config" data-lang="ssh_config">Host teika
- HostName **********
- User **********
- Port **********
- IdentityFile ~/.ssh/teika.key
-</code></pre><h1 id="基本のセットアップ">基本のセットアップ</h1>
-<h2 id="ssh-接続">SSH 接続</h2>
-<p>VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。</p>
-<h2 id="ユーザを作成する">ユーザを作成する</h2>
-<p>管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。<code>sudo</code> グループに追加して <code>sudo</code> できるようにし、<code>su</code> で切り替え。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo adduser **********
-</span></span><span style="display:flex;"><span>$ sudo adduser ********** sudo
-</span></span><span style="display:flex;"><span>$ su **********
-</span></span><span style="display:flex;"><span>$ cd
-</span></span></code></pre></div><h2 id="ホスト名を変える">ホスト名を変える</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo hostname teika
-</span></span></code></pre></div><h2 id="公開鍵を置く">公開鍵を置く</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ mkdir ~/.ssh
-</span></span><span style="display:flex;"><span>$ chmod <span style="color:#ae81ff">700</span> ~/.ssh
-</span></span><span style="display:flex;"><span>$ vi ~/.ssh/authorized_keys
-</span></span></code></pre></div><p><code>authorized_keys</code> には、ローカルで生成した <code>~/.ssh/teika.key.pub</code> と <code>~/.ssh/github2teika.key.pub</code> の内容をコピーする。</p>
-<h2 id="ssh-の設定-1">SSH の設定</h2>
-<p>SSH の設定を変更し、少しでも安全にしておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
-</span></span><span style="display:flex;"><span>$ sudo vi /etc/ssh/sshd_config
-</span></span></code></pre></div><ul>
-<li><code>Port</code> を変更</li>
-<li><code>PermitRootLogin</code> を <code>no</code> に</li>
-<li><code>PasswordAuthentication</code> を <code>no</code> に</li>
-</ul>
-<p>そして設定を反映。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo systemctl restart sshd
-</span></span><span style="display:flex;"><span>$ sudo systemctl status sshd
-</span></span></code></pre></div><h2 id="ssh-で接続確認">SSH で接続確認</h2>
-<p>今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh teika
-</span></span></code></pre></div><h2 id="ポートの遮断">ポートの遮断</h2>
-<p>デフォルトの 22 番を閉じ、設定したポートだけ空ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo ufw deny ssh
-</span></span><span style="display:flex;"><span>$ sudo ufw allow *******
-</span></span><span style="display:flex;"><span>$ sudo ufw enable
-</span></span><span style="display:flex;"><span>$ sudo ufw reload
-</span></span><span style="display:flex;"><span>$ sudo ufw status
-</span></span></code></pre></div><p>ここでもう一度 SSH の接続確認を挟む。</p>
-<h2 id="github-用の-ssh-鍵">GitHub 用の SSH 鍵</h2>
-<p>GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/github.key
-</span></span><span style="display:flex;"><span>$ cat ~/.ssh/github.key.pub
-</span></span></code></pre></div><p><a href="https://github.com/settings/ssh">GitHub の設定画面</a> から、この公開鍵を追加する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ vi ~/.ssh/config
-</span></span></code></pre></div><p>設定はこう。</p>
-<pre tabindex="0"><code class="language-ssh_config" data-lang="ssh_config">Host github.com
- HostName github.com
- User git
- IdentityFile ~/.ssh/github.key
-</code></pre><p>最後に接続できるか確認しておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>ssh -T github.com
-</span></span></code></pre></div><h2 id="パッケージの更新">パッケージの更新</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo apt update
-</span></span><span style="display:flex;"><span>$ sudo apt upgrade
-</span></span><span style="display:flex;"><span>$ sudo apt update
-</span></span><span style="display:flex;"><span>$ sudo apt upgrade
-</span></span><span style="display:flex;"><span>$ sudo apt autoremove
-</span></span></code></pre></div><h1 id="サイトホスティング用のセットアップ">サイトホスティング用のセットアップ</h1>
-<h2 id="dns-に-ip-アドレスを登録する">DNS に IP アドレスを登録する</h2>
-<p>このサーバは固定の IP アドレスがあるので、<code>A</code> レコードに直接入れるだけで済んだ。</p>
-<h2 id="使うソフトウェアのインストール">使うソフトウェアのインストール</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo apt install docker docker-compose git make
-</span></span></code></pre></div><h2 id="メインユーザが-docker-を使えるように">メインユーザが Docker を使えるように</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>sudo adduser ********** docker
-</span></span></code></pre></div><h2 id="httphttps-を通す">HTTP/HTTPS を通す</h2>
-<p>80 番と 443 番を空ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo ufw allow 80/tcp
-</span></span><span style="display:flex;"><span>$ sudo ufw allow 443/tcp
-</span></span><span style="display:flex;"><span>$ sudo ufw reload
-</span></span><span style="display:flex;"><span>$ sudo ufw status
-</span></span></code></pre></div><h2 id="リポジトリのクローン">リポジトリのクローン</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ cd
-</span></span><span style="display:flex;"><span>$ git clone git@github.com:nsfisis/nsfisis.dev.git
-</span></span><span style="display:flex;"><span>$ cd nsfisis.dev
-</span></span><span style="display:flex;"><span>$ git submodule update --init
-</span></span></code></pre></div><h2 id="certbot-で証明書取得">certbot で証明書取得</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ docker-compose up -d acme-challenge
-</span></span><span style="display:flex;"><span>$ make setup
-</span></span></code></pre></div><h2 id="サーバを稼動させる">サーバを稼動させる</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ make serve
-</span></span></code></pre></div><h1 id="感想">感想</h1>
-<p>(業務でなく) 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2023: ボツになったトークン問題 その 1</title>
- <link>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</link>
- <pubDate>Sun, 23 Oct 2022 09:54:07 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の、<a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a> において、昨年と同様に、弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> から、トークン問題を出題予定である。</p>
-<p>昨年のトークン問題の記事はこちら: <a href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022 トークン問題の解説</a></p>
-<p>すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。</p>
-<p>10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。</p>
-<h1 id="問題">問題</h1>
-<p>注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;No input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π);
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;Invalid input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">&#39;/(\x23.+?) /&#39;</span>, $s, $m);
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;056e831a4146bf123e8ea16613303d2e&#39;</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><h1 id="トークン入手方法">トークン入手方法</h1>
-<p>ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。それを <code>$π</code> なる変数に代入しているので、円周率を渡してみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.14
-</span></span><span style="display:flex;"><span>Failed.
-</span></span></code></pre></div><p>失敗してしまった。精度を上げてみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415
-</span></span><span style="display:flex;"><span>Failed.
-</span></span></code></pre></div><p>だめだった。これを成功するまで繰り返す。</p>
-<p>最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415926535897932
-</span></span><span style="display:flex;"><span>Token: #YO
-</span></span></code></pre></div><p>めでたくトークン「#YO」が手に入った。</p>
-<h1 id="解説">解説</h1>
-<p>短いので頭から追っていく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;No input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π);
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;Invalid input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>入力のバリデーション部分。数値のみ受け付ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span></code></pre></div><p><code>$π</code> を 2 文字ごとに区切り (<code>str_split</code>)、数値を ASCII コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。</p>
-<p>例えば、<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="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;656667&#39;</span>;
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $s;
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// =&gt; ABC
-</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">&#39;/(\x23.+?) /&#39;</span>, $s, $m);
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span></code></pre></div><p>正規表現でマッチングしている。<code>\x23</code> は <code>#</code> と同じであることに留意すると、この正規表現は「<code>#</code> から始まる 2 以上の長さ (含 <code>#</code>) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。</p>
-<p>なお、<code>#</code> を直接書いていないのは、<code>/#.+?) /</code> と書くと、<code>#.+?)</code> という意図せぬトークンが登録されてしまうからである。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;056e831a4146bf123e8ea16613303d2e&#39;</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>最後にトークンのハッシュ値を見て、想定解かどうかを確認する。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。</p>
-<p>最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも <code>M_PI</code> や <code>pi()</code> では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。</p>
-]]></description>
- </item>
-
- <item>
- <title>[PHP] fizzbuzz を書く。1行あたり2文字で。</title>
- <link>https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/</link>
- <pubDate>Thu, 29 Sep 2022 00:50:52 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/</guid>
- <description><![CDATA[ <h1 id="記事の構成について">記事の構成について</h1>
-<p>この記事は、普通の fizzbuzz を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、 <a href="https://gist.github.com/nsfisis/04c227d5a419867472a0b23a83ad2919#file-fizzbuzz-php-2-letters-per-line-and-supports-php-8-x-without-warnings">このページ</a> にソースコードがあるので、そちらを先に見てほしい。</p>
-<h1 id="レギュレーション">レギュレーション</h1>
-<p>PHP で、次のような制約の下に fizzbuzz を書いた。</p>
-<ul>
-<li>1行あたりの文字数は2文字までに収めること (ただし <code>&lt;?php</code> タグは除く)
-<ul>
-<li>厳密な定義: <code>&lt;?php</code> タグ以降のソースコードが、2 byte ごとに ラインフィード (LF) で区切られること</li>
-</ul>
-</li>
-<li>スペースやタブを使用しないこと</li>
-<li>ループのアンロールをしないこと
-<ul>
-<li>100 回ループの代わりに 100 回コードをコピペ、というのは禁止</li>
-</ul>
-</li>
-<li>PHP 7.4〜8.1 で動作すること</li>
-<li>実行時に Notice や Warning が出ないこと</li>
-<li>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)</li>
-</ul>
-<p>備考: PHP には <code>short_open_tag</code> というオプションがあり、これを有効にするとファイル冒頭の <code>&lt;?php</code> の代わりに <code>&lt;?</code> を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト off になっている環境が多いようなので、今回は使わないことにした。</p>
-<h1 id="主な障害">主な障害</h1>
-<p>1行あたりの文字数など、適当に改行を挟めばいいだけではないのか?</p>
-<p>特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">i\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">n\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">l\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">u\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">d\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">e\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">&lt;\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">s\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">t\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">d\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">i\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">o\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">.\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">h\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">&gt;\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span><span style="color:#75715e">
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>i\
-</span></span><span style="display:flex;"><span>n\
-</span></span><span style="display:flex;"><span>t\
-</span></span><span style="display:flex;"><span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span>
-</span></span><span style="display:flex;"><span>m\
-</span></span><span style="display:flex;"><span>a\
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span>n(
-</span></span><span style="display:flex;"><span>){
-</span></span><span style="display:flex;"><span>f\
-</span></span><span style="display:flex;"><span>o\
-</span></span><span style="display:flex;"><span>r(
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span>n\
-</span></span><span style="display:flex;"><span>t\
-</span></span><span style="display:flex;"><span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span>
-</span></span><span style="display:flex;"><span>i<span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>;
-</span></span><span style="display:flex;"><span>i<span style="color:#f92672">&lt;</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>\
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>\
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>;
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span>\
-</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span>)
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span>
-</span></span><span style="display:flex;"><span>(i
-</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span>\
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">15</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">==</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>)
-</span></span><span style="display:flex;"><span>p\
-</span></span><span style="display:flex;"><span>r\
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span>n\
-</span></span><span style="display:flex;"><span>t\
-</span></span><span style="display:flex;"><span>f(
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">F\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">i\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">B\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">u\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">10</span>
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">/* あとは同じように普通のプログラムを変形するだけなので省略 */</span>
-</span></span></code></pre></div><p>バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。</p>
-<p>さて、PHP ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、<code>echo</code> で出力することや、<code>for</code> でループすること、<code>new</code> でインスタンスを生成することができない。特に、出力は fizzbuzz をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。</p>
-<p>当然、名前が3文字以上ある関数も使えない。なお、標準 PHP の範囲内において、名前が 2文字以下の関数は以下のとおりである:</p>
-<ul>
-<li><code>_</code>: <code>gettext</code> のエイリアス</li>
-<li><code>dl</code>: 拡張モジュールをロードする</li>
-<li><code>pi</code>: 円周率を返す</li>
-</ul>
-<p>(環境によって多少は変わるかも)</p>
-<p>2文字の関数を定義しまくった拡張モジュールを用意しておいて <code>dl()</code> で読み込む行為は、レギュレーションで定めた</p>
-<blockquote>
-<ul>
-<li>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)</li>
-</ul>
-</blockquote>
-<p>に反する (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。</p>
-<p>また、2文字だと文字列がまともに書けないのも辛い。<code>''</code> だけで 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$a
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">a&#39;</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span></code></pre></div><p>とすると <code>$a</code> は <code>&quot;\na&quot;</code> になるのだが、余計な改行が入ってしまう。</p>
-<p>これらの障害をどのように乗り越えるのか、次節から見ていく。</p>
-<h1 id="解説">解説</h1>
-<h2 id="普通の--fizzbuzz">普通の (?) fizzbuzz</h2>
-<p>まずは普通に書くとしよう。</p>
-<pre tabindex="0"><code>&lt;?php
-
-for ($i = 1; $i &lt; 100; $i++) {
- echo (($i % 3 ? &#39;&#39; : &#39;Fizz&#39;) . ($i % 5 ? &#39;&#39; : &#39;Buzz&#39;) ?: $i) . &#34;\n&#34;;
-}
-</code></pre><p>素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。</p>
-<h2 id="for-の排除"><code>for</code> の排除</h2>
-<p><code>for</code> は、3文字もある長いキーワードである。こんなものは使えない。<code>array_</code> 系の関数を使って、適当に置き換えるとしよう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">range</span>(<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">100</span>);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">array_walk</span>(
-</span></span><span style="display:flex;"><span> $s,
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fn</span>($i) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">printf</span>((($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Fizz&#39;</span>) <span style="color:#f92672">.</span> ($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">5</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Buzz&#39;</span>) <span style="color:#f92672">?:</span> $i) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>),
-</span></span><span style="display:flex;"><span>);
-</span></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> に置き換えた。</p>
-<h2 id="関数呼び出しの短縮">関数呼び出しの短縮</h2>
-<p><code>range</code>、<code>array_walk</code>、<code>printf</code> は長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;range&#39;</span>;
-</span></span><span style="display:flex;"><span>$w <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;array_walk&#39;</span>;
-</span></span><span style="display:flex;"><span>$p <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;printf&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> $r(<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">100</span>);
-</span></span><span style="display:flex;"><span>$w(
-</span></span><span style="display:flex;"><span> $s,
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fn</span>($i) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> $p((($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Fizz&#39;</span>) <span style="color:#f92672">.</span> ($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">5</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Buzz&#39;</span>) <span style="color:#f92672">?:</span> $i) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>),
-</span></span><span style="display:flex;"><span>);
-</span></span></code></pre></div><p>これで関数を呼び出している所は短くなった。では、<code>$r</code> や <code>$w</code> や <code>$p</code>、また <code>'Fizz'</code> や <code>'Buzz'</code> はどうやって 1行2文字に収めるのか。次のテクニックへ移ろう。</p>
-<h2 id="余談-php-8x-で動作しなくてもいいなら">余談: PHP 8.x で動作しなくてもいいなら</h2>
-<p>今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。</p>
-<blockquote>
-<ul>
-<li>PHP 7.4〜8.1 で動作すること</li>
-</ul>
-</blockquote>
-<p>というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、 <code>Fizz</code> という文字列が欲しければ、次のようにする。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$f
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#a6e22e">F</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">i</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span></code></pre></div><p>こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、<code>@</code> 演算子を使って抑制してやるとよい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$f
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=@</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">F</span><span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">@</span><span style="color:#a6e22e">i</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">@</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">@</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span></code></pre></div><p>むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。</p>
-<h2 id="文字列リテラルの短縮">文字列リテラルの短縮</h2>
-<p>実際に使った手法の説明に移る。</p>
-<p>ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (<code>&amp;</code>、<code>|</code>、<code>^</code>) をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$a <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;12345&#34;</span>;
-</span></span><span style="display:flex;"><span>$b <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;world&#34;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// $a ^ $b は次のコードと同じ
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$result <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672">&lt;</span> <span style="color:#a6e22e">min</span>(<span style="color:#a6e22e">strlen</span>($a), <span style="color:#a6e22e">strlen</span>($b)); $i<span style="color:#f92672">++</span>) {
-</span></span><span style="display:flex;"><span> $result <span style="color:#f92672">.=</span> $a[$i] <span style="color:#f92672">^</span> $b[$i];
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $result;
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// =&gt; F]AXQ
-</span></span></span></code></pre></div><p>これを踏まえ、次のコードを見てみよう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;x</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">Om</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>$y <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">k!</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">o&#34;</span>;
-</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> $y;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>実行すると、<code>range</code> が表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;x
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o&#39;</span>
-</span></span><span style="display:flex;"><span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> $y;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>さらに <code>#</code> を使って適当に調整すると、次のようになる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;x
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o&#39;</span>
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>1行あたり2文字で、<code>range</code> という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。</p>
-<p>備考: <code>Buzz</code> 中にある小文字の <code>u</code> は、このロジックだと non-printable な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。</p>
-<h1 id="完成系">完成系</h1>
-<p>完成したものがこちら。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;i
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">S&#39;</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">b!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$c
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;x
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o&#39;</span>
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;k
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Sk
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">~}
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Ma
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">x!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">s!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$w
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;z
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Hd
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">G&#39;</span>
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">x!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">~!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$p
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;L
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[p
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$f
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;H
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[p
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">_!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$b
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$b
-</span></span><span style="display:flex;"><span>[<span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span>]<span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span>$c
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">13</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">*</span><span style="color:#ae81ff">9</span>
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>$s
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r
-</span></span><span style="display:flex;"><span>(<span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span>,(
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">10</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">**</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span>)
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>$w
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$s
-</span></span><span style="display:flex;"><span>,<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">fn</span>
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span>)<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span>$p
-</span></span><span style="display:flex;"><span>((
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span><span style="color:#ae81ff">3</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">?</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;&#39;</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$f
-</span></span><span style="display:flex;"><span>)<span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span><span style="color:#ae81ff">5</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">?</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;&#39;</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$b
-</span></span><span style="display:flex;"><span>)<span style="color:#f92672">?</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span>)<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">.</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>)
-</span></span><span style="display:flex;"><span>);
-</span></span></code></pre></div><h1 id="感想など">感想など</h1>
-<p>PHP は、スクリプト言語の中だとシンタックスシュガーが少ない (体感)。この挑戦は不可能に思われたが、PHP マニュアルとにらめっこしていたらなんとかなった。</p>
-<p>みんなもプログラムを細長くしよう。</p>
-<h1 id="余談2-別解">余談2: 別解</h1>
-<p>PHP では、バッククォートを使ってシェルを呼び出せる。これは <code>shell_exec</code> 関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">`
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">e\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">h\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> \
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">1\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">2\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">3\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">`</span>);
-</span></span></code></pre></div><p>なお、ここでは簡単のため出力に <code>printf</code> をそのまま使っているが、実際には <code>printf</code> という文字列を合成して可変関数で呼び出す。</p>
-<p>ただし、これでは</p>
-<blockquote>
-<ul>
-<li>スペースやタブを使用しないこと</li>
-</ul>
-</blockquote>
-<p>に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。</p>
-<p>もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$c <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;chr&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">$</span>{
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;_
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>}
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$c
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">32</span>
-</span></span><span style="display:flex;"><span>)<span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span>$c
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">92</span>
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">`
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">e\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">h\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">${
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;_
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;}
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">1\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">2\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">3\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">`</span>);
-</span></span></code></pre></div><p>先程と同じく、<code>chr</code> や <code>printf</code> を生成する部分は長くなるので省いた。</p>
-<pre tabindex="0"><code>${
-&#39;_
-&#39;}
-</code></pre><p>は変数で、中にはスペースとエスケープが入っている (<code>chr(32) . chr(92)</code>)。シェルに渡されている文字列は次のようになる。</p>
-<pre tabindex="0"><code>e\
-c\
-h\
-o\
- \
-1\
-2\
-3\
-</code></pre><p>これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。</p>
-<p>ということでこれは別解ということにしておく。</p>
-<p>ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。</p>
-<pre tabindex="0"><code>${
-&#39;_
-&#39;}
-</code></pre><p>最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。</p>
-]]></description>
- </item>
-
- <item>
- <title>弊社の PHP Foundation への寄付に寄せて</title>
- <link>https://blog.nsfisis.dev/posts/2022-08-31/support-for-communty-is-employee-benefits/</link>
- <pubDate>Wed, 31 Aug 2022 22:25:02 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-08-31/support-for-communty-is-employee-benefits/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p><strong>注: これは私個人の意見であり、所属する組織を代表するものではありません。</strong></p>
-<p>先日、私の勤める <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> が <a href="https://opencollective.com/phpfoundation">PHP Foundation</a> へ $2,000 の寄付をおこないました。</p>
-<p>記事: <a href="https://www.dgcircus.com/news/581">https://www.dgcircus.com/news/581</a></p>
-<p>本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。</p>
-<h1 id="なぜ">なぜ?</h1>
-<p>組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。</p>
-<p>当時の考えを端的にまとめた社内チャットの投稿があったので、それを引用します:</p>
-<blockquote>
-<p>結局これを通したい (私の中での) 最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、寄付の報告が流れてきたり、OSS のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか (これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。</p>
-<p>追記: 「肩身が狭くなる」というのがより適切でした。</p>
-</blockquote>
-<p>※文中の「↑にしても」は、ここに載せていない別の投稿を指しています。</p>
-<p>OSS を金銭的に支援したり、技術カンファレンスへ協賛したり (あるいは <a href="https://twitter.com/tomzoh">CTO</a> がカンファレンスを年2で主催したり: <a href="https://iosdc.jp">iOSDC</a> <a href="https://phperkaigi.jp">PHPerKaigi</a>) といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう (知らんけど)。これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。</p>
-<p>以上が、私が社内で寄付の件を進めた (かなり私的な) 理由です。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。この場を借りて感謝申し上げます。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</title>
- <link>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</link>
- <pubDate>Sat, 27 Aug 2022 18:55:28 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> が開催された (らしい)。</p>
-<p>カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。</p>
-<p>ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</a> <br>
-スライド: <a href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</a></p>
-<h1 id="解">解</h1>
-<p>細かいレギュレーションは不明だったので、勝手に定めた。</p>
-<ul>
-<li>コマンドライン引数の第1引数で受けとる</li>
-<li>結果は標準出力に出す</li>
-<li>コンマの直後にはスペースを1つ置く</li>
-<li>末尾コンマは禁止</li>
-<li>数字でないものは入ってこないものとする</li>
-<li>負数は入ってこないものとする</li>
-</ul>
-<p>書いたものがこちら:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span> $n<span style="color:#f92672">=</span>$argv[<span style="color:#ae81ff">1</span>];<span style="color:#66d9ef">foreach</span>([<span style="color:#ae81ff">1e4</span>,<span style="color:#ae81ff">5e3</span>,<span style="color:#ae81ff">2e3</span>,<span style="color:#ae81ff">1e3</span>,<span style="color:#ae81ff">500</span>,<span style="color:#ae81ff">100</span>,<span style="color:#ae81ff">50</span>,<span style="color:#ae81ff">10</span>,<span style="color:#ae81ff">5</span>,<span style="color:#ae81ff">1</span>]<span style="color:#66d9ef">as</span>$x)<span style="color:#66d9ef">for</span>(;$n<span style="color:#f92672">&gt;=</span>$x;$n<span style="color:#f92672">-=</span>$x)$r[]<span style="color:#f92672">=</span>$x;<span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>,$r<span style="color:#f92672">??</span>[]);<span style="color:#75715e">?&gt;</span><span style="color:#960050;background-color:#1e0010">]
-</span></span></span></code></pre></div><p>しめて 123 バイトとなった (末尾改行を含めずにカウント)。</p>
-<p>こちらは改行とスペースを追加したバージョン:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>];
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ([<span style="color:#ae81ff">1e4</span>, <span style="color:#ae81ff">5e3</span>, <span style="color:#ae81ff">2e3</span>, <span style="color:#ae81ff">1e3</span>, <span style="color:#ae81ff">500</span>, <span style="color:#ae81ff">100</span>, <span style="color:#ae81ff">50</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">1</span>] <span style="color:#66d9ef">as</span> $x)
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> (; $n <span style="color:#f92672">&gt;=</span> $x; $n <span style="color:#f92672">-=</span> $x)
-</span></span><span style="display:flex;"><span> $r[] <span style="color:#f92672">=</span> $x;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>, $r <span style="color:#f92672">??</span> []);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">?&gt;</span><span style="color:#960050;background-color:#1e0010">]
-</span></span></span></code></pre></div><h1 id="使用したテクニック">使用したテクニック</h1>
-<h2 id="指数表記">指数表記</h2>
-<p>割と多くの言語のゴルフで使えるテクニック。<code>e</code> を用いた指数表記で、大きな数を短く表す。このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。</p>
-<h2 id="foreach-や-for-の中身を1つの文に">foreach や for の中身を1つの文に</h2>
-<p><code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code> を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> を省略できる。C言語などでも使える。</p>
-<h2 id="r-に初期値を入れない">$r に初期値を入れない</h2>
-<p>PHP では、<code>$r[] = ...</code> のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は <code>$r</code> を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code> のような初期化が不要になる。</p>
-<p>ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> が未定義になってしまい、<code>implode()</code> に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。</p>
-<p>もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。</p>
-<h2 id="php-タグの外に文字列を置く">PHP タグの外に文字列を置く</h2>
-<p>PHP では、<code>&lt;?php</code> <code>?&gt;</code> で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず <code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>最後になりましたが、<a href="https://twitter.com/m3m0r7">めもりー</a> さん、楽しい問題をありがとうございました。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2022</title>
- <link>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</link>
- <pubDate>Sun, 01 May 2022 09:41:39 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>2022-04-09 から 2022-04-11 にかけて開催された、<a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> に、一般参加者として参加した。
-弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
-<p>昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。</p>
-<h1 id="感想">感想</h1>
-<h2 id="厳選おすすめトーク">厳選おすすめトーク</h2>
-<p>多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。</p>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント</a></p>
-<blockquote>
-<p>PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。</p>
-<p>本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</a></p>
-<blockquote>
-<p>PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか?<br>
-これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br>
-またそれらを理解した上でのエラーハンドリングを学びましょう。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</a></p>
-<blockquote>
-<p>毎日流れてくるエラーに皆さんはどう向き合ってますか?<br>
-エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br>
-サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br>
-エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</a></p>
-<blockquote>
-<p>昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。</p>
-<p>最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br>
-・「(私の思う)良い設計」を実現するための意思決定<br>
-・「ISUCONの問題」という位置付けに由来する取捨選択<br>
-・移植中に遭遇したトラブルとその解決策<br>
-といった文脈や葛藤が存在しています。</p>
-<p>本発表はそれらを共有することで<br>
-・PHPアプリケーションの設計、実装事例として役立ててもらう<br>
-・ISUCONの言語移植に興味を持ってもらう<br>
-・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br>
-ことを目的とします。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</a></p>
-<blockquote>
-<p>サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。</p>
-<p>フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。</p>
-<p>このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。</p>
-</blockquote>
-<h2 id="トークン問題の作成">トークン問題の作成</h2>
-<p>今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。</p>
-<h2 id="phper-チャレンジ">PHPer チャレンジ</h2>
-<p><a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。<br>
-また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> をいただいた。</p>
-<h2 id="カンファレンス全体への感想">カンファレンス全体への感想</h2>
-<p><a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。</p>
-<blockquote>
-<p>1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br>
-まあ初カンファレンスだし、とお茶を濁しておこう。</p>
-</blockquote>
-<p>この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。<br>
-これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。</p>
-<p>なお、アンカンファレンスについては、1日目の終わりに<a href="https://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e">トークン問題の解説放送</a>もおこなった。</p>
-<p>また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。
-今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。</p>
-<h1 id="そして来年へ">そして来年へ……?</h1>
-<p>PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。</p>
-<ul>
-<li>プロポーザルを出す</li>
-<li>PHPer チャレンジのトークン問題を 5題作成する</li>
-<li>現地に行く</li>
-<li>PHPer チャレンジで圧勝する</li>
-</ul>
-<hr>
-<p>最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。</p>
-<p>ではまた来年。</p>
-]]></description>
- </item>
-
- <item>
- <title>term-banner: ターミナルにバナーを表示するツールを書いた</title>
- <link>https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/</link>
- <pubDate>Sun, 24 Apr 2022 13:22:52 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>こんなものを作った。</p>
-<pre tabindex="0"><code>$ term-banner &#39;Hello, World!&#39; &#39;こんにちは、&#39; &#39;世界!&#39;
-</code></pre><p><img src="https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png" alt="term-banner のスクリーンショット"></p>
-<p>コマンドライン引数として渡した文字列をターミナルに大きく表示する。</p>
-<p>リポジトリはこちら: <a href="https://github.com/nsfisis/term-banner">https://github.com/nsfisis/term-banner</a></p>
-<h1 id="motivation">Motivation</h1>
-<p>以前、<a href="https://github.com/nsfisis/big-clock-mode">big-clock-mode</a> という似たようなプログラムを書いた。
-これは tmux の <code>:clock-mode</code> コマンドに着想を得たもので、<code>:clock-mode</code> よりも大きく現在時刻を表示する。</p>
-<p><code>big-clock-mode</code> を開発したのは、次のようなシチュエーションで使うためである。
-弊社では現在リモートワークが基本だが、web 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。
-こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。</p>
-<p>それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。</p>
-<p>しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。
-どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。</p>
-<p>そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。
-まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。</p>
-<h1 id="プログラム">プログラム</h1>
-<p>全体の流れは次のようになっている。</p>
-<ol>
-<li>フォントファイルを読み込む</li>
-<li>コマンドライン引数を Shift-JIS に変換する (フォントが Shift-JIS 基準で並んでいるため)</li>
-<li>1文字ずつレンダリングしていく</li>
-</ol>
-<p><code>big-clock-mode</code> が Go 製なので、今回も Go で書いた。
-PNG が標準ライブラリにあったり、Shift-JIS のエンコーディングが準標準ライブラリにあったりしたのは助かった。</p>
-<p>フォントファイルは <code>go:embed</code> で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。
-仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。</p>
-<h1 id="フォント">フォント</h1>
-<p>フリーの 8x8 ビットマップフォントである、<a href="https://littlelimit.net/misaki.htm">美咲フォント 2021-05-05a 版</a> を使わせていただいた。</p>
-<p>はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。
-同じく 8x8 で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。</p>
-<p>美咲フォントは、平仮名・片仮名に留まらず、JIS 第一・第二水準の漢字までサポートしている。
-第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。</p>
-<p>さらに言うと、実のところ美咲フォントは実サイズ 7x7 で作られており、余白が設けられている。
-これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。
-おかげでコーディングまで楽になった。</p>
-<p>ゴシック体と明朝体があったが、私の好みで明朝体の方にした。
-ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。</p>
-<p>2022-04-27 追記: <code>-f</code> オプションで選べるようにした。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>あなたもターミナルに住んでみませんか?</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2022 トークン問題の解説</title>
- <link>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</link>
- <pubDate>Sat, 09 Apr 2022 21:50:19 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>本日開始された <a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> の PHPer チャレンジにおいて、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。</p>
-<p>リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</a></p>
-<h1 id="第1問-brainf_ckphp">第1問 brainf_ck.php</h1>
-<p>ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">declare</span>(<span style="color:#a6e22e">strict_types</span><span style="color:#f92672">=</span><span style="color:#ae81ff">0</span><span style="color:#a6e22e">O1</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> <span style="color:#a6e22e">Dgcircus\PHPerKaigi\Y2022</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">/**
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * @todo
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Run this program to acquire a PHPer token.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> */</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">\error_reporting</span>(<span style="color:#f92672">~+!</span><span style="color:#e6db74">&#39;We are hiring!&#39;</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$z <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($f) <span style="color:#f92672">=&gt;</span> (<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=&gt;</span> $x($x)(<span style="color:#f92672">...</span>$xs)))(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=&gt;</span> $x($x)(<span style="color:#f92672">...</span>$xs)));
-</span></span><span style="display:flex;"><span>$id <span style="color:#f92672">=</span> <span style="color:#a6e22e">\spl_object_id</span>(<span style="color:#f92672">...</span>);
-</span></span><span style="display:flex;"><span>$put <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($c) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">\printf</span>(<span style="color:#e6db74">&#39;%c&#39;</span>, $c);
-</span></span><span style="display:flex;"><span>$mm <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\ArrayObject</span>(<span style="color:#a6e22e">\array_fill</span>(<span style="color:#f92672">+!!</span>[], $n, $p));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$👉 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [<span style="color:#f92672">++</span>$mp, <span style="color:#f92672">++</span>$pc];
-</span></span><span style="display:flex;"><span>$👈 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [<span style="color:#f92672">--</span>$mp, <span style="color:#f92672">++</span>$pc];
-</span></span><span style="display:flex;"><span>$👍 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$m[$mp]];
-</span></span><span style="display:flex;"><span>$👎 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$m[$mp]];
-</span></span><span style="display:flex;"><span>$📝 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, $put($m[$mp])];
-</span></span><span style="display:flex;"><span>$🤡 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($m[$mp]) {
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=&gt;</span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) {
-</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$n),
-</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=&gt;</span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> <span style="color:#f92672">++</span>$pc <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$n),
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">++</span>$pc, $n),
-</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])],
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc],
-</span></span><span style="display:flex;"><span>};
-</span></span><span style="display:flex;"><span>$🎪 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($m[$mp]) {
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc],
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) {
-</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">++</span>$n),
-</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=&gt;</span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> $pc<span style="color:#f92672">+!</span>[] <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">--</span>$n),
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">--</span>$pc, $n),
-</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])],
-</span></span><span style="display:flex;"><span>};
-</span></span><span style="display:flex;"><span>$🐘 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p) <span style="color:#f92672">=&gt;</span> $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">isset</span>($p[$pc]) <span style="color:#f92672">&amp;&amp;</span> $loop($m, $p, $b, $e, <span style="color:#f92672">...</span>($p[$pc]($m, $p, $b, $e, $mp, $pc)))
-</span></span><span style="display:flex;"><span>)($mm(<span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.!</span>[])), $p, $id($🤡), $id($🎪), <span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+!!</span>[]);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$🐘([
-</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $🤡,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👈, $👈, $👈, $👈, $👎,
-</span></span><span style="display:flex;"><span> $🎪,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👉, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👈, $👎, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span>]);
-</span></span></code></pre></div><p>この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。</p>
-<h2 id="解説">解説</h2>
-<h3 id="絵文字">絵文字</h3>
-<p>まず目につくのは大量の絵文字だろう。
-PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。</p>
-<h3 id="プログラム全体">プログラム全体</h3>
-<p>Brainf*ck のインタプリタとプログラムになっている。
-Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。</p>
-<p><a href="https://ja.wikipedia.org/wiki/Brainfuck">https://ja.wikipedia.org/wiki/Brainfuck</a></p>
-<p>なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。</p>
-<pre tabindex="0"><code>+ + + + + + + + + +
-[
- &gt; + + +
- &gt; + + + + +
- &gt; + + + + + + + + + + + +
- &gt; + + + + + + + + + +
- &lt; &lt; &lt; &lt; -
-]
-&gt; + + + + + .
-- - .
-&gt; - - - .
-&gt; - - - .
-- - .
-- .
-&lt; .
-&gt; &gt; - - .
-+ + + + + + + .
-&lt; - - - - .
-&lt; .
-&gt; + + .
-&gt; - .
-&lt; .
-</code></pre><p>実行結果はこちら: <a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a></p>
-<p>それぞれの絵文字で表された関数が、各命令に対応している。</p>
-<ul>
-<li><code>$👉</code>: <code>&gt;</code></li>
-<li><code>$👈</code>: <code>&lt;</code></li>
-<li><code>$👍</code>: <code>+</code></li>
-<li><code>$👎</code>: <code>-</code></li>
-<li><code>$📝</code>: <code>.</code></li>
-<li><code>$🤡</code>: <code>[</code></li>
-<li><code>$🎪</code>: <code>]</code></li>
-</ul>
-<p><code>,</code> (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。</p>
-<p>なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。</p>
-<h3 id="絵文字の選択">絵文字の選択</h3>
-<p>おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> は弊社デジタルサーカスにちなんでいる。
-また、<code>$🐘</code> は PHP のマスコットの象に由来する。</p>
-<h3 id="strict_types">strict_types</h3>
-<p><code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code> の数値リテラルだが、
-<code>0x0</code> や <code>0b1</code> のような値も受け付ける。
-今回は、PHP 8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。</p>
-<h3 id="url">URL</h3>
-<p>ソースコードのライセンスを示したこの部分だが、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span>
-</span></span></code></pre></div><p>完全に合法な PHP のコードである。
-<code>https:</code> 部分はラベル、<code>//</code> 以降は行コメントになっている。</p>
-<h3 id="リテラルなしで数値を生成する">リテラルなしで数値を生成する</h3>
-<p>ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。
-PHP では、型変換を利用することで任意の整数を作り出すことができる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">1</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">2</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">3</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]<span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">10</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.+!!</span>[]));
-</span></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 が作れる)。</p>
-<p>また、<code>error_reporting</code> に指定しているのは <code>-1</code> である。
-これは、<code>!</code> によって文字列を <code>false</code> にし、<code>+</code> によって <code>false</code> を <code>0</code> にし、さらにビット反転して <code>-1</code> にしている。</p>
-<h3 id="if-文なしで条件分岐"><code>if</code> 文なしで条件分岐</h3>
-<p>三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> を一切書かずに条件分岐ができる。
-また、<code>&amp;&amp;</code> / <code>||</code> も使えることがある。
-遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> のような形で分岐することもできる。</p>
-<h3 id="whilefor-文なしでループ"><code>while</code>、<code>for</code> 文なしでループ</h3>
-<p>不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。
-ここでは、一般に Z コンビネータとして知られるものを使った (<code>$z</code>)。</p>
-<p>実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。</p>
-<p>なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、
-あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。</p>
-<h1 id="第2問-riddlephp">第2問 riddle.php</h1>
-<p>ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">/*********************************************************
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * This program displays a PHPer token. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Guess &#39;N&#39;. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Hints: *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - N itself has no special meaning, e.g., 42, 8128, *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * it is selected at random. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Each element of $token represents a single letter. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - One letter consists of 5x5 cells. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Remember, the output is a complete PHPer token. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * License: *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * https://creativecommons.org/publicdomain/zero/1.0/ *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> *********************************************************/</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">N</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e">/* Change it to your answer. */</span>;
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x14B499C</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0BE34CC</span>, <span style="color:#ae81ff">0x01C9C69</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0ECA069</span>, <span style="color:#ae81ff">0x01C2449</span>, <span style="color:#ae81ff">0x0FDB166</span>, <span style="color:#ae81ff">0x01C9C69</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x01C1C66</span>, <span style="color:#ae81ff">0x0FC1C47</span>, <span style="color:#ae81ff">0x01C1C66</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x10C5858</span>, <span style="color:#ae81ff">0x1E4E3B8</span>, <span style="color:#ae81ff">0x1A2F2F8</span>,
-</span></span><span style="display:flex;"><span>];
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($token <span style="color:#66d9ef">as</span> $x) {
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{</span>$x<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。
-トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。</p>
-<p>ここでは、私の想定解を解説する。</p>
-<h2 id="読解">読解</h2>
-<p>まずはソースコードを読んでいく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 略
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>];
-</span></span></code></pre></div><p>数値からなる <code>$token</code> があり、各要素をループしている。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span></code></pre></div><p>まずは排他的論理和 (xor) を取り、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span></code></pre></div><p>二進数に変換して、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span></code></pre></div><p>0 を空白に、1 を <code>#</code> にし、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span></code></pre></div><p>5文字ごとに区切ったあと、改行で結合している。</p>
-<h2 id="ヒント">ヒント</h2>
-<p>次に、ソースコードに書いてあるヒントを読んでいく。</p>
-<ul>
-<li><code>N</code> それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている</li>
-<li><code>$token</code> の各要素は、1文字を表す</li>
-<li>1文字は 5x5 のセルからなる</li>
-<li>出力されるのは、完全な PHPer トークンである</li>
-</ul>
-<p>ここで、PHPer トークンは必ず <code>#</code> 記号から始まることを思いだすと、
-<code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code>#</code> になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。</p>
-<h2 id="解く">解く</h2>
-<p>ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> に変換されるような <code>N</code> を見つければよい。</p>
-<p><code>N</code> は高々</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>);
-</span></span></code></pre></div><p>なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0x14B499C</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>($x <span style="color:#f92672">===</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # &#34;</span>);
-</span></span></code></pre></div><p>この一連の変換に対する逆変換を考えると、次のようになる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # &#34;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;&#39;</span>, <span style="color:#a6e22e">explode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, $x));
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">bindec</span>($x);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#ae81ff">0x14B499C</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;N = </span><span style="color:#e6db74">$n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>これを実行すると、<code>N</code> が得られる。</p>
-<h1 id="第3問-toquinephp">第3問 toquine.php</h1>
-<p>ソースコードはこちら。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// License: https://creativecommons.org/publicdomain/zero/1.0/
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// This is a quine-like program to generate a PHPer token.
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Execute it like this: php toquine.php | php | php | php | ...
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#e6db74">&lt;&lt;&lt;&#39;</span><span style="color:#e6db74">Q</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&lt;?cuc
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ...
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f$f = %f;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$f = fge_ebg13($f); $kf = [
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f,
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">];
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g = ahyy.snyfr; sbe ($v = 0; $v &lt;= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g .= vzcybqr(&#34;\a&#34;, fge_fcyvg(fge_ercynpr([&#39;0&#39;,&#39;1&#39;], [&#39; &#39;,&#39;##&#39;], fcevags(pue(37) . &#39;025o&#39;, $kf[$v])), 012)) . &#34;\a\a&#34;;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$jf = neenl_znc(sa($j) =&gt; vzcybqr(&#39;, &#39;, $j), neenl_puhax(neenl_znc(sa($k) =&gt; fcevags(&#39;0k&#39; . pue(37) . &#39;07K&#39;, $k), $kf), 10));
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">cevags($f, $g, fge_ebg13(&#34;&lt;&lt;&lt;&#39;Q&#39;\a{$f}\aQ&#34;), vzcybqr(&#34;,\a&#34;, $jf));
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#e6db74">Q</span>;
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_rot13</span>($s); $xs <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x0AFABEA</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x0002800</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x0117041</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F295B7</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1151151</span>, <span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1F8C63F</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x1F8C631</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x1F8C63F</span>, <span style="color:#ae81ff">0x1F295B7</span>,
-</span></span><span style="display:flex;"><span>];
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">.</span><span style="color:#66d9ef">false</span>; <span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">intdiv</span>(<span style="color:#66d9ef">__LINE__</span><span style="color:#f92672">-</span><span style="color:#ae81ff">035</span>,<span style="color:#ae81ff">6</span>); <span style="color:#f92672">++</span>$i) <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">isset</span>($xs[$i])) <span style="color:#66d9ef">break</span>; <span style="color:#66d9ef">else</span>
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">.=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>(<span style="color:#a6e22e">str_replace</span>([<span style="color:#e6db74">&#39;0&#39;</span>,<span style="color:#e6db74">&#39;1&#39;</span>], [<span style="color:#e6db74">&#39; &#39;</span>,<span style="color:#e6db74">&#39;##&#39;</span>], <span style="color:#a6e22e">sprintf</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;025b&#39;</span>, $xs[$i])), <span style="color:#ae81ff">012</span>)) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>$ws <span style="color:#f92672">=</span> <span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($w) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>, $w), <span style="color:#a6e22e">array_chunk</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;0x&#39;</span> <span style="color:#f92672">.</span> <span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;07X&#39;</span>, $x), $xs), <span style="color:#ae81ff">10</span>));
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>($s, $t, <span style="color:#a6e22e">str_rot13</span>(<span style="color:#e6db74">&#34;&lt;&lt;&lt;&#39;D&#39;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">{</span>$s<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">D&#34;</span>), <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;,</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, $ws));
-</span></span></code></pre></div><p>コメントにもあるとおり、次のようにして実行すれば答えがでてくる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php toquine.php | php | php | php | ...
-</span></span></code></pre></div><p>実際にはもう少しパイプで繋げなければならない。</p>
-<h2 id="解説-1">解説</h2>
-<h3 id="プログラム全体-1">プログラム全体</h3>
-<p>コメントにもあるとおり、これは quine (風) のプログラムになっている。
-Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。</p>
-<p>このプログラムは、実行すると自身とほとんど同じプログラムを出力する。
-異なるのはトークンになっている部分のみである。</p>
-<h3 id="トークン">トークン</h3>
-<p><code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。</p>
-<h3 id="状態保持">状態保持</h3>
-<p>トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。
-このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code>__LINE__</code> から情報を取得している。</p>
-<h3 id="rot-13">ROT 13</h3>
-<p>Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。
-これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 変換を使って難読化した。</p>
-<p>それにしてもなぜこんなものが標準ライブラリに……。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。</p>
-<p>今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、
-来年は 5問、より面白い問題を持っていきます。</p>
-<p>実はもう作りはじめているので、どうか来年もありますように……。</p>
-]]></description>
- </item>
-
- <item>
- <title>Rust のプリミティブ型はどこからやって来るか</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/</link>
- <pubDate>Sat, 02 Oct 2021 09:39:27 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</a></p>
-<hr>
-<h1 id="前置き">前置き</h1>
-<p>Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">#![allow(non_camel_case_types)]</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">#![allow(dead_code)]</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">char</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i8</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i16</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i32</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i64</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i128</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">isize</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u8</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u16</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u32</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u64</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u128</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">usize</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f32</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f64</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">str</span>;
-</span></span></code></pre></div><p>では、普段単に <code>bool</code> と書いたとき、この <code>bool</code> は一体どこから来ているのか。rustc のソースを追ってみた。</p>
-<blockquote>
-<p>前提知識: 一般的なコンパイラの構造、用語。<code>rustc</code> そのものの知識は不要 (というよりも筆者自身がよく知らない)</p>
-</blockquote>
-<h1 id="調査">調査</h1>
-<p>調査に使用したソース (調査時点での最新 master)</p>
-<p><a href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</a></p>
-<p>どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。</p>
-<p>大雑把な構造としては、<code>compiler</code> フォルダ以下に <code>rustc_*</code> という名前のクレートが数十個入っている。これがどうやら <code>rustc</code> コマンドの実装部のようだ。</p>
-<p><code>rustc</code> はセルフホストされている (= <code>rustc</code> 自身が Rust で書かれている) ので、<code>bool</code> や <code>char</code> などで適当に検索をかけてもノイズが多すぎて話にならない。
-しかし、お誂え向きなことに <code>i128</code>/<code>u128</code> というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って <code>git grep</code> してみる。</p>
-<pre tabindex="0"><code>$ git grep &#34;\bi128\b&#34; | wc # i128
- 165 1069 15790
-
-$ git grep &#34;\bu128\b&#34; | wc # u128
- 293 2127 26667
-
-$ git grep &#34;\bbool\b&#34; | wc # cf. bool の結果
- 3563 23577 294659
-</code></pre><p>165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。</p>
-<pre tabindex="0"><code>$ git grep &#34;\bi128\b&#34;
-...
-rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));
-...
-</code></pre><p><code>rustc_resolve</code> というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#e6db74">/// Interns the names of the primitive types.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">///
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// All other types are defined somewhere and possibly imported, but the primitive ones need
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// special handling, since they have no place of origin.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">PrimitiveTypeTable</span> {
-</span></span><span style="display:flex;"><span> primitive_types: <span style="color:#a6e22e">FxHashMap</span><span style="color:#f92672">&lt;</span>Symbol, PrimTy<span style="color:#f92672">&gt;</span>,
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> PrimitiveTypeTable {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">new</span>() -&gt; <span style="color:#a6e22e">PrimitiveTypeTable</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> table <span style="color:#f92672">=</span> FxHashMap::default();
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">bool</span>, Bool);
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">char</span>, Char);
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">f32</span>, Float(FloatTy::F32));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">f64</span>, Float(FloatTy::F64));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">isize</span>, Int(IntTy::Isize));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i8</span>, Int(IntTy::I8));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i16</span>, Int(IntTy::I16));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i32</span>, Int(IntTy::I32));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i64</span>, Int(IntTy::I64));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i128</span>, Int(IntTy::I128));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">str</span>, Str);
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">usize</span>, Uint(UintTy::Usize));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u8</span>, Uint(UintTy::U8));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u16</span>, Uint(UintTy::U16));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u32</span>, Uint(UintTy::U32));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u64</span>, Uint(UintTy::U64));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u128</span>, Uint(UintTy::U128));
-</span></span><span style="display:flex;"><span> Self { primitive_types: <span style="color:#a6e22e">table</span> }
-</span></span><span style="display:flex;"><span> }
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、</p>
-<blockquote>
-<p>All other types are defined somewhere and possibly imported, but the primitive ones need special handling, since they have no place of origin.</p>
-</blockquote>
-<p>とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span> <span style="color:#e6db74">/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span> <span style="color:#e6db74">/// (略)
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">resolve_ident_in_lexical_scope</span>(
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">&amp;</span><span style="color:#66d9ef">mut</span> self,
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">mut</span> ident: <span style="color:#a6e22e">Ident</span>,
-</span></span><span style="display:flex;"><span> ns: <span style="color:#a6e22e">Namespace</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// (略)
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> ) -&gt; Option<span style="color:#f92672">&lt;</span>LexicalScopeBinding<span style="color:#f92672">&lt;&#39;</span><span style="color:#a6e22e">a</span><span style="color:#f92672">&gt;&gt;</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// (略)
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> ns <span style="color:#f92672">==</span> TypeNS {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">let</span> Some(prim_ty) <span style="color:#f92672">=</span> self.primitive_type_table.primitive_types.get(<span style="color:#f92672">&amp;</span>ident.name) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> binding <span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span> (Res::PrimTy(<span style="color:#f92672">*</span>prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
-</span></span><span style="display:flex;"><span> .to_name_binding(self.arenas);
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> Some(LexicalScopeBinding::Item(binding));
-</span></span><span style="display:flex;"><span> }
-</span></span><span style="display:flex;"><span> }
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> None
-</span></span><span style="display:flex;"><span> }
-</span></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> など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。</p>
-<p>なお、<code>ns</code> は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この <code>if</code> は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。</p>
-<p>重要なのは、これが <code>resolve_ident_in_lexical_scope()</code> の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。</p>
-<p>動作がわかったところで、例として次のコードを考える。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">#![allow(non_camel_case_types)]</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">main</span>() {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> _: <span style="color:#66d9ef">bool</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">bool</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>ここで <code>main()</code> の <code>bool</code> は <code>struct bool</code> として解決される。なぜなら、プリミティブ型の判定をする前に <code>bool</code> という名前の別の型が見つかるからだ。</p>
-<h1 id="まとめ">まとめ</h1>
-<p>Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。</p>
-]]></description>
- </item>
-
- <item>
- <title>[Ruby] then キーワードと case in</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</link>
- <pubDate>Sat, 02 Oct 2021 09:38:50 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</a></p>
-<hr>
-<h1 id="tl-dr">TL; DR</h1>
-<p><code>case</code> - <code>in</code> によるパターンマッチング構文でも、<code>case</code> - <code>when</code> と同じように <code>then</code> が使える (場合によっては使う必要がある)。</p>
-<h1 id="then-とは"><code>then</code> とは</h1>
-<p>使われることは稀だが、Ruby では <code>then</code> がキーワードになっている。次のように使う:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> cond <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">&#34;Y&#34;</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
-</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">&#34;N&#34;</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code> 構文がそれに当たる。
-上記のように、何か条件を書いた後 <code>then</code> を置き、式がそこで終了していることを示すマーカーとして機能する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># Example:</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> x <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">unless</span> x <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">begin</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">rescue</span> <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">when</span> p <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><h1 id="なぜ普段は書かなくてもよいのか">なぜ普段は書かなくてもよいのか</h1>
-<p>普通 Ruby のコードで <code>then</code> を書くことはない。なぜか。次のコードを実行してみるとわかる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span> puts <span style="color:#e6db74">&#39;Hello, World!&#39;</span> <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>次のような構文エラーが出力される。</p>
-<pre tabindex="0"><code>20:1: syntax error, unexpected local variable or method, expecting `then&#39; or &#39;;&#39; or &#39;\n&#39;
-if true puts &#39;Hello, World!&#39; end
- ^~~~
-20:1: syntax error, unexpected `end&#39;, expecting end-of-input
-...f true puts &#39;Hello, World!&#39; end
-</code></pre><p>二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code> か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。</p>
-<p>ポイントは改行が <code>then</code> (や <code>;</code>) の代わりとなることである。<code>true</code> の後に改行を入れてみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span>
-</span></span><span style="display:flex;"><span>puts <span style="color:#e6db74">&#39;Hello, World!&#39;</span> <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>無事 Hello, World! と出力されるようになった。</p>
-<h1 id="なぜ-then-や--や改行が必要か">なぜ <code>then</code> や <code>;</code> や改行が必要か</h1>
-<p>なぜ <code>then</code> や <code>;</code> や改行 (以下 「<code>then</code> 等」) が必要なのだろうか。次の例を見てほしい:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a b <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p><code>then</code> も <code>;</code> も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。
-この例は二通りに解釈できる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e"># その結果が truthy なら何もしない</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a(b) <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></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> も同じ役割を持つ。</p>
-<p>Ruby の場合、プログラマーが書きやすいよう改行でもって <code>then</code> が代用できるので、ほとんどの場合 <code>then</code> は必要ない。</p>
-<h1 id="case---in-における-then"><code>case</code> - <code>in</code> における <code>then</code></h1>
-<p>ようやく本題にたどり着いた。来る Ruby 3.0 では <code>case</code> と <code>in</code> キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして <code>then</code> 等が必要になる。
-(現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。</p>
-<p><a href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</a></p>
-<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in
- {
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- p-&gt;command_start = FALSE;
- $&lt;ctxt&gt;1 = p-&gt;ctxt;
- p-&gt;ctxt.in_kwarg = 1;
- $&lt;tbl&gt;$ = push_pvtbl(p);
- }
- {
- $&lt;tbl&gt;$ = push_pktbl(p);
- }
- p_top_expr then
- {
- pop_pktbl(p, $&lt;tbl&gt;3);
- pop_pvtbl(p, $&lt;tbl&gt;2);
- p-&gt;ctxt.in_kwarg = $&lt;ctxt&gt;1.in_kwarg;
- }
- compstmt
- p_cases
- {
- /*%%%*/
- $$ = NEW_IN($4, $7, $8, &amp;@$);
- /*% %*/
- /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
- }
- ;
-</code></pre><p>簡略版:</p>
-<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in p_top_expr then compstmt p_cases
- ;
-</code></pre><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>、改行のいずれかである。</p>
-<p>これにより、<code>case</code> - <code>when</code> による従来の構文と同じように、<code>then</code> 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span> <span style="color:#66d9ef">then</span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span> <span style="color:#66d9ef">then</span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span> <span style="color:#66d9ef">then</span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span>
-</span></span><span style="display:flex;"><span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span>; a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span>; b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span>; c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>ところで、<code>p_top_expr</code> には <code>if</code> による guard clause が書けるので、その場合は <code>if</code> - <code>then</code> と似たような見た目になる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">if</span> n <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">then</span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><h1 id="まとめ">まとめ</h1>
-<ul>
-<li><code>if</code> や <code>case</code> の条件の後ろには <code>then</code>、<code>;</code>、改行のいずれかが必要
-<ul>
-<li>通常は改行しておけばよい</li>
-</ul>
-</li>
-<li>3.0 で入る予定の <code>case</code> - <code>in</code> でも <code>then</code> 等が必要になる</li>
-<li>Ruby の構文を正確に知るには (現状) <code>parse.y</code> を直接読めばよい</li>
-</ul>
-]]></description>
- </item>
-
- <item>
- <title>[C&#43;&#43;] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</link>
- <pubDate>Sat, 02 Oct 2021 09:38:30 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</a></p>
-<hr>
-<p>タイトル落ち。まずはこのコードを見て欲しい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;iostream&gt;</span><span style="color:#75715e">
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// [[using]]
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">int</span> main() {
-</span></span><span style="display:flex;"><span> std<span style="color:#f92672">::</span>cout <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#34;Hello, World!&#34;</span> <span style="color:#f92672">&lt;&lt;</span> std<span style="color:#f92672">::</span>endl;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><blockquote>
-<p>コンパイラのバージョン
-$ clang++ &ndash;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</p>
-<p>コンパイルコマンド (C++17指定)
-$ clang++ &ndash;std=c++17 hoge.cpp</p>
-</blockquote>
-<p>この記事から得られるものはこれ以上ないので以下は蛇足になる。</p>
-<p>別件で cppreference.com の <a href="https://en.cppreference.com/w/cpp/language/identifiers">identifier のページ</a> を読んでいた時、次の文が目に止まった。</p>
-<blockquote>
-<ul>
-<li>the identifiers that are keywords cannot be used for other purposes;
-<ul>
-<li>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)</li>
-</ul>
-</li>
-</ul>
-</blockquote>
-<p>キーワードでも属性として指定する場合は非キーワードとして使えるらしい。
-実際にやってみる。</p>
-<p>同サイトの [keywords のページ] (<a href="https://en.cppreference.com/w/cpp/keyword">https://en.cppreference.com/w/cpp/keyword</a>) から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。
-大量の警告 (unknown attribute &lsquo;〇〇&rsquo; ignored) がコンパイラから出力されるが、コンパイルできる。</p>
-<p>上のコードでは <code>[[using]]</code> をコメントアウトしているが、これは <code>using</code> キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">// using の例
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]]</span> <span style="color:#960050;background-color:#1e0010">の糖衣構文</span>
-</span></span></code></pre></div><p>C++17 の仕様も見てみる (正確には標準化前のドラフト)。</p>
-<p>引用元: <a href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</a></p>
-<blockquote>
-<p>If a keyword or an alternative token that satisfies the syntactic requirements of an identifier is contained in an attribute-token, it is considered an identifier.</p>
-</blockquote>
-<p>「<code>identifier</code> の構文上の要件を満たすキーワードまたは代替トークンが <code>attribute-token</code> に含まれている場合、<code>identifier</code> とみなされる」とある。どうやら間違いないようだ。</p>
-<p>ところで、代替トークン (alternative token) とは <code>and</code> (<code>&amp;</code>) や <code>bitor</code> (<code>|</code>) などのことだが、<code>identifier</code> の構文上の要件を満たさないような代替トークンなどあるのか?
-疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい (参考: <a href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</a>)</p>
-<ul>
-<li><code>&lt;%</code> → <code>{</code></li>
-<li><code>%&gt;</code> → <code>}</code></li>
-<li><code>&lt;:</code> → <code>[</code></li>
-<li><code>:&gt;</code> → <code>]</code></li>
-<li><code>%:</code> → <code>#</code></li>
-<li><code>%:%:</code> → <code>##</code></li>
-</ul>
-<p>「<code>identifier</code> の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。</p>
-<p>調べた感想: 字句解析器か構文解析器が辛そう</p>
-]]></description>
- </item>
-
- <item>
- <title>[Ruby] 自身を実行している処理系の種類を判定する</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/</link>
- <pubDate>Sat, 02 Oct 2021 09:37:50 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</a></p>
-<hr>
-<p>Ruby という言語には複数の実装があるが、それらをスクリプト上からどのようにして programmatically に見分ければよいだろうか。</p>
-<p><code>Object</code> クラスに定義されている <code>RUBY_ENGINE</code> という定数がこの用途に使える。</p>
-<p>参考: <a href="https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html">Object::RUBY_ENGINE</a></p>
-<p>上記ページの例から引用する:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ruby-1.9.1 -ve <span style="color:#e6db74">&#39;p RUBY_ENGINE&#39;</span>
-</span></span><span style="display:flex;"><span>ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux]
-</span></span><span style="display:flex;"><span>&#34;ruby&#34;
-</span></span><span style="display:flex;"><span>$ jruby -ve <span style="color:#e6db74">&#39;p RUBY_ENGINE&#39;</span>
-</span></span><span style="display:flex;"><span>jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
-</span></span><span style="display:flex;"><span>&#34;jruby&#34;
-</span></span></code></pre></div><p>それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。</p>
-<p><a href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE correspond to which Ruby implementations?</a> より引用:</p>
-<blockquote>
-<table>
-<thead>
-<tr>
-<th style="text-align:center">RUBY_ENGINE</th>
-<th style="text-align:left">Implementation</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td style="text-align:center">&lt;undefined&gt;</td>
-<td style="text-align:left">MRI &lt; 1.9</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;ruby&rsquo;</td>
-<td style="text-align:left">MRI &gt;= 1.9 or REE</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;jruby&rsquo;</td>
-<td style="text-align:left">JRuby</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;macruby&rsquo;</td>
-<td style="text-align:left">MacRuby</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;rbx&rsquo;</td>
-<td style="text-align:left">Rubinius</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;maglev&rsquo;</td>
-<td style="text-align:left">MagLev</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;ironruby&rsquo;</td>
-<td style="text-align:left">IronRuby</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;cardinal&rsquo;</td>
-<td style="text-align:left">Cardinal</td>
-</tr>
-</tbody>
-</table>
-</blockquote>
-<p>なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も <code>'ruby'</code> が返ってくることを確認済み。</p>
-<p>この表にない主要な処理系として、<a href="https://mruby.org">mruby</a> は <code>'mruby'</code> を返す。</p>
-<p><a href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby 該当部分のソース</a> より引用:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * Ruby engine.
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">#define MRUBY_RUBY_ENGINE &#34;mruby&#34;
-</span></span></span></code></pre></div>]]></description>
- </item>
-
- <item>
- <title>Vimで選択した行の順番を入れ替える</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/</link>
- <pubDate>Sat, 02 Oct 2021 09:37:25 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/4fefb361d9a693803520">https://qiita.com/nsfisis/items/4fefb361d9a693803520</a></p>
-<hr>
-<h1 id="バージョン情報">バージョン情報</h1>
-<p><code>:version</code> の一部</p>
-<blockquote>
-<p>VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Jan 26 2020 11:30:30)
-macOS version
-Included patches: 1-148
-Huge version without GUI.</p>
-</blockquote>
-<h1 id="よく紹介されている手法">よく紹介されている手法</h1>
-<h2 id="tac--tail"><code>tac</code> / <code>tail</code></h2>
-<p><code>tac</code> や <code>tail -r</code> などの外部コマンドを <code>!</code> を使って呼び出し、置き換える。</p>
-<blockquote>
-<p>:h v_!</p>
-</blockquote>
-<p><code>tac</code> コマンドや <code>tail</code> の <code>-r</code> オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい</p>
-<h2 id="gm0"><code>:g/^/m0</code></h2>
-<p>こちらは外部コマンドに頼らず、Vim の機能のみを使う。<code>g</code> は <code>:global</code> コマンドの、<code>m</code> は <code>:move</code> コマンドの略</p>
-<p><code>:global</code> コマンドは <code>:[range]global/{pattern}/[command]</code> のように使い、<code>[range]</code> で指定された範囲の行のうち、<code>{pattern}</code> で指定された検索パターンにマッチする行に対して、順番に <code>[command]</code> で指定された Ex コマンドを呼び出す。</p>
-<blockquote>
-<p>:h :global</p>
-</blockquote>
-<p><code>:move</code> コマンドは <code>[range]:move {address}</code> のように使い、<code>[range]</code> で指定された範囲の行を <code>{address}</code> で指定された位置に移動させる。</p>
-<blockquote>
-<p>:h :move</p>
-</blockquote>
-<p><code>:g/^/m0</code> のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。</p>
-<p>なお、<code>:g/^/m0</code> は全ての行を入れ替えるが、<code>:N,Mg/^/mN-1</code> とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ &lt;<span style="color:#a6e22e">line1</span>&gt;,&lt;<span style="color:#a6e22e">line2</span>&gt;<span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span>&lt;<span style="color:#a6e22e">line1</span>&gt;<span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div><p>これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。</p>
-<h1 id="gm0-の問題点"><code>:g/^/m0</code> の問題点</h1>
-<p><code>:global</code> コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<code>^</code> は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<code>'hlsearch'</code> オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと <code>n</code> コマンドなどの際に不便である。</p>
-<blockquote>
-<p>:h @/</p>
-</blockquote>
-<h1 id="解決策">解決策</h1>
-<blockquote>
-<p>[2020/9/28追記]
-より簡潔な方法を見つけたので次節に追記した</p>
-</blockquote>
-<p>前述した <code>:Reverse</code> コマンドの定義を少し変えて、次のようにする:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#66d9ef">function</span>! <span style="color:#a6e22e">s</span>:<span style="color:#a6e22e">reverse_lines</span>(<span style="color:#a6e22e">from</span>, <span style="color:#a6e22e">to</span>) <span style="color:#a6e22e">abort</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#a6e22e">execute</span> <span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">&#34;%d,%dg/^/m%d&#34;</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">from</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">to</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">from</span> - <span style="color:#ae81ff">1</span>)<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">endfunction</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">call</span> &lt;<span style="color:#a6e22e">SID</span>&gt;<span style="color:#a6e22e">reverse_lines</span>(&lt;<span style="color:#a6e22e">line1</span>&gt;, &lt;<span style="color:#a6e22e">line2</span>&gt;)<span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div><p>実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。</p>
-<p>この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが <code>^</code> で上書きされることがなくなる。</p>
-<p>Vim のヘルプから該当箇所を引用する (強調は筆者による)。</p>
-<blockquote>
-<p>:h autocmd-searchpat</p>
-<p><strong>Autocommands do not change the current search patterns.</strong> Vim saves the current
-search patterns before executing autocommands then restores them after the
-autocommands finish. This means that autocommands do not affect the strings
-highlighted with the &lsquo;hlsearch&rsquo; option.</p>
-</blockquote>
-<p>これは autocommand の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは <code>:nohlsearch</code> のヘルプにある。同じく該当箇所を引用する (強調は筆者による)。</p>
-<blockquote>
-<p>:h :nohlsearch</p>
-<p>(略) This command doesn&rsquo;t work in an autocommand, because
-the highlighting state is saved and restored when
-executing autocommands |autocmd-searchpat|.
-<strong>Same thing for when invoking a user function.</strong></p>
-</blockquote>
-<p>この仕様により、<code>:g/^/m0</code> の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。</p>
-<h1 id="解決策-改訂版">解決策 (改訂版)</h1>
-<blockquote>
-<p>[2020/9/28追記]
-より簡潔な方法を見つけたため追記する</p>
-</blockquote>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">keeppatterns</span> &lt;<span style="color:#a6e22e">line1</span>&gt;,&lt;<span style="color:#a6e22e">line2</span>&gt;<span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span>&lt;<span style="color:#a6e22e">line1</span>&gt;<span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div><p>まさにこのための Exコマンド、<code>:keeppatterns</code> が存在する。<code>:keeppatterns {command}</code> のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。</p>
-<blockquote>
-<p>:h :keeppatterns</p>
-</blockquote>
-<h1 id="コピペ用再掲">コピペ用再掲</h1>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#75715e">&#34; License: Public Domain</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">keeppatterns</span> &lt;<span style="color:#a6e22e">line1</span>&gt;,&lt;<span style="color:#a6e22e">line2</span>&gt;<span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span>&lt;<span style="color:#a6e22e">line1</span>&gt;<span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div>]]></description>
- </item>
-
- <item>
- <title>[Vim] autocmd events の BufWrite/BufWritePre の違い</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/</link>
- <pubDate>Sat, 02 Oct 2021 09:37:12 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</a></p>
-<hr>
-<h1 id="tl-dr">TL; DR</h1>
-<p>違いはない。ただのエイリアス。</p>
-<h1 id="調査記録">調査記録</h1>
-<p>Vim の autocmd events には似通った名前のものがいくつかある。大抵は <code>:help</code> に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。</p>
-<ul>
-<li><code>BufRead</code>/<code>BufReadPost</code></li>
-<li><code>BufWrite</code>/<code>BufWritePre</code></li>
-<li><code>BufAdd</code>/<code>BufCreate</code></li>
-</ul>
-<p>このうち、<code>BufAdd</code>/<code>BufCreate</code> に関しては、<code>:help BufCreate</code> に</p>
-<blockquote>
-<p>The BufCreate event is for historic reasons.</p>
-</blockquote>
-<p>とあり、おそらくは <code>BufAdd</code> のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため vim と neovim のソースコードを調査した。</p>
-<blockquote>
-<p>ソースコードへのリンク
-<a href="https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2">vim (調査時点での master branch)</a>
-<a href="https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3">neovim (上に同じ)</a></p>
-</blockquote>
-<h2 id="vim-のソースコード">vim のソースコード</h2>
-<p>以下は、autocmd events の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。</p>
-<p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufAdd&#34;</span>, EVENT_BUFADD},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufCreate&#34;</span>, EVENT_BUFADD},
-</span></span></code></pre></div><p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufRead&#34;</span>, EVENT_BUFREADPOST},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufReadCmd&#34;</span>, EVENT_BUFREADCMD},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufReadPost&#34;</span>, EVENT_BUFREADPOST},
-</span></span></code></pre></div><p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufWrite&#34;</span>, EVENT_BUFWRITEPRE},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufWritePost&#34;</span>, EVENT_BUFWRITEPOST},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufWritePre&#34;</span>, EVENT_BUFWRITEPRE},
-</span></span></code></pre></div><h2 id="neovim-のソースコード">neovim のソースコード</h2>
-<p>neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua で書かれている。以下にある通り、はっきり <code>aliases</code> と書かれている。</p>
-<p><a href="https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124">https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span> aliases <span style="color:#f92672">=</span> {
-</span></span><span style="display:flex;"><span> BufCreate <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;BufAdd&#39;</span>,
-</span></span><span style="display:flex;"><span> BufRead <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;BufReadPost&#39;</span>,
-</span></span><span style="display:flex;"><span> BufWrite <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;BufWritePre&#39;</span>,
-</span></span><span style="display:flex;"><span> FileEncoding <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;EncodingChanged&#39;</span>,
-</span></span><span style="display:flex;"><span> },
-</span></span></code></pre></div><p>ところで、上では取り上げなかった <code>FileEncoding</code> だが、これは <code>:help FileEncoding</code> にしっかりと書いてある。</p>
-<pre tabindex="0"><code> *FileEncoding*
-FileEncoding Obsolete. It still works and is equivalent
- to |EncodingChanged|.
-</code></pre><h2 id="まとめ">まとめ</h2>
-<p>記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。</p>
-<ul>
-<li><code>BufAdd</code>/<code>BufCreate</code>
-<ul>
-<li>→ <code>BufCreate</code> は歴史的な理由により (&ldquo;for historic reasons&rdquo;) 存在しているため、新しい方 (<code>BufAdd</code>) を使う</li>
-</ul>
-</li>
-<li><code>BufRead</code>/<code>BufReadPost</code>
-<ul>
-<li>→ <code>BufReadPre</code> との対称性のため、あるいは <code>BufWritePost</code> との対称性のため <code>BufReadPost</code> を使う</li>
-</ul>
-</li>
-<li><code>BufWrite</code>/<code>BufWritePre</code>
-<ul>
-<li>→ <code>BufWritePost</code> との対称性のため、あるいは <code>BufReadPre</code> との対称性のため <code>BufWritePre</code> を使う</li>
-</ul>
-</li>
-<li><code>FileEncoding</code>/<code>EncodingChanged</code>
-<ul>
-<li>→ <code>FileEncoding</code> は &ldquo;Obsolete&rdquo; と明言されているので、<code>EncodingChanged</code> を使う</li>
-</ul>
-</li>
-</ul>
-<p>ところでこの調査で知ったのだが、<code>BufRead</code> と <code>BufWrite</code> は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら <code>Pre</code>/<code>Post</code> 付きのものを使った方が分かりやすいだろう。</p>
-]]></description>
- </item>
-
- <item>
- <title>[Python] クロージャとUnboundLocalError: local variable &#39;x&#39; referenced before assignment</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</link>
- <pubDate>Sat, 02 Oct 2021 09:32:37 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</a></p>
-<hr>
-<p>本記事は Python 3.7.6 の動作結果を元にして書かれている。</p>
-<p>Python でクロージャを作ろうと、次のようなコードを書いた。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>f()
-</span></span></code></pre></div><p>関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに 1 を足そうとしている。
-これを実行すると <code>x += 1</code> の箇所でエラーが発生する。</p>
-<blockquote>
-<p>UnboundLocalError: local variable &lsquo;x&rsquo; referenced before assignment</p>
-</blockquote>
-<p>local変数 <code>x</code> が代入前に参照された、とある。これは、<code>f</code> の <code>x</code> を参照するのではなく、新しく別の変数を <code>g</code> 内に作ってしまっているため。
-前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code> を変数宣言のための構文として擬似的に利用している。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># 注: var は正しい Python の文法ではない。上記参照のこと</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># f の local変数 &#39;x&#39; を宣言</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e"># x に 0 を代入</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>(): <span style="color:#75715e"># f の内部関数 g を定義</span>
-</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># g の local変数 &#39;x&#39; を宣言</span>
-</span></span><span style="display:flex;"><span> <span style="color:#75715e"># たまたま f にも同じ名前の変数があるが、それとは別の変数</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span> <span style="color:#75715e"># x に 1 を加算 (x = x + 1 の糖衣構文)</span>
-</span></span><span style="display:flex;"><span> <span style="color:#75715e"># 加算する前の値を参照しようとするが、まだ代入されていないためエラー</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span></code></pre></div><p>当初の意図を表現するには、次のように書けばよい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>():
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">nonlocal</span> x <span style="color:#75715e">## (*)</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span></code></pre></div><p><code>(*)</code> のように、<code>nonlocal</code> を追加する。これにより一つ外側のスコープ (<code>g</code> の一つ外側 = <code>f</code>) で定義されている <code>x</code> を探しに行くようになる。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2021</title>
- <link>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</link>
- <pubDate>Tue, 30 Mar 2021 23:22:40 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</guid>
- <description><![CDATA[ <h1 id="phperkaigi-2021-参加レポ">PHPerKaigi 2021 参加レポ</h1>
-<p>2021-03-26 から 2021-03-28 にかけて開催された、<a href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</a> に一般参加者として参加した。
-弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
-<p>このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。</p>
-<p>発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。</p>
-<h2 id="凡例">凡例</h2>
-<blockquote>
-<p>発表・スライドのメモ (引用ではない)</p>
-</blockquote>
-<p>感想など</p>
-<h2 id="day-0-前夜祭-20210327">Day 0 前夜祭 (2021/03/27)</h2>
-<h3 id="1730-a">17:30 [A]</h3>
-<p>PHP で AWS Lambda</p>
-<blockquote>
-<p>Rails のプロジェクトを PHPer のメンバのみでメンテ
-→他のメンバもわかる PHP にリプレースを検討</p>
-<p>サーバレス</p>
-<ul>
-<li>サーバ・インフラの管理が不要</li>
-<li>アプリケーションコードの知識だけで保守可能</li>
-</ul>
-<p>ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入?</p>
-<p>AWSの学習
-AWS のドキュメント
-DevelopersIO</p>
-<p>AWS Lambda のカスタムランタイムで PHP を動かす</p>
-<p>サーバのセットアップや維持管理を気にしなくて良い
-サーバーレスで PHP を動かすツールがすでにある
-サーバーレス構築はすんなり</p>
-<p>今は Laravel がルーティングしている
-Laravel Livewire を Lambda に載せられないか?
-デプロイ方法は?
-バッチ処理は? (Lambda は 15分の制限)</p>
-<p>Lambda でコンテナイメージがサポートされるように</p>
-<p>抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる</p>
-</blockquote>
-<p>AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。</p>
-<p>PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。</p>
-<p>勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。</p>
-<h3 id="1810-a">18:10 [A]</h3>
-<p>大規模サイトの SEO</p>
-<blockquote>
-<p>大規模サイト (100万ページ以上)
-Google の基準</p>
-<p>クロールバジェットを意識したSEO</p>
-<p>大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される
-これを満たさないなら、クロールバジェットを考えなくてもいい</p>
-<p>サーチコンソール
-「カバレッジ」の「除外」
-多すぎるのは問題→クロールバジェットを浪費している</p>
-<ul>
-<li>クエリの順番を決める</li>
-<li>空の値のルールを決めておく</li>
-<li>リダイレクトすればインデックスはうまくいく</li>
-<li>リンクが存在する限りクロールはされる</li>
-</ul>
-<p>リニューアル前のURL</p>
-<p>インデックスは移行される
-リンクのURLが存在する限り、別のURLとしてクロールされる
-リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い
-リニューアルで無視されるようになったパラメータも注意</p>
-<p>robotes.txt で拒否しているのにクロールされる
-一時的に拒否を外して 404 や 301 を読ませる
-内部リンクを確認する
-JS でのリンクに書き換え</p>
-<p>クエリパラメータからURLのパスに
-<code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code></p>
-<p>URL 設計だいじ</p>
-</blockquote>
-<p>SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。</p>
-<h3 id="1850-a">18:50 [A]</h3>
-<blockquote>
-<p>知覚可能
-操作可能
-理解可能
-堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など)</p>
-<ul>
-<li>
-<p>標準の HTML を適切に使う</p>
-</li>
-<li>
-<p>WAI-ARIA</p>
-</li>
-<li>
-<p>キーボードフレンドリー</p>
-</li>
-<li>
-<p>マシンフレンドリー</p>
-</li>
-<li>
-<p>SEOフレンドリー</p>
-</li>
-</ul>
-<p>button タグ
-→キーボード
-h1 タグ
-→スクリーンリーダー・クローラ
-a タグ</p>
-<p>WAI-ARIA
-HTML では表現できないセマンティクスを追加する</p>
-<ul>
-<li>ロール
-<ul>
-<li>何をするのか?</li>
-<li>ユーザーアクションによって変化しない</li>
-</ul>
-</li>
-<li>プロパティ
-<ul>
-<li>関連づけられたデータ</li>
-</ul>
-</li>
-<li>ステート
-<ul>
-<li>現在の状態</li>
-</ul>
-</li>
-</ul>
-<p>まずは標準の HTML 要素で解決する
-何でもかんでも WAI-ARIA を使えばいいというものではない</p>
-<p>マウスホバーでツールチップが出てくるが、キーボード操作では出てこない</p>
-<p>VoiceOver</p>
-<p>全ての属性を使う必要はない
-あくまでアクセシビリティを上げるための方法の一つにすぎない</p>
-</blockquote>
-<p>つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。</p>
-<h3 id="1930-a">19:30 [A]</h3>
-<p>PHP で FUSE</p>
-<p>個人的に楽しみだった発表。</p>
-<blockquote>
-<p>VFS (virtual filesystem) vs 具体的なファイルシステム</p>
-<p>最適な実装方法は状況により異なる</p>
-<p>アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS</p>
-<p>カーネルのプログラムを作るのは難しい</p>
-<ul>
-<li>権限がデカすぎる</li>
-<li>システム全体がクラッシュ</li>
-<li>セキュリティリスク</li>
-<li>開発サイクルを回しづらい</li>
-<li>ネイティブコードにコンパイルされる言語である必要がある</li>
-</ul>
-<p>Filesystem in USEr space (FUSE)</p>
-<ul>
-<li>特定の C の関数を呼ぶことで filesystem が作れる</li>
-<li>FFI を持つ言語なら FUSE が使える</li>
-</ul>
-<p>SSHFS / s3fs / Docker Desktop</p>
-<p>Linux 以外でも使える</p>
-<ul>
-<li>dokany (on Windows)</li>
-<li>osxfuse</li>
-</ul>
-<p>VFS: システムコールが呼ばれると、ファイルシステムによってコール
-FUSE: カーネル空間からユーザ空間へ通信</p>
-<p>高レベルなラッパで型をつける</p>
-<p>PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)</p>
-<ul>
-<li>grep できる</li>
-<li>sed できる</li>
-<li>編集できる</li>
-</ul>
-</blockquote>
-<p>期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。
-この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。</p>
-<h2 id="day-1-20210327">Day 1 (2021/03/27)</h2>
-<h3 id="1050-a">10:50 [A]</h3>
-<p>ATDD</p>
-<blockquote>
-<ul>
-<li>ユーザーストーリー</li>
-<li>ユニットテスト</li>
-<li>CI/CD</li>
-</ul>
-<p>ユーザストーリーの受け入れ条件が曖昧になりがち
-デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている</p>
-<p>Q2の強化
-アジャイルテストの4象限</p>
-<p>技術面/ビジネス面
-開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)</p>
-<ul>
-<li>Q1: 技術面 &amp; チーム支援
-<ul>
-<li>TDD</li>
-<li>ユニットテストなど</li>
-</ul>
-</li>
-<li>Q2: ビジネス面 &amp; チーム支援
-<ul>
-<li>ATDD</li>
-<li>ビジネス面の受け入れテストで駆動する</li>
-</ul>
-</li>
-</ul>
-<p>Agile Alliance
-ユーザストーリーのスキルレベルを高める</p>
-<p>テストピラミッド</p>
-<ul>
-<li>
-<p>UI Tests</p>
-</li>
-<li>
-<p>Service Tests</p>
-</li>
-<li>
-<p>Unit Tests</p>
-</li>
-<li>
-<p>異なる粒度のテストを書く</p>
-</li>
-<li>
-<p>高レベルになるほど、持つべきテストは少なくなる</p>
-<ul>
-<li>ピラミッド型になる</li>
-</ul>
-</li>
-</ul>
-<p>高レベルテストが多すぎる→アイスクリームコーン アンチパターン</p>
-<p>ATDD (Acceptance TDD)
-API経由・UI経由での高レベルテスト E2E test</p>
-<p>ストーリ受け入れテスト</p>
-<p>入れ子のフィードバックループ
-ATDD(外側) と TDD(内側)</p>
-<p>外部品質・内部品質</p>
-<p>バーティカルスライスのデリバリー</p>
-<ul>
-<li>cucumber</li>
-<li>gauge</li>
-<li>behat</li>
-</ul>
-<p>ユビキタス言語
-手動テストもspecに書く
-自動化は可能だがコスパが悪い
-失敗することがわかっているテスト(レッドテスト)はCIから外す
-失敗時の原因究明が難しい
-饒舌なエラーメッセージ
-状況のスナップショット</p>
-<p>Continuous Testing</p>
-</blockquote>
-<p>User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。
-高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。</p>
-<h3 id="1150-a">11:50 [A]</h3>
-<p>型解析を用いたリファクタリング</p>
-<p>型のある世界で生きてきた身として大いに楽しみにしていた発表。</p>
-<blockquote>
-<ul>
-<li>PHPStan</li>
-<li>Phan</li>
-<li>Psalm</li>
-</ul>
-<p>autoload も認識できる
-bootstrapFiles</p>
-<p>編集箇所と利用箇所を CI でチェック
-ルールレベルを徐々に引き上げていく
-警告が多すぎると見落としてしまう・無視されやすくなる</p>
-<p>型がついていないことによるエラーが多い</p>
-<p>型よりも詳細な検査 <code>Util_Assert::min</code></p>
-<p>SQL を静的解析
-placeholder の型付け</p>
-<p>警告レベルを低いレベルから導入
-タイプヒントを積極的に書いていく
-PHPStan の拡張を追加する</p>
-</blockquote>
-<p>昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。
-今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。</p>
-<h3 id="1230-a">12:30 [A]</h3>
-<p>昼食をとっていた。事前に何か食料を買っておくべきだった。</p>
-<h3 id="1310-a">13:10 [A]</h3>
-<p>Documentation as Code</p>
-<p>この発表も以前から非常に楽しみにしていた。</p>
-<blockquote>
-<p>開発開始までのオーバーヘッド
-新規にチームにジョイン
-担当範囲外の機能を理解
-オンボーディングのコスト</p>
-<p>PHPerKaigi 2020 で発表あり</p>
-<p>継続的にシステムの理解を助けるドキュメント</p>
-<p>継続的ドキュメンテーション
-システムとドキュメントの乖離</p>
-<p>書いてあることが間違っている・足りない</p>
-<ul>
-<li>徐々にずれていく</li>
-<li>システムの更新タイミングとドキュメントの更新タイミングに差がある</li>
-</ul>
-<p>システムとドキュメントは対応関係がある</p>
-<ul>
-<li>間違ったドキュメント</li>
-<li>存在しないドキュメント</li>
-</ul>
-<p>システムとドキュメントの乖離を定量化する
-継続的に
-システムの更新に近いタイミングで ドキュメントを更新し続ける</p>
-<p>Documentation as Code</p>
-<p>コードと同じツールでドキュメントを書く</p>
-<ul>
-<li>issue tracker</li>
-<li>vcs</li>
-<li>plain text markup</li>
-<li>automation</li>
-</ul>
-<p>開発者
-システム
-ドキュメント
-構造化データ
-ソフトウェア</p>
-<p>システムから構造化データを抽出する
-PHPDoc
-OpenAPI</p>
-<p>ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する</p>
-<p>ビューの単位でドキュメントに</p>
-<p>スタックトレースからのドキュメント生成</p>
-</blockquote>
-<p>ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。</p>
-<h3 id="1410-a">14:10 [A]</h3>
-<p>cookie による session 管理</p>
-<p>全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。</p>
-<h3 id="1450-a">14:50 [A]</h3>
-<p>PHP のエラーと例外</p>
-<blockquote>
-<p>エラー PHPエンジンがエラーを通知する
-例外 プログラムが投げる</p>
-<p>PHP7-8とエラー</p>
-<p>PHPエンジンのエラーの一部が \Error に変換されるようになった
-→ try-catch で捕捉できる</p>
-<p>\Error は例外とは異なる</p>
-<p>PHP8 でエラーレベルの引き上げ</p>
-<ul>
-<li>捕捉すべきもの
-<ul>
-<li>recoverable</li>
-</ul>
-</li>
-<li>捕捉すべきでないもの
-<ul>
-<li>unrecoverable</li>
-<li>開発時に対処できるもの</li>
-</ul>
-</li>
-</ul>
-<p>例外</p>
-<ul>
-<li>捕捉して事後処理</li>
-<li>捕捉せず(or 捕捉した上で)さらに上に是非を問う</li>
-</ul>
-<p>開発段階で例外を把握し、ハンドリングを考えておく</p>
-<p>\Throwable \Exception と \Error</p>
-<p>\Error はキャッチすべきでない</p>
-<ul>
-<li>
-<p>\Error</p>
-<ul>
-<li>本番で起きてはいけない</li>
-</ul>
-</li>
-<li>
-<p>\LogicException</p>
-<ul>
-<li>本番で起きてはいけない
-→生じないのだから捕捉もしない</li>
-</ul>
-</li>
-<li>
-<p>\RuntimeException</p>
-<ul>
-<li>起こるかもしれないので本番環境でも考慮する</li>
-</ul>
-</li>
-</ul>
-<p>捕捉して対応するのではなく、未然に防ぐ</p>
-<p>独自例外を使う
-\Exception を投げてしまうと、
-catch (\Exception)せざるを得ない
-→catch 範囲が広すぎる</p>
-<p>SPL の例外を使う</p>
-<p>例外翻訳
-上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する
-下位レイヤの知識に依存させない</p>
-<p>@throws
-捕捉してほしい例外を書き連ねておく</p>
-<p>呼び出しもとに負わせたい責任</p>
-</blockquote>
-<p>PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。</p>
-<p>個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。</p>
-<p>PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。</p>
-<h3 id="1530-a">15:30 [A]</h3>
-<p>Laravel のメール認証</p>
-<p>Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。</p>
-<h3 id="1610-a">16:10 [A]</h3>
-<p>gRPC</p>
-<blockquote>
-<p>Unary RPCs
-Server streaming RPCs
-Client streaming RPCs
-Bidirectional streaming RPCs</p>
-<p>Protobuf</p>
-<p>実装とAPIが乖離しにくい
-自動生成
-複数言語でも相互に使える</p>
-<p>マイクロサービスのサービス通信
-スマホアプリ
-ゲームサーバ</p>
-<p>PHP では?</p>
-<p>PHP ではストリーミングが難しい
-リクエストごとにプロセスが使い捨て</p>
-<p>PHP ではgRPCのクライアントしか対応していない</p>
-<p>gRPC-Web
-ブラウザで扱うためのJSライブラリ+プロトコル</p>
-<p>HTTP/1.1 でも使える
-Unary RPC と Server streaming RPC のみ</p>
-<p>Envoy
-Nginx などで相互に gRPC と gRPC-Web で変換</p>
-<p>Amp
-イベント駆動な並行処理のフレームワーク</p>
-<p>HTTP/2 対応</p>
-<p>C#のgRPC-Webが楽</p>
-</blockquote>
-<p>(発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。</p>
-<h3 id="1650-a">16:50 [A]</h3>
-<p>アーキテクチャテスト</p>
-<blockquote>
-<p>Independent Core Layer Pattern</p>
-<p>開発初期のアーキテクチャが崩れる
-アーキテクチャ観点のコードレビューができない</p>
-<p>どこにクラスを置けばよいか?
-ドキュメントがない</p>
-<p>アーキテクチャ設計に関する知識が属人化・暗黙知化</p>
-<p>ガイドライン</p>
-<ul>
-<li>最初にルールを決めるのは簡単</li>
-<li>ルール通り作り始めるのも簡単
-<ul>
-<li>→維持するのが難しい、人が決めたものゆえ壊れやすい</li>
-</ul>
-</li>
-</ul>
-<p>PHP の特性</p>
-<ul>
-<li>クラスは public</li>
-<li>可視性の制御が public / protected / private のみ</li>
-<li>依存関係の制御が困難</li>
-</ul>
-<p>アーキテクチャテスト
-クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する</p>
-<ul>
-<li>deptrac</li>
-<li>phpat</li>
-</ul>
-<p>Independent Core Layer Pattern</p>
-<p>アーキテクチャテストの失敗</p>
-<ul>
-<li>実装誤り</li>
-<li>or アーキテクチャが適切でない
-<ul>
-<li>開発の過程でフィードバックしていく</li>
-</ul>
-</li>
-</ul>
-<p>モジュラーモノリス→マイクロサービスへ</p>
-</blockquote>
-<h2 id="day-2-20210328">Day 2 (2021/03/28)</h2>
-<p>冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。</p>
-<p>残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。</p>
-<h2 id="全体の感想">全体の感想</h2>
-<p>Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。</p>
-<p>今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。</p>
-<p>1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。
-まあ初カンファレンスだし、とお茶を濁しておこう。</p>
-<p>さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。</p>
-<hr>
-<p>最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました!
-(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)</p>
-<p>ではまた来年。</p>
-]]></description>
- </item>
-
- <item>
- <title>My First Post</title>
- <link>https://blog.nsfisis.dev/posts/2021-03-05/my-first-post/</link>
- <pubDate>Fri, 05 Mar 2021 23:38:21 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-03-05/my-first-post/</guid>
- <description><![CDATA[ <h1 id="test">Test</h1>
-<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/posts/index.html b/docs/posts/index.html
deleted file mode 100644
index 56aee42..0000000
--- a/docs/posts/index.html
+++ /dev/null
@@ -1,172 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>Posts | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/posts/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>Posts</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>[備忘録] このサイト用の VPS をセットアップしたときのメモ</h2>
- </header>
- <section class="entry-content">
- <p>GitHub Pages でホストしていたこのサイトを VPS へ移行したので、
-そのときにやったことのメモ。99 % 自分用。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-10-28</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2023: ボツになったトークン問題 その 1</h2>
- </header>
- <section class="entry-content">
- <p>来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、
-ボツになった問題を公開する (その 1)。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-10-23</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[PHP] fizzbuzz を書く。1行あたり2文字で。</h2>
- </header>
- <section class="entry-content">
- <p>PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-09-29</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>弊社の PHP Foundation への寄付に寄せて</h2>
- </header>
- <section class="entry-content">
- <p>先日、私の勤めるデジタルサーカス株式会社が、PHP Foundation へ寄付をおこないました。
-本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-08-31</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-08-31/support-for-communty-is-employee-benefits/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2>
- </header>
- <section class="entry-content">
- <p>PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-08-27</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2022</h2>
- </header>
- <section class="entry-content">
- <p>2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-05-01</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>term-banner: ターミナルにバナーを表示するツールを書いた</h2>
- </header>
- <section class="entry-content">
- <p>ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-04-24</time>, updated on <time>2022-04-27</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2022 トークン問題の解説</h2>
- </header>
- <section class="entry-content">
- <p>PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-04-09</time>, updated on <time>2022-04-16</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>Rust のプリミティブ型はどこからやって来るか</h2>
- </header>
- <section class="entry-content">
- <p>Rust のプリミティブ型は予約語ではなく普通の識別子である。どのようにこれが名前解決されるのかを調べた。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Ruby] then キーワードと case in</h2>
- </header>
- <section class="entry-content">
- <p>Ruby 3.0 で追加される case in 構文と、then キーワードについて。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/"></a>
-</article>
-<footer class="page-footer">
- <nav class="pagination">
- <a class="next" href="/posts/page/2/"> →</a>
- </nav>
-</footer></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/posts/page/1/index.html b/docs/posts/page/1/index.html
deleted file mode 100644
index 1439f8c..0000000
--- a/docs/posts/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/posts/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/posts/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/posts/">
- </head>
-</html>
diff --git a/docs/posts/page/2/index.html b/docs/posts/page/2/index.html
deleted file mode 100644
index 52466e0..0000000
--- a/docs/posts/page/2/index.html
+++ /dev/null
@@ -1,133 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>Posts | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/posts/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>Posts</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>[C&#43;&#43;] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</h2>
- </header>
- <section class="entry-content">
- <p>C&#43;&#43; の属性構文の属性名には、キーワードが使える。ネタ記事。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Ruby] 自身を実行している処理系の種類を判定する</h2>
- </header>
- <section class="entry-content">
- <p>Ruby には複数の実装があるが、自身を実行している処理系の種類をスクリプト上からどのように判定すればよいだろうか。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>Vimで選択した行の順番を入れ替える</h2>
- </header>
- <section class="entry-content">
- <p>Vim で選択した行の順番を入れ替える方法。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Vim] autocmd events の BufWrite/BufWritePre の違い</h2>
- </header>
- <section class="entry-content">
- <p>Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、違いはないことがわかった。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Python] クロージャとUnboundLocalError: local variable &#39;x&#39; referenced before assignment</h2>
- </header>
- <section class="entry-content">
- <p>Python における UnboundLocalError の理由と対処法。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2021</h2>
- </header>
- <section class="entry-content">
- <p>2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-03-30</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>My First Post</h2>
- </header>
- <section class="entry-content">
- <p>これはテスト投稿です。これはテスト投稿です。これはテスト投稿です。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-03-05</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-03-05/my-first-post/"></a>
-</article>
-<footer class="page-footer">
- <nav class="pagination">
- <a class="prev" href="/posts/">← </a>
- </nav>
-</footer></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/sitemap.xml b/docs/sitemap.xml
deleted file mode 100644
index d16785d..0000000
--- a/docs/sitemap.xml
+++ /dev/null
@@ -1,107 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
- xmlns:xhtml="http://www.w3.org/1999/xhtml">
- <url>
- <loc>https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/</loc>
- <lastmod>2022-10-28+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/note-to-self/</loc>
- <lastmod>2022-10-28+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/</loc>
- <lastmod>2022-10-28+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/</loc>
- <lastmod>2022-10-28+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/php/</loc>
- <lastmod>2022-10-23+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/phperkaigi/</loc>
- <lastmod>2022-10-23+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</loc>
- <lastmod>2022-10-23+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/</loc>
- <lastmod>2022-09-29+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2022-08-31/support-for-communty-is-employee-benefits/</loc>
- <lastmod>2022-08-31+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/conference/</loc>
- <lastmod>2022-08-27+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</loc>
- <lastmod>2022-08-27+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/phpcon/</loc>
- <lastmod>2022-08-27+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</loc>
- <lastmod>2022-05-01+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/my-programs/</loc>
- <lastmod>2022-04-27+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/</loc>
- <lastmod>2022-04-27+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</loc>
- <lastmod>2022-04-16+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/rust/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/ruby/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/ruby3/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/cpp/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/cpp17/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/vim/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/python/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/tags/python3/</loc>
- <lastmod>2021-10-02+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/</loc>
- <lastmod>2021-03-31+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</loc>
- <lastmod>2021-03-30+09:00</lastmod>
- </url><url>
- <loc>https://blog.nsfisis.dev/posts/2021-03-05/my-first-post/</loc>
- <lastmod>2021-03-05+09:00</lastmod>
- </url>
-</urlset>
diff --git a/docs/tags/conference/feed.xml b/docs/tags/conference/feed.xml
deleted file mode 100644
index f536cbb..0000000
--- a/docs/tags/conference/feed.xml
+++ /dev/null
@@ -1,944 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>conference on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/conference/</link>
- <description>Recent content in conference on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sat, 27 Aug 2022 18:55:28 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/conference/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</title>
- <link>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</link>
- <pubDate>Sat, 27 Aug 2022 18:55:28 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> が開催された (らしい)。</p>
-<p>カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。</p>
-<p>ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</a> <br>
-スライド: <a href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</a></p>
-<h1 id="解">解</h1>
-<p>細かいレギュレーションは不明だったので、勝手に定めた。</p>
-<ul>
-<li>コマンドライン引数の第1引数で受けとる</li>
-<li>結果は標準出力に出す</li>
-<li>コンマの直後にはスペースを1つ置く</li>
-<li>末尾コンマは禁止</li>
-<li>数字でないものは入ってこないものとする</li>
-<li>負数は入ってこないものとする</li>
-</ul>
-<p>書いたものがこちら:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span> $n<span style="color:#f92672">=</span>$argv[<span style="color:#ae81ff">1</span>];<span style="color:#66d9ef">foreach</span>([<span style="color:#ae81ff">1e4</span>,<span style="color:#ae81ff">5e3</span>,<span style="color:#ae81ff">2e3</span>,<span style="color:#ae81ff">1e3</span>,<span style="color:#ae81ff">500</span>,<span style="color:#ae81ff">100</span>,<span style="color:#ae81ff">50</span>,<span style="color:#ae81ff">10</span>,<span style="color:#ae81ff">5</span>,<span style="color:#ae81ff">1</span>]<span style="color:#66d9ef">as</span>$x)<span style="color:#66d9ef">for</span>(;$n<span style="color:#f92672">&gt;=</span>$x;$n<span style="color:#f92672">-=</span>$x)$r[]<span style="color:#f92672">=</span>$x;<span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>,$r<span style="color:#f92672">??</span>[]);<span style="color:#75715e">?&gt;</span><span style="color:#960050;background-color:#1e0010">]
-</span></span></span></code></pre></div><p>しめて 123 バイトとなった (末尾改行を含めずにカウント)。</p>
-<p>こちらは改行とスペースを追加したバージョン:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>];
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ([<span style="color:#ae81ff">1e4</span>, <span style="color:#ae81ff">5e3</span>, <span style="color:#ae81ff">2e3</span>, <span style="color:#ae81ff">1e3</span>, <span style="color:#ae81ff">500</span>, <span style="color:#ae81ff">100</span>, <span style="color:#ae81ff">50</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">1</span>] <span style="color:#66d9ef">as</span> $x)
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> (; $n <span style="color:#f92672">&gt;=</span> $x; $n <span style="color:#f92672">-=</span> $x)
-</span></span><span style="display:flex;"><span> $r[] <span style="color:#f92672">=</span> $x;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>, $r <span style="color:#f92672">??</span> []);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">?&gt;</span><span style="color:#960050;background-color:#1e0010">]
-</span></span></span></code></pre></div><h1 id="使用したテクニック">使用したテクニック</h1>
-<h2 id="指数表記">指数表記</h2>
-<p>割と多くの言語のゴルフで使えるテクニック。<code>e</code> を用いた指数表記で、大きな数を短く表す。このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。</p>
-<h2 id="foreach-や-for-の中身を1つの文に">foreach や for の中身を1つの文に</h2>
-<p><code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code> を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> を省略できる。C言語などでも使える。</p>
-<h2 id="r-に初期値を入れない">$r に初期値を入れない</h2>
-<p>PHP では、<code>$r[] = ...</code> のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は <code>$r</code> を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code> のような初期化が不要になる。</p>
-<p>ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> が未定義になってしまい、<code>implode()</code> に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。</p>
-<p>もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。</p>
-<h2 id="php-タグの外に文字列を置く">PHP タグの外に文字列を置く</h2>
-<p>PHP では、<code>&lt;?php</code> <code>?&gt;</code> で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず <code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>最後になりましたが、<a href="https://twitter.com/m3m0r7">めもりー</a> さん、楽しい問題をありがとうございました。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2022</title>
- <link>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</link>
- <pubDate>Sun, 01 May 2022 09:41:39 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>2022-04-09 から 2022-04-11 にかけて開催された、<a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> に、一般参加者として参加した。
-弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
-<p>昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。</p>
-<h1 id="感想">感想</h1>
-<h2 id="厳選おすすめトーク">厳選おすすめトーク</h2>
-<p>多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。</p>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント</a></p>
-<blockquote>
-<p>PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。</p>
-<p>本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</a></p>
-<blockquote>
-<p>PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか?<br>
-これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br>
-またそれらを理解した上でのエラーハンドリングを学びましょう。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</a></p>
-<blockquote>
-<p>毎日流れてくるエラーに皆さんはどう向き合ってますか?<br>
-エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br>
-サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br>
-エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</a></p>
-<blockquote>
-<p>昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。</p>
-<p>最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br>
-・「(私の思う)良い設計」を実現するための意思決定<br>
-・「ISUCONの問題」という位置付けに由来する取捨選択<br>
-・移植中に遭遇したトラブルとその解決策<br>
-といった文脈や葛藤が存在しています。</p>
-<p>本発表はそれらを共有することで<br>
-・PHPアプリケーションの設計、実装事例として役立ててもらう<br>
-・ISUCONの言語移植に興味を持ってもらう<br>
-・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br>
-ことを目的とします。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</a></p>
-<blockquote>
-<p>サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。</p>
-<p>フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。</p>
-<p>このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。</p>
-</blockquote>
-<h2 id="トークン問題の作成">トークン問題の作成</h2>
-<p>今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。</p>
-<h2 id="phper-チャレンジ">PHPer チャレンジ</h2>
-<p><a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。<br>
-また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> をいただいた。</p>
-<h2 id="カンファレンス全体への感想">カンファレンス全体への感想</h2>
-<p><a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。</p>
-<blockquote>
-<p>1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br>
-まあ初カンファレンスだし、とお茶を濁しておこう。</p>
-</blockquote>
-<p>この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。<br>
-これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。</p>
-<p>なお、アンカンファレンスについては、1日目の終わりに<a href="https://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e">トークン問題の解説放送</a>もおこなった。</p>
-<p>また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。
-今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。</p>
-<h1 id="そして来年へ">そして来年へ……?</h1>
-<p>PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。</p>
-<ul>
-<li>プロポーザルを出す</li>
-<li>PHPer チャレンジのトークン問題を 5題作成する</li>
-<li>現地に行く</li>
-<li>PHPer チャレンジで圧勝する</li>
-</ul>
-<hr>
-<p>最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。</p>
-<p>ではまた来年。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2022 トークン問題の解説</title>
- <link>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</link>
- <pubDate>Sat, 09 Apr 2022 21:50:19 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>本日開始された <a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> の PHPer チャレンジにおいて、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。</p>
-<p>リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</a></p>
-<h1 id="第1問-brainf_ckphp">第1問 brainf_ck.php</h1>
-<p>ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">declare</span>(<span style="color:#a6e22e">strict_types</span><span style="color:#f92672">=</span><span style="color:#ae81ff">0</span><span style="color:#a6e22e">O1</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> <span style="color:#a6e22e">Dgcircus\PHPerKaigi\Y2022</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">/**
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * @todo
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Run this program to acquire a PHPer token.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> */</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">\error_reporting</span>(<span style="color:#f92672">~+!</span><span style="color:#e6db74">&#39;We are hiring!&#39;</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$z <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($f) <span style="color:#f92672">=&gt;</span> (<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=&gt;</span> $x($x)(<span style="color:#f92672">...</span>$xs)))(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=&gt;</span> $x($x)(<span style="color:#f92672">...</span>$xs)));
-</span></span><span style="display:flex;"><span>$id <span style="color:#f92672">=</span> <span style="color:#a6e22e">\spl_object_id</span>(<span style="color:#f92672">...</span>);
-</span></span><span style="display:flex;"><span>$put <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($c) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">\printf</span>(<span style="color:#e6db74">&#39;%c&#39;</span>, $c);
-</span></span><span style="display:flex;"><span>$mm <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\ArrayObject</span>(<span style="color:#a6e22e">\array_fill</span>(<span style="color:#f92672">+!!</span>[], $n, $p));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$👉 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [<span style="color:#f92672">++</span>$mp, <span style="color:#f92672">++</span>$pc];
-</span></span><span style="display:flex;"><span>$👈 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [<span style="color:#f92672">--</span>$mp, <span style="color:#f92672">++</span>$pc];
-</span></span><span style="display:flex;"><span>$👍 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$m[$mp]];
-</span></span><span style="display:flex;"><span>$👎 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$m[$mp]];
-</span></span><span style="display:flex;"><span>$📝 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, $put($m[$mp])];
-</span></span><span style="display:flex;"><span>$🤡 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($m[$mp]) {
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=&gt;</span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) {
-</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$n),
-</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=&gt;</span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> <span style="color:#f92672">++</span>$pc <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$n),
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">++</span>$pc, $n),
-</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])],
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc],
-</span></span><span style="display:flex;"><span>};
-</span></span><span style="display:flex;"><span>$🎪 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($m[$mp]) {
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc],
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) {
-</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">++</span>$n),
-</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=&gt;</span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> $pc<span style="color:#f92672">+!</span>[] <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">--</span>$n),
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">--</span>$pc, $n),
-</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])],
-</span></span><span style="display:flex;"><span>};
-</span></span><span style="display:flex;"><span>$🐘 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p) <span style="color:#f92672">=&gt;</span> $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">isset</span>($p[$pc]) <span style="color:#f92672">&amp;&amp;</span> $loop($m, $p, $b, $e, <span style="color:#f92672">...</span>($p[$pc]($m, $p, $b, $e, $mp, $pc)))
-</span></span><span style="display:flex;"><span>)($mm(<span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.!</span>[])), $p, $id($🤡), $id($🎪), <span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+!!</span>[]);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$🐘([
-</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $🤡,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👈, $👈, $👈, $👈, $👎,
-</span></span><span style="display:flex;"><span> $🎪,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👉, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👈, $👎, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span>]);
-</span></span></code></pre></div><p>この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。</p>
-<h2 id="解説">解説</h2>
-<h3 id="絵文字">絵文字</h3>
-<p>まず目につくのは大量の絵文字だろう。
-PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。</p>
-<h3 id="プログラム全体">プログラム全体</h3>
-<p>Brainf*ck のインタプリタとプログラムになっている。
-Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。</p>
-<p><a href="https://ja.wikipedia.org/wiki/Brainfuck">https://ja.wikipedia.org/wiki/Brainfuck</a></p>
-<p>なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。</p>
-<pre tabindex="0"><code>+ + + + + + + + + +
-[
- &gt; + + +
- &gt; + + + + +
- &gt; + + + + + + + + + + + +
- &gt; + + + + + + + + + +
- &lt; &lt; &lt; &lt; -
-]
-&gt; + + + + + .
-- - .
-&gt; - - - .
-&gt; - - - .
-- - .
-- .
-&lt; .
-&gt; &gt; - - .
-+ + + + + + + .
-&lt; - - - - .
-&lt; .
-&gt; + + .
-&gt; - .
-&lt; .
-</code></pre><p>実行結果はこちら: <a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a></p>
-<p>それぞれの絵文字で表された関数が、各命令に対応している。</p>
-<ul>
-<li><code>$👉</code>: <code>&gt;</code></li>
-<li><code>$👈</code>: <code>&lt;</code></li>
-<li><code>$👍</code>: <code>+</code></li>
-<li><code>$👎</code>: <code>-</code></li>
-<li><code>$📝</code>: <code>.</code></li>
-<li><code>$🤡</code>: <code>[</code></li>
-<li><code>$🎪</code>: <code>]</code></li>
-</ul>
-<p><code>,</code> (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。</p>
-<p>なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。</p>
-<h3 id="絵文字の選択">絵文字の選択</h3>
-<p>おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> は弊社デジタルサーカスにちなんでいる。
-また、<code>$🐘</code> は PHP のマスコットの象に由来する。</p>
-<h3 id="strict_types">strict_types</h3>
-<p><code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code> の数値リテラルだが、
-<code>0x0</code> や <code>0b1</code> のような値も受け付ける。
-今回は、PHP 8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。</p>
-<h3 id="url">URL</h3>
-<p>ソースコードのライセンスを示したこの部分だが、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span>
-</span></span></code></pre></div><p>完全に合法な PHP のコードである。
-<code>https:</code> 部分はラベル、<code>//</code> 以降は行コメントになっている。</p>
-<h3 id="リテラルなしで数値を生成する">リテラルなしで数値を生成する</h3>
-<p>ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。
-PHP では、型変換を利用することで任意の整数を作り出すことができる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">1</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">2</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">3</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]<span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">10</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.+!!</span>[]));
-</span></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 が作れる)。</p>
-<p>また、<code>error_reporting</code> に指定しているのは <code>-1</code> である。
-これは、<code>!</code> によって文字列を <code>false</code> にし、<code>+</code> によって <code>false</code> を <code>0</code> にし、さらにビット反転して <code>-1</code> にしている。</p>
-<h3 id="if-文なしで条件分岐"><code>if</code> 文なしで条件分岐</h3>
-<p>三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> を一切書かずに条件分岐ができる。
-また、<code>&amp;&amp;</code> / <code>||</code> も使えることがある。
-遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> のような形で分岐することもできる。</p>
-<h3 id="whilefor-文なしでループ"><code>while</code>、<code>for</code> 文なしでループ</h3>
-<p>不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。
-ここでは、一般に Z コンビネータとして知られるものを使った (<code>$z</code>)。</p>
-<p>実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。</p>
-<p>なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、
-あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。</p>
-<h1 id="第2問-riddlephp">第2問 riddle.php</h1>
-<p>ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">/*********************************************************
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * This program displays a PHPer token. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Guess &#39;N&#39;. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Hints: *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - N itself has no special meaning, e.g., 42, 8128, *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * it is selected at random. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Each element of $token represents a single letter. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - One letter consists of 5x5 cells. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Remember, the output is a complete PHPer token. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * License: *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * https://creativecommons.org/publicdomain/zero/1.0/ *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> *********************************************************/</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">N</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e">/* Change it to your answer. */</span>;
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x14B499C</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0BE34CC</span>, <span style="color:#ae81ff">0x01C9C69</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0ECA069</span>, <span style="color:#ae81ff">0x01C2449</span>, <span style="color:#ae81ff">0x0FDB166</span>, <span style="color:#ae81ff">0x01C9C69</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x01C1C66</span>, <span style="color:#ae81ff">0x0FC1C47</span>, <span style="color:#ae81ff">0x01C1C66</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x10C5858</span>, <span style="color:#ae81ff">0x1E4E3B8</span>, <span style="color:#ae81ff">0x1A2F2F8</span>,
-</span></span><span style="display:flex;"><span>];
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($token <span style="color:#66d9ef">as</span> $x) {
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{</span>$x<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。
-トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。</p>
-<p>ここでは、私の想定解を解説する。</p>
-<h2 id="読解">読解</h2>
-<p>まずはソースコードを読んでいく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 略
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>];
-</span></span></code></pre></div><p>数値からなる <code>$token</code> があり、各要素をループしている。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span></code></pre></div><p>まずは排他的論理和 (xor) を取り、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span></code></pre></div><p>二進数に変換して、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span></code></pre></div><p>0 を空白に、1 を <code>#</code> にし、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span></code></pre></div><p>5文字ごとに区切ったあと、改行で結合している。</p>
-<h2 id="ヒント">ヒント</h2>
-<p>次に、ソースコードに書いてあるヒントを読んでいく。</p>
-<ul>
-<li><code>N</code> それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている</li>
-<li><code>$token</code> の各要素は、1文字を表す</li>
-<li>1文字は 5x5 のセルからなる</li>
-<li>出力されるのは、完全な PHPer トークンである</li>
-</ul>
-<p>ここで、PHPer トークンは必ず <code>#</code> 記号から始まることを思いだすと、
-<code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code>#</code> になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。</p>
-<h2 id="解く">解く</h2>
-<p>ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> に変換されるような <code>N</code> を見つければよい。</p>
-<p><code>N</code> は高々</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>);
-</span></span></code></pre></div><p>なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0x14B499C</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>($x <span style="color:#f92672">===</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # &#34;</span>);
-</span></span></code></pre></div><p>この一連の変換に対する逆変換を考えると、次のようになる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # &#34;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;&#39;</span>, <span style="color:#a6e22e">explode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, $x));
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">bindec</span>($x);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#ae81ff">0x14B499C</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;N = </span><span style="color:#e6db74">$n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>これを実行すると、<code>N</code> が得られる。</p>
-<h1 id="第3問-toquinephp">第3問 toquine.php</h1>
-<p>ソースコードはこちら。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// License: https://creativecommons.org/publicdomain/zero/1.0/
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// This is a quine-like program to generate a PHPer token.
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Execute it like this: php toquine.php | php | php | php | ...
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#e6db74">&lt;&lt;&lt;&#39;</span><span style="color:#e6db74">Q</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&lt;?cuc
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ...
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f$f = %f;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$f = fge_ebg13($f); $kf = [
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f,
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">];
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g = ahyy.snyfr; sbe ($v = 0; $v &lt;= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g .= vzcybqr(&#34;\a&#34;, fge_fcyvg(fge_ercynpr([&#39;0&#39;,&#39;1&#39;], [&#39; &#39;,&#39;##&#39;], fcevags(pue(37) . &#39;025o&#39;, $kf[$v])), 012)) . &#34;\a\a&#34;;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$jf = neenl_znc(sa($j) =&gt; vzcybqr(&#39;, &#39;, $j), neenl_puhax(neenl_znc(sa($k) =&gt; fcevags(&#39;0k&#39; . pue(37) . &#39;07K&#39;, $k), $kf), 10));
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">cevags($f, $g, fge_ebg13(&#34;&lt;&lt;&lt;&#39;Q&#39;\a{$f}\aQ&#34;), vzcybqr(&#34;,\a&#34;, $jf));
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#e6db74">Q</span>;
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_rot13</span>($s); $xs <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x0AFABEA</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x0002800</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x0117041</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F295B7</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1151151</span>, <span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1F8C63F</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x1F8C631</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x1F8C63F</span>, <span style="color:#ae81ff">0x1F295B7</span>,
-</span></span><span style="display:flex;"><span>];
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">.</span><span style="color:#66d9ef">false</span>; <span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">intdiv</span>(<span style="color:#66d9ef">__LINE__</span><span style="color:#f92672">-</span><span style="color:#ae81ff">035</span>,<span style="color:#ae81ff">6</span>); <span style="color:#f92672">++</span>$i) <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">isset</span>($xs[$i])) <span style="color:#66d9ef">break</span>; <span style="color:#66d9ef">else</span>
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">.=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>(<span style="color:#a6e22e">str_replace</span>([<span style="color:#e6db74">&#39;0&#39;</span>,<span style="color:#e6db74">&#39;1&#39;</span>], [<span style="color:#e6db74">&#39; &#39;</span>,<span style="color:#e6db74">&#39;##&#39;</span>], <span style="color:#a6e22e">sprintf</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;025b&#39;</span>, $xs[$i])), <span style="color:#ae81ff">012</span>)) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>$ws <span style="color:#f92672">=</span> <span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($w) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>, $w), <span style="color:#a6e22e">array_chunk</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;0x&#39;</span> <span style="color:#f92672">.</span> <span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;07X&#39;</span>, $x), $xs), <span style="color:#ae81ff">10</span>));
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>($s, $t, <span style="color:#a6e22e">str_rot13</span>(<span style="color:#e6db74">&#34;&lt;&lt;&lt;&#39;D&#39;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">{</span>$s<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">D&#34;</span>), <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;,</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, $ws));
-</span></span></code></pre></div><p>コメントにもあるとおり、次のようにして実行すれば答えがでてくる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php toquine.php | php | php | php | ...
-</span></span></code></pre></div><p>実際にはもう少しパイプで繋げなければならない。</p>
-<h2 id="解説-1">解説</h2>
-<h3 id="プログラム全体-1">プログラム全体</h3>
-<p>コメントにもあるとおり、これは quine (風) のプログラムになっている。
-Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。</p>
-<p>このプログラムは、実行すると自身とほとんど同じプログラムを出力する。
-異なるのはトークンになっている部分のみである。</p>
-<h3 id="トークン">トークン</h3>
-<p><code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。</p>
-<h3 id="状態保持">状態保持</h3>
-<p>トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。
-このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code>__LINE__</code> から情報を取得している。</p>
-<h3 id="rot-13">ROT 13</h3>
-<p>Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。
-これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 変換を使って難読化した。</p>
-<p>それにしてもなぜこんなものが標準ライブラリに……。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。</p>
-<p>今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、
-来年は 5問、より面白い問題を持っていきます。</p>
-<p>実はもう作りはじめているので、どうか来年もありますように……。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2021</title>
- <link>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</link>
- <pubDate>Tue, 30 Mar 2021 23:22:40 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</guid>
- <description><![CDATA[ <h1 id="phperkaigi-2021-参加レポ">PHPerKaigi 2021 参加レポ</h1>
-<p>2021-03-26 から 2021-03-28 にかけて開催された、<a href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</a> に一般参加者として参加した。
-弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
-<p>このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。</p>
-<p>発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。</p>
-<h2 id="凡例">凡例</h2>
-<blockquote>
-<p>発表・スライドのメモ (引用ではない)</p>
-</blockquote>
-<p>感想など</p>
-<h2 id="day-0-前夜祭-20210327">Day 0 前夜祭 (2021/03/27)</h2>
-<h3 id="1730-a">17:30 [A]</h3>
-<p>PHP で AWS Lambda</p>
-<blockquote>
-<p>Rails のプロジェクトを PHPer のメンバのみでメンテ
-→他のメンバもわかる PHP にリプレースを検討</p>
-<p>サーバレス</p>
-<ul>
-<li>サーバ・インフラの管理が不要</li>
-<li>アプリケーションコードの知識だけで保守可能</li>
-</ul>
-<p>ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入?</p>
-<p>AWSの学習
-AWS のドキュメント
-DevelopersIO</p>
-<p>AWS Lambda のカスタムランタイムで PHP を動かす</p>
-<p>サーバのセットアップや維持管理を気にしなくて良い
-サーバーレスで PHP を動かすツールがすでにある
-サーバーレス構築はすんなり</p>
-<p>今は Laravel がルーティングしている
-Laravel Livewire を Lambda に載せられないか?
-デプロイ方法は?
-バッチ処理は? (Lambda は 15分の制限)</p>
-<p>Lambda でコンテナイメージがサポートされるように</p>
-<p>抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる</p>
-</blockquote>
-<p>AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。</p>
-<p>PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。</p>
-<p>勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。</p>
-<h3 id="1810-a">18:10 [A]</h3>
-<p>大規模サイトの SEO</p>
-<blockquote>
-<p>大規模サイト (100万ページ以上)
-Google の基準</p>
-<p>クロールバジェットを意識したSEO</p>
-<p>大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される
-これを満たさないなら、クロールバジェットを考えなくてもいい</p>
-<p>サーチコンソール
-「カバレッジ」の「除外」
-多すぎるのは問題→クロールバジェットを浪費している</p>
-<ul>
-<li>クエリの順番を決める</li>
-<li>空の値のルールを決めておく</li>
-<li>リダイレクトすればインデックスはうまくいく</li>
-<li>リンクが存在する限りクロールはされる</li>
-</ul>
-<p>リニューアル前のURL</p>
-<p>インデックスは移行される
-リンクのURLが存在する限り、別のURLとしてクロールされる
-リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い
-リニューアルで無視されるようになったパラメータも注意</p>
-<p>robotes.txt で拒否しているのにクロールされる
-一時的に拒否を外して 404 や 301 を読ませる
-内部リンクを確認する
-JS でのリンクに書き換え</p>
-<p>クエリパラメータからURLのパスに
-<code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code></p>
-<p>URL 設計だいじ</p>
-</blockquote>
-<p>SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。</p>
-<h3 id="1850-a">18:50 [A]</h3>
-<blockquote>
-<p>知覚可能
-操作可能
-理解可能
-堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など)</p>
-<ul>
-<li>
-<p>標準の HTML を適切に使う</p>
-</li>
-<li>
-<p>WAI-ARIA</p>
-</li>
-<li>
-<p>キーボードフレンドリー</p>
-</li>
-<li>
-<p>マシンフレンドリー</p>
-</li>
-<li>
-<p>SEOフレンドリー</p>
-</li>
-</ul>
-<p>button タグ
-→キーボード
-h1 タグ
-→スクリーンリーダー・クローラ
-a タグ</p>
-<p>WAI-ARIA
-HTML では表現できないセマンティクスを追加する</p>
-<ul>
-<li>ロール
-<ul>
-<li>何をするのか?</li>
-<li>ユーザーアクションによって変化しない</li>
-</ul>
-</li>
-<li>プロパティ
-<ul>
-<li>関連づけられたデータ</li>
-</ul>
-</li>
-<li>ステート
-<ul>
-<li>現在の状態</li>
-</ul>
-</li>
-</ul>
-<p>まずは標準の HTML 要素で解決する
-何でもかんでも WAI-ARIA を使えばいいというものではない</p>
-<p>マウスホバーでツールチップが出てくるが、キーボード操作では出てこない</p>
-<p>VoiceOver</p>
-<p>全ての属性を使う必要はない
-あくまでアクセシビリティを上げるための方法の一つにすぎない</p>
-</blockquote>
-<p>つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。</p>
-<h3 id="1930-a">19:30 [A]</h3>
-<p>PHP で FUSE</p>
-<p>個人的に楽しみだった発表。</p>
-<blockquote>
-<p>VFS (virtual filesystem) vs 具体的なファイルシステム</p>
-<p>最適な実装方法は状況により異なる</p>
-<p>アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS</p>
-<p>カーネルのプログラムを作るのは難しい</p>
-<ul>
-<li>権限がデカすぎる</li>
-<li>システム全体がクラッシュ</li>
-<li>セキュリティリスク</li>
-<li>開発サイクルを回しづらい</li>
-<li>ネイティブコードにコンパイルされる言語である必要がある</li>
-</ul>
-<p>Filesystem in USEr space (FUSE)</p>
-<ul>
-<li>特定の C の関数を呼ぶことで filesystem が作れる</li>
-<li>FFI を持つ言語なら FUSE が使える</li>
-</ul>
-<p>SSHFS / s3fs / Docker Desktop</p>
-<p>Linux 以外でも使える</p>
-<ul>
-<li>dokany (on Windows)</li>
-<li>osxfuse</li>
-</ul>
-<p>VFS: システムコールが呼ばれると、ファイルシステムによってコール
-FUSE: カーネル空間からユーザ空間へ通信</p>
-<p>高レベルなラッパで型をつける</p>
-<p>PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)</p>
-<ul>
-<li>grep できる</li>
-<li>sed できる</li>
-<li>編集できる</li>
-</ul>
-</blockquote>
-<p>期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。
-この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。</p>
-<h2 id="day-1-20210327">Day 1 (2021/03/27)</h2>
-<h3 id="1050-a">10:50 [A]</h3>
-<p>ATDD</p>
-<blockquote>
-<ul>
-<li>ユーザーストーリー</li>
-<li>ユニットテスト</li>
-<li>CI/CD</li>
-</ul>
-<p>ユーザストーリーの受け入れ条件が曖昧になりがち
-デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている</p>
-<p>Q2の強化
-アジャイルテストの4象限</p>
-<p>技術面/ビジネス面
-開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)</p>
-<ul>
-<li>Q1: 技術面 &amp; チーム支援
-<ul>
-<li>TDD</li>
-<li>ユニットテストなど</li>
-</ul>
-</li>
-<li>Q2: ビジネス面 &amp; チーム支援
-<ul>
-<li>ATDD</li>
-<li>ビジネス面の受け入れテストで駆動する</li>
-</ul>
-</li>
-</ul>
-<p>Agile Alliance
-ユーザストーリーのスキルレベルを高める</p>
-<p>テストピラミッド</p>
-<ul>
-<li>
-<p>UI Tests</p>
-</li>
-<li>
-<p>Service Tests</p>
-</li>
-<li>
-<p>Unit Tests</p>
-</li>
-<li>
-<p>異なる粒度のテストを書く</p>
-</li>
-<li>
-<p>高レベルになるほど、持つべきテストは少なくなる</p>
-<ul>
-<li>ピラミッド型になる</li>
-</ul>
-</li>
-</ul>
-<p>高レベルテストが多すぎる→アイスクリームコーン アンチパターン</p>
-<p>ATDD (Acceptance TDD)
-API経由・UI経由での高レベルテスト E2E test</p>
-<p>ストーリ受け入れテスト</p>
-<p>入れ子のフィードバックループ
-ATDD(外側) と TDD(内側)</p>
-<p>外部品質・内部品質</p>
-<p>バーティカルスライスのデリバリー</p>
-<ul>
-<li>cucumber</li>
-<li>gauge</li>
-<li>behat</li>
-</ul>
-<p>ユビキタス言語
-手動テストもspecに書く
-自動化は可能だがコスパが悪い
-失敗することがわかっているテスト(レッドテスト)はCIから外す
-失敗時の原因究明が難しい
-饒舌なエラーメッセージ
-状況のスナップショット</p>
-<p>Continuous Testing</p>
-</blockquote>
-<p>User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。
-高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。</p>
-<h3 id="1150-a">11:50 [A]</h3>
-<p>型解析を用いたリファクタリング</p>
-<p>型のある世界で生きてきた身として大いに楽しみにしていた発表。</p>
-<blockquote>
-<ul>
-<li>PHPStan</li>
-<li>Phan</li>
-<li>Psalm</li>
-</ul>
-<p>autoload も認識できる
-bootstrapFiles</p>
-<p>編集箇所と利用箇所を CI でチェック
-ルールレベルを徐々に引き上げていく
-警告が多すぎると見落としてしまう・無視されやすくなる</p>
-<p>型がついていないことによるエラーが多い</p>
-<p>型よりも詳細な検査 <code>Util_Assert::min</code></p>
-<p>SQL を静的解析
-placeholder の型付け</p>
-<p>警告レベルを低いレベルから導入
-タイプヒントを積極的に書いていく
-PHPStan の拡張を追加する</p>
-</blockquote>
-<p>昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。
-今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。</p>
-<h3 id="1230-a">12:30 [A]</h3>
-<p>昼食をとっていた。事前に何か食料を買っておくべきだった。</p>
-<h3 id="1310-a">13:10 [A]</h3>
-<p>Documentation as Code</p>
-<p>この発表も以前から非常に楽しみにしていた。</p>
-<blockquote>
-<p>開発開始までのオーバーヘッド
-新規にチームにジョイン
-担当範囲外の機能を理解
-オンボーディングのコスト</p>
-<p>PHPerKaigi 2020 で発表あり</p>
-<p>継続的にシステムの理解を助けるドキュメント</p>
-<p>継続的ドキュメンテーション
-システムとドキュメントの乖離</p>
-<p>書いてあることが間違っている・足りない</p>
-<ul>
-<li>徐々にずれていく</li>
-<li>システムの更新タイミングとドキュメントの更新タイミングに差がある</li>
-</ul>
-<p>システムとドキュメントは対応関係がある</p>
-<ul>
-<li>間違ったドキュメント</li>
-<li>存在しないドキュメント</li>
-</ul>
-<p>システムとドキュメントの乖離を定量化する
-継続的に
-システムの更新に近いタイミングで ドキュメントを更新し続ける</p>
-<p>Documentation as Code</p>
-<p>コードと同じツールでドキュメントを書く</p>
-<ul>
-<li>issue tracker</li>
-<li>vcs</li>
-<li>plain text markup</li>
-<li>automation</li>
-</ul>
-<p>開発者
-システム
-ドキュメント
-構造化データ
-ソフトウェア</p>
-<p>システムから構造化データを抽出する
-PHPDoc
-OpenAPI</p>
-<p>ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する</p>
-<p>ビューの単位でドキュメントに</p>
-<p>スタックトレースからのドキュメント生成</p>
-</blockquote>
-<p>ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。</p>
-<h3 id="1410-a">14:10 [A]</h3>
-<p>cookie による session 管理</p>
-<p>全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。</p>
-<h3 id="1450-a">14:50 [A]</h3>
-<p>PHP のエラーと例外</p>
-<blockquote>
-<p>エラー PHPエンジンがエラーを通知する
-例外 プログラムが投げる</p>
-<p>PHP7-8とエラー</p>
-<p>PHPエンジンのエラーの一部が \Error に変換されるようになった
-→ try-catch で捕捉できる</p>
-<p>\Error は例外とは異なる</p>
-<p>PHP8 でエラーレベルの引き上げ</p>
-<ul>
-<li>捕捉すべきもの
-<ul>
-<li>recoverable</li>
-</ul>
-</li>
-<li>捕捉すべきでないもの
-<ul>
-<li>unrecoverable</li>
-<li>開発時に対処できるもの</li>
-</ul>
-</li>
-</ul>
-<p>例外</p>
-<ul>
-<li>捕捉して事後処理</li>
-<li>捕捉せず(or 捕捉した上で)さらに上に是非を問う</li>
-</ul>
-<p>開発段階で例外を把握し、ハンドリングを考えておく</p>
-<p>\Throwable \Exception と \Error</p>
-<p>\Error はキャッチすべきでない</p>
-<ul>
-<li>
-<p>\Error</p>
-<ul>
-<li>本番で起きてはいけない</li>
-</ul>
-</li>
-<li>
-<p>\LogicException</p>
-<ul>
-<li>本番で起きてはいけない
-→生じないのだから捕捉もしない</li>
-</ul>
-</li>
-<li>
-<p>\RuntimeException</p>
-<ul>
-<li>起こるかもしれないので本番環境でも考慮する</li>
-</ul>
-</li>
-</ul>
-<p>捕捉して対応するのではなく、未然に防ぐ</p>
-<p>独自例外を使う
-\Exception を投げてしまうと、
-catch (\Exception)せざるを得ない
-→catch 範囲が広すぎる</p>
-<p>SPL の例外を使う</p>
-<p>例外翻訳
-上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する
-下位レイヤの知識に依存させない</p>
-<p>@throws
-捕捉してほしい例外を書き連ねておく</p>
-<p>呼び出しもとに負わせたい責任</p>
-</blockquote>
-<p>PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。</p>
-<p>個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。</p>
-<p>PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。</p>
-<h3 id="1530-a">15:30 [A]</h3>
-<p>Laravel のメール認証</p>
-<p>Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。</p>
-<h3 id="1610-a">16:10 [A]</h3>
-<p>gRPC</p>
-<blockquote>
-<p>Unary RPCs
-Server streaming RPCs
-Client streaming RPCs
-Bidirectional streaming RPCs</p>
-<p>Protobuf</p>
-<p>実装とAPIが乖離しにくい
-自動生成
-複数言語でも相互に使える</p>
-<p>マイクロサービスのサービス通信
-スマホアプリ
-ゲームサーバ</p>
-<p>PHP では?</p>
-<p>PHP ではストリーミングが難しい
-リクエストごとにプロセスが使い捨て</p>
-<p>PHP ではgRPCのクライアントしか対応していない</p>
-<p>gRPC-Web
-ブラウザで扱うためのJSライブラリ+プロトコル</p>
-<p>HTTP/1.1 でも使える
-Unary RPC と Server streaming RPC のみ</p>
-<p>Envoy
-Nginx などで相互に gRPC と gRPC-Web で変換</p>
-<p>Amp
-イベント駆動な並行処理のフレームワーク</p>
-<p>HTTP/2 対応</p>
-<p>C#のgRPC-Webが楽</p>
-</blockquote>
-<p>(発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。</p>
-<h3 id="1650-a">16:50 [A]</h3>
-<p>アーキテクチャテスト</p>
-<blockquote>
-<p>Independent Core Layer Pattern</p>
-<p>開発初期のアーキテクチャが崩れる
-アーキテクチャ観点のコードレビューができない</p>
-<p>どこにクラスを置けばよいか?
-ドキュメントがない</p>
-<p>アーキテクチャ設計に関する知識が属人化・暗黙知化</p>
-<p>ガイドライン</p>
-<ul>
-<li>最初にルールを決めるのは簡単</li>
-<li>ルール通り作り始めるのも簡単
-<ul>
-<li>→維持するのが難しい、人が決めたものゆえ壊れやすい</li>
-</ul>
-</li>
-</ul>
-<p>PHP の特性</p>
-<ul>
-<li>クラスは public</li>
-<li>可視性の制御が public / protected / private のみ</li>
-<li>依存関係の制御が困難</li>
-</ul>
-<p>アーキテクチャテスト
-クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する</p>
-<ul>
-<li>deptrac</li>
-<li>phpat</li>
-</ul>
-<p>Independent Core Layer Pattern</p>
-<p>アーキテクチャテストの失敗</p>
-<ul>
-<li>実装誤り</li>
-<li>or アーキテクチャが適切でない
-<ul>
-<li>開発の過程でフィードバックしていく</li>
-</ul>
-</li>
-</ul>
-<p>モジュラーモノリス→マイクロサービスへ</p>
-</blockquote>
-<h2 id="day-2-20210328">Day 2 (2021/03/28)</h2>
-<p>冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。</p>
-<p>残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。</p>
-<h2 id="全体の感想">全体の感想</h2>
-<p>Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。</p>
-<p>今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。</p>
-<p>1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。
-まあ初カンファレンスだし、とお茶を濁しておこう。</p>
-<p>さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。</p>
-<hr>
-<p>最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました!
-(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)</p>
-<p>ではまた来年。</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/conference/index.html b/docs/tags/conference/index.html
deleted file mode 100644
index 40c8675..0000000
--- a/docs/tags/conference/index.html
+++ /dev/null
@@ -1,92 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>conference | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/conference/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>conference</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2>
- </header>
- <section class="entry-content">
- <p>PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-08-27</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2022</h2>
- </header>
- <section class="entry-content">
- <p>2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-05-01</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2022 トークン問題の解説</h2>
- </header>
- <section class="entry-content">
- <p>PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-04-09</time>, updated on <time>2022-04-16</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2021</h2>
- </header>
- <section class="entry-content">
- <p>2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-03-30</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/conference/page/1/index.html b/docs/tags/conference/page/1/index.html
deleted file mode 100644
index 740f29e..0000000
--- a/docs/tags/conference/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/conference/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/conference/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/conference/">
- </head>
-</html>
diff --git a/docs/tags/cpp/feed.xml b/docs/tags/cpp/feed.xml
deleted file mode 100644
index 435e2f9..0000000
--- a/docs/tags/cpp/feed.xml
+++ /dev/null
@@ -1,89 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>cpp on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/cpp/</link>
- <description>Recent content in cpp on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sat, 02 Oct 2021 09:38:30 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/cpp/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>[C&#43;&#43;] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</link>
- <pubDate>Sat, 02 Oct 2021 09:38:30 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</a></p>
-<hr>
-<p>タイトル落ち。まずはこのコードを見て欲しい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;iostream&gt;</span><span style="color:#75715e">
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// [[using]]
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">int</span> main() {
-</span></span><span style="display:flex;"><span> std<span style="color:#f92672">::</span>cout <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#34;Hello, World!&#34;</span> <span style="color:#f92672">&lt;&lt;</span> std<span style="color:#f92672">::</span>endl;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><blockquote>
-<p>コンパイラのバージョン
-$ clang++ &ndash;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</p>
-<p>コンパイルコマンド (C++17指定)
-$ clang++ &ndash;std=c++17 hoge.cpp</p>
-</blockquote>
-<p>この記事から得られるものはこれ以上ないので以下は蛇足になる。</p>
-<p>別件で cppreference.com の <a href="https://en.cppreference.com/w/cpp/language/identifiers">identifier のページ</a> を読んでいた時、次の文が目に止まった。</p>
-<blockquote>
-<ul>
-<li>the identifiers that are keywords cannot be used for other purposes;
-<ul>
-<li>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)</li>
-</ul>
-</li>
-</ul>
-</blockquote>
-<p>キーワードでも属性として指定する場合は非キーワードとして使えるらしい。
-実際にやってみる。</p>
-<p>同サイトの [keywords のページ] (<a href="https://en.cppreference.com/w/cpp/keyword">https://en.cppreference.com/w/cpp/keyword</a>) から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。
-大量の警告 (unknown attribute &lsquo;〇〇&rsquo; ignored) がコンパイラから出力されるが、コンパイルできる。</p>
-<p>上のコードでは <code>[[using]]</code> をコメントアウトしているが、これは <code>using</code> キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">// using の例
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]]</span> <span style="color:#960050;background-color:#1e0010">の糖衣構文</span>
-</span></span></code></pre></div><p>C++17 の仕様も見てみる (正確には標準化前のドラフト)。</p>
-<p>引用元: <a href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</a></p>
-<blockquote>
-<p>If a keyword or an alternative token that satisfies the syntactic requirements of an identifier is contained in an attribute-token, it is considered an identifier.</p>
-</blockquote>
-<p>「<code>identifier</code> の構文上の要件を満たすキーワードまたは代替トークンが <code>attribute-token</code> に含まれている場合、<code>identifier</code> とみなされる」とある。どうやら間違いないようだ。</p>
-<p>ところで、代替トークン (alternative token) とは <code>and</code> (<code>&amp;</code>) や <code>bitor</code> (<code>|</code>) などのことだが、<code>identifier</code> の構文上の要件を満たさないような代替トークンなどあるのか?
-疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい (参考: <a href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</a>)</p>
-<ul>
-<li><code>&lt;%</code> → <code>{</code></li>
-<li><code>%&gt;</code> → <code>}</code></li>
-<li><code>&lt;:</code> → <code>[</code></li>
-<li><code>:&gt;</code> → <code>]</code></li>
-<li><code>%:</code> → <code>#</code></li>
-<li><code>%:%:</code> → <code>##</code></li>
-</ul>
-<p>「<code>identifier</code> の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。</p>
-<p>調べた感想: 字句解析器か構文解析器が辛そう</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/cpp/index.html b/docs/tags/cpp/index.html
deleted file mode 100644
index 73b29b1..0000000
--- a/docs/tags/cpp/index.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>cpp | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/cpp/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>cpp</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>[C&#43;&#43;] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</h2>
- </header>
- <section class="entry-content">
- <p>C&#43;&#43; の属性構文の属性名には、キーワードが使える。ネタ記事。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/cpp/page/1/index.html b/docs/tags/cpp/page/1/index.html
deleted file mode 100644
index ee45690..0000000
--- a/docs/tags/cpp/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/cpp/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/cpp/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/cpp/">
- </head>
-</html>
diff --git a/docs/tags/cpp17/feed.xml b/docs/tags/cpp17/feed.xml
deleted file mode 100644
index b1be398..0000000
--- a/docs/tags/cpp17/feed.xml
+++ /dev/null
@@ -1,89 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>cpp17 on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/cpp17/</link>
- <description>Recent content in cpp17 on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sat, 02 Oct 2021 09:38:30 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/cpp17/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>[C&#43;&#43;] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</link>
- <pubDate>Sat, 02 Oct 2021 09:38:30 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</a></p>
-<hr>
-<p>タイトル落ち。まずはこのコードを見て欲しい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;iostream&gt;</span><span style="color:#75715e">
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]]</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// [[using]]
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">int</span> main() {
-</span></span><span style="display:flex;"><span> std<span style="color:#f92672">::</span>cout <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#34;Hello, World!&#34;</span> <span style="color:#f92672">&lt;&lt;</span> std<span style="color:#f92672">::</span>endl;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><blockquote>
-<p>コンパイラのバージョン
-$ clang++ &ndash;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</p>
-<p>コンパイルコマンド (C++17指定)
-$ clang++ &ndash;std=c++17 hoge.cpp</p>
-</blockquote>
-<p>この記事から得られるものはこれ以上ないので以下は蛇足になる。</p>
-<p>別件で cppreference.com の <a href="https://en.cppreference.com/w/cpp/language/identifiers">identifier のページ</a> を読んでいた時、次の文が目に止まった。</p>
-<blockquote>
-<ul>
-<li>the identifiers that are keywords cannot be used for other purposes;
-<ul>
-<li>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)</li>
-</ul>
-</li>
-</ul>
-</blockquote>
-<p>キーワードでも属性として指定する場合は非キーワードとして使えるらしい。
-実際にやってみる。</p>
-<p>同サイトの [keywords のページ] (<a href="https://en.cppreference.com/w/cpp/keyword">https://en.cppreference.com/w/cpp/keyword</a>) から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。
-大量の警告 (unknown attribute &lsquo;〇〇&rsquo; ignored) がコンパイラから出力されるが、コンパイルできる。</p>
-<p>上のコードでは <code>[[using]]</code> をコメントアウトしているが、これは <code>using</code> キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#75715e">// using の例
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]]</span> <span style="color:#960050;background-color:#1e0010">の糖衣構文</span>
-</span></span></code></pre></div><p>C++17 の仕様も見てみる (正確には標準化前のドラフト)。</p>
-<p>引用元: <a href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</a></p>
-<blockquote>
-<p>If a keyword or an alternative token that satisfies the syntactic requirements of an identifier is contained in an attribute-token, it is considered an identifier.</p>
-</blockquote>
-<p>「<code>identifier</code> の構文上の要件を満たすキーワードまたは代替トークンが <code>attribute-token</code> に含まれている場合、<code>identifier</code> とみなされる」とある。どうやら間違いないようだ。</p>
-<p>ところで、代替トークン (alternative token) とは <code>and</code> (<code>&amp;</code>) や <code>bitor</code> (<code>|</code>) などのことだが、<code>identifier</code> の構文上の要件を満たさないような代替トークンなどあるのか?
-疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい (参考: <a href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</a>)</p>
-<ul>
-<li><code>&lt;%</code> → <code>{</code></li>
-<li><code>%&gt;</code> → <code>}</code></li>
-<li><code>&lt;:</code> → <code>[</code></li>
-<li><code>:&gt;</code> → <code>]</code></li>
-<li><code>%:</code> → <code>#</code></li>
-<li><code>%:%:</code> → <code>##</code></li>
-</ul>
-<p>「<code>identifier</code> の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。</p>
-<p>調べた感想: 字句解析器か構文解析器が辛そう</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/cpp17/index.html b/docs/tags/cpp17/index.html
deleted file mode 100644
index 3dd9d68..0000000
--- a/docs/tags/cpp17/index.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>cpp17 | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/cpp17/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>cpp17</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>[C&#43;&#43;] 属性構文の属性名にはキーワードが使える [[void]] [[for]]</h2>
- </header>
- <section class="entry-content">
- <p>C&#43;&#43; の属性構文の属性名には、キーワードが使える。ネタ記事。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/cpp17/page/1/index.html b/docs/tags/cpp17/page/1/index.html
deleted file mode 100644
index 74e12d4..0000000
--- a/docs/tags/cpp17/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/cpp17/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/cpp17/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/cpp17/">
- </head>
-</html>
diff --git a/docs/tags/feed.xml b/docs/tags/feed.xml
deleted file mode 100644
index b2ed11e..0000000
--- a/docs/tags/feed.xml
+++ /dev/null
@@ -1,137 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>Tags on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/</link>
- <description>Recent content in Tags on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Fri, 28 Oct 2022 21:55:23 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>note-to-self</title>
- <link>https://blog.nsfisis.dev/tags/note-to-self/</link>
- <pubDate>Fri, 28 Oct 2022 21:55:23 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/note-to-self/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>php</title>
- <link>https://blog.nsfisis.dev/tags/php/</link>
- <pubDate>Sun, 23 Oct 2022 09:54:07 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/php/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>phperkaigi</title>
- <link>https://blog.nsfisis.dev/tags/phperkaigi/</link>
- <pubDate>Sun, 23 Oct 2022 09:54:07 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/phperkaigi/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>conference</title>
- <link>https://blog.nsfisis.dev/tags/conference/</link>
- <pubDate>Sat, 27 Aug 2022 18:55:28 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/conference/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>phpcon</title>
- <link>https://blog.nsfisis.dev/tags/phpcon/</link>
- <pubDate>Sat, 27 Aug 2022 18:55:28 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/phpcon/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>my-programs</title>
- <link>https://blog.nsfisis.dev/tags/my-programs/</link>
- <pubDate>Sun, 24 Apr 2022 13:22:52 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/my-programs/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>rust</title>
- <link>https://blog.nsfisis.dev/tags/rust/</link>
- <pubDate>Sat, 02 Oct 2021 09:39:27 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/rust/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>ruby</title>
- <link>https://blog.nsfisis.dev/tags/ruby/</link>
- <pubDate>Sat, 02 Oct 2021 09:38:50 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/ruby/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>ruby3</title>
- <link>https://blog.nsfisis.dev/tags/ruby3/</link>
- <pubDate>Sat, 02 Oct 2021 09:38:50 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/ruby3/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>cpp</title>
- <link>https://blog.nsfisis.dev/tags/cpp/</link>
- <pubDate>Sat, 02 Oct 2021 09:38:30 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/cpp/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>cpp17</title>
- <link>https://blog.nsfisis.dev/tags/cpp17/</link>
- <pubDate>Sat, 02 Oct 2021 09:38:30 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/cpp17/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>vim</title>
- <link>https://blog.nsfisis.dev/tags/vim/</link>
- <pubDate>Sat, 02 Oct 2021 09:37:25 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/vim/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>python</title>
- <link>https://blog.nsfisis.dev/tags/python/</link>
- <pubDate>Sat, 02 Oct 2021 09:32:37 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/python/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- <item>
- <title>python3</title>
- <link>https://blog.nsfisis.dev/tags/python3/</link>
- <pubDate>Sat, 02 Oct 2021 09:32:37 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/tags/python3/</guid>
- <description><![CDATA[ ]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/index.html b/docs/tags/index.html
deleted file mode 100644
index 79ef62b..0000000
--- a/docs/tags/index.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>Tags | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>Tags</h1></header>
-</main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/my-programs/feed.xml b/docs/tags/my-programs/feed.xml
deleted file mode 100644
index 34cd4bb..0000000
--- a/docs/tags/my-programs/feed.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>my-programs on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/my-programs/</link>
- <description>Recent content in my-programs on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sun, 24 Apr 2022 13:22:52 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/my-programs/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>term-banner: ターミナルにバナーを表示するツールを書いた</title>
- <link>https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/</link>
- <pubDate>Sun, 24 Apr 2022 13:22:52 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>こんなものを作った。</p>
-<pre tabindex="0"><code>$ term-banner &#39;Hello, World!&#39; &#39;こんにちは、&#39; &#39;世界!&#39;
-</code></pre><p><img src="https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png" alt="term-banner のスクリーンショット"></p>
-<p>コマンドライン引数として渡した文字列をターミナルに大きく表示する。</p>
-<p>リポジトリはこちら: <a href="https://github.com/nsfisis/term-banner">https://github.com/nsfisis/term-banner</a></p>
-<h1 id="motivation">Motivation</h1>
-<p>以前、<a href="https://github.com/nsfisis/big-clock-mode">big-clock-mode</a> という似たようなプログラムを書いた。
-これは tmux の <code>:clock-mode</code> コマンドに着想を得たもので、<code>:clock-mode</code> よりも大きく現在時刻を表示する。</p>
-<p><code>big-clock-mode</code> を開発したのは、次のようなシチュエーションで使うためである。
-弊社では現在リモートワークが基本だが、web 会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。
-こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。</p>
-<p>それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。</p>
-<p>しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。
-どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。</p>
-<p>そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。
-まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。</p>
-<h1 id="プログラム">プログラム</h1>
-<p>全体の流れは次のようになっている。</p>
-<ol>
-<li>フォントファイルを読み込む</li>
-<li>コマンドライン引数を Shift-JIS に変換する (フォントが Shift-JIS 基準で並んでいるため)</li>
-<li>1文字ずつレンダリングしていく</li>
-</ol>
-<p><code>big-clock-mode</code> が Go 製なので、今回も Go で書いた。
-PNG が標準ライブラリにあったり、Shift-JIS のエンコーディングが準標準ライブラリにあったりしたのは助かった。</p>
-<p>フォントファイルは <code>go:embed</code> で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。
-仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。</p>
-<h1 id="フォント">フォント</h1>
-<p>フリーの 8x8 ビットマップフォントである、<a href="https://littlelimit.net/misaki.htm">美咲フォント 2021-05-05a 版</a> を使わせていただいた。</p>
-<p>はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。
-同じく 8x8 で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。</p>
-<p>美咲フォントは、平仮名・片仮名に留まらず、JIS 第一・第二水準の漢字までサポートしている。
-第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。</p>
-<p>さらに言うと、実のところ美咲フォントは実サイズ 7x7 で作られており、余白が設けられている。
-これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。
-おかげでコーディングまで楽になった。</p>
-<p>ゴシック体と明朝体があったが、私の好みで明朝体の方にした。
-ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。</p>
-<p>2022-04-27 追記: <code>-f</code> オプションで選べるようにした。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>あなたもターミナルに住んでみませんか?</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/my-programs/index.html b/docs/tags/my-programs/index.html
deleted file mode 100644
index bc71599..0000000
--- a/docs/tags/my-programs/index.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>my-programs | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/my-programs/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>my-programs</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>term-banner: ターミナルにバナーを表示するツールを書いた</h2>
- </header>
- <section class="entry-content">
- <p>ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-04-24</time>, updated on <time>2022-04-27</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/my-programs/page/1/index.html b/docs/tags/my-programs/page/1/index.html
deleted file mode 100644
index 36f7d78..0000000
--- a/docs/tags/my-programs/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/my-programs/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/my-programs/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/my-programs/">
- </head>
-</html>
diff --git a/docs/tags/note-to-self/feed.xml b/docs/tags/note-to-self/feed.xml
deleted file mode 100644
index 2a8f961..0000000
--- a/docs/tags/note-to-self/feed.xml
+++ /dev/null
@@ -1,123 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>note-to-self on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/note-to-self/</link>
- <description>Recent content in note-to-self on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Fri, 28 Oct 2022 21:55:23 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/note-to-self/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>[備忘録] このサイト用の VPS をセットアップしたときのメモ</title>
- <link>https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/</link>
- <pubDate>Fri, 28 Oct 2022 21:55:23 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS に移行した。そのときにおこなったサーバのセットアップ作業を書き残しておく。99 % 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。</p>
-<p>未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。</p>
-<h1 id="vps">VPS</h1>
-<p><a href="https://vps.sakura.ad.jp/">さくらの VPS</a> の 2 GB プラン。そこまで真面目に選定していないので、困ったら移動するかも。</p>
-<h1 id="事前準備">事前準備</h1>
-<h2 id="サーバのホスト名を決める">サーバのホスト名を決める</h2>
-<p>モチベーションが上がるという効能がある。今回は藤原定家から取って &ldquo;teika&rdquo; にした。たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。</p>
-<h2 id="ssh-の鍵生成">SSH の鍵生成</h2>
-<p>ローカルマシンで鍵を生成する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/teika.key
-</span></span><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/github2teika.key
-</span></span></code></pre></div><p><code>teika.key</code> はローカルからサーバへの接続用、<code>github2teika.key</code> は、GitHub Actions からサーバへのデプロイ用。</p>
-<h2 id="ssh-の設定">SSH の設定</h2>
-<p><code>.ssh/config</code> に設定しておく。</p>
-<pre tabindex="0"><code class="language-ssh_config" data-lang="ssh_config">Host teika
- HostName **********
- User **********
- Port **********
- IdentityFile ~/.ssh/teika.key
-</code></pre><h1 id="基本のセットアップ">基本のセットアップ</h1>
-<h2 id="ssh-接続">SSH 接続</h2>
-<p>VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。</p>
-<h2 id="ユーザを作成する">ユーザを作成する</h2>
-<p>管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。<code>sudo</code> グループに追加して <code>sudo</code> できるようにし、<code>su</code> で切り替え。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo adduser **********
-</span></span><span style="display:flex;"><span>$ sudo adduser ********** sudo
-</span></span><span style="display:flex;"><span>$ su **********
-</span></span><span style="display:flex;"><span>$ cd
-</span></span></code></pre></div><h2 id="ホスト名を変える">ホスト名を変える</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo hostname teika
-</span></span></code></pre></div><h2 id="公開鍵を置く">公開鍵を置く</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ mkdir ~/.ssh
-</span></span><span style="display:flex;"><span>$ chmod <span style="color:#ae81ff">700</span> ~/.ssh
-</span></span><span style="display:flex;"><span>$ vi ~/.ssh/authorized_keys
-</span></span></code></pre></div><p><code>authorized_keys</code> には、ローカルで生成した <code>~/.ssh/teika.key.pub</code> と <code>~/.ssh/github2teika.key.pub</code> の内容をコピーする。</p>
-<h2 id="ssh-の設定-1">SSH の設定</h2>
-<p>SSH の設定を変更し、少しでも安全にしておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
-</span></span><span style="display:flex;"><span>$ sudo vi /etc/ssh/sshd_config
-</span></span></code></pre></div><ul>
-<li><code>Port</code> を変更</li>
-<li><code>PermitRootLogin</code> を <code>no</code> に</li>
-<li><code>PasswordAuthentication</code> を <code>no</code> に</li>
-</ul>
-<p>そして設定を反映。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo systemctl restart sshd
-</span></span><span style="display:flex;"><span>$ sudo systemctl status sshd
-</span></span></code></pre></div><h2 id="ssh-で接続確認">SSH で接続確認</h2>
-<p>今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh teika
-</span></span></code></pre></div><h2 id="ポートの遮断">ポートの遮断</h2>
-<p>デフォルトの 22 番を閉じ、設定したポートだけ空ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo ufw deny ssh
-</span></span><span style="display:flex;"><span>$ sudo ufw allow *******
-</span></span><span style="display:flex;"><span>$ sudo ufw enable
-</span></span><span style="display:flex;"><span>$ sudo ufw reload
-</span></span><span style="display:flex;"><span>$ sudo ufw status
-</span></span></code></pre></div><p>ここでもう一度 SSH の接続確認を挟む。</p>
-<h2 id="github-用の-ssh-鍵">GitHub 用の SSH 鍵</h2>
-<p>GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ssh-keygen -t ed25519 -b <span style="color:#ae81ff">521</span> -f ~/.ssh/github.key
-</span></span><span style="display:flex;"><span>$ cat ~/.ssh/github.key.pub
-</span></span></code></pre></div><p><a href="https://github.com/settings/ssh">GitHub の設定画面</a> から、この公開鍵を追加する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ vi ~/.ssh/config
-</span></span></code></pre></div><p>設定はこう。</p>
-<pre tabindex="0"><code class="language-ssh_config" data-lang="ssh_config">Host github.com
- HostName github.com
- User git
- IdentityFile ~/.ssh/github.key
-</code></pre><p>最後に接続できるか確認しておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>ssh -T github.com
-</span></span></code></pre></div><h2 id="パッケージの更新">パッケージの更新</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo apt update
-</span></span><span style="display:flex;"><span>$ sudo apt upgrade
-</span></span><span style="display:flex;"><span>$ sudo apt update
-</span></span><span style="display:flex;"><span>$ sudo apt upgrade
-</span></span><span style="display:flex;"><span>$ sudo apt autoremove
-</span></span></code></pre></div><h1 id="サイトホスティング用のセットアップ">サイトホスティング用のセットアップ</h1>
-<h2 id="dns-に-ip-アドレスを登録する">DNS に IP アドレスを登録する</h2>
-<p>このサーバは固定の IP アドレスがあるので、<code>A</code> レコードに直接入れるだけで済んだ。</p>
-<h2 id="使うソフトウェアのインストール">使うソフトウェアのインストール</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo apt install docker docker-compose git make
-</span></span></code></pre></div><h2 id="メインユーザが-docker-を使えるように">メインユーザが Docker を使えるように</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>sudo adduser ********** docker
-</span></span></code></pre></div><h2 id="httphttps-を通す">HTTP/HTTPS を通す</h2>
-<p>80 番と 443 番を空ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ sudo ufw allow 80/tcp
-</span></span><span style="display:flex;"><span>$ sudo ufw allow 443/tcp
-</span></span><span style="display:flex;"><span>$ sudo ufw reload
-</span></span><span style="display:flex;"><span>$ sudo ufw status
-</span></span></code></pre></div><h2 id="リポジトリのクローン">リポジトリのクローン</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ cd
-</span></span><span style="display:flex;"><span>$ git clone git@github.com:nsfisis/nsfisis.dev.git
-</span></span><span style="display:flex;"><span>$ cd nsfisis.dev
-</span></span><span style="display:flex;"><span>$ git submodule update --init
-</span></span></code></pre></div><h2 id="certbot-で証明書取得">certbot で証明書取得</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ docker-compose up -d acme-challenge
-</span></span><span style="display:flex;"><span>$ make setup
-</span></span></code></pre></div><h2 id="サーバを稼動させる">サーバを稼動させる</h2>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ make serve
-</span></span></code></pre></div><h1 id="感想">感想</h1>
-<p>(業務でなく) 個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/note-to-self/index.html b/docs/tags/note-to-self/index.html
deleted file mode 100644
index 0539b70..0000000
--- a/docs/tags/note-to-self/index.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>note-to-self | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/note-to-self/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>note-to-self</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>[備忘録] このサイト用の VPS をセットアップしたときのメモ</h2>
- </header>
- <section class="entry-content">
- <p>GitHub Pages でホストしていたこのサイトを VPS へ移行したので、
-そのときにやったことのメモ。99 % 自分用。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-10-28</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-10-28/setup-server-for-this-site/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/note-to-self/page/1/index.html b/docs/tags/note-to-self/page/1/index.html
deleted file mode 100644
index 3d56366..0000000
--- a/docs/tags/note-to-self/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/note-to-self/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/note-to-self/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/note-to-self/">
- </head>
-</html>
diff --git a/docs/tags/page/1/index.html b/docs/tags/page/1/index.html
deleted file mode 100644
index 2dbd4ae..0000000
--- a/docs/tags/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/">
- </head>
-</html>
diff --git a/docs/tags/php/feed.xml b/docs/tags/php/feed.xml
deleted file mode 100644
index 32be73a..0000000
--- a/docs/tags/php/feed.xml
+++ /dev/null
@@ -1,1493 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>php on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/php/</link>
- <description>Recent content in php on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sun, 23 Oct 2022 09:54:07 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/php/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>PHPerKaigi 2023: ボツになったトークン問題 その 1</title>
- <link>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</link>
- <pubDate>Sun, 23 Oct 2022 09:54:07 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の、<a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a> において、昨年と同様に、弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> から、トークン問題を出題予定である。</p>
-<p>昨年のトークン問題の記事はこちら: <a href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022 トークン問題の解説</a></p>
-<p>すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。</p>
-<p>10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。</p>
-<h1 id="問題">問題</h1>
-<p>注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;No input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π);
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;Invalid input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">&#39;/(\x23.+?) /&#39;</span>, $s, $m);
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;056e831a4146bf123e8ea16613303d2e&#39;</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><h1 id="トークン入手方法">トークン入手方法</h1>
-<p>ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。それを <code>$π</code> なる変数に代入しているので、円周率を渡してみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.14
-</span></span><span style="display:flex;"><span>Failed.
-</span></span></code></pre></div><p>失敗してしまった。精度を上げてみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415
-</span></span><span style="display:flex;"><span>Failed.
-</span></span></code></pre></div><p>だめだった。これを成功するまで繰り返す。</p>
-<p>最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415926535897932
-</span></span><span style="display:flex;"><span>Token: #YO
-</span></span></code></pre></div><p>めでたくトークン「#YO」が手に入った。</p>
-<h1 id="解説">解説</h1>
-<p>短いので頭から追っていく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;No input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π);
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;Invalid input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>入力のバリデーション部分。数値のみ受け付ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span></code></pre></div><p><code>$π</code> を 2 文字ごとに区切り (<code>str_split</code>)、数値を ASCII コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。</p>
-<p>例えば、<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="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;656667&#39;</span>;
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $s;
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// =&gt; ABC
-</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">&#39;/(\x23.+?) /&#39;</span>, $s, $m);
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span></code></pre></div><p>正規表現でマッチングしている。<code>\x23</code> は <code>#</code> と同じであることに留意すると、この正規表現は「<code>#</code> から始まる 2 以上の長さ (含 <code>#</code>) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。</p>
-<p>なお、<code>#</code> を直接書いていないのは、<code>/#.+?) /</code> と書くと、<code>#.+?)</code> という意図せぬトークンが登録されてしまうからである。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;056e831a4146bf123e8ea16613303d2e&#39;</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>最後にトークンのハッシュ値を見て、想定解かどうかを確認する。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。</p>
-<p>最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも <code>M_PI</code> や <code>pi()</code> では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。</p>
-]]></description>
- </item>
-
- <item>
- <title>[PHP] fizzbuzz を書く。1行あたり2文字で。</title>
- <link>https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/</link>
- <pubDate>Thu, 29 Sep 2022 00:50:52 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/</guid>
- <description><![CDATA[ <h1 id="記事の構成について">記事の構成について</h1>
-<p>この記事は、普通の fizzbuzz を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、 <a href="https://gist.github.com/nsfisis/04c227d5a419867472a0b23a83ad2919#file-fizzbuzz-php-2-letters-per-line-and-supports-php-8-x-without-warnings">このページ</a> にソースコードがあるので、そちらを先に見てほしい。</p>
-<h1 id="レギュレーション">レギュレーション</h1>
-<p>PHP で、次のような制約の下に fizzbuzz を書いた。</p>
-<ul>
-<li>1行あたりの文字数は2文字までに収めること (ただし <code>&lt;?php</code> タグは除く)
-<ul>
-<li>厳密な定義: <code>&lt;?php</code> タグ以降のソースコードが、2 byte ごとに ラインフィード (LF) で区切られること</li>
-</ul>
-</li>
-<li>スペースやタブを使用しないこと</li>
-<li>ループのアンロールをしないこと
-<ul>
-<li>100 回ループの代わりに 100 回コードをコピペ、というのは禁止</li>
-</ul>
-</li>
-<li>PHP 7.4〜8.1 で動作すること</li>
-<li>実行時に Notice や Warning が出ないこと</li>
-<li>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)</li>
-</ul>
-<p>備考: PHP には <code>short_open_tag</code> というオプションがあり、これを有効にするとファイル冒頭の <code>&lt;?php</code> の代わりに <code>&lt;?</code> を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト off になっている環境が多いようなので、今回は使わないことにした。</p>
-<h1 id="主な障害">主な障害</h1>
-<p>1行あたりの文字数など、適当に改行を挟めばいいだけではないのか?</p>
-<p>特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">i\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">n\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">l\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">u\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">d\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">e\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">&lt;\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">s\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">t\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">d\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">i\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">o\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">.\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">h\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">&gt;\
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span><span style="color:#75715e">
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>i\
-</span></span><span style="display:flex;"><span>n\
-</span></span><span style="display:flex;"><span>t\
-</span></span><span style="display:flex;"><span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span>
-</span></span><span style="display:flex;"><span>m\
-</span></span><span style="display:flex;"><span>a\
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span>n(
-</span></span><span style="display:flex;"><span>){
-</span></span><span style="display:flex;"><span>f\
-</span></span><span style="display:flex;"><span>o\
-</span></span><span style="display:flex;"><span>r(
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span>n\
-</span></span><span style="display:flex;"><span>t\
-</span></span><span style="display:flex;"><span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*/</span>
-</span></span><span style="display:flex;"><span>i<span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>;
-</span></span><span style="display:flex;"><span>i<span style="color:#f92672">&lt;</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span>\
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>\
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>;
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span>\
-</span></span><span style="display:flex;"><span><span style="color:#f92672">+</span>)
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span>
-</span></span><span style="display:flex;"><span>(i
-</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span>\
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">15</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">==</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span>)
-</span></span><span style="display:flex;"><span>p\
-</span></span><span style="display:flex;"><span>r\
-</span></span><span style="display:flex;"><span>i\
-</span></span><span style="display:flex;"><span>n\
-</span></span><span style="display:flex;"><span>t\
-</span></span><span style="display:flex;"><span>f(
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">F\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">i\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">B\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">u\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">z\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">10</span>
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">/* あとは同じように普通のプログラムを変形するだけなので省略 */</span>
-</span></span></code></pre></div><p>バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。</p>
-<p>さて、PHP ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、<code>echo</code> で出力することや、<code>for</code> でループすること、<code>new</code> でインスタンスを生成することができない。特に、出力は fizzbuzz をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。</p>
-<p>当然、名前が3文字以上ある関数も使えない。なお、標準 PHP の範囲内において、名前が 2文字以下の関数は以下のとおりである:</p>
-<ul>
-<li><code>_</code>: <code>gettext</code> のエイリアス</li>
-<li><code>dl</code>: 拡張モジュールをロードする</li>
-<li><code>pi</code>: 円周率を返す</li>
-</ul>
-<p>(環境によって多少は変わるかも)</p>
-<p>2文字の関数を定義しまくった拡張モジュールを用意しておいて <code>dl()</code> で読み込む行為は、レギュレーションで定めた</p>
-<blockquote>
-<ul>
-<li>標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと)</li>
-</ul>
-</blockquote>
-<p>に反する (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。</p>
-<p>また、2文字だと文字列がまともに書けないのも辛い。<code>''</code> だけで 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$a
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">a&#39;</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span></code></pre></div><p>とすると <code>$a</code> は <code>&quot;\na&quot;</code> になるのだが、余計な改行が入ってしまう。</p>
-<p>これらの障害をどのように乗り越えるのか、次節から見ていく。</p>
-<h1 id="解説">解説</h1>
-<h2 id="普通の--fizzbuzz">普通の (?) fizzbuzz</h2>
-<p>まずは普通に書くとしよう。</p>
-<pre tabindex="0"><code>&lt;?php
-
-for ($i = 1; $i &lt; 100; $i++) {
- echo (($i % 3 ? &#39;&#39; : &#39;Fizz&#39;) . ($i % 5 ? &#39;&#39; : &#39;Buzz&#39;) ?: $i) . &#34;\n&#34;;
-}
-</code></pre><p>素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。</p>
-<h2 id="for-の排除"><code>for</code> の排除</h2>
-<p><code>for</code> は、3文字もある長いキーワードである。こんなものは使えない。<code>array_</code> 系の関数を使って、適当に置き換えるとしよう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">range</span>(<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">100</span>);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">array_walk</span>(
-</span></span><span style="display:flex;"><span> $s,
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fn</span>($i) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">printf</span>((($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Fizz&#39;</span>) <span style="color:#f92672">.</span> ($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">5</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Buzz&#39;</span>) <span style="color:#f92672">?:</span> $i) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>),
-</span></span><span style="display:flex;"><span>);
-</span></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> に置き換えた。</p>
-<h2 id="関数呼び出しの短縮">関数呼び出しの短縮</h2>
-<p><code>range</code>、<code>array_walk</code>、<code>printf</code> は長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;range&#39;</span>;
-</span></span><span style="display:flex;"><span>$w <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;array_walk&#39;</span>;
-</span></span><span style="display:flex;"><span>$p <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;printf&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> $r(<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">100</span>);
-</span></span><span style="display:flex;"><span>$w(
-</span></span><span style="display:flex;"><span> $s,
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fn</span>($i) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> $p((($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Fizz&#39;</span>) <span style="color:#f92672">.</span> ($i <span style="color:#f92672">%</span> <span style="color:#ae81ff">5</span> <span style="color:#f92672">?</span> <span style="color:#e6db74">&#39;&#39;</span> <span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;Buzz&#39;</span>) <span style="color:#f92672">?:</span> $i) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>),
-</span></span><span style="display:flex;"><span>);
-</span></span></code></pre></div><p>これで関数を呼び出している所は短くなった。では、<code>$r</code> や <code>$w</code> や <code>$p</code>、また <code>'Fizz'</code> や <code>'Buzz'</code> はどうやって 1行2文字に収めるのか。次のテクニックへ移ろう。</p>
-<h2 id="余談-php-8x-で動作しなくてもいいなら">余談: PHP 8.x で動作しなくてもいいなら</h2>
-<p>今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。</p>
-<blockquote>
-<ul>
-<li>PHP 7.4〜8.1 で動作すること</li>
-</ul>
-</blockquote>
-<p>というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、 <code>Fizz</code> という文字列が欲しければ、次のようにする。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$f
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#a6e22e">F</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">i</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span></code></pre></div><p>こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、<code>@</code> 演算子を使って抑制してやるとよい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$f
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=@</span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">F</span><span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">@</span><span style="color:#a6e22e">i</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">@</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">.</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">@</span><span style="color:#a6e22e">z</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span></code></pre></div><p>むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。</p>
-<h2 id="文字列リテラルの短縮">文字列リテラルの短縮</h2>
-<p>実際に使った手法の説明に移る。</p>
-<p>ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (<code>&amp;</code>、<code>|</code>、<code>^</code>) をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$a <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;12345&#34;</span>;
-</span></span><span style="display:flex;"><span>$b <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;world&#34;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// $a ^ $b は次のコードと同じ
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$result <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672">&lt;</span> <span style="color:#a6e22e">min</span>(<span style="color:#a6e22e">strlen</span>($a), <span style="color:#a6e22e">strlen</span>($b)); $i<span style="color:#f92672">++</span>) {
-</span></span><span style="display:flex;"><span> $result <span style="color:#f92672">.=</span> $a[$i] <span style="color:#f92672">^</span> $b[$i];
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $result;
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// =&gt; F]AXQ
-</span></span></span></code></pre></div><p>これを踏まえ、次のコードを見てみよう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;x</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">Om</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>$y <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">k!</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">o&#34;</span>;
-</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> $y;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>実行すると、<code>range</code> が表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;x
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o&#39;</span>
-</span></span><span style="display:flex;"><span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$r <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> $y;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>さらに <code>#</code> を使って適当に調整すると、次のようになる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;x
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o&#39;</span>
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">$r\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>1行あたり2文字で、<code>range</code> という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。</p>
-<p>備考: <code>Buzz</code> 中にある小文字の <code>u</code> は、このロジックだと non-printable な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。</p>
-<h1 id="完成系">完成系</h1>
-<p>完成したものがこちら。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;i
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">S&#39;</span>
-</span></span><span style="display:flex;"><span>;;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">b!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$c
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;x
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Om
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o&#39;</span>
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;k
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Sk
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">~}
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Ma
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">x!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">s!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">k!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$w
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;z
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Hd
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">G&#39;</span>
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">x!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">~!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$p
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;L
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[p
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$f
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;H
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[p
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$y
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">_!
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>;
-</span></span><span style="display:flex;"><span>$b
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$x
-</span></span><span style="display:flex;"><span><span style="color:#f92672">^</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$y
-</span></span><span style="display:flex;"><span>;<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$b
-</span></span><span style="display:flex;"><span>[<span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span>]<span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span>$c
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">13</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">*</span><span style="color:#ae81ff">9</span>
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>$s
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$r
-</span></span><span style="display:flex;"><span>(<span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span>,(
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">10</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">**</span>
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span>)
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>$w
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$s
-</span></span><span style="display:flex;"><span>,<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">fn</span>
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span>)<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span>$p
-</span></span><span style="display:flex;"><span>((
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span><span style="color:#ae81ff">3</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">?</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;&#39;</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$f
-</span></span><span style="display:flex;"><span>)<span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span><span style="color:#f92672">%</span><span style="color:#ae81ff">5</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">?</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#e6db74">&#39;&#39;</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$b
-</span></span><span style="display:flex;"><span>)<span style="color:#f92672">?</span>
-</span></span><span style="display:flex;"><span><span style="color:#f92672">:</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$i
-</span></span><span style="display:flex;"><span>)<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">.</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>)
-</span></span><span style="display:flex;"><span>);
-</span></span></code></pre></div><h1 id="感想など">感想など</h1>
-<p>PHP は、スクリプト言語の中だとシンタックスシュガーが少ない (体感)。この挑戦は不可能に思われたが、PHP マニュアルとにらめっこしていたらなんとかなった。</p>
-<p>みんなもプログラムを細長くしよう。</p>
-<h1 id="余談2-別解">余談2: 別解</h1>
-<p>PHP では、バッククォートを使ってシェルを呼び出せる。これは <code>shell_exec</code> 関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">`
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">e\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">h\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> \
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">1\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">2\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">3\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">`</span>);
-</span></span></code></pre></div><p>なお、ここでは簡単のため出力に <code>printf</code> をそのまま使っているが、実際には <code>printf</code> という文字列を合成して可変関数で呼び出す。</p>
-<p>ただし、これでは</p>
-<blockquote>
-<ul>
-<li>スペースやタブを使用しないこと</li>
-</ul>
-</blockquote>
-<p>に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。</p>
-<p>もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$c <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;chr&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">$</span>{
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;_
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>}
-</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span><span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>$c
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">32</span>
-</span></span><span style="display:flex;"><span>)<span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span>$c
-</span></span><span style="display:flex;"><span>(<span style="color:#75715e">#
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#ae81ff">92</span>
-</span></span><span style="display:flex;"><span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">`
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">e\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">c\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">h\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">o\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">${
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;_
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;}
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">1\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">2\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">3\
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">`</span>);
-</span></span></code></pre></div><p>先程と同じく、<code>chr</code> や <code>printf</code> を生成する部分は長くなるので省いた。</p>
-<pre tabindex="0"><code>${
-&#39;_
-&#39;}
-</code></pre><p>は変数で、中にはスペースとエスケープが入っている (<code>chr(32) . chr(92)</code>)。シェルに渡されている文字列は次のようになる。</p>
-<pre tabindex="0"><code>e\
-c\
-h\
-o\
- \
-1\
-2\
-3\
-</code></pre><p>これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。</p>
-<p>ということでこれは別解ということにしておく。</p>
-<p>ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。</p>
-<pre tabindex="0"><code>${
-&#39;_
-&#39;}
-</code></pre><p>最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</title>
- <link>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</link>
- <pubDate>Sat, 27 Aug 2022 18:55:28 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> が開催された (らしい)。</p>
-<p>カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。</p>
-<p>ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</a> <br>
-スライド: <a href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</a></p>
-<h1 id="解">解</h1>
-<p>細かいレギュレーションは不明だったので、勝手に定めた。</p>
-<ul>
-<li>コマンドライン引数の第1引数で受けとる</li>
-<li>結果は標準出力に出す</li>
-<li>コンマの直後にはスペースを1つ置く</li>
-<li>末尾コンマは禁止</li>
-<li>数字でないものは入ってこないものとする</li>
-<li>負数は入ってこないものとする</li>
-</ul>
-<p>書いたものがこちら:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span> $n<span style="color:#f92672">=</span>$argv[<span style="color:#ae81ff">1</span>];<span style="color:#66d9ef">foreach</span>([<span style="color:#ae81ff">1e4</span>,<span style="color:#ae81ff">5e3</span>,<span style="color:#ae81ff">2e3</span>,<span style="color:#ae81ff">1e3</span>,<span style="color:#ae81ff">500</span>,<span style="color:#ae81ff">100</span>,<span style="color:#ae81ff">50</span>,<span style="color:#ae81ff">10</span>,<span style="color:#ae81ff">5</span>,<span style="color:#ae81ff">1</span>]<span style="color:#66d9ef">as</span>$x)<span style="color:#66d9ef">for</span>(;$n<span style="color:#f92672">&gt;=</span>$x;$n<span style="color:#f92672">-=</span>$x)$r[]<span style="color:#f92672">=</span>$x;<span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>,$r<span style="color:#f92672">??</span>[]);<span style="color:#75715e">?&gt;</span><span style="color:#960050;background-color:#1e0010">]
-</span></span></span></code></pre></div><p>しめて 123 バイトとなった (末尾改行を含めずにカウント)。</p>
-<p>こちらは改行とスペースを追加したバージョン:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>];
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ([<span style="color:#ae81ff">1e4</span>, <span style="color:#ae81ff">5e3</span>, <span style="color:#ae81ff">2e3</span>, <span style="color:#ae81ff">1e3</span>, <span style="color:#ae81ff">500</span>, <span style="color:#ae81ff">100</span>, <span style="color:#ae81ff">50</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">1</span>] <span style="color:#66d9ef">as</span> $x)
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> (; $n <span style="color:#f92672">&gt;=</span> $x; $n <span style="color:#f92672">-=</span> $x)
-</span></span><span style="display:flex;"><span> $r[] <span style="color:#f92672">=</span> $x;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>, $r <span style="color:#f92672">??</span> []);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">?&gt;</span><span style="color:#960050;background-color:#1e0010">]
-</span></span></span></code></pre></div><h1 id="使用したテクニック">使用したテクニック</h1>
-<h2 id="指数表記">指数表記</h2>
-<p>割と多くの言語のゴルフで使えるテクニック。<code>e</code> を用いた指数表記で、大きな数を短く表す。このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。</p>
-<h2 id="foreach-や-for-の中身を1つの文に">foreach や for の中身を1つの文に</h2>
-<p><code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code> を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> を省略できる。C言語などでも使える。</p>
-<h2 id="r-に初期値を入れない">$r に初期値を入れない</h2>
-<p>PHP では、<code>$r[] = ...</code> のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は <code>$r</code> を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code> のような初期化が不要になる。</p>
-<p>ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> が未定義になってしまい、<code>implode()</code> に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。</p>
-<p>もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。</p>
-<h2 id="php-タグの外に文字列を置く">PHP タグの外に文字列を置く</h2>
-<p>PHP では、<code>&lt;?php</code> <code>?&gt;</code> で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず <code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>最後になりましたが、<a href="https://twitter.com/m3m0r7">めもりー</a> さん、楽しい問題をありがとうございました。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2022</title>
- <link>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</link>
- <pubDate>Sun, 01 May 2022 09:41:39 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>2022-04-09 から 2022-04-11 にかけて開催された、<a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> に、一般参加者として参加した。
-弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
-<p>昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。</p>
-<h1 id="感想">感想</h1>
-<h2 id="厳選おすすめトーク">厳選おすすめトーク</h2>
-<p>多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。</p>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント</a></p>
-<blockquote>
-<p>PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。</p>
-<p>本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</a></p>
-<blockquote>
-<p>PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか?<br>
-これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br>
-またそれらを理解した上でのエラーハンドリングを学びましょう。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</a></p>
-<blockquote>
-<p>毎日流れてくるエラーに皆さんはどう向き合ってますか?<br>
-エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br>
-サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br>
-エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</a></p>
-<blockquote>
-<p>昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。</p>
-<p>最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br>
-・「(私の思う)良い設計」を実現するための意思決定<br>
-・「ISUCONの問題」という位置付けに由来する取捨選択<br>
-・移植中に遭遇したトラブルとその解決策<br>
-といった文脈や葛藤が存在しています。</p>
-<p>本発表はそれらを共有することで<br>
-・PHPアプリケーションの設計、実装事例として役立ててもらう<br>
-・ISUCONの言語移植に興味を持ってもらう<br>
-・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br>
-ことを目的とします。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</a></p>
-<blockquote>
-<p>サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。</p>
-<p>フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。</p>
-<p>このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。</p>
-</blockquote>
-<h2 id="トークン問題の作成">トークン問題の作成</h2>
-<p>今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。</p>
-<h2 id="phper-チャレンジ">PHPer チャレンジ</h2>
-<p><a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。<br>
-また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> をいただいた。</p>
-<h2 id="カンファレンス全体への感想">カンファレンス全体への感想</h2>
-<p><a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。</p>
-<blockquote>
-<p>1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br>
-まあ初カンファレンスだし、とお茶を濁しておこう。</p>
-</blockquote>
-<p>この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。<br>
-これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。</p>
-<p>なお、アンカンファレンスについては、1日目の終わりに<a href="https://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e">トークン問題の解説放送</a>もおこなった。</p>
-<p>また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。
-今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。</p>
-<h1 id="そして来年へ">そして来年へ……?</h1>
-<p>PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。</p>
-<ul>
-<li>プロポーザルを出す</li>
-<li>PHPer チャレンジのトークン問題を 5題作成する</li>
-<li>現地に行く</li>
-<li>PHPer チャレンジで圧勝する</li>
-</ul>
-<hr>
-<p>最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。</p>
-<p>ではまた来年。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2022 トークン問題の解説</title>
- <link>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</link>
- <pubDate>Sat, 09 Apr 2022 21:50:19 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>本日開始された <a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> の PHPer チャレンジにおいて、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。</p>
-<p>リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</a></p>
-<h1 id="第1問-brainf_ckphp">第1問 brainf_ck.php</h1>
-<p>ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">declare</span>(<span style="color:#a6e22e">strict_types</span><span style="color:#f92672">=</span><span style="color:#ae81ff">0</span><span style="color:#a6e22e">O1</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> <span style="color:#a6e22e">Dgcircus\PHPerKaigi\Y2022</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">/**
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * @todo
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Run this program to acquire a PHPer token.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> */</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">\error_reporting</span>(<span style="color:#f92672">~+!</span><span style="color:#e6db74">&#39;We are hiring!&#39;</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$z <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($f) <span style="color:#f92672">=&gt;</span> (<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=&gt;</span> $x($x)(<span style="color:#f92672">...</span>$xs)))(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=&gt;</span> $x($x)(<span style="color:#f92672">...</span>$xs)));
-</span></span><span style="display:flex;"><span>$id <span style="color:#f92672">=</span> <span style="color:#a6e22e">\spl_object_id</span>(<span style="color:#f92672">...</span>);
-</span></span><span style="display:flex;"><span>$put <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($c) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">\printf</span>(<span style="color:#e6db74">&#39;%c&#39;</span>, $c);
-</span></span><span style="display:flex;"><span>$mm <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\ArrayObject</span>(<span style="color:#a6e22e">\array_fill</span>(<span style="color:#f92672">+!!</span>[], $n, $p));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$👉 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [<span style="color:#f92672">++</span>$mp, <span style="color:#f92672">++</span>$pc];
-</span></span><span style="display:flex;"><span>$👈 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [<span style="color:#f92672">--</span>$mp, <span style="color:#f92672">++</span>$pc];
-</span></span><span style="display:flex;"><span>$👍 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$m[$mp]];
-</span></span><span style="display:flex;"><span>$👎 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$m[$mp]];
-</span></span><span style="display:flex;"><span>$📝 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, $put($m[$mp])];
-</span></span><span style="display:flex;"><span>$🤡 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($m[$mp]) {
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=&gt;</span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) {
-</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$n),
-</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=&gt;</span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> <span style="color:#f92672">++</span>$pc <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$n),
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">++</span>$pc, $n),
-</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])],
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc],
-</span></span><span style="display:flex;"><span>};
-</span></span><span style="display:flex;"><span>$🎪 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($m[$mp]) {
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc],
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) {
-</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">++</span>$n),
-</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=&gt;</span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> $pc<span style="color:#f92672">+!</span>[] <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">--</span>$n),
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">--</span>$pc, $n),
-</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])],
-</span></span><span style="display:flex;"><span>};
-</span></span><span style="display:flex;"><span>$🐘 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p) <span style="color:#f92672">=&gt;</span> $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">isset</span>($p[$pc]) <span style="color:#f92672">&amp;&amp;</span> $loop($m, $p, $b, $e, <span style="color:#f92672">...</span>($p[$pc]($m, $p, $b, $e, $mp, $pc)))
-</span></span><span style="display:flex;"><span>)($mm(<span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.!</span>[])), $p, $id($🤡), $id($🎪), <span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+!!</span>[]);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$🐘([
-</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $🤡,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👈, $👈, $👈, $👈, $👎,
-</span></span><span style="display:flex;"><span> $🎪,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👉, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👈, $👎, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span>]);
-</span></span></code></pre></div><p>この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。</p>
-<h2 id="解説">解説</h2>
-<h3 id="絵文字">絵文字</h3>
-<p>まず目につくのは大量の絵文字だろう。
-PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。</p>
-<h3 id="プログラム全体">プログラム全体</h3>
-<p>Brainf*ck のインタプリタとプログラムになっている。
-Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。</p>
-<p><a href="https://ja.wikipedia.org/wiki/Brainfuck">https://ja.wikipedia.org/wiki/Brainfuck</a></p>
-<p>なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。</p>
-<pre tabindex="0"><code>+ + + + + + + + + +
-[
- &gt; + + +
- &gt; + + + + +
- &gt; + + + + + + + + + + + +
- &gt; + + + + + + + + + +
- &lt; &lt; &lt; &lt; -
-]
-&gt; + + + + + .
-- - .
-&gt; - - - .
-&gt; - - - .
-- - .
-- .
-&lt; .
-&gt; &gt; - - .
-+ + + + + + + .
-&lt; - - - - .
-&lt; .
-&gt; + + .
-&gt; - .
-&lt; .
-</code></pre><p>実行結果はこちら: <a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a></p>
-<p>それぞれの絵文字で表された関数が、各命令に対応している。</p>
-<ul>
-<li><code>$👉</code>: <code>&gt;</code></li>
-<li><code>$👈</code>: <code>&lt;</code></li>
-<li><code>$👍</code>: <code>+</code></li>
-<li><code>$👎</code>: <code>-</code></li>
-<li><code>$📝</code>: <code>.</code></li>
-<li><code>$🤡</code>: <code>[</code></li>
-<li><code>$🎪</code>: <code>]</code></li>
-</ul>
-<p><code>,</code> (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。</p>
-<p>なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。</p>
-<h3 id="絵文字の選択">絵文字の選択</h3>
-<p>おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> は弊社デジタルサーカスにちなんでいる。
-また、<code>$🐘</code> は PHP のマスコットの象に由来する。</p>
-<h3 id="strict_types">strict_types</h3>
-<p><code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code> の数値リテラルだが、
-<code>0x0</code> や <code>0b1</code> のような値も受け付ける。
-今回は、PHP 8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。</p>
-<h3 id="url">URL</h3>
-<p>ソースコードのライセンスを示したこの部分だが、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span>
-</span></span></code></pre></div><p>完全に合法な PHP のコードである。
-<code>https:</code> 部分はラベル、<code>//</code> 以降は行コメントになっている。</p>
-<h3 id="リテラルなしで数値を生成する">リテラルなしで数値を生成する</h3>
-<p>ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。
-PHP では、型変換を利用することで任意の整数を作り出すことができる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">1</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">2</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">3</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]<span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">10</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.+!!</span>[]));
-</span></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 が作れる)。</p>
-<p>また、<code>error_reporting</code> に指定しているのは <code>-1</code> である。
-これは、<code>!</code> によって文字列を <code>false</code> にし、<code>+</code> によって <code>false</code> を <code>0</code> にし、さらにビット反転して <code>-1</code> にしている。</p>
-<h3 id="if-文なしで条件分岐"><code>if</code> 文なしで条件分岐</h3>
-<p>三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> を一切書かずに条件分岐ができる。
-また、<code>&amp;&amp;</code> / <code>||</code> も使えることがある。
-遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> のような形で分岐することもできる。</p>
-<h3 id="whilefor-文なしでループ"><code>while</code>、<code>for</code> 文なしでループ</h3>
-<p>不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。
-ここでは、一般に Z コンビネータとして知られるものを使った (<code>$z</code>)。</p>
-<p>実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。</p>
-<p>なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、
-あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。</p>
-<h1 id="第2問-riddlephp">第2問 riddle.php</h1>
-<p>ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">/*********************************************************
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * This program displays a PHPer token. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Guess &#39;N&#39;. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Hints: *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - N itself has no special meaning, e.g., 42, 8128, *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * it is selected at random. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Each element of $token represents a single letter. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - One letter consists of 5x5 cells. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Remember, the output is a complete PHPer token. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * License: *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * https://creativecommons.org/publicdomain/zero/1.0/ *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> *********************************************************/</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">N</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e">/* Change it to your answer. */</span>;
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x14B499C</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0BE34CC</span>, <span style="color:#ae81ff">0x01C9C69</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0ECA069</span>, <span style="color:#ae81ff">0x01C2449</span>, <span style="color:#ae81ff">0x0FDB166</span>, <span style="color:#ae81ff">0x01C9C69</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x01C1C66</span>, <span style="color:#ae81ff">0x0FC1C47</span>, <span style="color:#ae81ff">0x01C1C66</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x10C5858</span>, <span style="color:#ae81ff">0x1E4E3B8</span>, <span style="color:#ae81ff">0x1A2F2F8</span>,
-</span></span><span style="display:flex;"><span>];
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($token <span style="color:#66d9ef">as</span> $x) {
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{</span>$x<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。
-トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。</p>
-<p>ここでは、私の想定解を解説する。</p>
-<h2 id="読解">読解</h2>
-<p>まずはソースコードを読んでいく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 略
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>];
-</span></span></code></pre></div><p>数値からなる <code>$token</code> があり、各要素をループしている。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span></code></pre></div><p>まずは排他的論理和 (xor) を取り、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span></code></pre></div><p>二進数に変換して、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span></code></pre></div><p>0 を空白に、1 を <code>#</code> にし、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span></code></pre></div><p>5文字ごとに区切ったあと、改行で結合している。</p>
-<h2 id="ヒント">ヒント</h2>
-<p>次に、ソースコードに書いてあるヒントを読んでいく。</p>
-<ul>
-<li><code>N</code> それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている</li>
-<li><code>$token</code> の各要素は、1文字を表す</li>
-<li>1文字は 5x5 のセルからなる</li>
-<li>出力されるのは、完全な PHPer トークンである</li>
-</ul>
-<p>ここで、PHPer トークンは必ず <code>#</code> 記号から始まることを思いだすと、
-<code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code>#</code> になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。</p>
-<h2 id="解く">解く</h2>
-<p>ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> に変換されるような <code>N</code> を見つければよい。</p>
-<p><code>N</code> は高々</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>);
-</span></span></code></pre></div><p>なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0x14B499C</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>($x <span style="color:#f92672">===</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # &#34;</span>);
-</span></span></code></pre></div><p>この一連の変換に対する逆変換を考えると、次のようになる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # &#34;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;&#39;</span>, <span style="color:#a6e22e">explode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, $x));
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">bindec</span>($x);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#ae81ff">0x14B499C</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;N = </span><span style="color:#e6db74">$n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>これを実行すると、<code>N</code> が得られる。</p>
-<h1 id="第3問-toquinephp">第3問 toquine.php</h1>
-<p>ソースコードはこちら。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// License: https://creativecommons.org/publicdomain/zero/1.0/
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// This is a quine-like program to generate a PHPer token.
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Execute it like this: php toquine.php | php | php | php | ...
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#e6db74">&lt;&lt;&lt;&#39;</span><span style="color:#e6db74">Q</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&lt;?cuc
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ...
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f$f = %f;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$f = fge_ebg13($f); $kf = [
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f,
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">];
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g = ahyy.snyfr; sbe ($v = 0; $v &lt;= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g .= vzcybqr(&#34;\a&#34;, fge_fcyvg(fge_ercynpr([&#39;0&#39;,&#39;1&#39;], [&#39; &#39;,&#39;##&#39;], fcevags(pue(37) . &#39;025o&#39;, $kf[$v])), 012)) . &#34;\a\a&#34;;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$jf = neenl_znc(sa($j) =&gt; vzcybqr(&#39;, &#39;, $j), neenl_puhax(neenl_znc(sa($k) =&gt; fcevags(&#39;0k&#39; . pue(37) . &#39;07K&#39;, $k), $kf), 10));
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">cevags($f, $g, fge_ebg13(&#34;&lt;&lt;&lt;&#39;Q&#39;\a{$f}\aQ&#34;), vzcybqr(&#34;,\a&#34;, $jf));
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#e6db74">Q</span>;
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_rot13</span>($s); $xs <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x0AFABEA</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x0002800</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x0117041</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F295B7</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1151151</span>, <span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1F8C63F</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x1F8C631</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x1F8C63F</span>, <span style="color:#ae81ff">0x1F295B7</span>,
-</span></span><span style="display:flex;"><span>];
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">.</span><span style="color:#66d9ef">false</span>; <span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">intdiv</span>(<span style="color:#66d9ef">__LINE__</span><span style="color:#f92672">-</span><span style="color:#ae81ff">035</span>,<span style="color:#ae81ff">6</span>); <span style="color:#f92672">++</span>$i) <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">isset</span>($xs[$i])) <span style="color:#66d9ef">break</span>; <span style="color:#66d9ef">else</span>
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">.=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>(<span style="color:#a6e22e">str_replace</span>([<span style="color:#e6db74">&#39;0&#39;</span>,<span style="color:#e6db74">&#39;1&#39;</span>], [<span style="color:#e6db74">&#39; &#39;</span>,<span style="color:#e6db74">&#39;##&#39;</span>], <span style="color:#a6e22e">sprintf</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;025b&#39;</span>, $xs[$i])), <span style="color:#ae81ff">012</span>)) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>$ws <span style="color:#f92672">=</span> <span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($w) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>, $w), <span style="color:#a6e22e">array_chunk</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;0x&#39;</span> <span style="color:#f92672">.</span> <span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;07X&#39;</span>, $x), $xs), <span style="color:#ae81ff">10</span>));
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>($s, $t, <span style="color:#a6e22e">str_rot13</span>(<span style="color:#e6db74">&#34;&lt;&lt;&lt;&#39;D&#39;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">{</span>$s<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">D&#34;</span>), <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;,</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, $ws));
-</span></span></code></pre></div><p>コメントにもあるとおり、次のようにして実行すれば答えがでてくる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php toquine.php | php | php | php | ...
-</span></span></code></pre></div><p>実際にはもう少しパイプで繋げなければならない。</p>
-<h2 id="解説-1">解説</h2>
-<h3 id="プログラム全体-1">プログラム全体</h3>
-<p>コメントにもあるとおり、これは quine (風) のプログラムになっている。
-Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。</p>
-<p>このプログラムは、実行すると自身とほとんど同じプログラムを出力する。
-異なるのはトークンになっている部分のみである。</p>
-<h3 id="トークン">トークン</h3>
-<p><code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。</p>
-<h3 id="状態保持">状態保持</h3>
-<p>トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。
-このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code>__LINE__</code> から情報を取得している。</p>
-<h3 id="rot-13">ROT 13</h3>
-<p>Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。
-これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 変換を使って難読化した。</p>
-<p>それにしてもなぜこんなものが標準ライブラリに……。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。</p>
-<p>今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、
-来年は 5問、より面白い問題を持っていきます。</p>
-<p>実はもう作りはじめているので、どうか来年もありますように……。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2021</title>
- <link>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</link>
- <pubDate>Tue, 30 Mar 2021 23:22:40 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</guid>
- <description><![CDATA[ <h1 id="phperkaigi-2021-参加レポ">PHPerKaigi 2021 参加レポ</h1>
-<p>2021-03-26 から 2021-03-28 にかけて開催された、<a href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</a> に一般参加者として参加した。
-弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
-<p>このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。</p>
-<p>発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。</p>
-<h2 id="凡例">凡例</h2>
-<blockquote>
-<p>発表・スライドのメモ (引用ではない)</p>
-</blockquote>
-<p>感想など</p>
-<h2 id="day-0-前夜祭-20210327">Day 0 前夜祭 (2021/03/27)</h2>
-<h3 id="1730-a">17:30 [A]</h3>
-<p>PHP で AWS Lambda</p>
-<blockquote>
-<p>Rails のプロジェクトを PHPer のメンバのみでメンテ
-→他のメンバもわかる PHP にリプレースを検討</p>
-<p>サーバレス</p>
-<ul>
-<li>サーバ・インフラの管理が不要</li>
-<li>アプリケーションコードの知識だけで保守可能</li>
-</ul>
-<p>ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入?</p>
-<p>AWSの学習
-AWS のドキュメント
-DevelopersIO</p>
-<p>AWS Lambda のカスタムランタイムで PHP を動かす</p>
-<p>サーバのセットアップや維持管理を気にしなくて良い
-サーバーレスで PHP を動かすツールがすでにある
-サーバーレス構築はすんなり</p>
-<p>今は Laravel がルーティングしている
-Laravel Livewire を Lambda に載せられないか?
-デプロイ方法は?
-バッチ処理は? (Lambda は 15分の制限)</p>
-<p>Lambda でコンテナイメージがサポートされるように</p>
-<p>抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる</p>
-</blockquote>
-<p>AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。</p>
-<p>PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。</p>
-<p>勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。</p>
-<h3 id="1810-a">18:10 [A]</h3>
-<p>大規模サイトの SEO</p>
-<blockquote>
-<p>大規模サイト (100万ページ以上)
-Google の基準</p>
-<p>クロールバジェットを意識したSEO</p>
-<p>大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される
-これを満たさないなら、クロールバジェットを考えなくてもいい</p>
-<p>サーチコンソール
-「カバレッジ」の「除外」
-多すぎるのは問題→クロールバジェットを浪費している</p>
-<ul>
-<li>クエリの順番を決める</li>
-<li>空の値のルールを決めておく</li>
-<li>リダイレクトすればインデックスはうまくいく</li>
-<li>リンクが存在する限りクロールはされる</li>
-</ul>
-<p>リニューアル前のURL</p>
-<p>インデックスは移行される
-リンクのURLが存在する限り、別のURLとしてクロールされる
-リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い
-リニューアルで無視されるようになったパラメータも注意</p>
-<p>robotes.txt で拒否しているのにクロールされる
-一時的に拒否を外して 404 や 301 を読ませる
-内部リンクを確認する
-JS でのリンクに書き換え</p>
-<p>クエリパラメータからURLのパスに
-<code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code></p>
-<p>URL 設計だいじ</p>
-</blockquote>
-<p>SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。</p>
-<h3 id="1850-a">18:50 [A]</h3>
-<blockquote>
-<p>知覚可能
-操作可能
-理解可能
-堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など)</p>
-<ul>
-<li>
-<p>標準の HTML を適切に使う</p>
-</li>
-<li>
-<p>WAI-ARIA</p>
-</li>
-<li>
-<p>キーボードフレンドリー</p>
-</li>
-<li>
-<p>マシンフレンドリー</p>
-</li>
-<li>
-<p>SEOフレンドリー</p>
-</li>
-</ul>
-<p>button タグ
-→キーボード
-h1 タグ
-→スクリーンリーダー・クローラ
-a タグ</p>
-<p>WAI-ARIA
-HTML では表現できないセマンティクスを追加する</p>
-<ul>
-<li>ロール
-<ul>
-<li>何をするのか?</li>
-<li>ユーザーアクションによって変化しない</li>
-</ul>
-</li>
-<li>プロパティ
-<ul>
-<li>関連づけられたデータ</li>
-</ul>
-</li>
-<li>ステート
-<ul>
-<li>現在の状態</li>
-</ul>
-</li>
-</ul>
-<p>まずは標準の HTML 要素で解決する
-何でもかんでも WAI-ARIA を使えばいいというものではない</p>
-<p>マウスホバーでツールチップが出てくるが、キーボード操作では出てこない</p>
-<p>VoiceOver</p>
-<p>全ての属性を使う必要はない
-あくまでアクセシビリティを上げるための方法の一つにすぎない</p>
-</blockquote>
-<p>つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。</p>
-<h3 id="1930-a">19:30 [A]</h3>
-<p>PHP で FUSE</p>
-<p>個人的に楽しみだった発表。</p>
-<blockquote>
-<p>VFS (virtual filesystem) vs 具体的なファイルシステム</p>
-<p>最適な実装方法は状況により異なる</p>
-<p>アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS</p>
-<p>カーネルのプログラムを作るのは難しい</p>
-<ul>
-<li>権限がデカすぎる</li>
-<li>システム全体がクラッシュ</li>
-<li>セキュリティリスク</li>
-<li>開発サイクルを回しづらい</li>
-<li>ネイティブコードにコンパイルされる言語である必要がある</li>
-</ul>
-<p>Filesystem in USEr space (FUSE)</p>
-<ul>
-<li>特定の C の関数を呼ぶことで filesystem が作れる</li>
-<li>FFI を持つ言語なら FUSE が使える</li>
-</ul>
-<p>SSHFS / s3fs / Docker Desktop</p>
-<p>Linux 以外でも使える</p>
-<ul>
-<li>dokany (on Windows)</li>
-<li>osxfuse</li>
-</ul>
-<p>VFS: システムコールが呼ばれると、ファイルシステムによってコール
-FUSE: カーネル空間からユーザ空間へ通信</p>
-<p>高レベルなラッパで型をつける</p>
-<p>PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)</p>
-<ul>
-<li>grep できる</li>
-<li>sed できる</li>
-<li>編集できる</li>
-</ul>
-</blockquote>
-<p>期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。
-この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。</p>
-<h2 id="day-1-20210327">Day 1 (2021/03/27)</h2>
-<h3 id="1050-a">10:50 [A]</h3>
-<p>ATDD</p>
-<blockquote>
-<ul>
-<li>ユーザーストーリー</li>
-<li>ユニットテスト</li>
-<li>CI/CD</li>
-</ul>
-<p>ユーザストーリーの受け入れ条件が曖昧になりがち
-デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている</p>
-<p>Q2の強化
-アジャイルテストの4象限</p>
-<p>技術面/ビジネス面
-開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)</p>
-<ul>
-<li>Q1: 技術面 &amp; チーム支援
-<ul>
-<li>TDD</li>
-<li>ユニットテストなど</li>
-</ul>
-</li>
-<li>Q2: ビジネス面 &amp; チーム支援
-<ul>
-<li>ATDD</li>
-<li>ビジネス面の受け入れテストで駆動する</li>
-</ul>
-</li>
-</ul>
-<p>Agile Alliance
-ユーザストーリーのスキルレベルを高める</p>
-<p>テストピラミッド</p>
-<ul>
-<li>
-<p>UI Tests</p>
-</li>
-<li>
-<p>Service Tests</p>
-</li>
-<li>
-<p>Unit Tests</p>
-</li>
-<li>
-<p>異なる粒度のテストを書く</p>
-</li>
-<li>
-<p>高レベルになるほど、持つべきテストは少なくなる</p>
-<ul>
-<li>ピラミッド型になる</li>
-</ul>
-</li>
-</ul>
-<p>高レベルテストが多すぎる→アイスクリームコーン アンチパターン</p>
-<p>ATDD (Acceptance TDD)
-API経由・UI経由での高レベルテスト E2E test</p>
-<p>ストーリ受け入れテスト</p>
-<p>入れ子のフィードバックループ
-ATDD(外側) と TDD(内側)</p>
-<p>外部品質・内部品質</p>
-<p>バーティカルスライスのデリバリー</p>
-<ul>
-<li>cucumber</li>
-<li>gauge</li>
-<li>behat</li>
-</ul>
-<p>ユビキタス言語
-手動テストもspecに書く
-自動化は可能だがコスパが悪い
-失敗することがわかっているテスト(レッドテスト)はCIから外す
-失敗時の原因究明が難しい
-饒舌なエラーメッセージ
-状況のスナップショット</p>
-<p>Continuous Testing</p>
-</blockquote>
-<p>User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。
-高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。</p>
-<h3 id="1150-a">11:50 [A]</h3>
-<p>型解析を用いたリファクタリング</p>
-<p>型のある世界で生きてきた身として大いに楽しみにしていた発表。</p>
-<blockquote>
-<ul>
-<li>PHPStan</li>
-<li>Phan</li>
-<li>Psalm</li>
-</ul>
-<p>autoload も認識できる
-bootstrapFiles</p>
-<p>編集箇所と利用箇所を CI でチェック
-ルールレベルを徐々に引き上げていく
-警告が多すぎると見落としてしまう・無視されやすくなる</p>
-<p>型がついていないことによるエラーが多い</p>
-<p>型よりも詳細な検査 <code>Util_Assert::min</code></p>
-<p>SQL を静的解析
-placeholder の型付け</p>
-<p>警告レベルを低いレベルから導入
-タイプヒントを積極的に書いていく
-PHPStan の拡張を追加する</p>
-</blockquote>
-<p>昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。
-今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。</p>
-<h3 id="1230-a">12:30 [A]</h3>
-<p>昼食をとっていた。事前に何か食料を買っておくべきだった。</p>
-<h3 id="1310-a">13:10 [A]</h3>
-<p>Documentation as Code</p>
-<p>この発表も以前から非常に楽しみにしていた。</p>
-<blockquote>
-<p>開発開始までのオーバーヘッド
-新規にチームにジョイン
-担当範囲外の機能を理解
-オンボーディングのコスト</p>
-<p>PHPerKaigi 2020 で発表あり</p>
-<p>継続的にシステムの理解を助けるドキュメント</p>
-<p>継続的ドキュメンテーション
-システムとドキュメントの乖離</p>
-<p>書いてあることが間違っている・足りない</p>
-<ul>
-<li>徐々にずれていく</li>
-<li>システムの更新タイミングとドキュメントの更新タイミングに差がある</li>
-</ul>
-<p>システムとドキュメントは対応関係がある</p>
-<ul>
-<li>間違ったドキュメント</li>
-<li>存在しないドキュメント</li>
-</ul>
-<p>システムとドキュメントの乖離を定量化する
-継続的に
-システムの更新に近いタイミングで ドキュメントを更新し続ける</p>
-<p>Documentation as Code</p>
-<p>コードと同じツールでドキュメントを書く</p>
-<ul>
-<li>issue tracker</li>
-<li>vcs</li>
-<li>plain text markup</li>
-<li>automation</li>
-</ul>
-<p>開発者
-システム
-ドキュメント
-構造化データ
-ソフトウェア</p>
-<p>システムから構造化データを抽出する
-PHPDoc
-OpenAPI</p>
-<p>ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する</p>
-<p>ビューの単位でドキュメントに</p>
-<p>スタックトレースからのドキュメント生成</p>
-</blockquote>
-<p>ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。</p>
-<h3 id="1410-a">14:10 [A]</h3>
-<p>cookie による session 管理</p>
-<p>全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。</p>
-<h3 id="1450-a">14:50 [A]</h3>
-<p>PHP のエラーと例外</p>
-<blockquote>
-<p>エラー PHPエンジンがエラーを通知する
-例外 プログラムが投げる</p>
-<p>PHP7-8とエラー</p>
-<p>PHPエンジンのエラーの一部が \Error に変換されるようになった
-→ try-catch で捕捉できる</p>
-<p>\Error は例外とは異なる</p>
-<p>PHP8 でエラーレベルの引き上げ</p>
-<ul>
-<li>捕捉すべきもの
-<ul>
-<li>recoverable</li>
-</ul>
-</li>
-<li>捕捉すべきでないもの
-<ul>
-<li>unrecoverable</li>
-<li>開発時に対処できるもの</li>
-</ul>
-</li>
-</ul>
-<p>例外</p>
-<ul>
-<li>捕捉して事後処理</li>
-<li>捕捉せず(or 捕捉した上で)さらに上に是非を問う</li>
-</ul>
-<p>開発段階で例外を把握し、ハンドリングを考えておく</p>
-<p>\Throwable \Exception と \Error</p>
-<p>\Error はキャッチすべきでない</p>
-<ul>
-<li>
-<p>\Error</p>
-<ul>
-<li>本番で起きてはいけない</li>
-</ul>
-</li>
-<li>
-<p>\LogicException</p>
-<ul>
-<li>本番で起きてはいけない
-→生じないのだから捕捉もしない</li>
-</ul>
-</li>
-<li>
-<p>\RuntimeException</p>
-<ul>
-<li>起こるかもしれないので本番環境でも考慮する</li>
-</ul>
-</li>
-</ul>
-<p>捕捉して対応するのではなく、未然に防ぐ</p>
-<p>独自例外を使う
-\Exception を投げてしまうと、
-catch (\Exception)せざるを得ない
-→catch 範囲が広すぎる</p>
-<p>SPL の例外を使う</p>
-<p>例外翻訳
-上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する
-下位レイヤの知識に依存させない</p>
-<p>@throws
-捕捉してほしい例外を書き連ねておく</p>
-<p>呼び出しもとに負わせたい責任</p>
-</blockquote>
-<p>PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。</p>
-<p>個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。</p>
-<p>PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。</p>
-<h3 id="1530-a">15:30 [A]</h3>
-<p>Laravel のメール認証</p>
-<p>Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。</p>
-<h3 id="1610-a">16:10 [A]</h3>
-<p>gRPC</p>
-<blockquote>
-<p>Unary RPCs
-Server streaming RPCs
-Client streaming RPCs
-Bidirectional streaming RPCs</p>
-<p>Protobuf</p>
-<p>実装とAPIが乖離しにくい
-自動生成
-複数言語でも相互に使える</p>
-<p>マイクロサービスのサービス通信
-スマホアプリ
-ゲームサーバ</p>
-<p>PHP では?</p>
-<p>PHP ではストリーミングが難しい
-リクエストごとにプロセスが使い捨て</p>
-<p>PHP ではgRPCのクライアントしか対応していない</p>
-<p>gRPC-Web
-ブラウザで扱うためのJSライブラリ+プロトコル</p>
-<p>HTTP/1.1 でも使える
-Unary RPC と Server streaming RPC のみ</p>
-<p>Envoy
-Nginx などで相互に gRPC と gRPC-Web で変換</p>
-<p>Amp
-イベント駆動な並行処理のフレームワーク</p>
-<p>HTTP/2 対応</p>
-<p>C#のgRPC-Webが楽</p>
-</blockquote>
-<p>(発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。</p>
-<h3 id="1650-a">16:50 [A]</h3>
-<p>アーキテクチャテスト</p>
-<blockquote>
-<p>Independent Core Layer Pattern</p>
-<p>開発初期のアーキテクチャが崩れる
-アーキテクチャ観点のコードレビューができない</p>
-<p>どこにクラスを置けばよいか?
-ドキュメントがない</p>
-<p>アーキテクチャ設計に関する知識が属人化・暗黙知化</p>
-<p>ガイドライン</p>
-<ul>
-<li>最初にルールを決めるのは簡単</li>
-<li>ルール通り作り始めるのも簡単
-<ul>
-<li>→維持するのが難しい、人が決めたものゆえ壊れやすい</li>
-</ul>
-</li>
-</ul>
-<p>PHP の特性</p>
-<ul>
-<li>クラスは public</li>
-<li>可視性の制御が public / protected / private のみ</li>
-<li>依存関係の制御が困難</li>
-</ul>
-<p>アーキテクチャテスト
-クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する</p>
-<ul>
-<li>deptrac</li>
-<li>phpat</li>
-</ul>
-<p>Independent Core Layer Pattern</p>
-<p>アーキテクチャテストの失敗</p>
-<ul>
-<li>実装誤り</li>
-<li>or アーキテクチャが適切でない
-<ul>
-<li>開発の過程でフィードバックしていく</li>
-</ul>
-</li>
-</ul>
-<p>モジュラーモノリス→マイクロサービスへ</p>
-</blockquote>
-<h2 id="day-2-20210328">Day 2 (2021/03/28)</h2>
-<p>冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。</p>
-<p>残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。</p>
-<h2 id="全体の感想">全体の感想</h2>
-<p>Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。</p>
-<p>今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。</p>
-<p>1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。
-まあ初カンファレンスだし、とお茶を濁しておこう。</p>
-<p>さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。</p>
-<hr>
-<p>最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました!
-(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)</p>
-<p>ではまた来年。</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/php/index.html b/docs/tags/php/index.html
deleted file mode 100644
index e38f0a9..0000000
--- a/docs/tags/php/index.html
+++ /dev/null
@@ -1,117 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>php | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/php/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>php</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2023: ボツになったトークン問題 その 1</h2>
- </header>
- <section class="entry-content">
- <p>来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、
-ボツになった問題を公開する (その 1)。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-10-23</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[PHP] fizzbuzz を書く。1行あたり2文字で。</h2>
- </header>
- <section class="entry-content">
- <p>PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-09-29</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2>
- </header>
- <section class="entry-content">
- <p>PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-08-27</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2022</h2>
- </header>
- <section class="entry-content">
- <p>2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-05-01</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2022 トークン問題の解説</h2>
- </header>
- <section class="entry-content">
- <p>PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-04-09</time>, updated on <time>2022-04-16</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2021</h2>
- </header>
- <section class="entry-content">
- <p>2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-03-30</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/php/page/1/index.html b/docs/tags/php/page/1/index.html
deleted file mode 100644
index 9d866e9..0000000
--- a/docs/tags/php/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/php/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/php/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/php/">
- </head>
-</html>
diff --git a/docs/tags/phpcon/feed.xml b/docs/tags/phpcon/feed.xml
deleted file mode 100644
index b5b8325..0000000
--- a/docs/tags/phpcon/feed.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>phpcon on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/phpcon/</link>
- <description>Recent content in phpcon on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sat, 27 Aug 2022 18:55:28 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/phpcon/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</title>
- <link>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</link>
- <pubDate>Sat, 27 Aug 2022 18:55:28 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a> が開催された (らしい)。</p>
-<p>カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。</p>
-<p>ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772">https://twitter.com/m3m0r7/status/1563397620231712772</a> <br>
-スライド: <a href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</a></p>
-<h1 id="解">解</h1>
-<p>細かいレギュレーションは不明だったので、勝手に定めた。</p>
-<ul>
-<li>コマンドライン引数の第1引数で受けとる</li>
-<li>結果は標準出力に出す</li>
-<li>コンマの直後にはスペースを1つ置く</li>
-<li>末尾コンマは禁止</li>
-<li>数字でないものは入ってこないものとする</li>
-<li>負数は入ってこないものとする</li>
-</ul>
-<p>書いたものがこちら:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span> $n<span style="color:#f92672">=</span>$argv[<span style="color:#ae81ff">1</span>];<span style="color:#66d9ef">foreach</span>([<span style="color:#ae81ff">1e4</span>,<span style="color:#ae81ff">5e3</span>,<span style="color:#ae81ff">2e3</span>,<span style="color:#ae81ff">1e3</span>,<span style="color:#ae81ff">500</span>,<span style="color:#ae81ff">100</span>,<span style="color:#ae81ff">50</span>,<span style="color:#ae81ff">10</span>,<span style="color:#ae81ff">5</span>,<span style="color:#ae81ff">1</span>]<span style="color:#66d9ef">as</span>$x)<span style="color:#66d9ef">for</span>(;$n<span style="color:#f92672">&gt;=</span>$x;$n<span style="color:#f92672">-=</span>$x)$r[]<span style="color:#f92672">=</span>$x;<span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>,$r<span style="color:#f92672">??</span>[]);<span style="color:#75715e">?&gt;</span><span style="color:#960050;background-color:#1e0010">]
-</span></span></span></code></pre></div><p>しめて 123 バイトとなった (末尾改行を含めずにカウント)。</p>
-<p>こちらは改行とスペースを追加したバージョン:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>[<span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>];
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ([<span style="color:#ae81ff">1e4</span>, <span style="color:#ae81ff">5e3</span>, <span style="color:#ae81ff">2e3</span>, <span style="color:#ae81ff">1e3</span>, <span style="color:#ae81ff">500</span>, <span style="color:#ae81ff">100</span>, <span style="color:#ae81ff">50</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">1</span>] <span style="color:#66d9ef">as</span> $x)
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">for</span> (; $n <span style="color:#f92672">&gt;=</span> $x; $n <span style="color:#f92672">-=</span> $x)
-</span></span><span style="display:flex;"><span> $r[] <span style="color:#f92672">=</span> $x;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>, $r <span style="color:#f92672">??</span> []);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">?&gt;</span><span style="color:#960050;background-color:#1e0010">]
-</span></span></span></code></pre></div><h1 id="使用したテクニック">使用したテクニック</h1>
-<h2 id="指数表記">指数表記</h2>
-<p>割と多くの言語のゴルフで使えるテクニック。<code>e</code> を用いた指数表記で、大きな数を短く表す。このコードでは <code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。</p>
-<h2 id="foreach-や-for-の中身を1つの文に">foreach や for の中身を1つの文に</h2>
-<p><code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code> を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code> を省略できる。C言語などでも使える。</p>
-<h2 id="r-に初期値を入れない">$r に初期値を入れない</h2>
-<p>PHP では、<code>$r[] = ...</code> のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は <code>$r</code> を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code> のような初期化が不要になる。</p>
-<p>ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code> が未定義になってしまい、<code>implode()</code> に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。</p>
-<p>もし 0 が渡されたケースを無視するなら、これが不要になるので 4 バイト縮む。</p>
-<h2 id="php-タグの外に文字列を置く">PHP タグの外に文字列を置く</h2>
-<p>PHP では、<code>&lt;?php</code> <code>?&gt;</code> で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず <code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>最後になりましたが、<a href="https://twitter.com/m3m0r7">めもりー</a> さん、楽しい問題をありがとうございました。</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/phpcon/index.html b/docs/tags/phpcon/index.html
deleted file mode 100644
index d3d3cba..0000000
--- a/docs/tags/phpcon/index.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>phpcon | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/phpcon/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>phpcon</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2>
- </header>
- <section class="entry-content">
- <p>PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-08-27</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-08-27/php-conference-okinawa-code-golf/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/phpcon/page/1/index.html b/docs/tags/phpcon/page/1/index.html
deleted file mode 100644
index 736f0cb..0000000
--- a/docs/tags/phpcon/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/phpcon/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/phpcon/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/phpcon/">
- </head>
-</html>
diff --git a/docs/tags/phperkaigi/feed.xml b/docs/tags/phperkaigi/feed.xml
deleted file mode 100644
index 439bf91..0000000
--- a/docs/tags/phperkaigi/feed.xml
+++ /dev/null
@@ -1,974 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>phperkaigi on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/phperkaigi/</link>
- <description>Recent content in phperkaigi on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sun, 23 Oct 2022 09:54:07 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/phperkaigi/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>PHPerKaigi 2023: ボツになったトークン問題 その 1</title>
- <link>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</link>
- <pubDate>Sun, 23 Oct 2022 09:54:07 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点) の、<a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a> において、昨年と同様に、弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> から、トークン問題を出題予定である。</p>
-<p>昨年のトークン問題の記事はこちら: <a href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022 トークン問題の解説</a></p>
-<p>すでに 2023 年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi 開催を待つ間に紹介しようと思う。</p>
-<p>10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。</p>
-<h1 id="問題">問題</h1>
-<p>注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;No input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π);
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;Invalid input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">&#39;/(\x23.+?) /&#39;</span>, $s, $m);
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;056e831a4146bf123e8ea16613303d2e&#39;</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><h1 id="トークン入手方法">トークン入手方法</h1>
-<p>ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。それを <code>$π</code> なる変数に代入しているので、円周率を渡してみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.14
-</span></span><span style="display:flex;"><span>Failed.
-</span></span></code></pre></div><p>失敗してしまった。精度を上げてみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415
-</span></span><span style="display:flex;"><span>Failed.
-</span></span></code></pre></div><p>だめだった。これを成功するまで繰り返す。</p>
-<p>最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php Q.php 3.1415926535897932
-</span></span><span style="display:flex;"><span>Token: #YO
-</span></span></code></pre></div><p>めでたくトークン「#YO」が手に入った。</p>
-<h1 id="解説">解説</h1>
-<p>短いので頭から追っていく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> $argv[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#66d9ef">null</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ($π <span style="color:#f92672">===</span> <span style="color:#66d9ef">null</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;No input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#a6e22e">trim</span>($π);
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">is_numeric</span>($π)) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">exit</span>(<span style="color:#e6db74">&#39;Invalid input.&#39;</span>);
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>入力のバリデーション部分。数値のみ受け付ける。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span></code></pre></div><p><code>$π</code> を 2 文字ごとに区切り (<code>str_split</code>)、数値を ASCII コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。</p>
-<p>例えば、<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="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$π <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;656667&#39;</span>;
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#f92672">...</span>), <span style="color:#a6e22e">str_split</span>($π, <span style="color:#ae81ff">2</span>)));
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> $s;
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// =&gt; ABC
-</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">preg_match</span>(<span style="color:#e6db74">&#39;/(\x23.+?) /&#39;</span>, $s, $m);
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> $m[<span style="color:#ae81ff">1</span>] <span style="color:#f92672">??</span> <span style="color:#e6db74">&#39;&#39;</span>;
-</span></span></code></pre></div><p>正規表現でマッチングしている。<code>\x23</code> は <code>#</code> と同じであることに留意すると、この正規表現は「<code>#</code> から始まる 2 以上の長さ (含 <code>#</code>) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。</p>
-<p>なお、<code>#</code> を直接書いていないのは、<code>/#.+?) /</code> と書くと、<code>#.+?)</code> という意図せぬトークンが登録されてしまうからである。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">md5</span>($t) <span style="color:#f92672">===</span> <span style="color:#e6db74">&#39;056e831a4146bf123e8ea16613303d2e&#39;</span>) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Token: </span><span style="color:#e6db74">{</span>$t<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>} <span style="color:#66d9ef">else</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;Failed.</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>最後にトークンのハッシュ値を見て、想定解かどうかを確認する。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>円周率を何桁も計算して ASCII コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。</p>
-<p>最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた (ちなみに、それでも <code>M_PI</code> や <code>pi()</code> では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100 万桁目くらいに埋まっていてくれたほうがよかったかもしれない。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2022</title>
- <link>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</link>
- <pubDate>Sun, 01 May 2022 09:41:39 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>2022-04-09 から 2022-04-11 にかけて開催された、<a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> に、一般参加者として参加した。
-弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
-<p>昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。</p>
-<h1 id="感想">感想</h1>
-<h2 id="厳選おすすめトーク">厳選おすすめトーク</h2>
-<p>多くの素晴らしいトークの中から、特におすすめのものを 5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。</p>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント</a></p>
-<blockquote>
-<p>PHP はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。</p>
-<p>本講演では PHP 8.1 をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</a></p>
-<blockquote>
-<p>PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice 理解していますか?<br>
-これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br>
-またそれらを理解した上でのエラーハンドリングを学びましょう。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</a></p>
-<blockquote>
-<p>毎日流れてくるエラーに皆さんはどう向き合ってますか?<br>
-エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br>
-サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br>
-エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</a></p>
-<blockquote>
-<p>昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。</p>
-<p>最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br>
-・「(私の思う)良い設計」を実現するための意思決定<br>
-・「ISUCONの問題」という位置付けに由来する取捨選択<br>
-・移植中に遭遇したトラブルとその解決策<br>
-といった文脈や葛藤が存在しています。</p>
-<p>本発表はそれらを共有することで<br>
-・PHPアプリケーションの設計、実装事例として役立ててもらう<br>
-・ISUCONの言語移植に興味を持ってもらう<br>
-・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br>
-ことを目的とします。</p>
-</blockquote>
-<p><a href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</a></p>
-<blockquote>
-<p>サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。</p>
-<p>フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。</p>
-<p>このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。</p>
-</blockquote>
-<h2 id="トークン問題の作成">トークン問題の作成</h2>
-<p>今回は、PHPer チャレンジ用に弊社のトークン問題を 3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。</p>
-<h2 id="phper-チャレンジ">PHPer チャレンジ</h2>
-<p><a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。<br>
-また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a> をいただいた。</p>
-<h2 id="カンファレンス全体への感想">カンファレンス全体への感想</h2>
-<p><a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a> では、こんなことを書いた。</p>
-<blockquote>
-<p>1つ個人的な反省点としては、(中略) Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br>
-まあ初カンファレンスだし、とお茶を濁しておこう。</p>
-</blockquote>
-<p>この反省を踏まえ、今年は積極的にほかの場 (公式の Discord サーバや、アンカンファレンス) にも参加した。<br>
-これにより、参加体験の質がはるかに向上した。特に Discord に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる (ことが多い) ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。</p>
-<p>なお、アンカンファレンスについては、1日目の終わりに<a href="https://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e">トークン問題の解説放送</a>もおこなった。</p>
-<p>また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。
-今年は 3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。</p>
-<h1 id="そして来年へ">そして来年へ……?</h1>
-<p>PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の 4つを目標としたい。</p>
-<ul>
-<li>プロポーザルを出す</li>
-<li>PHPer チャレンジのトークン問題を 5題作成する</li>
-<li>現地に行く</li>
-<li>PHPer チャレンジで圧勝する</li>
-</ul>
-<hr>
-<p>最後になりましたが、PHPerKaigi のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。</p>
-<p>ではまた来年。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2022 トークン問題の解説</title>
- <link>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</link>
- <pubDate>Sat, 09 Apr 2022 21:50:19 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/</guid>
- <description><![CDATA[ <h1 id="はじめに">はじめに</h1>
-<p>本日開始された <a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> の PHPer チャレンジにおいて、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。</p>
-<p>リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens">https://github.com/nsfisis/PHPerKaigi2022-tokens</a></p>
-<h1 id="第1問-brainf_ckphp">第1問 brainf_ck.php</h1>
-<p>ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">declare</span>(<span style="color:#a6e22e">strict_types</span><span style="color:#f92672">=</span><span style="color:#ae81ff">0</span><span style="color:#a6e22e">O1</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">namespace</span> <span style="color:#a6e22e">Dgcircus\PHPerKaigi\Y2022</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">/**
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * @todo
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Run this program to acquire a PHPer token.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> */</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">\error_reporting</span>(<span style="color:#f92672">~+!</span><span style="color:#e6db74">&#39;We are hiring!&#39;</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$z <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($f) <span style="color:#f92672">=&gt;</span> (<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=&gt;</span> $x($x)(<span style="color:#f92672">...</span>$xs)))(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> $f(<span style="color:#a6e22e">fn</span>(<span style="color:#f92672">...</span>$xs) <span style="color:#f92672">=&gt;</span> $x($x)(<span style="color:#f92672">...</span>$xs)));
-</span></span><span style="display:flex;"><span>$id <span style="color:#f92672">=</span> <span style="color:#a6e22e">\spl_object_id</span>(<span style="color:#f92672">...</span>);
-</span></span><span style="display:flex;"><span>$put <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($c) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">\printf</span>(<span style="color:#e6db74">&#39;%c&#39;</span>, $c);
-</span></span><span style="display:flex;"><span>$mm <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">\ArrayObject</span>(<span style="color:#a6e22e">\array_fill</span>(<span style="color:#f92672">+!!</span>[], $n, $p));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$👉 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [<span style="color:#f92672">++</span>$mp, <span style="color:#f92672">++</span>$pc];
-</span></span><span style="display:flex;"><span>$👈 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [<span style="color:#f92672">--</span>$mp, <span style="color:#f92672">++</span>$pc];
-</span></span><span style="display:flex;"><span>$👍 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$m[$mp]];
-</span></span><span style="display:flex;"><span>$👎 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$m[$mp]];
-</span></span><span style="display:flex;"><span>$📝 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc, $put($m[$mp])];
-</span></span><span style="display:flex;"><span>$🤡 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($m[$mp]) {
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=&gt;</span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) {
-</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">++</span>$n),
-</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=&gt;</span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> <span style="color:#f92672">++</span>$pc <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">++</span>$pc, <span style="color:#f92672">--</span>$n),
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">++</span>$pc, $n),
-</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])],
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc],
-</span></span><span style="display:flex;"><span>};
-</span></span><span style="display:flex;"><span>$🎪 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($m[$mp]) {
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">=&gt;</span> [$mp, <span style="color:#f92672">++</span>$pc],
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> [$mp, $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($pc, $n) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">match</span> ($id($p[$pc])) {
-</span></span><span style="display:flex;"><span> $e <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">++</span>$n),
-</span></span><span style="display:flex;"><span> $b <span style="color:#f92672">=&gt;</span> $n <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[] <span style="color:#f92672">?</span> $pc<span style="color:#f92672">+!</span>[] <span style="color:#f92672">:</span> $loop(<span style="color:#f92672">--</span>$pc, <span style="color:#f92672">--</span>$n),
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">default</span> <span style="color:#f92672">=&gt;</span> $loop(<span style="color:#f92672">--</span>$pc, $n),
-</span></span><span style="display:flex;"><span> })($pc, <span style="color:#f92672">-!</span>[])],
-</span></span><span style="display:flex;"><span>};
-</span></span><span style="display:flex;"><span>$🐘 <span style="color:#f92672">=</span> <span style="color:#a6e22e">fn</span>($p) <span style="color:#f92672">=&gt;</span> $z(<span style="color:#a6e22e">fn</span>($loop) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">fn</span>($m, $p, $b, $e, $mp, $pc) <span style="color:#f92672">=&gt;</span>
-</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">isset</span>($p[$pc]) <span style="color:#f92672">&amp;&amp;</span> $loop($m, $p, $b, $e, <span style="color:#f92672">...</span>($p[$pc]($m, $p, $b, $e, $mp, $pc)))
-</span></span><span style="display:flex;"><span>)($mm(<span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.!</span>[])), $p, $id($🤡), $id($🎪), <span style="color:#f92672">+!!</span>[], <span style="color:#f92672">+!!</span>[]);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$🐘([
-</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $🤡,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-</span></span><span style="display:flex;"><span> $👈, $👈, $👈, $👈, $👎,
-</span></span><span style="display:flex;"><span> $🎪,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $👍, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👉, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👈, $👎, $👎, $👎, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👍, $👍, $📝,
-</span></span><span style="display:flex;"><span> $👉, $👎, $📝,
-</span></span><span style="display:flex;"><span> $👈, $📝,
-</span></span><span style="display:flex;"><span>]);
-</span></span></code></pre></div><p>この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。</p>
-<h2 id="解説">解説</h2>
-<h3 id="絵文字">絵文字</h3>
-<p>まず目につくのは大量の絵文字だろう。
-PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。</p>
-<h3 id="プログラム全体">プログラム全体</h3>
-<p>Brainf*ck のインタプリタとプログラムになっている。
-Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。</p>
-<p><a href="https://ja.wikipedia.org/wiki/Brainfuck">https://ja.wikipedia.org/wiki/Brainfuck</a></p>
-<p>なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。</p>
-<pre tabindex="0"><code>+ + + + + + + + + +
-[
- &gt; + + +
- &gt; + + + + +
- &gt; + + + + + + + + + + + +
- &gt; + + + + + + + + + +
- &lt; &lt; &lt; &lt; -
-]
-&gt; + + + + + .
-- - .
-&gt; - - - .
-&gt; - - - .
-- - .
-- .
-&lt; .
-&gt; &gt; - - .
-+ + + + + + + .
-&lt; - - - - .
-&lt; .
-&gt; + + .
-&gt; - .
-&lt; .
-</code></pre><p>実行結果はこちら: <a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a></p>
-<p>それぞれの絵文字で表された関数が、各命令に対応している。</p>
-<ul>
-<li><code>$👉</code>: <code>&gt;</code></li>
-<li><code>$👈</code>: <code>&lt;</code></li>
-<li><code>$👍</code>: <code>+</code></li>
-<li><code>$👎</code>: <code>-</code></li>
-<li><code>$📝</code>: <code>.</code></li>
-<li><code>$🤡</code>: <code>[</code></li>
-<li><code>$🎪</code>: <code>]</code></li>
-</ul>
-<p><code>,</code> (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。</p>
-<p>なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。</p>
-<h3 id="絵文字の選択">絵文字の選択</h3>
-<p>おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code> は弊社デジタルサーカスにちなんでいる。
-また、<code>$🐘</code> は PHP のマスコットの象に由来する。</p>
-<h3 id="strict_types">strict_types</h3>
-<p><code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code> の数値リテラルだが、
-<code>0x0</code> や <code>0b1</code> のような値も受け付ける。
-今回は、PHP 8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。</p>
-<h3 id="url">URL</h3>
-<p>ソースコードのライセンスを示したこの部分だが、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">https</span><span style="color:#f92672">://</span><span style="color:#a6e22e">creativecommons</span><span style="color:#f92672">.</span><span style="color:#a6e22e">org</span><span style="color:#f92672">/</span><span style="color:#a6e22e">publicdomain</span><span style="color:#f92672">/</span><span style="color:#a6e22e">zero</span><span style="color:#f92672">/</span><span style="color:#ae81ff">1.0</span><span style="color:#f92672">/</span>
-</span></span></code></pre></div><p>完全に合法な PHP のコードである。
-<code>https:</code> 部分はラベル、<code>//</code> 以降は行コメントになっている。</p>
-<h3 id="リテラルなしで数値を生成する">リテラルなしで数値を生成する</h3>
-<p>ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。
-PHP では、型変換を利用することで任意の整数を作り出すことができる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">1</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">2</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">3</span> <span style="color:#f92672">===</span> <span style="color:#f92672">!</span>[]<span style="color:#f92672">+!</span>[]<span style="color:#f92672">+!</span>[]);
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">10</span> <span style="color:#f92672">===</span> <span style="color:#f92672">+</span>(<span style="color:#f92672">!</span>[]<span style="color:#f92672">.+!!</span>[]));
-</span></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 が作れる)。</p>
-<p>また、<code>error_reporting</code> に指定しているのは <code>-1</code> である。
-これは、<code>!</code> によって文字列を <code>false</code> にし、<code>+</code> によって <code>false</code> を <code>0</code> にし、さらにビット反転して <code>-1</code> にしている。</p>
-<h3 id="if-文なしで条件分岐"><code>if</code> 文なしで条件分岐</h3>
-<p>三項演算子ないし <code>match</code> 式を使うことで、<code>if</code> を一切書かずに条件分岐ができる。
-また、<code>&amp;&amp;</code> / <code>||</code> も使えることがある。
-遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code> のような形で分岐することもできる。</p>
-<h3 id="whilefor-文なしでループ"><code>while</code>、<code>for</code> 文なしでループ</h3>
-<p>不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。
-ここでは、一般に Z コンビネータとして知られるものを使った (<code>$z</code>)。</p>
-<p>実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。</p>
-<p>なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、
-あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。</p>
-<h1 id="第2問-riddlephp">第2問 riddle.php</h1>
-<p>ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#e6db74">/*********************************************************
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * This program displays a PHPer token. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Guess &#39;N&#39;. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * Hints: *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - N itself has no special meaning, e.g., 42, 8128, *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * it is selected at random. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Each element of $token represents a single letter. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - One letter consists of 5x5 cells. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * - Remember, the output is a complete PHPer token. *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * License: *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> * https://creativecommons.org/publicdomain/zero/1.0/ *
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> *********************************************************/</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">N</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e">/* Change it to your answer. */</span>;
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x14B499C</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0BE34CC</span>, <span style="color:#ae81ff">0x01C9C69</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x0ECA069</span>, <span style="color:#ae81ff">0x01C2449</span>, <span style="color:#ae81ff">0x0FDB166</span>, <span style="color:#ae81ff">0x01C9C69</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x01C1C66</span>, <span style="color:#ae81ff">0x0FC1C47</span>, <span style="color:#ae81ff">0x01C1C66</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">0x10C5858</span>, <span style="color:#ae81ff">0x1E4E3B8</span>, <span style="color:#ae81ff">0x1A2F2F8</span>,
-</span></span><span style="display:flex;"><span>];
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($token <span style="color:#66d9ef">as</span> $x) {
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{</span>$x<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。
-トークンを得るためには、ソースコードを読み、定数 <code>N</code> を特定する必要がある。</p>
-<p>ここでは、私の想定解を解説する。</p>
-<h2 id="読解">読解</h2>
-<p>まずはソースコードを読んでいく。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span>$token <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// 略
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>];
-</span></span></code></pre></div><p>数値からなる <code>$token</code> があり、各要素をループしている。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span></code></pre></div><p>まずは排他的論理和 (xor) を取り、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span></code></pre></div><p>二進数に変換して、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span></code></pre></div><p>0 を空白に、1 を <code>#</code> にし、</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span> $x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span></code></pre></div><p>5文字ごとに区切ったあと、改行で結合している。</p>
-<h2 id="ヒント">ヒント</h2>
-<p>次に、ソースコードに書いてあるヒントを読んでいく。</p>
-<ul>
-<li><code>N</code> それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている</li>
-<li><code>$token</code> の各要素は、1文字を表す</li>
-<li>1文字は 5x5 のセルからなる</li>
-<li>出力されるのは、完全な PHPer トークンである</li>
-</ul>
-<p>ここで、PHPer トークンは必ず <code>#</code> 記号から始まることを思いだすと、
-<code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code>#</code> になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。</p>
-<h2 id="解く">解く</h2>
-<p>ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code> に変換されるような <code>N</code> を見つければよい。</p>
-<p><code>N</code> は高々</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>(<span style="color:#ae81ff">0</span> <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">N</span> <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span><span style="color:#a6e22e">b11111_11111_11111_11111_11111</span>);
-</span></span></code></pre></div><p>なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0x14B499C</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#a6e22e">N</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;%025b&#39;</span>, $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>($x, <span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">5</span>));
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">assert</span>($x <span style="color:#f92672">===</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # &#34;</span>);
-</span></span></code></pre></div><p>この一連の変換に対する逆変換を考えると、次のようになる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # </span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;#####</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">.</span>
-</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34; # # &#34;</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;&#39;</span>, <span style="color:#a6e22e">explode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, $x));
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_replace</span>(<span style="color:#a6e22e">search</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39; &#39;</span>, <span style="color:#e6db74">&#39;#&#39;</span>], <span style="color:#a6e22e">replace</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>], <span style="color:#a6e22e">subject</span><span style="color:#f92672">:</span> $x);
-</span></span><span style="display:flex;"><span>$x <span style="color:#f92672">=</span> <span style="color:#a6e22e">bindec</span>($x);
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>$n <span style="color:#f92672">=</span> $x <span style="color:#f92672">^</span> <span style="color:#ae81ff">0x14B499C</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">echo</span> <span style="color:#e6db74">&#34;N = </span><span style="color:#e6db74">$n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span></code></pre></div><p>これを実行すると、<code>N</code> が得られる。</p>
-<h1 id="第3問-toquinephp">第3問 toquine.php</h1>
-<p>ソースコードはこちら。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#f92672">&lt;?</span><span style="color:#a6e22e">php</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">// License: https://creativecommons.org/publicdomain/zero/1.0/
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// This is a quine-like program to generate a PHPer token.
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Execute it like this: php toquine.php | php | php | php | ...
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#e6db74">&lt;&lt;&lt;&#39;</span><span style="color:#e6db74">Q</span><span style="color:#e6db74">&#39;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&lt;?cuc
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ...
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f$f = %f;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$f = fge_ebg13($f); $kf = [
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">%f,
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">];
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g = ahyy.snyfr; sbe ($v = 0; $v &lt;= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$g .= vzcybqr(&#34;\a&#34;, fge_fcyvg(fge_ercynpr([&#39;0&#39;,&#39;1&#39;], [&#39; &#39;,&#39;##&#39;], fcevags(pue(37) . &#39;025o&#39;, $kf[$v])), 012)) . &#34;\a\a&#34;;
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$jf = neenl_znc(sa($j) =&gt; vzcybqr(&#39;, &#39;, $j), neenl_puhax(neenl_znc(sa($k) =&gt; fcevags(&#39;0k&#39; . pue(37) . &#39;07K&#39;, $k), $kf), 10));
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">cevags($f, $g, fge_ebg13(&#34;&lt;&lt;&lt;&#39;Q&#39;\a{$f}\aQ&#34;), vzcybqr(&#34;,\a&#34;, $jf));
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#e6db74">Q</span>;
-</span></span><span style="display:flex;"><span>$s <span style="color:#f92672">=</span> <span style="color:#a6e22e">str_rot13</span>($s); $xs <span style="color:#f92672">=</span> [
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x0AFABEA</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x0002800</span>, <span style="color:#ae81ff">0x1F2109F</span>, <span style="color:#ae81ff">0x0117041</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F295B7</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1151151</span>, <span style="color:#ae81ff">0x010FC21</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x1F294A7</span>, <span style="color:#ae81ff">0x1F295B7</span>, <span style="color:#ae81ff">0x1F8C63F</span>,
-</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0x1F8C631</span>, <span style="color:#ae81ff">0x1FAD6B5</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x17AD6BD</span>, <span style="color:#ae81ff">0x1F8C63F</span>, <span style="color:#ae81ff">0x1F295B7</span>,
-</span></span><span style="display:flex;"><span>];
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">.</span><span style="color:#66d9ef">false</span>; <span style="color:#66d9ef">for</span> ($i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; $i <span style="color:#f92672">&lt;=</span> <span style="color:#a6e22e">intdiv</span>(<span style="color:#66d9ef">__LINE__</span><span style="color:#f92672">-</span><span style="color:#ae81ff">035</span>,<span style="color:#ae81ff">6</span>); <span style="color:#f92672">++</span>$i) <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span><span style="color:#a6e22e">isset</span>($xs[$i])) <span style="color:#66d9ef">break</span>; <span style="color:#66d9ef">else</span>
-</span></span><span style="display:flex;"><span>$t <span style="color:#f92672">.=</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#a6e22e">str_split</span>(<span style="color:#a6e22e">str_replace</span>([<span style="color:#e6db74">&#39;0&#39;</span>,<span style="color:#e6db74">&#39;1&#39;</span>], [<span style="color:#e6db74">&#39; &#39;</span>,<span style="color:#e6db74">&#39;##&#39;</span>], <span style="color:#a6e22e">sprintf</span>(<span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;025b&#39;</span>, $xs[$i])), <span style="color:#ae81ff">012</span>)) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n\n</span><span style="color:#e6db74">&#34;</span>;
-</span></span><span style="display:flex;"><span>$ws <span style="color:#f92672">=</span> <span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($w) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#39;, &#39;</span>, $w), <span style="color:#a6e22e">array_chunk</span>(<span style="color:#a6e22e">array_map</span>(<span style="color:#a6e22e">fn</span>($x) <span style="color:#f92672">=&gt;</span> <span style="color:#a6e22e">sprintf</span>(<span style="color:#e6db74">&#39;0x&#39;</span> <span style="color:#f92672">.</span> <span style="color:#a6e22e">chr</span>(<span style="color:#ae81ff">37</span>) <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;07X&#39;</span>, $x), $xs), <span style="color:#ae81ff">10</span>));
-</span></span><span style="display:flex;"><span><span style="color:#a6e22e">printf</span>($s, $t, <span style="color:#a6e22e">str_rot13</span>(<span style="color:#e6db74">&#34;&lt;&lt;&lt;&#39;D&#39;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">{</span>$s<span style="color:#e6db74">}</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">D&#34;</span>), <span style="color:#a6e22e">implode</span>(<span style="color:#e6db74">&#34;,</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, $ws));
-</span></span></code></pre></div><p>コメントにもあるとおり、次のようにして実行すれば答えがでてくる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ php toquine.php | php | php | php | ...
-</span></span></code></pre></div><p>実際にはもう少しパイプで繋げなければならない。</p>
-<h2 id="解説-1">解説</h2>
-<h3 id="プログラム全体-1">プログラム全体</h3>
-<p>コメントにもあるとおり、これは quine (風) のプログラムになっている。
-Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。</p>
-<p>このプログラムは、実行すると自身とほとんど同じプログラムを出力する。
-異なるのはトークンになっている部分のみである。</p>
-<h3 id="トークン">トークン</h3>
-<p><code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code> とほぼ同じなので省略する。</p>
-<h3 id="状態保持">状態保持</h3>
-<p>トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。
-このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code>__LINE__</code> から情報を取得している。</p>
-<h3 id="rot-13">ROT 13</h3>
-<p>Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。
-これがあまり美しくないので、<code>toquine.php</code> では、ROT 13 変換を使って難読化した。</p>
-<p>それにしてもなぜこんなものが標準ライブラリに……。</p>
-<h1 id="おわりに">おわりに</h1>
-<p>解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。</p>
-<p>今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、
-来年は 5問、より面白い問題を持っていきます。</p>
-<p>実はもう作りはじめているので、どうか来年もありますように……。</p>
-]]></description>
- </item>
-
- <item>
- <title>PHPerKaigi 2021</title>
- <link>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</link>
- <pubDate>Tue, 30 Mar 2021 23:22:40 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/</guid>
- <description><![CDATA[ <h1 id="phperkaigi-2021-参加レポ">PHPerKaigi 2021 参加レポ</h1>
-<p>2021-03-26 から 2021-03-28 にかけて開催された、<a href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</a> に一般参加者として参加した。
-弊社<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> (今年1月から勤務) はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
-<p>このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。</p>
-<p>発表はトラック A、B に分かれていたのだが、今回はすべて A トラックを視聴している (切り替えるのが面倒だっただけ)。</p>
-<h2 id="凡例">凡例</h2>
-<blockquote>
-<p>発表・スライドのメモ (引用ではない)</p>
-</blockquote>
-<p>感想など</p>
-<h2 id="day-0-前夜祭-20210327">Day 0 前夜祭 (2021/03/27)</h2>
-<h3 id="1730-a">17:30 [A]</h3>
-<p>PHP で AWS Lambda</p>
-<blockquote>
-<p>Rails のプロジェクトを PHPer のメンバのみでメンテ
-→他のメンバもわかる PHP にリプレースを検討</p>
-<p>サーバレス</p>
-<ul>
-<li>サーバ・インフラの管理が不要</li>
-<li>アプリケーションコードの知識だけで保守可能</li>
-</ul>
-<p>ゼロベースで作れる案件が (Railsの件とは別に) あるため、そちらで試験的に導入?</p>
-<p>AWSの学習
-AWS のドキュメント
-DevelopersIO</p>
-<p>AWS Lambda のカスタムランタイムで PHP を動かす</p>
-<p>サーバのセットアップや維持管理を気にしなくて良い
-サーバーレスで PHP を動かすツールがすでにある
-サーバーレス構築はすんなり</p>
-<p>今は Laravel がルーティングしている
-Laravel Livewire を Lambda に載せられないか?
-デプロイ方法は?
-バッチ処理は? (Lambda は 15分の制限)</p>
-<p>Lambda でコンテナイメージがサポートされるように</p>
-<p>抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる</p>
-</blockquote>
-<p>AWS Lambda のような Function as a Service はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に web サービスを作る具体的なイメージがまだ見えない (注: すべて for me として書いている)。</p>
-<p>PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。</p>
-<p>勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP + Laravel などでは動かなさそう) だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。</p>
-<h3 id="1810-a">18:10 [A]</h3>
-<p>大規模サイトの SEO</p>
-<blockquote>
-<p>大規模サイト (100万ページ以上)
-Google の基準</p>
-<p>クロールバジェットを意識したSEO</p>
-<p>大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト (10,000以上) でコンテンツが目まぐるしく変更される
-これを満たさないなら、クロールバジェットを考えなくてもいい</p>
-<p>サーチコンソール
-「カバレッジ」の「除外」
-多すぎるのは問題→クロールバジェットを浪費している</p>
-<ul>
-<li>クエリの順番を決める</li>
-<li>空の値のルールを決めておく</li>
-<li>リダイレクトすればインデックスはうまくいく</li>
-<li>リンクが存在する限りクロールはされる</li>
-</ul>
-<p>リニューアル前のURL</p>
-<p>インデックスは移行される
-リンクのURLが存在する限り、別のURLとしてクロールされる
-リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い
-リニューアルで無視されるようになったパラメータも注意</p>
-<p>robotes.txt で拒否しているのにクロールされる
-一時的に拒否を外して 404 や 301 を読ませる
-内部リンクを確認する
-JS でのリンクに書き換え</p>
-<p>クエリパラメータからURLのパスに
-<code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code></p>
-<p>URL 設計だいじ</p>
-</blockquote>
-<p>SEO (Search Engine Optimization) は大して知らないので新鮮な話が多かった。その分語れることも少ない……。</p>
-<h3 id="1850-a">18:50 [A]</h3>
-<blockquote>
-<p>知覚可能
-操作可能
-理解可能
-堅牢 ちゃんとしたHTMLを書く (閉じタグ・入れ子構造など)</p>
-<ul>
-<li>
-<p>標準の HTML を適切に使う</p>
-</li>
-<li>
-<p>WAI-ARIA</p>
-</li>
-<li>
-<p>キーボードフレンドリー</p>
-</li>
-<li>
-<p>マシンフレンドリー</p>
-</li>
-<li>
-<p>SEOフレンドリー</p>
-</li>
-</ul>
-<p>button タグ
-→キーボード
-h1 タグ
-→スクリーンリーダー・クローラ
-a タグ</p>
-<p>WAI-ARIA
-HTML では表現できないセマンティクスを追加する</p>
-<ul>
-<li>ロール
-<ul>
-<li>何をするのか?</li>
-<li>ユーザーアクションによって変化しない</li>
-</ul>
-</li>
-<li>プロパティ
-<ul>
-<li>関連づけられたデータ</li>
-</ul>
-</li>
-<li>ステート
-<ul>
-<li>現在の状態</li>
-</ul>
-</li>
-</ul>
-<p>まずは標準の HTML 要素で解決する
-何でもかんでも WAI-ARIA を使えばいいというものではない</p>
-<p>マウスホバーでツールチップが出てくるが、キーボード操作では出てこない</p>
-<p>VoiceOver</p>
-<p>全ての属性を使う必要はない
-あくまでアクセシビリティを上げるための方法の一つにすぎない</p>
-</blockquote>
-<p>つい最近 WAI-ARIA についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが) いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。</p>
-<h3 id="1930-a">19:30 [A]</h3>
-<p>PHP で FUSE</p>
-<p>個人的に楽しみだった発表。</p>
-<blockquote>
-<p>VFS (virtual filesystem) vs 具体的なファイルシステム</p>
-<p>最適な実装方法は状況により異なる</p>
-<p>アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS</p>
-<p>カーネルのプログラムを作るのは難しい</p>
-<ul>
-<li>権限がデカすぎる</li>
-<li>システム全体がクラッシュ</li>
-<li>セキュリティリスク</li>
-<li>開発サイクルを回しづらい</li>
-<li>ネイティブコードにコンパイルされる言語である必要がある</li>
-</ul>
-<p>Filesystem in USEr space (FUSE)</p>
-<ul>
-<li>特定の C の関数を呼ぶことで filesystem が作れる</li>
-<li>FFI を持つ言語なら FUSE が使える</li>
-</ul>
-<p>SSHFS / s3fs / Docker Desktop</p>
-<p>Linux 以外でも使える</p>
-<ul>
-<li>dokany (on Windows)</li>
-<li>osxfuse</li>
-</ul>
-<p>VFS: システムコールが呼ばれると、ファイルシステムによってコール
-FUSE: カーネル空間からユーザ空間へ通信</p>
-<p>高レベルなラッパで型をつける</p>
-<p>PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)</p>
-<ul>
-<li>grep できる</li>
-<li>sed できる</li>
-<li>編集できる</li>
-</ul>
-</blockquote>
-<p>期待通りの興味深い発表だった。FUSE 自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。
-この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ (ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。</p>
-<h2 id="day-1-20210327">Day 1 (2021/03/27)</h2>
-<h3 id="1050-a">10:50 [A]</h3>
-<p>ATDD</p>
-<blockquote>
-<ul>
-<li>ユーザーストーリー</li>
-<li>ユニットテスト</li>
-<li>CI/CD</li>
-</ul>
-<p>ユーザストーリーの受け入れ条件が曖昧になりがち
-デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている</p>
-<p>Q2の強化
-アジャイルテストの4象限</p>
-<p>技術面/ビジネス面
-開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)</p>
-<ul>
-<li>Q1: 技術面 &amp; チーム支援
-<ul>
-<li>TDD</li>
-<li>ユニットテストなど</li>
-</ul>
-</li>
-<li>Q2: ビジネス面 &amp; チーム支援
-<ul>
-<li>ATDD</li>
-<li>ビジネス面の受け入れテストで駆動する</li>
-</ul>
-</li>
-</ul>
-<p>Agile Alliance
-ユーザストーリーのスキルレベルを高める</p>
-<p>テストピラミッド</p>
-<ul>
-<li>
-<p>UI Tests</p>
-</li>
-<li>
-<p>Service Tests</p>
-</li>
-<li>
-<p>Unit Tests</p>
-</li>
-<li>
-<p>異なる粒度のテストを書く</p>
-</li>
-<li>
-<p>高レベルになるほど、持つべきテストは少なくなる</p>
-<ul>
-<li>ピラミッド型になる</li>
-</ul>
-</li>
-</ul>
-<p>高レベルテストが多すぎる→アイスクリームコーン アンチパターン</p>
-<p>ATDD (Acceptance TDD)
-API経由・UI経由での高レベルテスト E2E test</p>
-<p>ストーリ受け入れテスト</p>
-<p>入れ子のフィードバックループ
-ATDD(外側) と TDD(内側)</p>
-<p>外部品質・内部品質</p>
-<p>バーティカルスライスのデリバリー</p>
-<ul>
-<li>cucumber</li>
-<li>gauge</li>
-<li>behat</li>
-</ul>
-<p>ユビキタス言語
-手動テストもspecに書く
-自動化は可能だがコスパが悪い
-失敗することがわかっているテスト(レッドテスト)はCIから外す
-失敗時の原因究明が難しい
-饒舌なエラーメッセージ
-状況のスナップショット</p>
-<p>Continuous Testing</p>
-</blockquote>
-<p>User Acceptance Test (UAT) くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。
-高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。</p>
-<h3 id="1150-a">11:50 [A]</h3>
-<p>型解析を用いたリファクタリング</p>
-<p>型のある世界で生きてきた身として大いに楽しみにしていた発表。</p>
-<blockquote>
-<ul>
-<li>PHPStan</li>
-<li>Phan</li>
-<li>Psalm</li>
-</ul>
-<p>autoload も認識できる
-bootstrapFiles</p>
-<p>編集箇所と利用箇所を CI でチェック
-ルールレベルを徐々に引き上げていく
-警告が多すぎると見落としてしまう・無視されやすくなる</p>
-<p>型がついていないことによるエラーが多い</p>
-<p>型よりも詳細な検査 <code>Util_Assert::min</code></p>
-<p>SQL を静的解析
-placeholder の型付け</p>
-<p>警告レベルを低いレベルから導入
-タイプヒントを積極的に書いていく
-PHPStan の拡張を追加する</p>
-</blockquote>
-<p>昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。
-今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で Ruby の typeprof には注目している。</p>
-<h3 id="1230-a">12:30 [A]</h3>
-<p>昼食をとっていた。事前に何か食料を買っておくべきだった。</p>
-<h3 id="1310-a">13:10 [A]</h3>
-<p>Documentation as Code</p>
-<p>この発表も以前から非常に楽しみにしていた。</p>
-<blockquote>
-<p>開発開始までのオーバーヘッド
-新規にチームにジョイン
-担当範囲外の機能を理解
-オンボーディングのコスト</p>
-<p>PHPerKaigi 2020 で発表あり</p>
-<p>継続的にシステムの理解を助けるドキュメント</p>
-<p>継続的ドキュメンテーション
-システムとドキュメントの乖離</p>
-<p>書いてあることが間違っている・足りない</p>
-<ul>
-<li>徐々にずれていく</li>
-<li>システムの更新タイミングとドキュメントの更新タイミングに差がある</li>
-</ul>
-<p>システムとドキュメントは対応関係がある</p>
-<ul>
-<li>間違ったドキュメント</li>
-<li>存在しないドキュメント</li>
-</ul>
-<p>システムとドキュメントの乖離を定量化する
-継続的に
-システムの更新に近いタイミングで ドキュメントを更新し続ける</p>
-<p>Documentation as Code</p>
-<p>コードと同じツールでドキュメントを書く</p>
-<ul>
-<li>issue tracker</li>
-<li>vcs</li>
-<li>plain text markup</li>
-<li>automation</li>
-</ul>
-<p>開発者
-システム
-ドキュメント
-構造化データ
-ソフトウェア</p>
-<p>システムから構造化データを抽出する
-PHPDoc
-OpenAPI</p>
-<p>ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する</p>
-<p>ビューの単位でドキュメントに</p>
-<p>スタックトレースからのドキュメント生成</p>
-</blockquote>
-<p>ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な (乖離しない) 情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。</p>
-<h3 id="1410-a">14:10 [A]</h3>
-<p>cookie による session 管理</p>
-<p>全体的に基本的な話だったので特に触れない。Cookie やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。</p>
-<h3 id="1450-a">14:50 [A]</h3>
-<p>PHP のエラーと例外</p>
-<blockquote>
-<p>エラー PHPエンジンがエラーを通知する
-例外 プログラムが投げる</p>
-<p>PHP7-8とエラー</p>
-<p>PHPエンジンのエラーの一部が \Error に変換されるようになった
-→ try-catch で捕捉できる</p>
-<p>\Error は例外とは異なる</p>
-<p>PHP8 でエラーレベルの引き上げ</p>
-<ul>
-<li>捕捉すべきもの
-<ul>
-<li>recoverable</li>
-</ul>
-</li>
-<li>捕捉すべきでないもの
-<ul>
-<li>unrecoverable</li>
-<li>開発時に対処できるもの</li>
-</ul>
-</li>
-</ul>
-<p>例外</p>
-<ul>
-<li>捕捉して事後処理</li>
-<li>捕捉せず(or 捕捉した上で)さらに上に是非を問う</li>
-</ul>
-<p>開発段階で例外を把握し、ハンドリングを考えておく</p>
-<p>\Throwable \Exception と \Error</p>
-<p>\Error はキャッチすべきでない</p>
-<ul>
-<li>
-<p>\Error</p>
-<ul>
-<li>本番で起きてはいけない</li>
-</ul>
-</li>
-<li>
-<p>\LogicException</p>
-<ul>
-<li>本番で起きてはいけない
-→生じないのだから捕捉もしない</li>
-</ul>
-</li>
-<li>
-<p>\RuntimeException</p>
-<ul>
-<li>起こるかもしれないので本番環境でも考慮する</li>
-</ul>
-</li>
-</ul>
-<p>捕捉して対応するのではなく、未然に防ぐ</p>
-<p>独自例外を使う
-\Exception を投げてしまうと、
-catch (\Exception)せざるを得ない
-→catch 範囲が広すぎる</p>
-<p>SPL の例外を使う</p>
-<p>例外翻訳
-上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する
-下位レイヤの知識に依存させない</p>
-<p>@throws
-捕捉してほしい例外を書き連ねておく</p>
-<p>呼び出しもとに負わせたい責任</p>
-</blockquote>
-<p>PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で PHP を書き始めてから 4ヶ月ほどになる)。</p>
-<p>個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell などのエラーを「値として」扱う言語だと思っている。try-catch は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる (C のそれはまともな型付けではない。念のため)。</p>
-<p>PHP のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。</p>
-<h3 id="1530-a">15:30 [A]</h3>
-<p>Laravel のメール認証</p>
-<p>Laravel の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。</p>
-<h3 id="1610-a">16:10 [A]</h3>
-<p>gRPC</p>
-<blockquote>
-<p>Unary RPCs
-Server streaming RPCs
-Client streaming RPCs
-Bidirectional streaming RPCs</p>
-<p>Protobuf</p>
-<p>実装とAPIが乖離しにくい
-自動生成
-複数言語でも相互に使える</p>
-<p>マイクロサービスのサービス通信
-スマホアプリ
-ゲームサーバ</p>
-<p>PHP では?</p>
-<p>PHP ではストリーミングが難しい
-リクエストごとにプロセスが使い捨て</p>
-<p>PHP ではgRPCのクライアントしか対応していない</p>
-<p>gRPC-Web
-ブラウザで扱うためのJSライブラリ+プロトコル</p>
-<p>HTTP/1.1 でも使える
-Unary RPC と Server streaming RPC のみ</p>
-<p>Envoy
-Nginx などで相互に gRPC と gRPC-Web で変換</p>
-<p>Amp
-イベント駆動な並行処理のフレームワーク</p>
-<p>HTTP/2 対応</p>
-<p>C#のgRPC-Webが楽</p>
-</blockquote>
-<p>(発表の中でもまさに同じことをおっしゃっていたが) PHP 以外の方が向いているだろう、というのが第一の感想である。gRPC はそれ自体というよりも Protobuf というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。</p>
-<h3 id="1650-a">16:50 [A]</h3>
-<p>アーキテクチャテスト</p>
-<blockquote>
-<p>Independent Core Layer Pattern</p>
-<p>開発初期のアーキテクチャが崩れる
-アーキテクチャ観点のコードレビューができない</p>
-<p>どこにクラスを置けばよいか?
-ドキュメントがない</p>
-<p>アーキテクチャ設計に関する知識が属人化・暗黙知化</p>
-<p>ガイドライン</p>
-<ul>
-<li>最初にルールを決めるのは簡単</li>
-<li>ルール通り作り始めるのも簡単
-<ul>
-<li>→維持するのが難しい、人が決めたものゆえ壊れやすい</li>
-</ul>
-</li>
-</ul>
-<p>PHP の特性</p>
-<ul>
-<li>クラスは public</li>
-<li>可視性の制御が public / protected / private のみ</li>
-<li>依存関係の制御が困難</li>
-</ul>
-<p>アーキテクチャテスト
-クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する</p>
-<ul>
-<li>deptrac</li>
-<li>phpat</li>
-</ul>
-<p>Independent Core Layer Pattern</p>
-<p>アーキテクチャテストの失敗</p>
-<ul>
-<li>実装誤り</li>
-<li>or アーキテクチャが適切でない
-<ul>
-<li>開発の過程でフィードバックしていく</li>
-</ul>
-</li>
-</ul>
-<p>モジュラーモノリス→マイクロサービスへ</p>
-</blockquote>
-<h2 id="day-2-20210328">Day 2 (2021/03/28)</h2>
-<p>冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。</p>
-<p>残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。</p>
-<h2 id="全体の感想">全体の感想</h2>
-<p>Day 2 にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも (特に初参加者として) 嬉しいポイントだった。</p>
-<p>今回、雑談/登壇者への質問等向けに Discord サーバもあったのだが、こちらは参加こそしたものの ROM のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord 表示に 1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった (さらにいうと Zoom でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。</p>
-<p>1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。
-まあ初カンファレンスだし、とお茶を濁しておこう。</p>
-<p>さて、カンファレンスで一つ気になったことがある。それは、Discord という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。</p>
-<hr>
-<p>最後になりましたが、毎年の PHPerKaigi 開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました!
-(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)</p>
-<p>ではまた来年。</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/phperkaigi/index.html b/docs/tags/phperkaigi/index.html
deleted file mode 100644
index ac09c96..0000000
--- a/docs/tags/phperkaigi/index.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>phperkaigi | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/phperkaigi/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>phperkaigi</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2023: ボツになったトークン問題 その 1</h2>
- </header>
- <section class="entry-content">
- <p>来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、
-ボツになった問題を公開する (その 1)。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-10-23</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2022</h2>
- </header>
- <section class="entry-content">
- <p>2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-05-01</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-05-01/phperkaigi-2022/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2022 トークン問題の解説</h2>
- </header>
- <section class="entry-content">
- <p>PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2022-04-09</time>, updated on <time>2022-04-16</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2022-04-09/phperkaigi-2022-tokens/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>PHPerKaigi 2021</h2>
- </header>
- <section class="entry-content">
- <p>2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-03-30</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-03-30/phperkaigi-2021/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/phperkaigi/page/1/index.html b/docs/tags/phperkaigi/page/1/index.html
deleted file mode 100644
index 38c704d..0000000
--- a/docs/tags/phperkaigi/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/phperkaigi/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/phperkaigi/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/phperkaigi/">
- </head>
-</html>
diff --git a/docs/tags/python/feed.xml b/docs/tags/python/feed.xml
deleted file mode 100644
index 3b8ba29..0000000
--- a/docs/tags/python/feed.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>python on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/python/</link>
- <description>Recent content in python on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sat, 02 Oct 2021 09:32:37 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/python/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>[Python] クロージャとUnboundLocalError: local variable &#39;x&#39; referenced before assignment</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</link>
- <pubDate>Sat, 02 Oct 2021 09:32:37 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</a></p>
-<hr>
-<p>本記事は Python 3.7.6 の動作結果を元にして書かれている。</p>
-<p>Python でクロージャを作ろうと、次のようなコードを書いた。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>f()
-</span></span></code></pre></div><p>関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに 1 を足そうとしている。
-これを実行すると <code>x += 1</code> の箇所でエラーが発生する。</p>
-<blockquote>
-<p>UnboundLocalError: local variable &lsquo;x&rsquo; referenced before assignment</p>
-</blockquote>
-<p>local変数 <code>x</code> が代入前に参照された、とある。これは、<code>f</code> の <code>x</code> を参照するのではなく、新しく別の変数を <code>g</code> 内に作ってしまっているため。
-前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code> を変数宣言のための構文として擬似的に利用している。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># 注: var は正しい Python の文法ではない。上記参照のこと</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># f の local変数 &#39;x&#39; を宣言</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e"># x に 0 を代入</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>(): <span style="color:#75715e"># f の内部関数 g を定義</span>
-</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># g の local変数 &#39;x&#39; を宣言</span>
-</span></span><span style="display:flex;"><span> <span style="color:#75715e"># たまたま f にも同じ名前の変数があるが、それとは別の変数</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span> <span style="color:#75715e"># x に 1 を加算 (x = x + 1 の糖衣構文)</span>
-</span></span><span style="display:flex;"><span> <span style="color:#75715e"># 加算する前の値を参照しようとするが、まだ代入されていないためエラー</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span></code></pre></div><p>当初の意図を表現するには、次のように書けばよい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>():
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">nonlocal</span> x <span style="color:#75715e">## (*)</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span></code></pre></div><p><code>(*)</code> のように、<code>nonlocal</code> を追加する。これにより一つ外側のスコープ (<code>g</code> の一つ外側 = <code>f</code>) で定義されている <code>x</code> を探しに行くようになる。</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/python/index.html b/docs/tags/python/index.html
deleted file mode 100644
index 884872e..0000000
--- a/docs/tags/python/index.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>python | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/python/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>python</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Python] クロージャとUnboundLocalError: local variable &#39;x&#39; referenced before assignment</h2>
- </header>
- <section class="entry-content">
- <p>Python における UnboundLocalError の理由と対処法。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/python/page/1/index.html b/docs/tags/python/page/1/index.html
deleted file mode 100644
index ca045d7..0000000
--- a/docs/tags/python/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/python/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/python/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/python/">
- </head>
-</html>
diff --git a/docs/tags/python3/feed.xml b/docs/tags/python3/feed.xml
deleted file mode 100644
index 260f94a..0000000
--- a/docs/tags/python3/feed.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>python3 on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/python3/</link>
- <description>Recent content in python3 on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sat, 02 Oct 2021 09:32:37 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/python3/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>[Python] クロージャとUnboundLocalError: local variable &#39;x&#39; referenced before assignment</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</link>
- <pubDate>Sat, 02 Oct 2021 09:32:37 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</a></p>
-<hr>
-<p>本記事は Python 3.7.6 の動作結果を元にして書かれている。</p>
-<p>Python でクロージャを作ろうと、次のようなコードを書いた。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span>f()
-</span></span></code></pre></div><p>関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに 1 を足そうとしている。
-これを実行すると <code>x += 1</code> の箇所でエラーが発生する。</p>
-<blockquote>
-<p>UnboundLocalError: local variable &lsquo;x&rsquo; referenced before assignment</p>
-</blockquote>
-<p>local変数 <code>x</code> が代入前に参照された、とある。これは、<code>f</code> の <code>x</code> を参照するのではなく、新しく別の変数を <code>g</code> 内に作ってしまっているため。
-前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code> を変数宣言のための構文として擬似的に利用している。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># 注: var は正しい Python の文法ではない。上記参照のこと</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># f の local変数 &#39;x&#39; を宣言</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e"># x に 0 を代入</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>(): <span style="color:#75715e"># f の内部関数 g を定義</span>
-</span></span><span style="display:flex;"><span> var x <span style="color:#75715e"># g の local変数 &#39;x&#39; を宣言</span>
-</span></span><span style="display:flex;"><span> <span style="color:#75715e"># たまたま f にも同じ名前の変数があるが、それとは別の変数</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span> <span style="color:#75715e"># x に 1 を加算 (x = x + 1 の糖衣構文)</span>
-</span></span><span style="display:flex;"><span> <span style="color:#75715e"># 加算する前の値を参照しようとするが、まだ代入されていないためエラー</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span></code></pre></div><p>当初の意図を表現するには、次のように書けばよい。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f</span>():
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">g</span>():
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">nonlocal</span> x <span style="color:#75715e">## (*)</span>
-</span></span><span style="display:flex;"><span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> g()
-</span></span></code></pre></div><p><code>(*)</code> のように、<code>nonlocal</code> を追加する。これにより一つ外側のスコープ (<code>g</code> の一つ外側 = <code>f</code>) で定義されている <code>x</code> を探しに行くようになる。</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/python3/index.html b/docs/tags/python3/index.html
deleted file mode 100644
index 5e18ffd..0000000
--- a/docs/tags/python3/index.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>python3 | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/python3/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>python3</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Python] クロージャとUnboundLocalError: local variable &#39;x&#39; referenced before assignment</h2>
- </header>
- <section class="entry-content">
- <p>Python における UnboundLocalError の理由と対処法。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/python-unbound-local-error/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/python3/page/1/index.html b/docs/tags/python3/page/1/index.html
deleted file mode 100644
index 1c8bbe3..0000000
--- a/docs/tags/python3/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/python3/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/python3/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/python3/">
- </head>
-</html>
diff --git a/docs/tags/ruby/feed.xml b/docs/tags/ruby/feed.xml
deleted file mode 100644
index 50612e5..0000000
--- a/docs/tags/ruby/feed.xml
+++ /dev/null
@@ -1,230 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>ruby on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/ruby/</link>
- <description>Recent content in ruby on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sat, 02 Oct 2021 09:38:50 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/ruby/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>[Ruby] then キーワードと case in</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</link>
- <pubDate>Sat, 02 Oct 2021 09:38:50 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</a></p>
-<hr>
-<h1 id="tl-dr">TL; DR</h1>
-<p><code>case</code> - <code>in</code> によるパターンマッチング構文でも、<code>case</code> - <code>when</code> と同じように <code>then</code> が使える (場合によっては使う必要がある)。</p>
-<h1 id="then-とは"><code>then</code> とは</h1>
-<p>使われることは稀だが、Ruby では <code>then</code> がキーワードになっている。次のように使う:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> cond <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">&#34;Y&#34;</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
-</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">&#34;N&#34;</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code> 構文がそれに当たる。
-上記のように、何か条件を書いた後 <code>then</code> を置き、式がそこで終了していることを示すマーカーとして機能する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># Example:</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> x <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">unless</span> x <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">begin</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">rescue</span> <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">when</span> p <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><h1 id="なぜ普段は書かなくてもよいのか">なぜ普段は書かなくてもよいのか</h1>
-<p>普通 Ruby のコードで <code>then</code> を書くことはない。なぜか。次のコードを実行してみるとわかる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span> puts <span style="color:#e6db74">&#39;Hello, World!&#39;</span> <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>次のような構文エラーが出力される。</p>
-<pre tabindex="0"><code>20:1: syntax error, unexpected local variable or method, expecting `then&#39; or &#39;;&#39; or &#39;\n&#39;
-if true puts &#39;Hello, World!&#39; end
- ^~~~
-20:1: syntax error, unexpected `end&#39;, expecting end-of-input
-...f true puts &#39;Hello, World!&#39; end
-</code></pre><p>二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code> か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。</p>
-<p>ポイントは改行が <code>then</code> (や <code>;</code>) の代わりとなることである。<code>true</code> の後に改行を入れてみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span>
-</span></span><span style="display:flex;"><span>puts <span style="color:#e6db74">&#39;Hello, World!&#39;</span> <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>無事 Hello, World! と出力されるようになった。</p>
-<h1 id="なぜ-then-や--や改行が必要か">なぜ <code>then</code> や <code>;</code> や改行が必要か</h1>
-<p>なぜ <code>then</code> や <code>;</code> や改行 (以下 「<code>then</code> 等」) が必要なのだろうか。次の例を見てほしい:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a b <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p><code>then</code> も <code>;</code> も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。
-この例は二通りに解釈できる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e"># その結果が truthy なら何もしない</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a(b) <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></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> も同じ役割を持つ。</p>
-<p>Ruby の場合、プログラマーが書きやすいよう改行でもって <code>then</code> が代用できるので、ほとんどの場合 <code>then</code> は必要ない。</p>
-<h1 id="case---in-における-then"><code>case</code> - <code>in</code> における <code>then</code></h1>
-<p>ようやく本題にたどり着いた。来る Ruby 3.0 では <code>case</code> と <code>in</code> キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして <code>then</code> 等が必要になる。
-(現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。</p>
-<p><a href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</a></p>
-<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in
- {
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- p-&gt;command_start = FALSE;
- $&lt;ctxt&gt;1 = p-&gt;ctxt;
- p-&gt;ctxt.in_kwarg = 1;
- $&lt;tbl&gt;$ = push_pvtbl(p);
- }
- {
- $&lt;tbl&gt;$ = push_pktbl(p);
- }
- p_top_expr then
- {
- pop_pktbl(p, $&lt;tbl&gt;3);
- pop_pvtbl(p, $&lt;tbl&gt;2);
- p-&gt;ctxt.in_kwarg = $&lt;ctxt&gt;1.in_kwarg;
- }
- compstmt
- p_cases
- {
- /*%%%*/
- $$ = NEW_IN($4, $7, $8, &amp;@$);
- /*% %*/
- /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
- }
- ;
-</code></pre><p>簡略版:</p>
-<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in p_top_expr then compstmt p_cases
- ;
-</code></pre><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>、改行のいずれかである。</p>
-<p>これにより、<code>case</code> - <code>when</code> による従来の構文と同じように、<code>then</code> 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span> <span style="color:#66d9ef">then</span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span> <span style="color:#66d9ef">then</span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span> <span style="color:#66d9ef">then</span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span>
-</span></span><span style="display:flex;"><span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span>; a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span>; b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span>; c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>ところで、<code>p_top_expr</code> には <code>if</code> による guard clause が書けるので、その場合は <code>if</code> - <code>then</code> と似たような見た目になる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">if</span> n <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">then</span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><h1 id="まとめ">まとめ</h1>
-<ul>
-<li><code>if</code> や <code>case</code> の条件の後ろには <code>then</code>、<code>;</code>、改行のいずれかが必要
-<ul>
-<li>通常は改行しておけばよい</li>
-</ul>
-</li>
-<li>3.0 で入る予定の <code>case</code> - <code>in</code> でも <code>then</code> 等が必要になる</li>
-<li>Ruby の構文を正確に知るには (現状) <code>parse.y</code> を直接読めばよい</li>
-</ul>
-]]></description>
- </item>
-
- <item>
- <title>[Ruby] 自身を実行している処理系の種類を判定する</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/</link>
- <pubDate>Sat, 02 Oct 2021 09:37:50 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</a></p>
-<hr>
-<p>Ruby という言語には複数の実装があるが、それらをスクリプト上からどのようにして programmatically に見分ければよいだろうか。</p>
-<p><code>Object</code> クラスに定義されている <code>RUBY_ENGINE</code> という定数がこの用途に使える。</p>
-<p>参考: <a href="https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html">Object::RUBY_ENGINE</a></p>
-<p>上記ページの例から引用する:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell-session" data-lang="shell-session"><span style="display:flex;"><span>$ ruby-1.9.1 -ve <span style="color:#e6db74">&#39;p RUBY_ENGINE&#39;</span>
-</span></span><span style="display:flex;"><span>ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux]
-</span></span><span style="display:flex;"><span>&#34;ruby&#34;
-</span></span><span style="display:flex;"><span>$ jruby -ve <span style="color:#e6db74">&#39;p RUBY_ENGINE&#39;</span>
-</span></span><span style="display:flex;"><span>jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
-</span></span><span style="display:flex;"><span>&#34;jruby&#34;
-</span></span></code></pre></div><p>それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。</p>
-<p><a href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE correspond to which Ruby implementations?</a> より引用:</p>
-<blockquote>
-<table>
-<thead>
-<tr>
-<th style="text-align:center">RUBY_ENGINE</th>
-<th style="text-align:left">Implementation</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td style="text-align:center">&lt;undefined&gt;</td>
-<td style="text-align:left">MRI &lt; 1.9</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;ruby&rsquo;</td>
-<td style="text-align:left">MRI &gt;= 1.9 or REE</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;jruby&rsquo;</td>
-<td style="text-align:left">JRuby</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;macruby&rsquo;</td>
-<td style="text-align:left">MacRuby</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;rbx&rsquo;</td>
-<td style="text-align:left">Rubinius</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;maglev&rsquo;</td>
-<td style="text-align:left">MagLev</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;ironruby&rsquo;</td>
-<td style="text-align:left">IronRuby</td>
-</tr>
-<tr>
-<td style="text-align:center">&lsquo;cardinal&rsquo;</td>
-<td style="text-align:left">Cardinal</td>
-</tr>
-</tbody>
-</table>
-</blockquote>
-<p>なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も <code>'ruby'</code> が返ってくることを確認済み。</p>
-<p>この表にない主要な処理系として、<a href="https://mruby.org">mruby</a> は <code>'mruby'</code> を返す。</p>
-<p><a href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby 該当部分のソース</a> より引用:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">/*
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * Ruby engine.
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">#define MRUBY_RUBY_ENGINE &#34;mruby&#34;
-</span></span></span></code></pre></div>]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/ruby/index.html b/docs/tags/ruby/index.html
deleted file mode 100644
index a23cbbf..0000000
--- a/docs/tags/ruby/index.html
+++ /dev/null
@@ -1,68 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>ruby | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/ruby/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>ruby</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Ruby] then キーワードと case in</h2>
- </header>
- <section class="entry-content">
- <p>Ruby 3.0 で追加される case in 構文と、then キーワードについて。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Ruby] 自身を実行している処理系の種類を判定する</h2>
- </header>
- <section class="entry-content">
- <p>Ruby には複数の実装があるが、自身を実行している処理系の種類をスクリプト上からどのように判定すればよいだろうか。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/ruby-detect-running-implementation/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/ruby/page/1/index.html b/docs/tags/ruby/page/1/index.html
deleted file mode 100644
index 9374bc8..0000000
--- a/docs/tags/ruby/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/ruby/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/ruby/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/ruby/">
- </head>
-</html>
diff --git a/docs/tags/ruby3/feed.xml b/docs/tags/ruby3/feed.xml
deleted file mode 100644
index 530cc62..0000000
--- a/docs/tags/ruby3/feed.xml
+++ /dev/null
@@ -1,155 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>ruby3 on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/ruby3/</link>
- <description>Recent content in ruby3 on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sat, 02 Oct 2021 09:38:50 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/ruby3/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>[Ruby] then キーワードと case in</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</link>
- <pubDate>Sat, 02 Oct 2021 09:38:50 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</a></p>
-<hr>
-<h1 id="tl-dr">TL; DR</h1>
-<p><code>case</code> - <code>in</code> によるパターンマッチング構文でも、<code>case</code> - <code>when</code> と同じように <code>then</code> が使える (場合によっては使う必要がある)。</p>
-<h1 id="then-とは"><code>then</code> とは</h1>
-<p>使われることは稀だが、Ruby では <code>then</code> がキーワードになっている。次のように使う:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> cond <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">&#34;Y&#34;</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
-</span></span><span style="display:flex;"><span> puts <span style="color:#e6db74">&#34;N&#34;</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code> 構文がそれに当たる。
-上記のように、何か条件を書いた後 <code>then</code> を置き、式がそこで終了していることを示すマーカーとして機能する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># Example:</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> x <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">unless</span> x <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">begin</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">rescue</span> <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">when</span> p <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><h1 id="なぜ普段は書かなくてもよいのか">なぜ普段は書かなくてもよいのか</h1>
-<p>普通 Ruby のコードで <code>then</code> を書くことはない。なぜか。次のコードを実行してみるとわかる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span> puts <span style="color:#e6db74">&#39;Hello, World!&#39;</span> <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>次のような構文エラーが出力される。</p>
-<pre tabindex="0"><code>20:1: syntax error, unexpected local variable or method, expecting `then&#39; or &#39;;&#39; or &#39;\n&#39;
-if true puts &#39;Hello, World!&#39; end
- ^~~~
-20:1: syntax error, unexpected `end&#39;, expecting end-of-input
-...f true puts &#39;Hello, World!&#39; end
-</code></pre><p>二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code> か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。</p>
-<p>ポイントは改行が <code>then</code> (や <code>;</code>) の代わりとなることである。<code>true</code> の後に改行を入れてみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#66d9ef">true</span>
-</span></span><span style="display:flex;"><span>puts <span style="color:#e6db74">&#39;Hello, World!&#39;</span> <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>無事 Hello, World! と出力されるようになった。</p>
-<h1 id="なぜ-then-や--や改行が必要か">なぜ <code>then</code> や <code>;</code> や改行が必要か</h1>
-<p>なぜ <code>then</code> や <code>;</code> や改行 (以下 「<code>then</code> 等」) が必要なのだろうか。次の例を見てほしい:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a b <span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p><code>then</code> も <code>;</code> も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。
-この例は二通りに解釈できる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e"># その結果が truthy なら何もしない</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> a(b) <span style="color:#66d9ef">then</span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></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> も同じ役割を持つ。</p>
-<p>Ruby の場合、プログラマーが書きやすいよう改行でもって <code>then</code> が代用できるので、ほとんどの場合 <code>then</code> は必要ない。</p>
-<h1 id="case---in-における-then"><code>case</code> - <code>in</code> における <code>then</code></h1>
-<p>ようやく本題にたどり着いた。来る Ruby 3.0 では <code>case</code> と <code>in</code> キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして <code>then</code> 等が必要になる。
-(現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。</p>
-<p><a href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</a></p>
-<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in
- {
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- p-&gt;command_start = FALSE;
- $&lt;ctxt&gt;1 = p-&gt;ctxt;
- p-&gt;ctxt.in_kwarg = 1;
- $&lt;tbl&gt;$ = push_pvtbl(p);
- }
- {
- $&lt;tbl&gt;$ = push_pktbl(p);
- }
- p_top_expr then
- {
- pop_pktbl(p, $&lt;tbl&gt;3);
- pop_pvtbl(p, $&lt;tbl&gt;2);
- p-&gt;ctxt.in_kwarg = $&lt;ctxt&gt;1.in_kwarg;
- }
- compstmt
- p_cases
- {
- /*%%%*/
- $$ = NEW_IN($4, $7, $8, &amp;@$);
- /*% %*/
- /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
- }
- ;
-</code></pre><p>簡略版:</p>
-<pre tabindex="0"><code class="language-yacc" data-lang="yacc">p_case_body : keyword_in p_top_expr then compstmt p_cases
- ;
-</code></pre><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>、改行のいずれかである。</p>
-<p>これにより、<code>case</code> - <code>when</code> による従来の構文と同じように、<code>then</code> 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span> <span style="color:#66d9ef">then</span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span> <span style="color:#66d9ef">then</span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span> <span style="color:#66d9ef">then</span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span>
-</span></span><span style="display:flex;"><span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span>
-</span></span><span style="display:flex;"><span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span>
-</span></span><span style="display:flex;"><span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">1</span>; a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">2</span>; b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">3</span>; c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><p>ところで、<code>p_top_expr</code> には <code>if</code> による guard clause が書けるので、その場合は <code>if</code> - <code>then</code> と似たような見た目になる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">case</span> x
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> a
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">if</span> n <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0</span> <span style="color:#66d9ef">then</span> b
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">in</span> n <span style="color:#66d9ef">then</span> c
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
-</span></span></code></pre></div><h1 id="まとめ">まとめ</h1>
-<ul>
-<li><code>if</code> や <code>case</code> の条件の後ろには <code>then</code>、<code>;</code>、改行のいずれかが必要
-<ul>
-<li>通常は改行しておけばよい</li>
-</ul>
-</li>
-<li>3.0 で入る予定の <code>case</code> - <code>in</code> でも <code>then</code> 等が必要になる</li>
-<li>Ruby の構文を正確に知るには (現状) <code>parse.y</code> を直接読めばよい</li>
-</ul>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/ruby3/index.html b/docs/tags/ruby3/index.html
deleted file mode 100644
index b204a64..0000000
--- a/docs/tags/ruby3/index.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>ruby3 | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/ruby3/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>ruby3</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Ruby] then キーワードと case in</h2>
- </header>
- <section class="entry-content">
- <p>Ruby 3.0 で追加される case in 構文と、then キーワードについて。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/ruby-then-keyword-and-case-in/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/ruby3/page/1/index.html b/docs/tags/ruby3/page/1/index.html
deleted file mode 100644
index 15caf8a..0000000
--- a/docs/tags/ruby3/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/ruby3/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/ruby3/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/ruby3/">
- </head>
-</html>
diff --git a/docs/tags/rust/feed.xml b/docs/tags/rust/feed.xml
deleted file mode 100644
index 60f98d3..0000000
--- a/docs/tags/rust/feed.xml
+++ /dev/null
@@ -1,143 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>rust on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/rust/</link>
- <description>Recent content in rust on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sat, 02 Oct 2021 09:39:27 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/rust/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>Rust のプリミティブ型はどこからやって来るか</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/</link>
- <pubDate>Sat, 02 Oct 2021 09:39:27 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</a></p>
-<hr>
-<h1 id="前置き">前置き</h1>
-<p>Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">#![allow(non_camel_case_types)]</span>
-</span></span><span style="display:flex;"><span><span style="color:#75715e">#![allow(dead_code)]</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">char</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i8</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i16</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i32</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i64</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">i128</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">isize</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u8</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u16</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u32</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u64</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">u128</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">usize</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f32</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">f64</span>;
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">str</span>;
-</span></span></code></pre></div><p>では、普段単に <code>bool</code> と書いたとき、この <code>bool</code> は一体どこから来ているのか。rustc のソースを追ってみた。</p>
-<blockquote>
-<p>前提知識: 一般的なコンパイラの構造、用語。<code>rustc</code> そのものの知識は不要 (というよりも筆者自身がよく知らない)</p>
-</blockquote>
-<h1 id="調査">調査</h1>
-<p>調査に使用したソース (調査時点での最新 master)</p>
-<p><a href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</a></p>
-<p>どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。</p>
-<p>大雑把な構造としては、<code>compiler</code> フォルダ以下に <code>rustc_*</code> という名前のクレートが数十個入っている。これがどうやら <code>rustc</code> コマンドの実装部のようだ。</p>
-<p><code>rustc</code> はセルフホストされている (= <code>rustc</code> 自身が Rust で書かれている) ので、<code>bool</code> や <code>char</code> などで適当に検索をかけてもノイズが多すぎて話にならない。
-しかし、お誂え向きなことに <code>i128</code>/<code>u128</code> というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って <code>git grep</code> してみる。</p>
-<pre tabindex="0"><code>$ git grep &#34;\bi128\b&#34; | wc # i128
- 165 1069 15790
-
-$ git grep &#34;\bu128\b&#34; | wc # u128
- 293 2127 26667
-
-$ git grep &#34;\bbool\b&#34; | wc # cf. bool の結果
- 3563 23577 294659
-</code></pre><p>165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。</p>
-<pre tabindex="0"><code>$ git grep &#34;\bi128\b&#34;
-...
-rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));
-...
-</code></pre><p><code>rustc_resolve</code> というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#e6db74">/// Interns the names of the primitive types.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">///
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// All other types are defined somewhere and possibly imported, but the primitive ones need
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">/// special handling, since they have no place of origin.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span><span style="color:#66d9ef">struct</span> <span style="color:#a6e22e">PrimitiveTypeTable</span> {
-</span></span><span style="display:flex;"><span> primitive_types: <span style="color:#a6e22e">FxHashMap</span><span style="color:#f92672">&lt;</span>Symbol, PrimTy<span style="color:#f92672">&gt;</span>,
-</span></span><span style="display:flex;"><span>}
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">impl</span> PrimitiveTypeTable {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">new</span>() -&gt; <span style="color:#a6e22e">PrimitiveTypeTable</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> <span style="color:#66d9ef">mut</span> table <span style="color:#f92672">=</span> FxHashMap::default();
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">bool</span>, Bool);
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">char</span>, Char);
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">f32</span>, Float(FloatTy::F32));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">f64</span>, Float(FloatTy::F64));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">isize</span>, Int(IntTy::Isize));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i8</span>, Int(IntTy::I8));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i16</span>, Int(IntTy::I16));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i32</span>, Int(IntTy::I32));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i64</span>, Int(IntTy::I64));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">i128</span>, Int(IntTy::I128));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">str</span>, Str);
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">usize</span>, Uint(UintTy::Usize));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u8</span>, Uint(UintTy::U8));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u16</span>, Uint(UintTy::U16));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u32</span>, Uint(UintTy::U32));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u64</span>, Uint(UintTy::U64));
-</span></span><span style="display:flex;"><span> table.insert(sym::<span style="color:#66d9ef">u128</span>, Uint(UintTy::U128));
-</span></span><span style="display:flex;"><span> Self { primitive_types: <span style="color:#a6e22e">table</span> }
-</span></span><span style="display:flex;"><span> }
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、</p>
-<blockquote>
-<p>All other types are defined somewhere and possibly imported, but the primitive ones need special handling, since they have no place of origin.</p>
-</blockquote>
-<p>とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span> <span style="color:#e6db74">/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span> <span style="color:#e6db74">/// (略)
-</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"></span> <span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">resolve_ident_in_lexical_scope</span>(
-</span></span><span style="display:flex;"><span> <span style="color:#f92672">&amp;</span><span style="color:#66d9ef">mut</span> self,
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">mut</span> ident: <span style="color:#a6e22e">Ident</span>,
-</span></span><span style="display:flex;"><span> ns: <span style="color:#a6e22e">Namespace</span>,
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// (略)
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> ) -&gt; Option<span style="color:#f92672">&lt;</span>LexicalScopeBinding<span style="color:#f92672">&lt;&#39;</span><span style="color:#a6e22e">a</span><span style="color:#f92672">&gt;&gt;</span> {
-</span></span><span style="display:flex;"><span> <span style="color:#75715e">// (略)
-</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> ns <span style="color:#f92672">==</span> TypeNS {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">let</span> Some(prim_ty) <span style="color:#f92672">=</span> self.primitive_type_table.primitive_types.get(<span style="color:#f92672">&amp;</span>ident.name) {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> binding <span style="color:#f92672">=</span>
-</span></span><span style="display:flex;"><span> (Res::PrimTy(<span style="color:#f92672">*</span>prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
-</span></span><span style="display:flex;"><span> .to_name_binding(self.arenas);
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> Some(LexicalScopeBinding::Item(binding));
-</span></span><span style="display:flex;"><span> }
-</span></span><span style="display:flex;"><span> }
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span> None
-</span></span><span style="display:flex;"><span> }
-</span></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> など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。</p>
-<p>なお、<code>ns</code> は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この <code>if</code> は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。</p>
-<p>重要なのは、これが <code>resolve_ident_in_lexical_scope()</code> の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。</p>
-<p>動作がわかったところで、例として次のコードを考える。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span><span style="color:#75715e">#![allow(non_camel_case_types)]</span>
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">struct</span> <span style="color:#66d9ef">bool</span>;
-</span></span><span style="display:flex;"><span>
-</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fn</span> <span style="color:#a6e22e">main</span>() {
-</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> _: <span style="color:#66d9ef">bool</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">bool</span>;
-</span></span><span style="display:flex;"><span>}
-</span></span></code></pre></div><p>ここで <code>main()</code> の <code>bool</code> は <code>struct bool</code> として解決される。なぜなら、プリミティブ型の判定をする前に <code>bool</code> という名前の別の型が見つかるからだ。</p>
-<h1 id="まとめ">まとめ</h1>
-<p>Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/rust/index.html b/docs/tags/rust/index.html
deleted file mode 100644
index 7b89cc4..0000000
--- a/docs/tags/rust/index.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>rust | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/rust/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>rust</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>Rust のプリミティブ型はどこからやって来るか</h2>
- </header>
- <section class="entry-content">
- <p>Rust のプリミティブ型は予約語ではなく普通の識別子である。どのようにこれが名前解決されるのかを調べた。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/rust-where-are-primitive-types-from/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/rust/page/1/index.html b/docs/tags/rust/page/1/index.html
deleted file mode 100644
index 5cf7d43..0000000
--- a/docs/tags/rust/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/rust/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/rust/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/rust/">
- </head>
-</html>
diff --git a/docs/tags/vim/feed.xml b/docs/tags/vim/feed.xml
deleted file mode 100644
index 73bb677..0000000
--- a/docs/tags/vim/feed.xml
+++ /dev/null
@@ -1,191 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>vim on REPL: Rest-Eat-Program Loop</title>
- <link>https://blog.nsfisis.dev/tags/vim/</link>
- <description>Recent content in vim on REPL: Rest-Eat-Program Loop</description>
- <generator>Hugo -- gohugo.io</generator>
- <language>ja-JP</language>
- <lastBuildDate>Sat, 02 Oct 2021 09:37:25 +0900</lastBuildDate><atom:link href="https://blog.nsfisis.dev/tags/vim/feed.xml" rel="self" type="application/rss+xml" />
- <item>
- <title>Vimで選択した行の順番を入れ替える</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/</link>
- <pubDate>Sat, 02 Oct 2021 09:37:25 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/4fefb361d9a693803520">https://qiita.com/nsfisis/items/4fefb361d9a693803520</a></p>
-<hr>
-<h1 id="バージョン情報">バージョン情報</h1>
-<p><code>:version</code> の一部</p>
-<blockquote>
-<p>VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Jan 26 2020 11:30:30)
-macOS version
-Included patches: 1-148
-Huge version without GUI.</p>
-</blockquote>
-<h1 id="よく紹介されている手法">よく紹介されている手法</h1>
-<h2 id="tac--tail"><code>tac</code> / <code>tail</code></h2>
-<p><code>tac</code> や <code>tail -r</code> などの外部コマンドを <code>!</code> を使って呼び出し、置き換える。</p>
-<blockquote>
-<p>:h v_!</p>
-</blockquote>
-<p><code>tac</code> コマンドや <code>tail</code> の <code>-r</code> オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい</p>
-<h2 id="gm0"><code>:g/^/m0</code></h2>
-<p>こちらは外部コマンドに頼らず、Vim の機能のみを使う。<code>g</code> は <code>:global</code> コマンドの、<code>m</code> は <code>:move</code> コマンドの略</p>
-<p><code>:global</code> コマンドは <code>:[range]global/{pattern}/[command]</code> のように使い、<code>[range]</code> で指定された範囲の行のうち、<code>{pattern}</code> で指定された検索パターンにマッチする行に対して、順番に <code>[command]</code> で指定された Ex コマンドを呼び出す。</p>
-<blockquote>
-<p>:h :global</p>
-</blockquote>
-<p><code>:move</code> コマンドは <code>[range]:move {address}</code> のように使い、<code>[range]</code> で指定された範囲の行を <code>{address}</code> で指定された位置に移動させる。</p>
-<blockquote>
-<p>:h :move</p>
-</blockquote>
-<p><code>:g/^/m0</code> のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。</p>
-<p>なお、<code>:g/^/m0</code> は全ての行を入れ替えるが、<code>:N,Mg/^/mN-1</code> とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ &lt;<span style="color:#a6e22e">line1</span>&gt;,&lt;<span style="color:#a6e22e">line2</span>&gt;<span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span>&lt;<span style="color:#a6e22e">line1</span>&gt;<span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div><p>これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。</p>
-<h1 id="gm0-の問題点"><code>:g/^/m0</code> の問題点</h1>
-<p><code>:global</code> コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<code>^</code> は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<code>'hlsearch'</code> オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと <code>n</code> コマンドなどの際に不便である。</p>
-<blockquote>
-<p>:h @/</p>
-</blockquote>
-<h1 id="解決策">解決策</h1>
-<blockquote>
-<p>[2020/9/28追記]
-より簡潔な方法を見つけたので次節に追記した</p>
-</blockquote>
-<p>前述した <code>:Reverse</code> コマンドの定義を少し変えて、次のようにする:</p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#66d9ef">function</span>! <span style="color:#a6e22e">s</span>:<span style="color:#a6e22e">reverse_lines</span>(<span style="color:#a6e22e">from</span>, <span style="color:#a6e22e">to</span>) <span style="color:#a6e22e">abort</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#a6e22e">execute</span> <span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">&#34;%d,%dg/^/m%d&#34;</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">from</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">to</span>, <span style="color:#a6e22e">a</span>:<span style="color:#a6e22e">from</span> - <span style="color:#ae81ff">1</span>)<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">endfunction</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">call</span> &lt;<span style="color:#a6e22e">SID</span>&gt;<span style="color:#a6e22e">reverse_lines</span>(&lt;<span style="color:#a6e22e">line1</span>&gt;, &lt;<span style="color:#a6e22e">line2</span>&gt;)<span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div><p>実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。</p>
-<p>この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが <code>^</code> で上書きされることがなくなる。</p>
-<p>Vim のヘルプから該当箇所を引用する (強調は筆者による)。</p>
-<blockquote>
-<p>:h autocmd-searchpat</p>
-<p><strong>Autocommands do not change the current search patterns.</strong> Vim saves the current
-search patterns before executing autocommands then restores them after the
-autocommands finish. This means that autocommands do not affect the strings
-highlighted with the &lsquo;hlsearch&rsquo; option.</p>
-</blockquote>
-<p>これは autocommand の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは <code>:nohlsearch</code> のヘルプにある。同じく該当箇所を引用する (強調は筆者による)。</p>
-<blockquote>
-<p>:h :nohlsearch</p>
-<p>(略) This command doesn&rsquo;t work in an autocommand, because
-the highlighting state is saved and restored when
-executing autocommands |autocmd-searchpat|.
-<strong>Same thing for when invoking a user function.</strong></p>
-</blockquote>
-<p>この仕様により、<code>:g/^/m0</code> の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。</p>
-<h1 id="解決策-改訂版">解決策 (改訂版)</h1>
-<blockquote>
-<p>[2020/9/28追記]
-より簡潔な方法を見つけたため追記する</p>
-</blockquote>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">keeppatterns</span> &lt;<span style="color:#a6e22e">line1</span>&gt;,&lt;<span style="color:#a6e22e">line2</span>&gt;<span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span>&lt;<span style="color:#a6e22e">line1</span>&gt;<span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div><p>まさにこのための Exコマンド、<code>:keeppatterns</code> が存在する。<code>:keeppatterns {command}</code> のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。</p>
-<blockquote>
-<p>:h :keeppatterns</p>
-</blockquote>
-<h1 id="コピペ用再掲">コピペ用再掲</h1>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#75715e">&#34; License: Public Domain</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">command</span>! -<span style="color:#a6e22e">bar</span> -<span style="color:#a6e22e">range</span>=%<span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">Reverse</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> \ <span style="color:#a6e22e">keeppatterns</span> &lt;<span style="color:#a6e22e">line1</span>&gt;,&lt;<span style="color:#a6e22e">line2</span>&gt;<span style="color:#a6e22e">g</span><span style="color:#e6db74">/^/</span><span style="color:#a6e22e">m</span>&lt;<span style="color:#a6e22e">line1</span>&gt;<span style="color:#ae81ff">-1</span><span style="color:#960050;background-color:#1e0010">
-</span></span></span></code></pre></div>]]></description>
- </item>
-
- <item>
- <title>[Vim] autocmd events の BufWrite/BufWritePre の違い</title>
- <link>https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/</link>
- <pubDate>Sat, 02 Oct 2021 09:37:12 +0900</pubDate>
-
- <guid>https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/</guid>
- <description><![CDATA[ <p>この記事は Qiita から移植してきたものです。
-元 URL: <a href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</a></p>
-<hr>
-<h1 id="tl-dr">TL; DR</h1>
-<p>違いはない。ただのエイリアス。</p>
-<h1 id="調査記録">調査記録</h1>
-<p>Vim の autocmd events には似通った名前のものがいくつかある。大抵は <code>:help</code> に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。</p>
-<ul>
-<li><code>BufRead</code>/<code>BufReadPost</code></li>
-<li><code>BufWrite</code>/<code>BufWritePre</code></li>
-<li><code>BufAdd</code>/<code>BufCreate</code></li>
-</ul>
-<p>このうち、<code>BufAdd</code>/<code>BufCreate</code> に関しては、<code>:help BufCreate</code> に</p>
-<blockquote>
-<p>The BufCreate event is for historic reasons.</p>
-</blockquote>
-<p>とあり、おそらくは <code>BufAdd</code> のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため vim と neovim のソースコードを調査した。</p>
-<blockquote>
-<p>ソースコードへのリンク
-<a href="https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2">vim (調査時点での master branch)</a>
-<a href="https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3">neovim (上に同じ)</a></p>
-</blockquote>
-<h2 id="vim-のソースコード">vim のソースコード</h2>
-<p>以下は、autocmd events の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。</p>
-<p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufAdd&#34;</span>, EVENT_BUFADD},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufCreate&#34;</span>, EVENT_BUFADD},
-</span></span></code></pre></div><p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufRead&#34;</span>, EVENT_BUFREADPOST},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufReadCmd&#34;</span>, EVENT_BUFREADCMD},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufReadPost&#34;</span>, EVENT_BUFREADPOST},
-</span></span></code></pre></div><p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufWrite&#34;</span>, EVENT_BUFWRITEPRE},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufWritePost&#34;</span>, EVENT_BUFWRITEPOST},
-</span></span><span style="display:flex;"><span> {<span style="color:#e6db74">&#34;BufWritePre&#34;</span>, EVENT_BUFWRITEPRE},
-</span></span></code></pre></div><h2 id="neovim-のソースコード">neovim のソースコード</h2>
-<p>neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua で書かれている。以下にある通り、はっきり <code>aliases</code> と書かれている。</p>
-<p><a href="https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124">https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124</a></p>
-<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span> aliases <span style="color:#f92672">=</span> {
-</span></span><span style="display:flex;"><span> BufCreate <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;BufAdd&#39;</span>,
-</span></span><span style="display:flex;"><span> BufRead <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;BufReadPost&#39;</span>,
-</span></span><span style="display:flex;"><span> BufWrite <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;BufWritePre&#39;</span>,
-</span></span><span style="display:flex;"><span> FileEncoding <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;EncodingChanged&#39;</span>,
-</span></span><span style="display:flex;"><span> },
-</span></span></code></pre></div><p>ところで、上では取り上げなかった <code>FileEncoding</code> だが、これは <code>:help FileEncoding</code> にしっかりと書いてある。</p>
-<pre tabindex="0"><code> *FileEncoding*
-FileEncoding Obsolete. It still works and is equivalent
- to |EncodingChanged|.
-</code></pre><h2 id="まとめ">まとめ</h2>
-<p>記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。</p>
-<ul>
-<li><code>BufAdd</code>/<code>BufCreate</code>
-<ul>
-<li>→ <code>BufCreate</code> は歴史的な理由により (&ldquo;for historic reasons&rdquo;) 存在しているため、新しい方 (<code>BufAdd</code>) を使う</li>
-</ul>
-</li>
-<li><code>BufRead</code>/<code>BufReadPost</code>
-<ul>
-<li>→ <code>BufReadPre</code> との対称性のため、あるいは <code>BufWritePost</code> との対称性のため <code>BufReadPost</code> を使う</li>
-</ul>
-</li>
-<li><code>BufWrite</code>/<code>BufWritePre</code>
-<ul>
-<li>→ <code>BufWritePost</code> との対称性のため、あるいは <code>BufReadPre</code> との対称性のため <code>BufWritePre</code> を使う</li>
-</ul>
-</li>
-<li><code>FileEncoding</code>/<code>EncodingChanged</code>
-<ul>
-<li>→ <code>FileEncoding</code> は &ldquo;Obsolete&rdquo; と明言されているので、<code>EncodingChanged</code> を使う</li>
-</ul>
-</li>
-</ul>
-<p>ところでこの調査で知ったのだが、<code>BufRead</code> と <code>BufWrite</code> は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら <code>Pre</code>/<code>Post</code> 付きのものを使った方が分かりやすいだろう。</p>
-]]></description>
- </item>
-
- </channel>
-</rss>
diff --git a/docs/tags/vim/index.html b/docs/tags/vim/index.html
deleted file mode 100644
index 5964ab8..0000000
--- a/docs/tags/vim/index.html
+++ /dev/null
@@ -1,68 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-
- <title>vim | REPL: Rest-Eat-Program Loop</title>
-
- <meta name="description" content="">
- <meta name="author" content="nsfisis">
-
- <link href="https://blog.nsfisis.dev/an-old-hope.min.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/style.css" rel="stylesheet">
- <link href="https://blog.nsfisis.dev/custom.css" rel="stylesheet">
-
- <link rel="icon" href="https://blog.nsfisis.dev/favicon.svg">
- <meta name="generator" content="Hugo 0.102.1" />
-
- <link rel="alternate" type="application/rss+xml" href="https://blog.nsfisis.dev/tags/vim/feed.xml" title="REPL: Rest-Eat-Program Loop" />
-
- </head>
- <body class="list">
- <header class="header">
- <nav class="nav">
- <p class="logo"><a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></p>
- </nav>
- </header>
- <main class="main">
-
-<header class="page-header"><h1>vim</h1></header>
-
-<article class="post-entry">
- <header class="entry-header">
- <h2>Vimで選択した行の順番を入れ替える</h2>
- </header>
- <section class="entry-content">
- <p>Vim で選択した行の順番を入れ替える方法。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/vim-swap-order-of-selected-lines/"></a>
-</article>
-<article class="post-entry">
- <header class="entry-header">
- <h2>[Vim] autocmd events の BufWrite/BufWritePre の違い</h2>
- </header>
- <section class="entry-content">
- <p>Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、違いはないことがわかった。</p>
- </section>
- <footer class="entry-footer">
- Posted on <time>2021-10-02</time>
- </footer>
- <a class="entry-link" href="https://blog.nsfisis.dev/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/"></a>
-</article></main>
-<footer class="footer">
- <span>&copy; 2022 <a href="https://blog.nsfisis.dev">REPL: Rest-Eat-Program Loop</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="https://blog.nsfisis.dev/highlight.min.js"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
-
diff --git a/docs/tags/vim/page/1/index.html b/docs/tags/vim/page/1/index.html
deleted file mode 100644
index 52be41d..0000000
--- a/docs/tags/vim/page/1/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html lang="ja-JP">
- <head>
- <title>https://blog.nsfisis.dev/tags/vim/</title>
- <link rel="canonical" href="https://blog.nsfisis.dev/tags/vim/">
- <meta name="robots" content="noindex">
- <meta charset="utf-8">
- <meta http-equiv="refresh" content="0; url=https://blog.nsfisis.dev/tags/vim/">
- </head>
-</html>
diff --git a/lib/command.rb b/lib/command.rb
new file mode 100644
index 0000000..81692b3
--- /dev/null
+++ b/lib/command.rb
@@ -0,0 +1,152 @@
+module NulDoc
+ class Command
+ def initialize(config)
+ @config = config
+ @content_dir = @config[:content_dir]
+ @dest_dir = @config[:dest_dir]
+ @template_dir = @config[:template_dir]
+ @parser = NulDoc::Parser.new(
+ {
+ 'author' => @config[:author],
+ 'site-copyright-year' => @config[:site_copyright_year],
+ 'site-name' => @config[:site_name],
+ 'source-highlighter' => 'rouge',
+ 'reproducible' => true,
+ 'sectids' => false,
+ },
+ @content_dir,
+ @template_dir,
+ )
+ end
+
+ def run
+ posts = generate_posts(@content_dir + '/posts')
+ generate_tags(posts)
+ generate_posts_list(posts)
+ end
+
+ private
+
+ def generate_posts(source_dir)
+ post_files = collect_post_files(source_dir)
+ posts = parse_posts(post_files)
+ output_posts(posts)
+ posts
+ end
+
+ def collect_post_files(source_dir)
+ file_paths = []
+ Dir.glob('**/*.adoc', base: source_dir, sort: true) do |path|
+ file_paths << "#{source_dir}/#{path}"
+ end
+ file_paths
+ end
+
+ def parse_posts(post_file_paths)
+ post_file_paths.map { @parser.parse_file(_1) }
+ end
+
+ def output_posts(posts)
+ posts.each do |post|
+ destination_file_path = post.attributes['source-file-path']
+ .sub(@content_dir, @dest_dir)
+ .sub('.adoc', '/index.html')
+ destination_dir = File.dirname(destination_file_path)
+ unless Dir.exist?(destination_dir)
+ FileUtils.makedirs(destination_dir)
+ end
+ open(destination_file_path, 'w') do |f|
+ f.puts(post.convert)
+ end
+ end
+ end
+
+ def generate_tags(posts)
+ tags_and_posts = collect_tags(posts)
+ tag_docs = build_tag_docs(tags_and_posts)
+ output_tags(tag_docs)
+ end
+
+ def collect_tags(posts)
+ tags_and_posts = {}
+ posts.each do |post|
+ post.attributes['tags'].each do |tag|
+ tags_and_posts[tag] ||= []
+ tags_and_posts[tag] << post
+ end
+ end
+ tags_and_posts
+ .transform_values {|posts|
+ posts.sort_by {|post|
+ post.attributes['revision-history'].first.date # created_at
+ }.reverse
+ }
+ .sort_by {|tag, _| tag.slug }
+ .to_h
+ end
+
+ def build_tag_docs(tags_and_posts)
+ tags_and_posts.map do |tag, posts|
+ [tag, build_tag_doc(tag, posts)]
+ end
+ end
+
+ def build_tag_doc(tag, posts)
+ erb = ERB.new(File.read(@template_dir + '/tag.html.erb'))
+ erb.result_with_hash({
+ tag: tag,
+ posts: posts,
+ author: @config[:author],
+ site_copyright_year: @config[:site_copyright_year],
+ site_name: @config[:site_name],
+ lang: 'ja-JP', # TODO
+ copyright_year: posts.last.attributes['revision-history'].first.date.year,
+ description: "タグ「#{tag.label}」のついた記事一覧",
+ })
+ end
+
+ def output_tags(tag_docs)
+ tag_docs.each do |tag, html|
+ destination_file_path = "#{@dest_dir}/tags/#{tag.slug}/index.html"
+ destination_dir = File.dirname(destination_file_path)
+ unless Dir.exist?(destination_dir)
+ FileUtils.makedirs(destination_dir)
+ end
+ open(destination_file_path, 'w') do |f|
+ f.puts(html)
+ end
+ end
+ end
+
+ def generate_posts_list(posts)
+ html = build_posts_list_doc(posts)
+ output_posts_list(html)
+ end
+
+ def build_posts_list_doc(posts)
+ erb = ERB.new(File.read(@template_dir + '/posts_list.html.erb'))
+ erb.result_with_hash({
+ posts: posts.reverse,
+ author: @config[:author],
+ site_copyright_year: @config[:site_copyright_year],
+ site_name: @config[:site_name],
+ lang: 'ja-JP', # TODO
+ copyright_year: @config[:site_copyright_year],
+ description: "記事一覧",
+ doctitle: "Posts",
+ header_title: "Posts",
+ })
+ end
+
+ def output_posts_list(html)
+ destination_file_path = "#{@dest_dir}/posts/index.html"
+ destination_dir = File.dirname(destination_file_path)
+ unless Dir.exist?(destination_dir)
+ FileUtils.makedirs(destination_dir)
+ end
+ open(destination_file_path, 'w') do |f|
+ f.puts(html)
+ end
+ end
+ end
+end
diff --git a/lib/extensions/document_title_processor.rb b/lib/extensions/document_title_processor.rb
new file mode 100644
index 0000000..fd25844
--- /dev/null
+++ b/lib/extensions/document_title_processor.rb
@@ -0,0 +1,15 @@
+module Nuldoc
+ module Extensions
+ class DocumentTitleProcessor < Asciidoctor::Extensions::TreeProcessor
+ def process(doc)
+ doc.title = substitute_document_title(doc.title)
+ end
+
+ private
+
+ def substitute_document_title(title)
+ title.sub(/\A\[(.+?)\] /, '【\1】')
+ end
+ end
+ end
+end
diff --git a/lib/extensions/lang_attribute_processor.rb b/lib/extensions/lang_attribute_processor.rb
new file mode 100644
index 0000000..65511bc
--- /dev/null
+++ b/lib/extensions/lang_attribute_processor.rb
@@ -0,0 +1,9 @@
+module Nuldoc
+ module Extensions
+ class LangAttributeProcessor < Asciidoctor::Extensions::TreeProcessor
+ def process(doc)
+ doc.attributes['lang'] ||= 'ja-JP'
+ end
+ end
+ end
+end
diff --git a/lib/extensions/revision_history_processor.rb b/lib/extensions/revision_history_processor.rb
new file mode 100644
index 0000000..f416de0
--- /dev/null
+++ b/lib/extensions/revision_history_processor.rb
@@ -0,0 +1,27 @@
+module Nuldoc
+ module Extensions
+ class RevisionHistoryProcessor < Asciidoctor::Extensions::TreeProcessor
+ def process(doc)
+ revisions = []
+ i = 1
+ loop do
+ break unless (rev = doc.attributes["revision-#{i}"])
+ revisions << parse_revision(rev)
+ i += 1
+ end
+ doc.attributes['revision-history'] = revisions
+ end
+
+ private
+
+ def parse_revision(rev)
+ m = rev.match(/\A(\d\d\d\d-\d\d-\d\d) (.*)\z/)
+ raise unless m
+ Revision.new(
+ date: Date.parse(m[1], '%Y-%m-%d'),
+ remark: m[2],
+ )
+ end
+ end
+ end
+end
diff --git a/lib/extensions/section_id_validator.rb b/lib/extensions/section_id_validator.rb
new file mode 100644
index 0000000..2ad496c
--- /dev/null
+++ b/lib/extensions/section_id_validator.rb
@@ -0,0 +1,29 @@
+module Nuldoc
+ module Extensions
+ class SectionIdValidator < Asciidoctor::Extensions::TreeProcessor
+ def process(doc)
+ errors = []
+ (doc.find_by(context: :section) {_1.level > 0}).each do |section|
+ errors << validate_section(section)
+ end
+ error_message = errors.compact.join("\n")
+ unless error_message.empty?
+ raise "SectionIdValidator (#{doc.attributes['source-file-path']}):\n#{error_message}"
+ end
+ end
+
+ private
+
+ def validate_section(section)
+ id = section.id
+ unless id
+ return "Section '#{section.title}': each section MUST have an id."
+ end
+ unless id.match?(/\A[-0-9a-z]+\z/)
+ return "Section '#{section.title}' (##{id}): section id MUST consist of either hyphen, digits or lowercases."
+ end
+ nil
+ end
+ end
+ end
+end
diff --git a/lib/extensions/source_id_processor.rb b/lib/extensions/source_id_processor.rb
new file mode 100644
index 0000000..13813e0
--- /dev/null
+++ b/lib/extensions/source_id_processor.rb
@@ -0,0 +1,12 @@
+module Nuldoc
+ module Extensions
+ class SourceIdProcessor < Asciidoctor::Extensions::TreeProcessor
+ def process(doc)
+ errors = []
+ (doc.find_by(context: :listing) {_1.style == 'source'}).each do |source|
+ source.id = "source.#{source.id}"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/extensions/source_id_validator.rb b/lib/extensions/source_id_validator.rb
new file mode 100644
index 0000000..6e04deb
--- /dev/null
+++ b/lib/extensions/source_id_validator.rb
@@ -0,0 +1,32 @@
+module Nuldoc
+ module Extensions
+ class SourceIdValidator < Asciidoctor::Extensions::TreeProcessor
+ def process(doc)
+ errors = []
+ (doc.find_by(context: :listing) {_1.style == 'source'}).each do |source|
+ errors << validate_section(source)
+ end
+ error_message = errors.compact.join("\n")
+ unless error_message.empty?
+ raise "SourceIdValidator (#{doc.attributes['source-file-path']}):\n#{error_message}"
+ end
+ end
+
+ private
+
+ def validate_section(source)
+ id = source.id
+ unless id
+ return "Each source MUST have an id."
+ end
+ if id.start_with?('source.')
+ return "Source id (##{id}) MUST NOT start with 'source.', which is appended by `nul`."
+ end
+ unless id.match?(/\A[-0-9a-z]+\z/)
+ return "Source id (##{id}) MUST consist of either hypen, digits or lowercases."
+ end
+ nil
+ end
+ end
+ end
+end
diff --git a/lib/extensions/tags_processor.rb b/lib/extensions/tags_processor.rb
new file mode 100644
index 0000000..efbd2a8
--- /dev/null
+++ b/lib/extensions/tags_processor.rb
@@ -0,0 +1,20 @@
+module Nuldoc
+ module Extensions
+ class TagsProcessor < Asciidoctor::Extensions::TreeProcessor
+ def process(doc)
+ doc.attributes['tags'] = convert_tags(doc.attributes['tags'])
+ end
+
+ private
+
+ def convert_tags(tags)
+ return [] unless tags
+
+ tags
+ .split(',')
+ .map(&:strip)
+ .map { Tag.from_slug(_1) }
+ end
+ end
+ end
+end
diff --git a/lib/parser.rb b/lib/parser.rb
new file mode 100644
index 0000000..8ae3303
--- /dev/null
+++ b/lib/parser.rb
@@ -0,0 +1,54 @@
+module NulDoc
+ class Parser
+ def initialize(common_attributes, content_dir, template_dir)
+ @common_attributes = common_attributes
+ @content_dir = content_dir
+ @template_dir = template_dir
+ end
+
+ def parse_file(file_path)
+ Asciidoctor.load_file(
+ file_path,
+ backend: :html5,
+ doctype: :article,
+ standalone: true,
+ safe: :unsafe,
+ template_dirs: [@template_dir],
+ template_engine: 'erb',
+ attributes: @common_attributes.merge({
+ 'source-file-path' => file_path,
+ 'href' => file_path.sub(@content_dir, '').sub('.adoc', '/'),
+ }),
+ extension_registry: Asciidoctor::Extensions.create do
+ tree_processor Nuldoc::Extensions::RevisionHistoryProcessor
+ tree_processor Nuldoc::Extensions::DocumentTitleProcessor
+ tree_processor Nuldoc::Extensions::LangAttributeProcessor
+ # tree_processor Nuldoc::Extensions::SectionIdValidator
+ # tree_processor Nuldoc::Extensions::SourceIdValidator
+ tree_processor Nuldoc::Extensions::TagsProcessor
+
+ # MUST BE AT THE END
+ tree_processor Nuldoc::Extensions::SourceIdProcessor
+ end,
+ )
+ end
+
+ def parse_string(s, copyright_year)
+ Asciidoctor.convert(
+ s,
+ backend: :html5,
+ doctype: :article,
+ safe: :unsafe,
+ template_dirs: [@template_dir],
+ template_engine: 'erb',
+ attributes: @common_attributes.merge({
+ 'copyright-year' => copyright_year,
+ }),
+ extension_registry: Asciidoctor::Extensions.create do
+ tree_processor Nuldoc::Extensions::LangAttributeProcessor
+ tree_processor Nuldoc::Extensions::TagsProcessor
+ end,
+ )
+ end
+ end
+end
diff --git a/lib/revision.rb b/lib/revision.rb
new file mode 100644
index 0000000..b986a14
--- /dev/null
+++ b/lib/revision.rb
@@ -0,0 +1,3 @@
+module Nuldoc
+ Revision = Struct.new(:date, :remark, keyword_init: true)
+end
diff --git a/lib/tag.rb b/lib/tag.rb
new file mode 100644
index 0000000..a7c13b2
--- /dev/null
+++ b/lib/tag.rb
@@ -0,0 +1,26 @@
+module Nuldoc
+ Tag = Struct.new(:slug, :label, keyword_init: true) do
+ LABELS = {
+ 'conference' => 'カンファレンス',
+ 'cpp' => 'C++',
+ 'cpp17' => 'C++ 17',
+ 'note-to-self' => '備忘録',
+ 'php' => 'PHP',
+ 'phpcon' => 'PHP カンファレンス',
+ 'phperkaigi' => 'PHPerKaigi',
+ 'python' => 'Python',
+ 'python3' => 'Python 3',
+ 'ruby' => 'Ruby',
+ 'ruby3' => 'Ruby 3',
+ 'rust' => 'Rust',
+ 'vim' => 'Vim',
+ }
+
+ def self.from_slug(slug)
+ Tag.new(
+ slug: slug,
+ label: (LABELS[slug] || raise("No label for tag '#{slug}'")),
+ )
+ end
+ end
+end
diff --git a/nginx.conf b/nginx.conf
index 7b84774..9097f28 100644
--- a/nginx.conf
+++ b/nginx.conf
@@ -8,6 +8,9 @@ server {
error_page 404 /404.html;
+ # TODO
+ rewrite ^/$ /posts/ redirect;
+
rewrite ^/posts/(my-first-post)/?$ /posts/2021-03-05/$1/ permanent;
rewrite ^/posts/(phperkaigi-2021)/?$ /posts/2021-03-30/$1/ permanent;
rewrite ^/posts/(cpp-you-can-use-keywords-in-attributes)/?$ /posts/2021-10-02/$1/ permanent;
diff --git a/nuldoc.rb b/nuldoc.rb
new file mode 100644
index 0000000..363383e
--- /dev/null
+++ b/nuldoc.rb
@@ -0,0 +1,24 @@
+require 'date'
+require 'fileutils'
+require 'asciidoctor'
+
+require_relative 'lib/command'
+require_relative 'lib/parser'
+require_relative 'lib/extensions/document_title_processor'
+require_relative 'lib/extensions/lang_attribute_processor'
+require_relative 'lib/extensions/revision_history_processor'
+require_relative 'lib/extensions/section_id_validator'
+require_relative 'lib/extensions/source_id_processor'
+require_relative 'lib/extensions/source_id_validator'
+require_relative 'lib/extensions/tags_processor'
+require_relative 'lib/revision'
+require_relative 'lib/tag'
+
+NulDoc::Command.new({
+ author: 'nsfisis',
+ site_name: 'REPL: Rest-Eat-Program Loop',
+ site_copyright_year: 2021,
+ content_dir: __dir__ + '/content',
+ dest_dir: __dir__ + '/public',
+ template_dir: __dir__ + '/templates',
+}).run
diff --git a/docs/custom.css b/public/custom.css
index f492b95..d3b1672 100644
--- a/docs/custom.css
+++ b/public/custom.css
@@ -18,9 +18,12 @@
padding-right: 0.3rem;
}
-.post-content h1::before { content: '#'; }
-.post-content h2::before { content: '##'; }
-.post-content h3::before { content: '###'; }
-.post-content h4::before { content: '####'; }
-.post-content h5::before { content: '#####'; }
-.post-content h6::before { content: '######'; }
+.post-content h2::before { content: '#'; }
+.post-content h3::before { content: '##'; }
+.post-content h4::before { content: '###'; }
+.post-content h5::before { content: '####'; }
+.post-content h6::before { content: '#####'; }
+
+li.revision {
+ list-style: inside;
+}
diff --git a/docs/favicon.svg b/public/favicon.svg
index d122ea1..d122ea1 100644
--- a/docs/favicon.svg
+++ b/public/favicon.svg
diff --git a/public/hl.css b/public/hl.css
new file mode 100644
index 0000000..fabe9de
--- /dev/null
+++ b/public/hl.css
@@ -0,0 +1,214 @@
+/* ruby -rrouge -e 'puts Rouge::Themes::Github.render(scope: ".highlight")' */
+.highlight table td { padding: 5px; }
+.highlight table pre { margin: 0; }
+.highlight .cm {
+ color: #999988;
+ font-style: italic;
+}
+.highlight .cp {
+ color: #999999;
+ font-weight: bold;
+}
+.highlight .c1 {
+ color: #999988;
+ font-style: italic;
+}
+.highlight .cs {
+ color: #999999;
+ font-weight: bold;
+ font-style: italic;
+}
+.highlight .c, .highlight .ch, .highlight .cd, .highlight .cpf {
+ color: #999988;
+ font-style: italic;
+}
+.highlight .err {
+ color: #a61717;
+ background-color: #e3d2d2;
+}
+.highlight .gd {
+ color: #000000;
+ background-color: #ffdddd;
+}
+.highlight .ge {
+ color: #000000;
+ font-style: italic;
+}
+.highlight .gr {
+ color: #aa0000;
+}
+.highlight .gh {
+ color: #999999;
+}
+.highlight .gi {
+ color: #000000;
+ background-color: #ddffdd;
+}
+.highlight .go {
+ color: #888888;
+}
+.highlight .gp {
+ color: #555555;
+}
+.highlight .gs {
+ font-weight: bold;
+}
+.highlight .gu {
+ color: #aaaaaa;
+}
+.highlight .gt {
+ color: #aa0000;
+}
+.highlight .kc {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .kd {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .kn {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .kp {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .kr {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .kt {
+ color: #445588;
+ font-weight: bold;
+}
+.highlight .k, .highlight .kv {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .mf {
+ color: #009999;
+}
+.highlight .mh {
+ color: #009999;
+}
+.highlight .il {
+ color: #009999;
+}
+.highlight .mi {
+ color: #009999;
+}
+.highlight .mo {
+ color: #009999;
+}
+.highlight .m, .highlight .mb, .highlight .mx {
+ color: #009999;
+}
+.highlight .sa {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .sb {
+ color: #d14;
+}
+.highlight .sc {
+ color: #d14;
+}
+.highlight .sd {
+ color: #d14;
+}
+.highlight .s2 {
+ color: #d14;
+}
+.highlight .se {
+ color: #d14;
+}
+.highlight .sh {
+ color: #d14;
+}
+.highlight .si {
+ color: #d14;
+}
+.highlight .sx {
+ color: #d14;
+}
+.highlight .sr {
+ color: #009926;
+}
+.highlight .s1 {
+ color: #d14;
+}
+.highlight .ss {
+ color: #990073;
+}
+.highlight .s, .highlight .dl {
+ color: #d14;
+}
+.highlight .na {
+ color: #008080;
+}
+.highlight .bp {
+ color: #999999;
+}
+.highlight .nb {
+ color: #0086B3;
+}
+.highlight .nc {
+ color: #445588;
+ font-weight: bold;
+}
+.highlight .no {
+ color: #008080;
+}
+.highlight .nd {
+ color: #3c5d5d;
+ font-weight: bold;
+}
+.highlight .ni {
+ color: #800080;
+}
+.highlight .ne {
+ color: #990000;
+ font-weight: bold;
+}
+.highlight .nf, .highlight .fm {
+ color: #990000;
+ font-weight: bold;
+}
+.highlight .nl {
+ color: #990000;
+ font-weight: bold;
+}
+.highlight .nn {
+ color: #555555;
+}
+.highlight .nt {
+ color: #000080;
+}
+.highlight .vc {
+ color: #008080;
+}
+.highlight .vg {
+ color: #008080;
+}
+.highlight .vi {
+ color: #008080;
+}
+.highlight .nv, .highlight .vm {
+ color: #008080;
+}
+.highlight .ow {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .o {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .w {
+ color: #bbbbbb;
+}
+.highlight {
+ background-color: #f8f8f8;
+} \ No newline at end of file
diff --git a/public/posts/2021-03-05/my-first-post/index.html b/public/posts/2021-03-05/my-first-post/index.html
new file mode 100644
index 0000000..fbf7237
--- /dev/null
+++ b/public/posts/2021-03-05/my-first-post/index.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="これはテスト投稿です。これはテスト投稿です。これはテスト投稿です。">
+ <meta name="keywords" content="">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>My First Post | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">My First Post</h1>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2021-03-05">2021-03-05</time>: 公開
+ </li>
+
+ </ol>
+ </section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ Test
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
+veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
+velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
+occaecat cupidatat non proident, sunt in culpa qui officia deserunt
+mollit anim id est laborum.</p>
+</div>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2021-03-30/phperkaigi-2021/index.html b/public/posts/2021-03-30/phperkaigi-2021/index.html
new file mode 100644
index 0000000..46fce9b
--- /dev/null
+++ b/public/posts/2021-03-30/phperkaigi-2021/index.html
@@ -0,0 +1,1195 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。">
+ <meta name="keywords" content="カンファレンス,PHP,PHPerKaigi">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHPerKaigi 2021 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHPerKaigi 2021</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/conference/">カンファレンス</a>
+ </li>
+
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+
+ <li class="tag">
+ <a href="/tags/phperkaigi/">PHPerKaigi</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2021-03-30">2021-03-30</time>: 公開
+ </li>
+
+ </ol>
+ </section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ PHPerKaigi 2021 参加レポ
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>2021-03-26 から 2021-03-28
+にかけて開催された、 <a href="https://phperkaigi.jp/2021/">PHPerKaigi 2021</a>
+に一般参加者として参加した。
+弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a>
+(今年1月から勤務)
+はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
+</div>
+<div class="paragraph">
+<p>このようなカンファレンスには初めて参加するのでかねてより心待ちにしていたのだが、生憎2日目から体調を崩してしまい、この記事も途中までとなっている。まだ見ていないセッションも多いが、ひとまず現時点での参加レポを書いておく。</p>
+</div>
+<div class="paragraph">
+<p>発表はトラック A、B に分かれていたのだが、今回はすべて A
+トラックを視聴している (切り替えるのが面倒だっただけ)。</p>
+</div>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 凡例
+
+ </h3>
+ <div class="section-body">
+ <div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>発表・スライドのメモ (引用ではない)</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>感想など</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ Day 0 前夜祭 (2021/03/27)
+
+ </h3>
+ <div class="section-body">
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 17:30 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>PHP で AWS Lambda</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>Rails のプロジェクトを PHPer のメンバのみでメンテ →他のメンバもわかる
+PHP にリプレースを検討</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>サーバレス</p>
+</li>
+<li>
+<p>サーバ・インフラの管理が不要</p>
+</li>
+<li>
+<p>アプリケーションコードの知識だけで保守可能</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>ゼロベースで作れる案件が (Railsの件とは別に)
+あるため、そちらで試験的に導入?</p>
+</div>
+<div class="paragraph">
+<p>AWSの学習 AWS のドキュメント DevelopersIO</p>
+</div>
+<div class="paragraph">
+<p>AWS Lambda のカスタムランタイムで PHP を動かす</p>
+</div>
+<div class="paragraph">
+<p>サーバのセットアップや維持管理を気にしなくて良い サーバーレスで PHP
+を動かすツールがすでにある サーバーレス構築はすんなり</p>
+</div>
+<div class="paragraph">
+<p>今は Laravel がルーティングしている Laravel Livewire を Lambda
+に載せられないか? デプロイ方法は? バッチ処理は? (Lambda は
+15分の制限)</p>
+</div>
+<div class="paragraph">
+<p>Lambda でコンテナイメージがサポートされるように</p>
+</div>
+<div class="paragraph">
+<p>抽象化されたもの「だけ」しか知らないよりも具象の理解は助けになる</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>AWS Lambda のような Function as a Service
+はマイクロサービス化における一つの到達点に思えるのだが、これを使って実際に
+web サービスを作る具体的なイメージがまだ見えない (注: すべて for me
+として書いている)。</p>
+</div>
+<div class="paragraph">
+<p>PHP on AWS Lambda があれだけ簡単に動かせるのには驚いた。</p>
+</div>
+<div class="paragraph">
+<p>勝手に AWS Lambda だとフットプリントの軽さが求められそう (= PHP<br>
+Laravel などでは動かなさそう)
+だという先入観を持っていたのだが、この発表のデモによればそうでもないらしい。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 18:10 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>大規模サイトの SEO</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>大規模サイト (100万ページ以上) Google の基準</p>
+</div>
+<div class="paragraph">
+<p>クロールバジェットを意識したSEO</p>
+</div>
+<div class="paragraph">
+<p>大規模サイトでコンテンツが中頻度 (1回/週) で更新 OR 中規模サイト
+(10,000以上) でコンテンツが目まぐるしく変更される
+これを満たさないなら、クロールバジェットを考えなくてもいい</p>
+</div>
+<div class="paragraph">
+<p>サーチコンソール 「カバレッジ」の「除外」
+多すぎるのは問題→クロールバジェットを浪費している</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>クエリの順番を決める</p>
+</li>
+<li>
+<p>空の値のルールを決めておく</p>
+</li>
+<li>
+<p>リダイレクトすればインデックスはうまくいく</p>
+</li>
+<li>
+<p>リンクが存在する限りクロールはされる</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>リニューアル前のURL</p>
+</div>
+<div class="paragraph">
+<p>インデックスは移行される
+リンクのURLが存在する限り、別のURLとしてクロールされる
+リダイレクトされるとはいえ、リニューアル前のURLは移行した方が良い
+リニューアルで無視されるようになったパラメータも注意</p>
+</div>
+<div class="paragraph">
+<p>robotes.txt で拒否しているのにクロールされる 一時的に拒否を外して 404 や
+301 を読ませる 内部リンクを確認する JS でのリンクに書き換え</p>
+</div>
+<div class="paragraph">
+<p>クエリパラメータからURLのパスに <code>/tokyo?area=HOGE</code> → <code>/tokyo/HOGE</code></p>
+</div>
+<div class="paragraph">
+<p>URL 設計だいじ</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>SEO (Search Engine Optimization)
+は大して知らないので新鮮な話が多かった。その分語れることも少ない……。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 18:50 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>知覚可能 操作可能 理解可能 堅牢 ちゃんとしたHTMLを書く
+(閉じタグ・入れ子構造など)</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>標準の HTML を適切に使う</p>
+</li>
+<li>
+<p>WAI-ARIA</p>
+</li>
+<li>
+<p>キーボードフレンドリー</p>
+</li>
+<li>
+<p>マシンフレンドリー</p>
+</li>
+<li>
+<p>SEOフレンドリー</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>button タグ →キーボード h1 タグ →スクリーンリーダー・クローラ a タグ</p>
+</div>
+<div class="paragraph">
+<p>WAI-ARIA HTML では表現できないセマンティクスを追加する</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>ロール</p>
+<div class="ulist">
+<ul>
+<li>
+<p>何をするのか?</p>
+</li>
+<li>
+<p>ユーザーアクションによって変化しない</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>プロパティ</p>
+<div class="ulist">
+<ul>
+<li>
+<p>関連づけられたデータ</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>ステート</p>
+<div class="ulist">
+<ul>
+<li>
+<p>現在の状態</p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>まずは標準の HTML 要素で解決する 何でもかんでも WAI-ARIA
+を使えばいいというものではない</p>
+</div>
+<div class="paragraph">
+<p>マウスホバーでツールチップが出てくるが、キーボード操作では出てこない</p>
+</div>
+<div class="paragraph">
+<p>VoiceOver</p>
+</div>
+<div class="paragraph">
+<p>全ての属性を使う必要はない
+あくまでアクセシビリティを上げるための方法の一つにすぎない</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>つい最近 WAI-ARIA
+についての記事を読んだばかりだったので個人的にタイムリーな話題だった。(あまりこの言葉を使いたくないのだが)
+いわゆる「健常者」にとって、こうした問題を普段の生活の中で意識するのは難しい。だからこそ情報へのアンテナは張っておくようにしたい。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 19:30 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>PHP で FUSE</p>
+</div>
+<div class="paragraph">
+<p>個人的に楽しみだった発表。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>VFS (virtual filesystem) vs 具体的なファイルシステム</p>
+</div>
+<div class="paragraph">
+<p>最適な実装方法は状況により異なる</p>
+</div>
+<div class="paragraph">
+<p>アプリケーションに見せるAPIは変えずに実装を隠蔽する→VFS</p>
+</div>
+<div class="paragraph">
+<p>カーネルのプログラムを作るのは難しい
+* 権限がデカすぎる
+* システム全体がクラッシュ
+* セキュリティリスク
+* 開発サイクルを回しづらい
+* ネイティブコードにコンパイルされる言語である必要がある</p>
+</div>
+<div class="paragraph">
+<p>Filesystem in USEr space (FUSE)</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>特定の C の関数を呼ぶことで filesystem が作れる</p>
+</li>
+<li>
+<p>FFI を持つ言語なら FUSE が使える</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>SSHFS / s3fs / Docker Desktop</p>
+</div>
+<div class="paragraph">
+<p>Linux 以外でも使える</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>dokany (on Windows)</p>
+</li>
+<li>
+<p>osxfuse</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>VFS: システムコールが呼ばれると、ファイルシステムによってコール FUSE:
+カーネル空間からユーザ空間へ通信</p>
+</div>
+<div class="paragraph">
+<p>高レベルなラッパで型をつける</p>
+</div>
+<div class="paragraph">
+<p>PHP 以外では Wordpress を FUSE にマウントする実装がある (C, Python など)</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>grep できる</p>
+</li>
+<li>
+<p>sed できる</p>
+</li>
+<li>
+<p>編集できる</p>
+</li>
+</ul>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>期待通りの興味深い発表だった。FUSE
+自体も今回の発表で知ったのだが、これ本体の実装を見るのも面白そうだ。
+この発表を聞きながらファイルシステムにマウントできそうなものを考えていたのだが、およそ木構造をしているものすべてと言えそうだ
+(ハンマーしか持っていないと云々)。何かできそうだがなかなか思いつかない。</p>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ Day 1 (2021/03/27)
+
+ </h3>
+ <div class="section-body">
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 10:50 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>ATDD</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="ulist">
+<ul>
+<li>
+<p>ユーザーストーリー</p>
+</li>
+<li>
+<p>ユニットテスト</p>
+</li>
+<li>
+<p>CI/CD</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>ユーザストーリーの受け入れ条件が曖昧になりがち
+デグレチェックがユニットレベルでは収まらない場合、手動で同じシナリオをテストしている</p>
+</div>
+<div class="paragraph">
+<p>Q2の強化 アジャイルテストの4象限</p>
+</div>
+<div class="paragraph">
+<p>技術面/ビジネス面
+開発チーム支援(コーディング前・コーディング中)/製品批評(コーディング後)</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>Q1: 技術面 &amp; チーム支援</p>
+<div class="ulist">
+<ul>
+<li>
+<p>TDD</p>
+</li>
+<li>
+<p>ユニットテストなど</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>Q2: ビジネス面 &amp; チーム支援</p>
+<div class="ulist">
+<ul>
+<li>
+<p>ATDD</p>
+</li>
+<li>
+<p>ビジネス面の受け入れテストで駆動する</p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Agile Alliance ユーザストーリーのスキルレベルを高める</p>
+</div>
+<div class="paragraph">
+<p>テストピラミッド</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>UI Tests</p>
+</li>
+<li>
+<p>Service Tests</p>
+</li>
+<li>
+<p>Unit Tests</p>
+</li>
+<li>
+<p>異なる粒度のテストを書く</p>
+</li>
+<li>
+<p>高レベルになるほど、持つべきテストは少なくなる</p>
+<div class="ulist">
+<ul>
+<li>
+<p>ピラミッド型になる</p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>高レベルテストが多すぎる→アイスクリームコーン アンチパターン</p>
+</div>
+<div class="paragraph">
+<p>ATDD (Acceptance TDD) API経由・UI経由での高レベルテスト E2E test</p>
+</div>
+<div class="paragraph">
+<p>ストーリ受け入れテスト</p>
+</div>
+<div class="paragraph">
+<p>入れ子のフィードバックループ ATDD(外側) と TDD(内側)</p>
+</div>
+<div class="paragraph">
+<p>外部品質・内部品質</p>
+</div>
+<div class="paragraph">
+<p>バーティカルスライスのデリバリー</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>cucumber</p>
+</li>
+<li>
+<p>gauge</p>
+</li>
+<li>
+<p>behat</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>ユビキタス言語 手動テストもspecに書く 自動化は可能だがコスパが悪い
+失敗することがわかっているテスト(レッドテスト)はCIから外す
+失敗時の原因究明が難しい 饒舌なエラーメッセージ 状況のスナップショット</p>
+</div>
+<div class="paragraph">
+<p>Continuous Testing</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>User Acceptance Test (UAT)
+くらいの規模になると個人開発・趣味開発では触れない領域なので、大いに勉強になった。スライドに添付されている資料が相当に充実していたので、これを読むのが本番といった様相すら感じる。
+高レベルテストの自動化は現在のプロジェクトでも感じており、自動化のチャンスは伺っている。とはいえセッションでも指摘されているように自動化することにコストがかかりすぎる領域があるのも事実で、そのバランスが難しい。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 11:50 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>型解析を用いたリファクタリング</p>
+</div>
+<div class="paragraph">
+<p>型のある世界で生きてきた身として大いに楽しみにしていた発表。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="ulist">
+<ul>
+<li>
+<p>PHPStan</p>
+</li>
+<li>
+<p>Phan</p>
+</li>
+<li>
+<p>Psalm</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>autoload も認識できる bootstrapFiles</p>
+</div>
+<div class="paragraph">
+<p>編集箇所と利用箇所を CI でチェック ルールレベルを徐々に引き上げていく
+警告が多すぎると見落としてしまう・無視されやすくなる</p>
+</div>
+<div class="paragraph">
+<p>型がついていないことによるエラーが多い</p>
+</div>
+<div class="paragraph">
+<p>型よりも詳細な検査 <code>Util_Assert::min</code></p>
+</div>
+<div class="paragraph">
+<p>SQL を静的解析 placeholder の型付け</p>
+</div>
+<div class="paragraph">
+<p>警告レベルを低いレベルから導入 タイプヒントを積極的に書いていく PHPStan
+の拡張を追加する</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>昨今、動的型付き言語での型宣言・型アノテーション・型ヒントの導入が相次いでいる。長らく静的型付き言語を書いてきた私からすると、ようやく気づいたかといったところだが、ともかく型を導入する言語が増えてきた。
+今のプロジェクトでも新しく追加するコードには型をつけるよう努めているが、どうしても古いコードには型がついていない。個人的には型のないコードに対してどう型を自動的に付けるかという点に興味があり、その点で
+Ruby の typeprof には注目している。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 12:30 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>昼食をとっていた。事前に何か食料を買っておくべきだった。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 13:10 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>Documentation as Code</p>
+</div>
+<div class="paragraph">
+<p>この発表も以前から非常に楽しみにしていた。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>開発開始までのオーバーヘッド 新規にチームにジョイン
+担当範囲外の機能を理解 オンボーディングのコスト</p>
+</div>
+<div class="paragraph">
+<p>PHPerKaigi 2020 で発表あり</p>
+</div>
+<div class="paragraph">
+<p>継続的にシステムの理解を助けるドキュメント</p>
+</div>
+<div class="paragraph">
+<p>継続的ドキュメンテーション システムとドキュメントの乖離</p>
+</div>
+<div class="paragraph">
+<p>書いてあることが間違っている・足りない * 徐々にずれていく *
+システムの更新タイミングとドキュメントの更新タイミングに差がある</p>
+</div>
+<div class="paragraph">
+<p>システムとドキュメントは対応関係がある * 間違ったドキュメント *
+存在しないドキュメント</p>
+</div>
+<div class="paragraph">
+<p>システムとドキュメントの乖離を定量化する 継続的に
+システムの更新に近いタイミングで ドキュメントを更新し続ける</p>
+</div>
+<div class="paragraph">
+<p>Documentation as Code</p>
+</div>
+<div class="paragraph">
+<p>コードと同じツールでドキュメントを書く * issue tracker * vcs * plain
+text markup * automation</p>
+</div>
+<div class="paragraph">
+<p>開発者 システム ドキュメント 構造化データ ソフトウェア</p>
+</div>
+<div class="paragraph">
+<p>システムから構造化データを抽出する PHPDoc OpenAPI</p>
+</div>
+<div class="paragraph">
+<p>ビュー 関心ごとに合わせてアーキテクチャを一つ以上の側面(断面)で説明する</p>
+</div>
+<div class="paragraph">
+<p>ビューの単位でドキュメントに</p>
+</div>
+<div class="paragraph">
+<p>スタックトレースからのドキュメント生成</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>ドキュメントの管理は現プロジェクトでも課題と感じている。作られた当初は正しくても、実態と乖離していくのを止めるのは困難を極める。全体的に興味深い発表だったが、特にスタックトレースからのドキュメント生成というアイデアに惹かれるものを感じた。スタックトレースという実態と不可分な
+(乖離しない)
+情報を起点にするのは理にかなっている。問題はトレースをいつ、どう取るかだろうか。それを自動化しなければ、実態との乖離が避けられないだろう。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 14:10 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>cookie による session 管理</p>
+</div>
+<div class="paragraph">
+<p>全体的に基本的な話だったので特に触れない。Cookie
+やセッションの話としては非常に分かりやすくまとめられていたので、知らない人が学ぶにはいい教材だろう。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 14:50 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>PHP のエラーと例外</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>エラー PHPエンジンがエラーを通知する 例外 プログラムが投げる</p>
+</div>
+<div class="paragraph">
+<p>PHP7-8とエラー</p>
+</div>
+<div class="paragraph">
+<p>PHPエンジンのエラーの一部が に変換されるようになった → try-catch
+で捕捉できる</p>
+</div>
+<div class="paragraph">
+<p>は例外とは異なる</p>
+</div>
+<div class="paragraph">
+<p>PHP8 でエラーレベルの引き上げ</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>捕捉すべきもの</p>
+<div class="ulist">
+<ul>
+<li>
+<p>recoverable</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>捕捉すべきでないもの</p>
+<div class="ulist">
+<ul>
+<li>
+<p>unrecoverable</p>
+</li>
+<li>
+<p>開発時に対処できるもの</p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>例外 * 捕捉して事後処理 * 捕捉せず(or 捕捉した上で)さらに上に是非を問う</p>
+</div>
+<div class="paragraph">
+<p>開発段階で例外を把握し、ハンドリングを考えておく</p>
+</div>
+<div class="paragraph">
+<p>と</p>
+</div>
+<div class="paragraph">
+<p>はキャッチすべきでない</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p></p>
+<div class="ulist">
+<ul>
+<li>
+<p>本番で起きてはいけない</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p></p>
+<div class="ulist">
+<ul>
+<li>
+<p>本番で起きてはいけない →生じないのだから捕捉もしない</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p></p>
+<div class="ulist">
+<ul>
+<li>
+<p>起こるかもしれないので本番環境でも考慮する</p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>捕捉して対応するのではなく、未然に防ぐ</p>
+</div>
+<div class="paragraph">
+<p>独自例外を使う を投げてしまうと、 catch ()せざるを得ない →catch
+範囲が広すぎる</p>
+</div>
+<div class="paragraph">
+<p>SPL の例外を使う</p>
+</div>
+<div class="paragraph">
+<p>例外翻訳
+上位のレイヤが下位のレイヤの例外を捕捉し、上位レイヤのAPIに「翻訳」する
+下位レイヤの知識に依存させない</p>
+</div>
+<div class="paragraph">
+<p>@throws 捕捉してほしい例外を書き連ねておく</p>
+</div>
+<div class="paragraph">
+<p>呼び出しもとに負わせたい責任</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>PHP を学んでいる途中の私としては、今まさに聞きたい発表だった (現時点で
+PHP を書き始めてから 4ヶ月ほどになる)。</p>
+</div>
+<div class="paragraph">
+<p>個人的に例外やエラーを最もうまく扱っているのは Go、Swift、Rust、Haskell
+などのエラーを「値として」扱う言語だと思っている。try-catch
+は通常の処理フローを完全に壊してしまう上、構文としても重すぎる。値としてのエラー通知は
+C言語時代への回帰ともいえるが、その頃と異なるのはエラーを暗黙のうちに握り潰すことがないということだ。これらの言語は型を持っており、静的に検証ができる
+(C のそれはまともな型付けではない。念のため)。</p>
+</div>
+<div class="paragraph">
+<p>PHP
+のように、すでに例外が言語システムに根ざしている言語ではどうすればよいか。この場合も同じく静的検証の力を借りることになるだろう。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 15:30 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>Laravel のメール認証</p>
+</div>
+<div class="paragraph">
+<p>Laravel
+の知識がない私にはまったくついていけなかった。また、個人的にタイトルがややミスリーディングに感じた。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 16:10 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>gRPC</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>Unary RPCs Server streaming RPCs Client streaming RPCs Bidirectional
+streaming RPCs</p>
+</div>
+<div class="paragraph">
+<p>Protobuf</p>
+</div>
+<div class="paragraph">
+<p>実装とAPIが乖離しにくい 自動生成 複数言語でも相互に使える</p>
+</div>
+<div class="paragraph">
+<p>マイクロサービスのサービス通信 スマホアプリ ゲームサーバ</p>
+</div>
+<div class="paragraph">
+<p>PHP では?</p>
+</div>
+<div class="paragraph">
+<p>PHP ではストリーミングが難しい リクエストごとにプロセスが使い捨て</p>
+</div>
+<div class="paragraph">
+<p>PHP ではgRPCのクライアントしか対応していない</p>
+</div>
+<div class="paragraph">
+<p>gRPC-Web ブラウザで扱うためのJSライブラリ+プロトコル</p>
+</div>
+<div class="paragraph">
+<p>HTTP/1.1 でも使える Unary RPC と Server streaming RPC のみ</p>
+</div>
+<div class="paragraph">
+<p>Envoy Nginx などで相互に gRPC と gRPC-Web で変換</p>
+</div>
+<div class="paragraph">
+<p>Amp イベント駆動な並行処理のフレームワーク</p>
+</div>
+<div class="paragraph">
+<p>HTTP/2 対応</p>
+</div>
+<div class="paragraph">
+<p>C#のgRPC-Webが楽</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>(発表の中でもまさに同じことをおっしゃっていたが) PHP
+以外の方が向いているだろう、というのが第一の感想である。gRPC
+はそれ自体というよりも Protobuf
+というエコシステムに乗れることのメリットが大きいと感じる。そのエコシステムにうまく乗れない時点で、うーんという感じ。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 16:50 [A]
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>アーキテクチャテスト</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>Independent Core Layer Pattern</p>
+</div>
+<div class="paragraph">
+<p>開発初期のアーキテクチャが崩れる
+アーキテクチャ観点のコードレビューができない</p>
+</div>
+<div class="paragraph">
+<p>どこにクラスを置けばよいか? ドキュメントがない</p>
+</div>
+<div class="paragraph">
+<p>アーキテクチャ設計に関する知識が属人化・暗黙知化</p>
+</div>
+<div class="paragraph">
+<p>ガイドライン * 最初にルールを決めるのは簡単 *
+ルール通り作り始めるのも簡単 *
+→維持するのが難しい、人が決めたものゆえ壊れやすい</p>
+</div>
+<div class="paragraph">
+<p>PHP の特性 * クラスは public * 可視性の制御が public / protected /
+private のみ * 依存関係の制御が困難</p>
+</div>
+<div class="paragraph">
+<p>アーキテクチャテスト
+クラスの依存関係や実装ルールをコードとして表現し、自動テスト化する</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>deptrac</p>
+</li>
+<li>
+<p>phpat</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>Independent Core Layer Pattern</p>
+</div>
+<div class="paragraph">
+<p>アーキテクチャテストの失敗 * 実装誤り * or アーキテクチャが適切でない *
+開発の過程でフィードバックしていく</p>
+</div>
+<div class="paragraph">
+<p>モジュラーモノリス→マイクロサービスへ</p>
+</div>
+</blockquote>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ Day 2 (2021/03/28)
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>冒頭に書いた通り、2日目から体調が悪くまともに聴けていない。途中までは頭痛を我慢しつつ見ていたのだが、まともに入ってこなかった。</p>
+</div>
+<div class="paragraph">
+<p>残念ではあるが、いずれにせよ見られていない発表は他にもあるので、今週末にでもまとめて見ようと思う。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 全体の感想
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>Day 2
+にほとんど参加できなかったのは残念だが、イベント自体は大変楽しく、また興味深いものであった。自分がまったく知らない領域の話を聞けるのはこうしたイベントならではだと感じる。オンライン開催ゆえ現地に行く必要がなく、気軽に参加できたのも
+(特に初参加者として) 嬉しいポイントだった。</p>
+</div>
+<div class="paragraph">
+<p>今回、雑談/登壇者への質問等向けに Discord
+サーバもあったのだが、こちらは参加こそしたものの ROM
+のままになってしまった。発表に1ウィンドウ、メモを書くのに1ウィンドウ、Discord
+表示に
+1ウィンドウで私にはもう脳のリソースとディスプレイのスペースが追いつかなかった
+(さらにいうと Zoom
+でアンカンファレンスもやっていたようだ。こちらはまったく参加していない)。</p>
+</div>
+<div class="paragraph">
+<p>1つ個人的な反省点としては、一つ一つのセッションを真剣に聞き過ぎたというものがある。もっと適当に聞いておけばよかった。これだけだと大変語弊があるのだが、言い方を変えると、Discord
+しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。
+まあ初カンファレンスだし、とお茶を濁しておこう。</p>
+</div>
+<div class="paragraph">
+<p>さて、カンファレンスで一つ気になったことがある。それは、Discord
+という書き込み場所が増えたことでニコ生のコメントの流量が吸い取られてしまったのではないか、という点だ。ニコニコだけ見ていると過疎っているかのように見えた発表も、Discord
+の方では盛り上がっている、というのを何度か見かけた。ニコニコのコメント方式は盛り上がりを如実に反映するが、逆もまたしかり。Discord
+があったこと自体はプラスだったと思うが、この点はマイナスだったのではないかと感じる。</p>
+</div>
+<hr>
+<div class="paragraph">
+<p>最後になりましたが、毎年の PHPerKaigi
+開催にご尽力されている皆様、スピーカーの皆様、楽しい3日間でした。ありがとうございました!
+(ずっと常体で書いてしまったのでいきなり仏頂面から笑顔になったようで気持ち悪い)</p>
+</div>
+<div class="paragraph">
+<p>ではまた来年。</p>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html b/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html
new file mode 100644
index 0000000..16a8188
--- /dev/null
+++ b/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html
@@ -0,0 +1,209 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="C++ の属性構文の属性名には、キーワードが使える。ネタ記事。">
+ <meta name="keywords" content="C++,C++ 17">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【C++】属性構文の属性名にはキーワードが使える | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【C++】属性構文の属性名にはキーワードが使える</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/cpp/">C++</a>
+ </li>
+
+ <li class="tag">
+ <a href="/tags/cpp17/">C++ 17</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+
+ </ol>
+ </section>
+ <div class="paragraph">
+<p>この記事は Qiita から移植してきたものです。 元 URL:
+<a href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b" class="bare">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</a></p>
+</div>
+<hr>
+<div class="paragraph">
+<p>タイトル落ち。まずはこのコードを見て欲しい。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="cpp"><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
+</span>
+<span class="p">[[</span><span class="k">alignas</span><span class="p">]]</span> <span class="p">[[</span><span class="k">alignof</span><span class="p">]]</span> <span class="p">[[</span><span class="n">and</span><span class="p">]]</span> <span class="p">[[</span><span class="n">and_eq</span><span class="p">]]</span> <span class="p">[[</span><span class="k">asm</span><span class="p">]]</span> <span class="p">[[</span><span class="k">auto</span><span class="p">]]</span> <span class="p">[[</span><span class="n">bitand</span><span class="p">]]</span>
+<span class="p">[[</span><span class="n">bitor</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">bool</span><span class="p">]]</span> <span class="p">[[</span><span class="k">break</span><span class="p">]]</span> <span class="p">[[</span><span class="k">case</span><span class="p">]]</span> <span class="p">[[</span><span class="k">catch</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">char</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">char16_t</span><span class="p">]]</span>
+<span class="p">[[</span><span class="kt">char32_t</span><span class="p">]]</span> <span class="p">[[</span><span class="k">class</span><span class="p">]]</span> <span class="p">[[</span><span class="n">compl</span><span class="p">]]</span> <span class="p">[[</span><span class="k">const</span><span class="p">]]</span> <span class="p">[[</span><span class="k">const_cast</span><span class="p">]]</span> <span class="p">[[</span><span class="k">constexpr</span><span class="p">]]</span>
+<span class="p">[[</span><span class="k">continue</span><span class="p">]]</span> <span class="p">[[</span><span class="k">decltype</span><span class="p">]]</span> <span class="p">[[</span><span class="k">default</span><span class="p">]]</span> <span class="p">[[</span><span class="k">delete</span><span class="p">]]</span> <span class="p">[[</span><span class="k">do</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">double</span><span class="p">]]</span>
+<span class="p">[[</span><span class="k">dynamic_cast</span><span class="p">]]</span> <span class="p">[[</span><span class="k">else</span><span class="p">]]</span> <span class="p">[[</span><span class="k">enum</span><span class="p">]]</span> <span class="p">[[</span><span class="k">explicit</span><span class="p">]]</span> <span class="p">[[</span><span class="k">export</span><span class="p">]]</span> <span class="p">[[</span><span class="k">extern</span><span class="p">]]</span> <span class="p">[[</span><span class="nb">false</span><span class="p">]]</span>
+<span class="p">[[</span><span class="k">final</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">float</span><span class="p">]]</span> <span class="p">[[</span><span class="k">for</span><span class="p">]]</span> <span class="p">[[</span><span class="k">friend</span><span class="p">]]</span> <span class="p">[[</span><span class="k">goto</span><span class="p">]]</span> <span class="p">[[</span><span class="k">if</span><span class="p">]]</span> <span class="p">[[</span><span class="kr">inline</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">int</span><span class="p">]]</span>
+<span class="p">[[</span><span class="kt">long</span><span class="p">]]</span> <span class="p">[[</span><span class="k">mutable</span><span class="p">]]</span> <span class="p">[[</span><span class="k">namespace</span><span class="p">]]</span> <span class="p">[[</span><span class="k">new</span><span class="p">]]</span> <span class="p">[[</span><span class="k">noexcept</span><span class="p">]]</span> <span class="p">[[</span><span class="n">not</span><span class="p">]]</span> <span class="p">[[</span><span class="n">not_eq</span><span class="p">]]</span>
+<span class="p">[[</span><span class="nb">nullptr</span><span class="p">]]</span> <span class="p">[[</span><span class="k">operator</span><span class="p">]]</span> <span class="p">[[</span><span class="n">or</span><span class="p">]]</span> <span class="p">[[</span><span class="n">or_eq</span><span class="p">]]</span> <span class="p">[[</span><span class="k">override</span><span class="p">]]</span> <span class="p">[[</span><span class="k">private</span><span class="p">]]</span>
+<span class="p">[[</span><span class="k">protected</span><span class="p">]]</span> <span class="p">[[</span><span class="k">public</span><span class="p">]]</span> <span class="p">[[</span><span class="k">register</span><span class="p">]]</span> <span class="p">[[</span><span class="k">reinterpret_cast</span><span class="p">]]</span> <span class="p">[[</span><span class="k">return</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">short</span><span class="p">]]</span>
+<span class="p">[[</span><span class="kt">signed</span><span class="p">]]</span> <span class="p">[[</span><span class="k">sizeof</span><span class="p">]]</span> <span class="p">[[</span><span class="k">static</span><span class="p">]]</span> <span class="p">[[</span><span class="k">static_assert</span><span class="p">]]</span> <span class="p">[[</span><span class="k">static_cast</span><span class="p">]]</span> <span class="p">[[</span><span class="k">struct</span><span class="p">]]</span>
+<span class="p">[[</span><span class="k">switch</span><span class="p">]]</span> <span class="p">[[</span><span class="k">template</span><span class="p">]]</span> <span class="p">[[</span><span class="k">this</span><span class="p">]]</span> <span class="p">[[</span><span class="k">thread_local</span><span class="p">]]</span> <span class="p">[[</span><span class="k">throw</span><span class="p">]]</span> <span class="p">[[</span><span class="nb">true</span><span class="p">]]</span> <span class="p">[[</span><span class="k">try</span><span class="p">]]</span>
+<span class="p">[[</span><span class="k">typedef</span><span class="p">]]</span> <span class="p">[[</span><span class="k">typeid</span><span class="p">]]</span> <span class="p">[[</span><span class="k">typename</span><span class="p">]]</span> <span class="p">[[</span><span class="k">union</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">unsigned</span><span class="p">]]</span>
+<span class="p">[[</span><span class="k">virtual</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">void</span><span class="p">]]</span> <span class="p">[[</span><span class="k">volatile</span><span class="p">]]</span> <span class="p">[[</span><span class="kt">wchar_t</span><span class="p">]]</span> <span class="p">[[</span><span class="k">while</span><span class="p">]]</span> <span class="p">[[</span><span class="n">xor</span><span class="p">]]</span> <span class="p">[[</span><span class="n">xor_eq</span><span class="p">]]</span>
+<span class="c1">// [[using]]</span>
+<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
+ <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Hello, World!"</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
+<span class="p">}</span></code></pre>
+</div>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>コンパイラのバージョン $ 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</p>
+</div>
+<div class="paragraph">
+<p>コンパイルコマンド (C17指定) $ clang –std=c++17 hoge.cpp</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>この記事から得られるものはこれ以上ないので以下は蛇足になる。</p>
+</div>
+<div class="paragraph">
+<p>別件で cppreference.com の
+<a href="https://en.cppreference.com/w/cpp/language/identifiers">identifier
+のページ</a> を読んでいた時、次の文が目に止まった。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="ulist">
+<ul>
+<li>
+<p>the identifiers that are keywords cannot be used for other purposes;</p>
+<div class="ulist">
+<ul>
+<li>
+<p>The only place they can be used as non-keywords is in an
+attribute-token. (e.g. <a id="private"></a> is a valid attribute) (since C++11)</p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>キーワードでも属性として指定する場合は非キーワードとして使えるらしい。
+実際にやってみる。</p>
+</div>
+<div class="paragraph">
+<p>同サイトの <a href="https://en.cppreference.com/w/cpp/keyword">keywords のページ</a>
+から一覧を拝借し、上のコードが出来上がった (C++17
+においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown
+attribute `〇〇' ignored)
+がコンパイラから出力されるが、コンパイルできる。</p>
+</div>
+<div class="paragraph">
+<p>上のコードでは <code><a id="using"></a></code> をコメントアウトしているが、これは <code>using</code>
+キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="cpp"><span class="c1">// using の例</span>
+<span class="p">[[</span><span class="k">using</span> <span class="n">foo</span><span class="o">:</span> <span class="n">attr1</span><span class="p">,</span> <span class="n">attr2</span><span class="p">]]</span> <span class="kt">int</span> <span class="n">x</span><span class="p">;</span> <span class="c1">// [[foo::attr1, foo::attr2]] の糖衣構文</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>C++17 の仕様も見てみる (正確には標準化前のドラフト)。</p>
+</div>
+<div class="paragraph">
+<p>引用元: <a href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4" class="bare">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</a></p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>If a keyword or an alternative token that satisfies the syntactic
+requirements of an identifier is contained in an attribute-token, it is
+considered an identifier.</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>「<code>identifier</code> の構文上の要件を満たすキーワードまたは代替トークンが
+<code>attribute-token</code> に含まれている場合、<code>identifier</code>
+とみなされる」とある。どうやら間違いないようだ。</p>
+</div>
+<div class="paragraph">
+<p>ところで、代替トークン (alternative token) とは <code>and</code> (<code>&amp;</code>) や <code>bitor</code>
+(<code>|</code>) などのことだが、<code>identifier</code>
+の構文上の要件を満たさないような代替トークンなどあるのか?
+疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい
+(参考:
+<a href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</a>)</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><code>&lt;%</code> → <code>{</code></p>
+</li>
+<li>
+<p><code>%&gt;</code> → <code>}</code></p>
+</li>
+<li>
+<p><code>&lt;:</code> → <code>[</code></p>
+</li>
+<li>
+<p><code>:&gt;</code> → <code>]</code></p>
+</li>
+<li>
+<p><code>%:</code> → <code>#</code></p>
+</li>
+<li>
+<p><code>%:%:</code> → <code>##</code></p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>「<code>identifier</code>
+の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。</p>
+</div>
+<div class="paragraph">
+<p>調べた感想: 字句解析器か構文解析器が辛そう</p>
+</div>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2021-10-02/python-unbound-local-error/index.html b/public/posts/2021-10-02/python-unbound-local-error/index.html
new file mode 100644
index 0000000..20e1e0e
--- /dev/null
+++ b/public/posts/2021-10-02/python-unbound-local-error/index.html
@@ -0,0 +1,131 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="Python における UnboundLocalError の理由と対処法。">
+ <meta name="keywords" content="Python,Python 3">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【Python】クロージャとUnboundLocalError: local variable 'x' referenced before assignment | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【Python】クロージャとUnboundLocalError: local variable 'x' referenced before assignment</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/python/">Python</a>
+ </li>
+
+ <li class="tag">
+ <a href="/tags/python3/">Python 3</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+
+ </ol>
+ </section>
+ <div class="paragraph">
+<p>この記事は Qiita から移植してきたものです。 元 URL:
+<a href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399" class="bare">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</a></p>
+</div>
+<hr>
+<div class="paragraph">
+<p>本記事は Python 3.7.6 の動作結果を元にして書かれている。</p>
+</div>
+<div class="paragraph">
+<p>Python でクロージャを作ろうと、次のようなコードを書いた。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="python"><span class="k">def</span> <span class="nf">f</span><span class="p">():</span>
+ <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span>
+ <span class="k">def</span> <span class="nf">g</span><span class="p">():</span>
+ <span class="n">x</span> <span class="o">+=</span> <span class="mi">1</span>
+ <span class="n">g</span><span class="p">()</span>
+
+<span class="n">f</span><span class="p">()</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>関数 <code>g</code> から 関数 <code>f</code> のスコープ内で定義された変数 <code>x</code> を参照し、それに
+1 を足そうとしている。 これを実行すると <code>x += 1</code>
+の箇所でエラーが発生する。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>UnboundLocalError: local variable `x' referenced before assignment</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>local変数 <code>x</code> が代入前に参照された、とある。これは、<code>f</code> の <code>x</code>
+を参照するのではなく、新しく別の変数を <code>g</code> 内に作ってしまっているため。
+前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code>
+を変数宣言のための構文として擬似的に利用している。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="python"><span class="c1"># 注: var は正しい Python の文法ではない。上記参照のこと
+</span><span class="k">def</span> <span class="nf">f</span><span class="p">():</span>
+ <span class="n">var</span> <span class="n">x</span> <span class="c1"># f の local変数 'x' を宣言
+</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># x に 0 を代入
+</span> <span class="k">def</span> <span class="nf">g</span><span class="p">():</span> <span class="c1"># f の内部関数 g を定義
+</span> <span class="n">var</span> <span class="n">x</span> <span class="c1"># g の local変数 'x' を宣言
+</span> <span class="c1"># たまたま f にも同じ名前の変数があるが、それとは別の変数
+</span> <span class="n">x</span> <span class="o">+=</span> <span class="mi">1</span> <span class="c1"># x に 1 を加算 (x = x + 1 の糖衣構文)
+</span> <span class="c1"># 加算する前の値を参照しようとするが、まだ代入されていないためエラー
+</span> <span class="n">g</span><span class="p">()</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>当初の意図を表現するには、次のように書けばよい。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="python"><span class="k">def</span> <span class="nf">f</span><span class="p">():</span>
+ <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span>
+ <span class="k">def</span> <span class="nf">g</span><span class="p">():</span>
+ <span class="k">nonlocal</span> <span class="n">x</span> <span class="c1">## (*)
+</span> <span class="n">x</span> <span class="o">+=</span> <span class="mi">1</span>
+ <span class="n">g</span><span class="p">()</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><code>(*)</code> のように、<code>nonlocal</code> を追加する。これにより一つ外側のスコープ (<code>g</code>
+の一つ外側 = <code>f</code>) で定義されている <code>x</code> を探しに行くようになる。</p>
+</div>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2021-10-02/ruby-detect-running-implementation/index.html b/public/posts/2021-10-02/ruby-detect-running-implementation/index.html
new file mode 100644
index 0000000..6fe62d7
--- /dev/null
+++ b/public/posts/2021-10-02/ruby-detect-running-implementation/index.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="Ruby には複数の実装があるが、自身を実行している処理系の種類を スクリプト上からどのように判定すればよいだろうか。">
+ <meta name="keywords" content="Ruby">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【Ruby】自身を実行している処理系の種類を判定する | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【Ruby】自身を実行している処理系の種類を判定する</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/ruby/">Ruby</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+
+ </ol>
+ </section>
+ <div class="paragraph">
+<p>この記事は Qiita から移植してきたものです。 元 URL:
+<a href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791" class="bare">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</a></p>
+</div>
+<hr>
+<div class="paragraph">
+<p>Ruby
+という言語には複数の実装があるが、それらをスクリプト上からどのようにして
+programmatically に見分ければよいだろうか。</p>
+</div>
+<div class="paragraph">
+<p><code>Object</code> クラスに定義されている <code>RUBY_ENGINE</code>
+という定数がこの用途に使える。</p>
+</div>
+<div class="paragraph">
+<p>参考:
+<a href="https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html">Object::RUBY_ENGINE</a></p>
+</div>
+<div class="paragraph">
+<p>上記ページの例から引用する:</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>ruby-1.9.1 <span class="nt">-ve</span> <span class="s1">'p RUBY_ENGINE'</span>
+<span class="go">ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux]
+"ruby"
+</span><span class="gp">$</span><span class="w"> </span>jruby <span class="nt">-ve</span> <span class="s1">'p RUBY_ENGINE'</span>
+<span class="go">jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
+"jruby"</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>それぞれの処理系がどのような値を返すかだが、stack overflow
+に良い質問と回答があった。</p>
+</div>
+<div class="paragraph">
+<p><a href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE
+correspond to which Ruby implementations?</a> より引用:</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<table class="tableblock frame-all grid-all stretch">
+<colgroup>
+<col style="width: 50%;">
+<col style="width: 50%;">
+</colgroup>
+<thead>
+<tr>
+<th class="tableblock halign-center valign-top">RUBY_ENGINE</th>
+<th class="tableblock halign-left valign-top">Implementation</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="tableblock halign-center valign-top"><p class="tableblock">&lt;undefined&gt;</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">MRI &lt; 1.9</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-center valign-top"><p class="tableblock">`ruby'</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">MRI &gt;= 1.9 or REE</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-center valign-top"><p class="tableblock">`jruby'</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">JRuby</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-center valign-top"><p class="tableblock">`macruby'</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">MacRuby</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-center valign-top"><p class="tableblock">`rbx'</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Rubinius</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-center valign-top"><p class="tableblock">`maglev'</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">MagLev</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-center valign-top"><p class="tableblock">`ironruby'</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">IronRuby</p></td>
+</tr>
+<tr>
+<td class="tableblock halign-center valign-top"><p class="tableblock">`cardinal'</p></td>
+<td class="tableblock halign-left valign-top"><p class="tableblock">Cardinal</p></td>
+</tr>
+</tbody>
+</table>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>なお、この質問・回答は
+2014年になされたものであり、値は変わっている可能性がある。MRI (aka
+CRuby) については執筆時現在 (2020/12/8) も <code>'ruby'</code>
+が返ってくることを確認済み。</p>
+</div>
+<div class="paragraph">
+<p>この表にない主要な処理系として、https://mruby.org[mruby] は <code>'mruby'</code>
+を返す。</p>
+</div>
+<div class="paragraph">
+<p><a href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby
+該当部分のソース</a> より引用:</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="c"><span class="cm">/*
+ * Ruby engine.
+ */</span>
+<span class="cp">#define MRUBY_RUBY_ENGINE "mruby"</span></code></pre>
+</div>
+</div>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html b/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html
new file mode 100644
index 0000000..7ddf636
--- /dev/null
+++ b/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html
@@ -0,0 +1,392 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="Ruby 3.0 で追加される case in 構文と、then キーワードについて。">
+ <meta name="keywords" content="Ruby,Ruby 3">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【Ruby】then キーワードと case in | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【Ruby】then キーワードと case in</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/ruby/">Ruby</a>
+ </li>
+
+ <li class="tag">
+ <a href="/tags/ruby3/">Ruby 3</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+
+ </ol>
+ </section>
+ <div id="preamble">
+<div class="sectionbody">
+<div class="paragraph">
+<p>この記事は Qiita から移植してきたものです。 元 URL:
+<a href="https://qiita.com/nsfisis/items/787a8cf888a304497223" class="bare">https://qiita.com/nsfisis/items/787a8cf888a304497223</a></p>
+</div>
+<hr>
+</div>
+</div>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ TL; DR
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p><code>case</code> - <code>in</code> によるパターンマッチング構文でも、<code>case</code> - <code>when</code>
+と同じように <code>then</code> が使える (場合によっては使う必要がある)。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ <code>then</code> とは
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>使われることは稀だが、Ruby では <code>then</code>
+がキーワードになっている。次のように使う:</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="ruby"><span class="k">if</span> <span class="n">cond</span> <span class="k">then</span>
+ <span class="nb">puts</span> <span class="s2">"Y"</span>
+<span class="k">else</span>
+ <span class="nb">puts</span> <span class="s2">"N"</span>
+<span class="k">end</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code>
+構文がそれに当たる。 上記のように、何か条件を書いた後 <code>then</code>
+を置き、式がそこで終了していることを示すマーカーとして機能する。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="ruby"><span class="c1"># Example:</span>
+
+<span class="k">if</span> <span class="n">x</span> <span class="k">then</span>
+ <span class="n">a</span>
+<span class="k">end</span>
+
+<span class="k">unless</span> <span class="n">x</span> <span class="k">then</span>
+ <span class="n">a</span>
+<span class="k">end</span>
+
+<span class="k">begin</span>
+ <span class="n">a</span>
+<span class="k">rescue</span> <span class="k">then</span>
+ <span class="n">b</span>
+<span class="k">end</span>
+
+<span class="k">case</span> <span class="n">x</span>
+<span class="k">when</span> <span class="nb">p</span> <span class="k">then</span>
+ <span class="n">a</span>
+<span class="k">end</span></code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ なぜ普段は書かなくてもよいのか
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>普通 Ruby のコードで <code>then</code>
+を書くことはない。なぜか。次のコードを実行してみるとわかる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="ruby"><span class="k">if</span> <span class="kp">true</span> <span class="nb">puts</span> <span class="s1">'Hello, World!'</span> <span class="k">end</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>次のような構文エラーが出力される。</p>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre>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</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>二つ目のメッセージは無視して一つ目を読むと、<code>then</code> か <code>;</code>
+か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。</p>
+</div>
+<div class="paragraph">
+<p>ポイントは改行が <code>then</code> (や <code>;</code>) の代わりとなることである。<code>true</code>
+の後に改行を入れてみる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="ruby"><span class="k">if</span> <span class="kp">true</span>
+<span class="nb">puts</span> <span class="s1">'Hello, World!'</span> <span class="k">end</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>無事 Hello, World! と出力されるようになった。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ なぜ <code>then</code> や <code>;</code> や改行が必要か
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>なぜ <code>then</code> や <code>;</code> や改行 (以下 「<code>then</code> 等」)
+が必要なのだろうか。次の例を見てほしい:</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="ruby"><span class="k">if</span> <span class="n">a</span> <span class="n">b</span> <span class="k">end</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><code>then</code> も <code>;</code>
+も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。
+この例は二通りに解釈できる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="ruby"><span class="c1"># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価</span>
+<span class="k">if</span> <span class="n">a</span> <span class="k">then</span>
+ <span class="n">b</span>
+<span class="k">end</span></code></pre>
+</div>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="ruby"><span class="c1"># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、</span>
+<span class="c1"># その結果が truthy なら何もしない</span>
+<span class="k">if</span> <span class="n">a</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="k">then</span>
+<span class="k">end</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<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> も同じ役割を持つ。</p>
+</div>
+<div class="paragraph">
+<p>Ruby の場合、プログラマーが書きやすいよう改行でもって <code>then</code>
+が代用できるので、ほとんどの場合 <code>then</code> は必要ない。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ <code>case</code> - <code>in</code> における <code>then</code>
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>ようやく本題にたどり着いた。来る Ruby 3.0 では <code>case</code> と <code>in</code>
+キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして
+<code>then</code> 等が必要になる。 (現在の) Ruby には formal
+な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc
+の説明は省略)。</p>
+</div>
+<div class="paragraph">
+<p><a href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986" class="bare">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</a></p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="yacc">p_case_body : keyword_in
+ {
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ p-&gt;command_start = FALSE;
+ $&lt;ctxt&gt;1 = p-&gt;ctxt;
+ p-&gt;ctxt.in_kwarg = 1;
+ $&lt;tbl&gt;$ = push_pvtbl(p);
+ }
+ {
+ $&lt;tbl&gt;$ = push_pktbl(p);
+ }
+ p_top_expr then
+ {
+ pop_pktbl(p, $&lt;tbl&gt;3);
+ pop_pvtbl(p, $&lt;tbl&gt;2);
+ p-&gt;ctxt.in_kwarg = $&lt;ctxt&gt;1.in_kwarg;
+ }
+ compstmt
+ p_cases
+ {
+ /*%%%*/
+ $$ = NEW_IN($4, $7, $8, &amp;@$);
+ /*% %*/
+ /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
+ }
+ ;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>簡略版:</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="yacc">p_case_body : keyword_in p_top_expr then compstmt p_cases
+ ;</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<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>、改行のいずれかである。</p>
+</div>
+<div class="paragraph">
+<p>これにより、<code>case</code> - <code>when</code> による従来の構文と同じように、<code>then</code>
+等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="ruby"><span class="k">case</span> <span class="n">x</span>
+<span class="k">in</span> <span class="mi">1</span> <span class="k">then</span> <span class="n">a</span>
+<span class="k">in</span> <span class="mi">2</span> <span class="k">then</span> <span class="n">b</span>
+<span class="k">in</span> <span class="mi">3</span> <span class="k">then</span> <span class="n">c</span>
+<span class="k">end</span>
+
+<span class="k">case</span> <span class="n">x</span>
+<span class="k">in</span> <span class="mi">1</span>
+ <span class="n">a</span>
+<span class="k">in</span> <span class="mi">2</span>
+ <span class="n">b</span>
+<span class="k">in</span> <span class="mi">3</span>
+ <span class="n">c</span>
+<span class="k">end</span>
+
+<span class="k">case</span> <span class="n">x</span>
+<span class="k">in</span> <span class="mi">1</span><span class="p">;</span> <span class="n">a</span>
+<span class="k">in</span> <span class="mi">2</span><span class="p">;</span> <span class="n">b</span>
+<span class="k">in</span> <span class="mi">3</span><span class="p">;</span> <span class="n">c</span>
+<span class="k">end</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>ところで、<code>p_top_expr</code> には <code>if</code> による guard clause
+が書けるので、その場合は <code>if</code> - <code>then</code> と似たような見た目になる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="ruby"><span class="k">case</span> <span class="n">x</span>
+<span class="k">in</span> <span class="mi">0</span> <span class="k">then</span> <span class="n">a</span>
+<span class="k">in</span> <span class="n">n</span> <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="k">then</span> <span class="n">b</span>
+<span class="k">in</span> <span class="n">n</span> <span class="k">then</span> <span class="n">c</span>
+<span class="k">end</span></code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ まとめ
+
+ </h2>
+ <div class="section-body">
+ <div class="ulist">
+<ul>
+<li>
+<p><code>if</code> や <code>case</code> の条件の後ろには <code>then</code>、<code>;</code>、改行のいずれかが必要</p>
+<div class="ulist">
+<ul>
+<li>
+<p>通常は改行しておけばよい</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>3.0 で入る予定の <code>case</code> - <code>in</code> でも <code>then</code> 等が必要になる</p>
+</li>
+<li>
+<p>Ruby の構文を正確に知るには (現状) <code>parse.y</code> を直接読めばよい</p>
+</li>
+</ul>
+</div>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html b/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html
new file mode 100644
index 0000000..27f2632
--- /dev/null
+++ b/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html
@@ -0,0 +1,317 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="Rust のプリミティブ型は予約語ではなく普通の識別子である。 どのようにこれが名前解決されるのかを調べた。">
+ <meta name="keywords" content="Rust">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>Rust のプリミティブ型はどこからやって来るか | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">Rust のプリミティブ型はどこからやって来るか</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/rust/">Rust</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+
+ </ol>
+ </section>
+ <div id="preamble">
+<div class="sectionbody">
+<div class="paragraph">
+<p>この記事は Qiita から移植してきたものです。 元 URL:
+<a href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565" class="bare">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</a></p>
+</div>
+<hr>
+</div>
+</div>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 前置き
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>Rust
+において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="rust"><span class="nd">#![allow(non_camel_case_types)]</span>
+<span class="nd">#![allow(dead_code)]</span>
+
+<span class="k">struct</span> <span class="nb">bool</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">char</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">i8</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">i16</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">i32</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">i64</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">i128</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">isize</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">u8</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">u16</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">u32</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">u64</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">u128</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">usize</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">f32</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">f64</span><span class="p">;</span>
+<span class="k">struct</span> <span class="nb">str</span><span class="p">;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>では、普段単に <code>bool</code> と書いたとき、この <code>bool</code>
+は一体どこから来ているのか。rustc のソースを追ってみた。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>前提知識: 一般的なコンパイラの構造、用語。<code>rustc</code> そのものの知識は不要
+(というよりも筆者自身がよく知らない)</p>
+</div>
+</blockquote>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 調査
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>調査に使用したソース (調査時点での最新 master)</p>
+</div>
+<div class="paragraph">
+<p><a href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98" class="bare">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</a></p>
+</div>
+<div class="paragraph">
+<p>どのようにして調べるか。rustc
+の構造には詳しくないため、すぐに当たりをつけるのは難しい。</p>
+</div>
+<div class="paragraph">
+<p>大雑把な構造としては、<code>compiler</code> フォルダ以下に <code>rustc_*</code>
+という名前のクレートが数十個入っている。これがどうやら <code>rustc</code>
+コマンドの実装部のようだ。</p>
+</div>
+<div class="paragraph">
+<p><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>
+<div class="literalblock">
+<div class="content">
+<pre>$ 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</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>165
+程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。</p>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre>$ git grep "\bi128\b"
+...
+rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));
+...</pre>
+</div>
+</div>
+<div class="paragraph">
+<p><code>rustc_resolve</code>
+というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="rust"><span class="cd">/// Interns the names of the primitive types.</span>
+<span class="cd">///</span>
+<span class="cd">/// All other types are defined somewhere and possibly imported, but the primitive ones need</span>
+<span class="cd">/// special handling, since they have no place of origin.</span>
+<span class="k">struct</span> <span class="n">PrimitiveTypeTable</span> <span class="p">{</span>
+ <span class="n">primitive_types</span><span class="p">:</span> <span class="n">FxHashMap</span><span class="o">&lt;</span><span class="n">Symbol</span><span class="p">,</span> <span class="n">PrimTy</span><span class="o">&gt;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="k">impl</span> <span class="n">PrimitiveTypeTable</span> <span class="p">{</span>
+ <span class="k">fn</span> <span class="nf">new</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="n">PrimitiveTypeTable</span> <span class="p">{</span>
+ <span class="k">let</span> <span class="k">mut</span> <span class="n">table</span> <span class="o">=</span> <span class="nn">FxHashMap</span><span class="p">::</span><span class="nf">default</span><span class="p">();</span>
+
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">bool</span><span class="p">,</span> <span class="n">Bool</span><span class="p">);</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">char</span><span class="p">,</span> <span class="n">Char</span><span class="p">);</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">f32</span><span class="p">,</span> <span class="nf">Float</span><span class="p">(</span><span class="nn">FloatTy</span><span class="p">::</span><span class="n">F32</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">f64</span><span class="p">,</span> <span class="nf">Float</span><span class="p">(</span><span class="nn">FloatTy</span><span class="p">::</span><span class="n">F64</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">isize</span><span class="p">,</span> <span class="nf">Int</span><span class="p">(</span><span class="nn">IntTy</span><span class="p">::</span><span class="n">Isize</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">i8</span><span class="p">,</span> <span class="nf">Int</span><span class="p">(</span><span class="nn">IntTy</span><span class="p">::</span><span class="n">I8</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">i16</span><span class="p">,</span> <span class="nf">Int</span><span class="p">(</span><span class="nn">IntTy</span><span class="p">::</span><span class="n">I16</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">i32</span><span class="p">,</span> <span class="nf">Int</span><span class="p">(</span><span class="nn">IntTy</span><span class="p">::</span><span class="n">I32</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">i64</span><span class="p">,</span> <span class="nf">Int</span><span class="p">(</span><span class="nn">IntTy</span><span class="p">::</span><span class="n">I64</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">i128</span><span class="p">,</span> <span class="nf">Int</span><span class="p">(</span><span class="nn">IntTy</span><span class="p">::</span><span class="n">I128</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">str</span><span class="p">,</span> <span class="n">Str</span><span class="p">);</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">usize</span><span class="p">,</span> <span class="nf">Uint</span><span class="p">(</span><span class="nn">UintTy</span><span class="p">::</span><span class="n">Usize</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">u8</span><span class="p">,</span> <span class="nf">Uint</span><span class="p">(</span><span class="nn">UintTy</span><span class="p">::</span><span class="n">U8</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">u16</span><span class="p">,</span> <span class="nf">Uint</span><span class="p">(</span><span class="nn">UintTy</span><span class="p">::</span><span class="n">U16</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">u32</span><span class="p">,</span> <span class="nf">Uint</span><span class="p">(</span><span class="nn">UintTy</span><span class="p">::</span><span class="n">U32</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">u64</span><span class="p">,</span> <span class="nf">Uint</span><span class="p">(</span><span class="nn">UintTy</span><span class="p">::</span><span class="n">U64</span><span class="p">));</span>
+ <span class="n">table</span><span class="nf">.insert</span><span class="p">(</span><span class="nn">sym</span><span class="p">::</span><span class="nb">u128</span><span class="p">,</span> <span class="nf">Uint</span><span class="p">(</span><span class="nn">UintTy</span><span class="p">::</span><span class="n">U128</span><span class="p">));</span>
+ <span class="k">Self</span> <span class="p">{</span> <span class="n">primitive_types</span><span class="p">:</span> <span class="n">table</span> <span class="p">}</span>
+ <span class="p">}</span>
+<span class="p">}</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>これは初めに列挙したプリミティブ型の一覧と一致している。doc comment
+にも、</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>All other types are defined somewhere and possibly imported, but the
+primitive ones need special handling, since they have no place of
+origin.</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>とある。次はこの struct
+の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="rust"> <span class="cd">/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.</span>
+ <span class="cd">/// (略)</span>
+ <span class="k">fn</span> <span class="nf">resolve_ident_in_lexical_scope</span><span class="p">(</span>
+ <span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span>
+ <span class="k">mut</span> <span class="n">ident</span><span class="p">:</span> <span class="n">Ident</span><span class="p">,</span>
+ <span class="n">ns</span><span class="p">:</span> <span class="n">Namespace</span><span class="p">,</span>
+ <span class="c1">// (略)</span>
+ <span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="n">LexicalScopeBinding</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;&gt;</span> <span class="p">{</span>
+ <span class="c1">// (略)</span>
+
+ <span class="k">if</span> <span class="n">ns</span> <span class="o">==</span> <span class="n">TypeNS</span> <span class="p">{</span>
+ <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">prim_ty</span><span class="p">)</span> <span class="o">=</span> <span class="k">self</span><span class="py">.primitive_type_table.primitive_types</span><span class="nf">.get</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ident</span><span class="py">.name</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">let</span> <span class="n">binding</span> <span class="o">=</span>
+ <span class="p">(</span><span class="nn">Res</span><span class="p">::</span><span class="nf">PrimTy</span><span class="p">(</span><span class="o">*</span><span class="n">prim_ty</span><span class="p">),</span> <span class="nn">ty</span><span class="p">::</span><span class="nn">Visibility</span><span class="p">::</span><span class="n">Public</span><span class="p">,</span> <span class="n">DUMMY_SP</span><span class="p">,</span> <span class="nn">ExpnId</span><span class="p">::</span><span class="nf">root</span><span class="p">())</span>
+ <span class="nf">.to_name_binding</span><span class="p">(</span><span class="k">self</span><span class="py">.arenas</span><span class="p">);</span>
+ <span class="k">return</span> <span class="nf">Some</span><span class="p">(</span><span class="nn">LexicalScopeBinding</span><span class="p">::</span><span class="nf">Item</span><span class="p">(</span><span class="n">binding</span><span class="p">));</span>
+ <span class="p">}</span>
+ <span class="p">}</span>
+
+ <span class="nb">None</span>
+ <span class="p">}</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<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> など)
+かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。</p>
+</div>
+<div class="paragraph">
+<p>なお、<code>ns</code> は「名前空間」を示す変数である。Rust
+における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この
+<code>if</code>
+は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。</p>
+</div>
+<div class="paragraph">
+<p>重要なのは、これが <code>resolve_ident_in_lexical_scope()</code>
+の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。</p>
+</div>
+<div class="paragraph">
+<p>動作がわかったところで、例として次のコードを考える。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="rust"><span class="nd">#![allow(non_camel_case_types)]</span>
+
+<span class="k">struct</span> <span class="nb">bool</span><span class="p">;</span>
+
+<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
+ <span class="k">let</span> <span class="n">_</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="nb">bool</span><span class="p">;</span>
+<span class="p">}</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>ここで <code>main()</code> の <code>bool</code> は <code>struct bool</code>
+として解決される。なぜなら、プリミティブ型の判定をする前に <code>bool</code>
+という名前の別の型が見つかるからだ。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ まとめ
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>Rust
+のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。</p>
+</div>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html b/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html
new file mode 100644
index 0000000..94912ed
--- /dev/null
+++ b/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html
@@ -0,0 +1,299 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、 違いはないことがわかった。">
+ <meta name="keywords" content="Vim">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【Vim】autocmd events の BufWrite/BufWritePre の違い | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【Vim】autocmd events の BufWrite/BufWritePre の違い</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/vim/">Vim</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+
+ </ol>
+ </section>
+ <div id="preamble">
+<div class="sectionbody">
+<div class="paragraph">
+<p>この記事は Qiita から移植してきたものです。 元 URL:
+<a href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25" class="bare">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</a></p>
+</div>
+<hr>
+</div>
+</div>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ TL; DR
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>違いはない。ただのエイリアス。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 調査記録
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>Vim の autocmd events には似通った名前のものがいくつかある。大抵は
+<code>:help</code>
+に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><code>BufRead</code>/<code>BufReadPost</code></p>
+</li>
+<li>
+<p><code>BufWrite</code>/<code>BufWritePre</code></p>
+</li>
+<li>
+<p><code>BufAdd</code>/<code>BufCreate</code></p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>このうち、<code>BufAdd</code>/<code>BufCreate</code> に関しては、<code>:help BufCreate</code> に</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>The BufCreate event is for historic reasons.</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>とあり、おそらくは <code>BufAdd</code>
+のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため
+vim と neovim のソースコードを調査した。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>ソースコードへのリンク
+<a href="https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2">vim
+(調査時点での master branch)</a>
+<a href="https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3">neovim
+(上に同じ)</a></p>
+</div>
+</blockquote>
+</div>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ vim のソースコード
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>以下は、autocmd events
+の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。</p>
+</div>
+<div class="paragraph">
+<p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86" class="bare">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86</a></p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="c"> <span class="p">{</span><span class="s">"BufAdd"</span><span class="p">,</span> <span class="n">EVENT_BUFADD</span><span class="p">},</span>
+ <span class="p">{</span><span class="s">"BufCreate"</span><span class="p">,</span> <span class="n">EVENT_BUFADD</span><span class="p">},</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97" class="bare">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97</a></p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="c"> <span class="p">{</span><span class="s">"BufRead"</span><span class="p">,</span> <span class="n">EVENT_BUFREADPOST</span><span class="p">},</span>
+ <span class="p">{</span><span class="s">"BufReadCmd"</span><span class="p">,</span> <span class="n">EVENT_BUFREADCMD</span><span class="p">},</span>
+ <span class="p">{</span><span class="s">"BufReadPost"</span><span class="p">,</span> <span class="n">EVENT_BUFREADPOST</span><span class="p">},</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105" class="bare">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105</a></p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="c"> <span class="p">{</span><span class="s">"BufWrite"</span><span class="p">,</span> <span class="n">EVENT_BUFWRITEPRE</span><span class="p">},</span>
+ <span class="p">{</span><span class="s">"BufWritePost"</span><span class="p">,</span> <span class="n">EVENT_BUFWRITEPOST</span><span class="p">},</span>
+ <span class="p">{</span><span class="s">"BufWritePre"</span><span class="p">,</span> <span class="n">EVENT_BUFWRITEPRE</span><span class="p">},</span></code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ neovim のソースコード
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua
+で書かれている。以下にある通り、はっきり <code>aliases</code> と書かれている。</p>
+</div>
+<div class="paragraph">
+<p><a href="https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124" class="bare">https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124</a></p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="lua"> <span class="n">aliases</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="n">BufCreate</span> <span class="o">=</span> <span class="s1">'BufAdd'</span><span class="p">,</span>
+ <span class="n">BufRead</span> <span class="o">=</span> <span class="s1">'BufReadPost'</span><span class="p">,</span>
+ <span class="n">BufWrite</span> <span class="o">=</span> <span class="s1">'BufWritePre'</span><span class="p">,</span>
+ <span class="n">FileEncoding</span> <span class="o">=</span> <span class="s1">'EncodingChanged'</span><span class="p">,</span>
+ <span class="p">},</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>ところで、上では取り上げなかった <code>FileEncoding</code> だが、これは
+<code>:help FileEncoding</code> にしっかりと書いてある。</p>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre> *FileEncoding*
+FileEncoding Obsolete. It still works and is equivalent
+ to |EncodingChanged|.</pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ まとめ
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><code>BufAdd</code>/<code>BufCreate</code></p>
+<div class="ulist">
+<ul>
+<li>
+<p>→ <code>BufCreate</code> は歴史的な理由により (<code>`for historic reasons'')
+存在しているため、新しい方 (`BufAdd</code>) を使う</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p><code>BufRead</code>/<code>BufReadPost</code></p>
+<div class="ulist">
+<ul>
+<li>
+<p>→ <code>BufReadPre</code> との対称性のため、あるいは <code>BufWritePost</code>
+との対称性のため <code>BufReadPost</code> を使う</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p><code>BufWrite</code>/<code>BufWritePre</code></p>
+<div class="ulist">
+<ul>
+<li>
+<p>→ <code>BufWritePost</code> との対称性のため、あるいは <code>BufReadPre</code>
+との対称性のため <code>BufWritePre</code> を使う</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p><code>FileEncoding</code>/<code>EncodingChanged</code></p>
+<div class="ulist">
+<ul>
+<li>
+<p>→ <code>FileEncoding</code> は <code>`Obsolete''
+と明言されているので、`EncodingChanged</code> を使う</p>
+</li>
+</ul>
+</div>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>ところでこの調査で知ったのだが、<code>BufRead</code> と <code>BufWrite</code>
+は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら
+<code>Pre</code>/<code>Post</code> 付きのものを使った方が分かりやすいだろう。</p>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html b/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html
new file mode 100644
index 0000000..2b66f2e
--- /dev/null
+++ b/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html
@@ -0,0 +1,366 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="Vim で選択した行の順番を入れ替える方法。">
+ <meta name="keywords" content="Vim">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>Vimで選択した行の順番を入れ替える | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">Vimで選択した行の順番を入れ替える</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/vim/">Vim</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2021-10-02">2021-10-02</time>: Qiita から移植
+ </li>
+
+ </ol>
+ </section>
+ <div id="preamble">
+<div class="sectionbody">
+<div class="paragraph">
+<p>この記事は Qiita から移植してきたものです。 元 URL:
+<a href="https://qiita.com/nsfisis/items/4fefb361d9a693803520" class="bare">https://qiita.com/nsfisis/items/4fefb361d9a693803520</a></p>
+</div>
+<hr>
+</div>
+</div>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ バージョン情報
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p><code>:version</code> の一部</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Jan 26 2020 11:30:30) macOS
+version Included patches: 1-148 Huge version without GUI.</p>
+</div>
+</blockquote>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ よく紹介されている手法
+
+ </h2>
+ <div class="section-body">
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ <code>tac</code> / <code>tail</code>
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p><code>tac</code> や <code>tail -r</code> などの外部コマンドを <code>!</code>
+を使って呼び出し、置き換える。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>:h v_!</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p><code>tac</code> コマンドや <code>tail</code> の <code>-r</code>
+オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ <code>:g/^/m0</code>
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>こちらは外部コマンドに頼らず、Vim の機能のみを使う。<code>g</code> は <code>:global</code>
+コマンドの、<code>m</code> は <code>:move</code> コマンドの略</p>
+</div>
+<div class="paragraph">
+<p><code>:global</code> コマンドは <code>:[range]global/{pattern}/[command]</code>
+のように使い、<code>[range]</code> で指定された範囲の行のうち、<code>{pattern}</code>
+で指定された検索パターンにマッチする行に対して、順番に <code>[command]</code>
+で指定された Ex コマンドを呼び出す。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>:h :global</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p><code>:move</code> コマンドは <code>[range]:move {address}</code> のように使い、<code>[range]</code>
+で指定された範囲の行を <code>{address}</code> で指定された位置に移動させる。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>:h :move</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p><code>:g/^/m0</code> のように組み合わせると、「すべての行を1行ずつ
+0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。</p>
+</div>
+<div class="paragraph">
+<p>なお、<code>:g/^/m0</code> は全ての行を入れ替えるが、<code>:N,Mg/^/mN-1</code> とすることで
+N行目から
+M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="vim">command<span class="p">!</span> <span class="p">-</span>bar <span class="p">-</span><span class="nb">range</span><span class="p">=</span>%
+<span class="se"> \</span> Reverse
+<span class="se"> \</span> <span class="p">&lt;</span>line1<span class="p">&gt;,&lt;</span>line2<span class="p">&gt;</span><span class="k">g</span><span class="sr">/^/</span><span class="k">m</span><span class="p">&lt;</span>line1<span class="p">&gt;</span><span class="m">-1</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。</p>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ <code>:g/^/m0</code> の問題点
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p><code>:global</code>
+コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<code>^</code>
+は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<code>'hlsearch'</code>
+オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと
+<code>n</code> コマンドなどの際に不便である。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>:h @/</p>
+</div>
+</blockquote>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 解決策
+
+ </h2>
+ <div class="section-body">
+ <div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>[2020/9/28追記] より簡潔な方法を見つけたので次節に追記した</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>前述した <code>:Reverse</code> コマンドの定義を少し変えて、次のようにする:</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="vim"><span class="k">function</span><span class="p">!</span> <span class="nv">s:reverse_lines</span><span class="p">(</span>from<span class="p">,</span> <span class="k">to</span><span class="p">)</span> abort
+ <span class="nb">execute</span> <span class="nb">printf</span><span class="p">(</span><span class="s2">"%d,%dg/^/m%d"</span><span class="p">,</span> <span class="nv">a:from</span><span class="p">,</span> <span class="nv">a:to</span><span class="p">,</span> <span class="nv">a:from</span> <span class="p">-</span> <span class="m">1</span><span class="p">)</span>
+<span class="k">endfunction</span>
+
+command<span class="p">!</span> <span class="p">-</span>bar <span class="p">-</span><span class="nb">range</span><span class="p">=</span>%
+<span class="se"> \</span> Reverse
+<span class="se"> \</span> <span class="k">call</span> <span class="p">&lt;</span>SID<span class="p">&gt;</span>reverse_lines<span class="p">(&lt;</span>line1<span class="p">&gt;,</span> <span class="p">&lt;</span>line2<span class="p">&gt;)</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。</p>
+</div>
+<div class="paragraph">
+<p>この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが
+<code>^</code> で上書きされることがなくなる。</p>
+</div>
+<div class="paragraph">
+<p>Vim のヘルプから該当箇所を引用する (強調は筆者による)。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>:h autocmd-searchpat</p>
+</div>
+<div class="paragraph">
+<p><strong>Autocommands do not change the current search patterns.</strong> Vim saves the
+current search patterns before executing autocommands then restores them
+after the autocommands finish. This means that autocommands do not
+affect the strings highlighted with the `hlsearch' option.</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>これは autocommand
+の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは
+<code>:nohlsearch</code> のヘルプにある。同じく該当箇所を引用する
+(強調は筆者による)。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>:h :nohlsearch</p>
+</div>
+<div class="paragraph">
+<p>(略) This command doesn’t work in an autocommand, because the
+highlighting state is saved and restored when executing autocommands
+|autocmd-searchpat|. <strong>Same thing for when invoking a user function.</strong></p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>この仕様により、<code>:g/^/m0</code>
+の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 解決策 (改訂版)
+
+ </h2>
+ <div class="section-body">
+ <div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>[2020/9/28追記] より簡潔な方法を見つけたため追記する</p>
+</div>
+</blockquote>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="vim">command<span class="p">!</span> <span class="p">-</span>bar <span class="p">-</span><span class="nb">range</span><span class="p">=</span>%
+<span class="se"> \</span> Reverse
+<span class="se"> \</span> <span class="k">keeppatterns</span> <span class="p">&lt;</span>line1<span class="p">&gt;,&lt;</span>line2<span class="p">&gt;</span><span class="k">g</span><span class="sr">/^/</span><span class="k">m</span><span class="p">&lt;</span>line1<span class="p">&gt;</span><span class="m">-1</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>まさにこのための Exコマンド、<code>:keeppatterns</code>
+が存在する。<code>:keeppatterns {command}</code>
+のように使い、読んで字の如く、後ろに続く
+Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>:h :keeppatterns</p>
+</div>
+</blockquote>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ コピペ用再掲
+
+ </h2>
+ <div class="section-body">
+ <div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="vim"><span class="c">" License: Public Domain</span>
+
+command<span class="p">!</span> <span class="p">-</span>bar <span class="p">-</span><span class="nb">range</span><span class="p">=</span>%
+<span class="se"> \</span> Reverse
+<span class="se"> \</span> <span class="k">keeppatterns</span> <span class="p">&lt;</span>line1<span class="p">&gt;,&lt;</span>line2<span class="p">&gt;</span><span class="k">g</span><span class="sr">/^/</span><span class="k">m</span><span class="p">&lt;</span>line1<span class="p">&gt;</span><span class="m">-1</span></code></pre>
+</div>
+</div>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html b/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html
new file mode 100644
index 0000000..afb6eac
--- /dev/null
+++ b/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html
@@ -0,0 +1,876 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。">
+ <meta name="keywords" content="カンファレンス,PHP,PHPerKaigi">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHPerKaigi 2022 トークン問題の解説 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHPerKaigi 2022 トークン問題の解説</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/conference/">カンファレンス</a>
+ </li>
+
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+
+ <li class="tag">
+ <a href="/tags/phperkaigi/">PHPerKaigi</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2022-04-09">2022-04-09</time>: 公開
+ </li>
+
+ <li class="revision">
+ <time datetime="2022-04-16">2022-04-16</time>: 2問目、3問目の解説を追加、1問目に加筆
+ </li>
+
+ </ol>
+ </section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ はじめに
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>本日開始された <a href="https://phperkaigi.jp/2022/">PHPerKaigi 2022</a> の PHPer
+チャレンジにおいて、弊社
+<a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> の問題を
+3問作成した。この記事では、これらの問題の解説をおこなう。</p>
+</div>
+<div class="paragraph">
+<p>リポジトリはこちら: <a href="https://github.com/nsfisis/PHPerKaigi2022-tokens" class="bare">https://github.com/nsfisis/PHPerKaigi2022-tokens</a></p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 第1問 brainf_ck.php
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="o">&lt;?</span><span class="n">php</span>
+
+<span class="k">declare</span><span class="p">(</span><span class="n">strict_types</span><span class="o">=</span><span class="mi">0</span><span class="no">O1</span><span class="p">);</span>
+
+<span class="kn">namespace</span> <span class="nn">Dgcircus\PHPerKaigi\Y2022</span><span class="p">;</span>
+
+<span class="cd">/**
+ * @todo
+ * Run this program to acquire a PHPer token.
+ */</span>
+
+<span class="n">https</span><span class="o">://</span><span class="n">creativecommons</span><span class="mf">.</span><span class="n">org</span><span class="o">/</span><span class="n">publicdomain</span><span class="o">/</span><span class="n">zero</span><span class="o">/</span><span class="mf">1.0</span><span class="o">/</span>
+
+<span class="err">\</span><span class="nb">error_reporting</span><span class="p">(</span><span class="o">~+!</span><span class="s1">'We are hiring!'</span><span class="p">);</span>
+
+<span class="nv">$z</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$f</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$f</span><span class="p">(</span><span class="k">fn</span><span class="p">(...</span><span class="nv">$xs</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$x</span><span class="p">(</span><span class="nv">$x</span><span class="p">)(</span><span class="mf">...</span><span class="nv">$xs</span><span class="p">)))(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$f</span><span class="p">(</span><span class="k">fn</span><span class="p">(...</span><span class="nv">$xs</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$x</span><span class="p">(</span><span class="nv">$x</span><span class="p">)(</span><span class="mf">...</span><span class="nv">$xs</span><span class="p">)));</span>
+<span class="nv">$id</span> <span class="o">=</span> <span class="err">\</span><span class="nb">spl_object_id</span><span class="p">(</span><span class="mf">...</span><span class="p">);</span>
+<span class="nv">$put</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$c</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="err">\</span><span class="nb">printf</span><span class="p">(</span><span class="s1">'%c'</span><span class="p">,</span> <span class="nv">$c</span><span class="p">);</span>
+<span class="nv">$mm</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$p</span><span class="p">,</span> <span class="nv">$n</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="err">\</span><span class="nf">ArrayObject</span><span class="p">(</span><span class="err">\</span><span class="nb">array_fill</span><span class="p">(</span><span class="o">+!!</span><span class="p">[],</span> <span class="nv">$n</span><span class="p">,</span> <span class="nv">$p</span><span class="p">));</span>
+
+<span class="err">$👉</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="o">++</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">];</span>
+<span class="err">$👈</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="o">--</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">];</span>
+<span class="err">$👍</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">++</span><span class="nv">$m</span><span class="p">[</span><span class="nv">$mp</span><span class="p">]];</span>
+<span class="err">$👎</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">--</span><span class="nv">$m</span><span class="p">[</span><span class="nv">$mp</span><span class="p">]];</span>
+<span class="err">$📝</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">,</span> <span class="nv">$put</span><span class="p">(</span><span class="nv">$m</span><span class="p">[</span><span class="nv">$mp</span><span class="p">])];</span>
+<span class="err">$🤡</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">match</span> <span class="p">(</span><span class="nv">$m</span><span class="p">[</span><span class="nv">$mp</span><span class="p">])</span> <span class="p">{</span>
+ <span class="o">+!!</span><span class="p">[]</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="nv">$z</span><span class="p">(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$loop</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$pc</span><span class="p">,</span> <span class="nv">$n</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">match</span> <span class="p">(</span><span class="nv">$id</span><span class="p">(</span><span class="nv">$p</span><span class="p">[</span><span class="nv">$pc</span><span class="p">]))</span> <span class="p">{</span>
+ <span class="nv">$b</span> <span class="o">=&gt;</span> <span class="nv">$loop</span><span class="p">(</span><span class="o">++</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">++</span><span class="nv">$n</span><span class="p">),</span>
+ <span class="nv">$e</span> <span class="o">=&gt;</span> <span class="nv">$n</span> <span class="o">===</span> <span class="o">+!!</span><span class="p">[]</span> <span class="o">?</span> <span class="o">++</span><span class="nv">$pc</span> <span class="o">:</span> <span class="nv">$loop</span><span class="p">(</span><span class="o">++</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">--</span><span class="nv">$n</span><span class="p">),</span>
+ <span class="k">default</span> <span class="o">=&gt;</span> <span class="nv">$loop</span><span class="p">(</span><span class="o">++</span><span class="nv">$pc</span><span class="p">,</span> <span class="nv">$n</span><span class="p">),</span>
+ <span class="p">})(</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">-!</span><span class="p">[])],</span>
+ <span class="k">default</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">],</span>
+<span class="p">};</span>
+<span class="err">$🎪</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">match</span> <span class="p">(</span><span class="nv">$m</span><span class="p">[</span><span class="nv">$mp</span><span class="p">])</span> <span class="p">{</span>
+ <span class="o">+!!</span><span class="p">[]</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="o">++</span><span class="nv">$pc</span><span class="p">],</span>
+ <span class="k">default</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nv">$mp</span><span class="p">,</span> <span class="nv">$z</span><span class="p">(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$loop</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$pc</span><span class="p">,</span> <span class="nv">$n</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">match</span> <span class="p">(</span><span class="nv">$id</span><span class="p">(</span><span class="nv">$p</span><span class="p">[</span><span class="nv">$pc</span><span class="p">]))</span> <span class="p">{</span>
+ <span class="nv">$e</span> <span class="o">=&gt;</span> <span class="nv">$loop</span><span class="p">(</span><span class="o">--</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">++</span><span class="nv">$n</span><span class="p">),</span>
+ <span class="nv">$b</span> <span class="o">=&gt;</span> <span class="nv">$n</span> <span class="o">===</span> <span class="o">+!!</span><span class="p">[]</span> <span class="o">?</span> <span class="nv">$pc</span><span class="o">+!</span><span class="p">[]</span> <span class="o">:</span> <span class="nv">$loop</span><span class="p">(</span><span class="o">--</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">--</span><span class="nv">$n</span><span class="p">),</span>
+ <span class="k">default</span> <span class="o">=&gt;</span> <span class="nv">$loop</span><span class="p">(</span><span class="o">--</span><span class="nv">$pc</span><span class="p">,</span> <span class="nv">$n</span><span class="p">),</span>
+ <span class="p">})(</span><span class="nv">$pc</span><span class="p">,</span> <span class="o">-!</span><span class="p">[])],</span>
+<span class="p">};</span>
+<span class="err">$🐘</span> <span class="o">=</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$p</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nv">$z</span><span class="p">(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$loop</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">fn</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)</span> <span class="o">=&gt;</span>
+ <span class="k">isset</span><span class="p">(</span><span class="nv">$p</span><span class="p">[</span><span class="nv">$pc</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="nv">$loop</span><span class="p">(</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="mf">...</span><span class="p">(</span><span class="nv">$p</span><span class="p">[</span><span class="nv">$pc</span><span class="p">](</span><span class="nv">$m</span><span class="p">,</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$b</span><span class="p">,</span> <span class="nv">$e</span><span class="p">,</span> <span class="nv">$mp</span><span class="p">,</span> <span class="nv">$pc</span><span class="p">)))</span>
+<span class="p">)(</span><span class="nv">$mm</span><span class="p">(</span><span class="o">+!!</span><span class="p">[],</span> <span class="o">+</span><span class="p">(</span><span class="o">!</span><span class="p">[]</span><span class="mf">.</span><span class="o">!</span><span class="p">[])),</span> <span class="nv">$p</span><span class="p">,</span> <span class="nv">$id</span><span class="p">(</span><span class="err">$🤡</span><span class="p">),</span> <span class="nv">$id</span><span class="p">(</span><span class="err">$🎪</span><span class="p">),</span> <span class="o">+!!</span><span class="p">[],</span> <span class="o">+!!</span><span class="p">[]);</span>
+
+<span class="err">$🐘</span><span class="p">([</span>
+ <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span>
+ <span class="err">$🤡</span><span class="p">,</span>
+ <span class="err">$👉</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span>
+ <span class="err">$👉</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span>
+ <span class="err">$👉</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span>
+ <span class="err">$👉</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span>
+ <span class="err">$👈</span><span class="p">,</span> <span class="err">$👈</span><span class="p">,</span> <span class="err">$👈</span><span class="p">,</span> <span class="err">$👈</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span>
+ <span class="err">$🎪</span><span class="p">,</span>
+ <span class="err">$👉</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👉</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👉</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👈</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👉</span><span class="p">,</span> <span class="err">$👉</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👈</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👈</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👉</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$👍</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👉</span><span class="p">,</span> <span class="err">$👎</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+ <span class="err">$👈</span><span class="p">,</span> <span class="err">$📝</span><span class="p">,</span>
+<span class="p">]);</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。</p>
+</div>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 解説
+
+ </h3>
+ <div class="section-body">
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 絵文字
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>まず目につくのは大量の絵文字だろう。 PHP
+は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ プログラム全体
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck
+とは、難解プログラミング言語のひとつであり、ここで説明するよりも
+Wikipedia の該当ページを読んだ方がよい。</p>
+</div>
+<div class="paragraph">
+<p><a href="https://ja.wikipedia.org/wiki/Brainfuck" class="bare">https://ja.wikipedia.org/wiki/Brainfuck</a></p>
+</div>
+<div class="paragraph">
+<p>なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。</p>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre>+ + + + + + + + + +
+[
+ &gt; + + +
+ &gt; + + + + +
+ &gt; + + + + + + + + + + + +
+ &gt; + + + + + + + + + +
+ &lt; &lt; &lt; &lt; -
+]
+&gt; + + + + + .
+- - .
+&gt; - - - .
+&gt; - - - .
+- - .
+- .
+&lt; .
+&gt; &gt; - - .
++ + + + + + + .
+&lt; - - - - .
+&lt; .
+&gt; + + .
+&gt; - .
+&lt; .</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>実行結果はこちら: <a href="https://ideone.com/22VWmb" class="bare">https://ideone.com/22VWmb</a></p>
+</div>
+<div class="paragraph">
+<p>それぞれの絵文字で表された関数が、各命令に対応している。</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><code>$👉</code>: <code>&gt;</code></p>
+</li>
+<li>
+<p><code>$👈</code>: <code>&lt;</code></p>
+</li>
+<li>
+<p><code>$👍</code>: <code>+</code></p>
+</li>
+<li>
+<p><code>$👎</code>: <code>-</code></p>
+</li>
+<li>
+<p><code>$📝</code>: <code>.</code></p>
+</li>
+<li>
+<p><code>$🤡</code>: <code>[</code></p>
+</li>
+<li>
+<p><code>$🎪</code>: <code>]</code></p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p><code>,</code> (入力) に対応する関数はない
+(このプログラムでは使わないので用意していない)。</p>
+</div>
+<div class="paragraph">
+<p>なお、<code>$🐘</code> はいわゆる main 関数であり、プログラムの実行部分である。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 絵文字の選択
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>おおよそ意味に合致するよう選んでいるが、<code>$🤡</code> と <code>$🎪</code>
+は弊社デジタルサーカスにちなんでいる。 また、<code>$🐘</code> は PHP
+のマスコットの象に由来する。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ strict_types
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p><code>declare</code> 文の <code>strict_types</code> に指定できるのは、<code>0</code> か <code>1</code>
+の数値リテラルだが、 <code>0x0</code> や <code>0b1</code> のような値も受け付ける。 今回は、PHP
+8.1 から追加された、<code>0O</code> または <code>0o</code> から始まる八進数リテラルを使った。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ URL
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>ソースコードのライセンスを示したこの部分だが、</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="n">https</span><span class="o">://</span><span class="n">creativecommons</span><span class="mf">.</span><span class="n">org</span><span class="o">/</span><span class="n">publicdomain</span><span class="o">/</span><span class="n">zero</span><span class="o">/</span><span class="mf">1.0</span><span class="o">/</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>完全に合法な PHP のコードである。 <code>https:</code> 部分はラベル、<code>//</code>
+以降は行コメントになっている。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ リテラルなしで数値を生成する
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。
+PHP では、型変換を利用することで任意の整数を作り出すことができる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nb">assert</span><span class="p">(</span><span class="mi">0</span> <span class="o">===</span> <span class="o">+!!</span><span class="p">[]);</span>
+<span class="nb">assert</span><span class="p">(</span><span class="mi">1</span> <span class="o">===</span> <span class="o">+!</span><span class="p">[]);</span>
+<span class="nb">assert</span><span class="p">(</span><span class="mi">2</span> <span class="o">===</span> <span class="o">!</span><span class="p">[]</span><span class="o">+!</span><span class="p">[]);</span>
+<span class="nb">assert</span><span class="p">(</span><span class="mi">3</span> <span class="o">===</span> <span class="o">!</span><span class="p">[]</span><span class="o">+!</span><span class="p">[]</span><span class="o">+!</span><span class="p">[]);</span>
+<span class="nb">assert</span><span class="p">(</span><span class="mi">10</span> <span class="o">===</span> <span class="o">+</span><span class="p">(</span><span class="o">!</span><span class="p">[]</span><span class="mf">.</span><span class="o">+!!</span><span class="p">[]));</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<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 が作れる)。</p>
+</div>
+<div class="paragraph">
+<p>また、<code>error_reporting</code> に指定しているのは <code>-1</code> である。 これは、<code>!</code>
+によって文字列を <code>false</code> にし、<code>+</code> によって <code>false</code> を <code>0</code>
+にし、さらにビット反転して <code>-1</code> にしている。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ <code>if</code> 文なしで条件分岐
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>三項演算子ないし <code>match</code> 式を使うことで、<code>if</code>
+を一切書かずに条件分岐ができる。 また、<code>&amp;&amp;</code> / <code>||</code> も使えることがある。
+遅延評価が不要なケースでは、<code>[$t, $f][$cond]</code>
+のような形で分岐することもできる。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ <code>while</code>、<code>for</code> 文なしでループ
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>不動点コンビネータを使って無名再帰する
+(詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に
+Z コンビネータとして知られるものを使った (<code>$z</code>)。</p>
+</div>
+<div class="paragraph">
+<p>実際のところ、<code>$🤡</code> や <code>$🎪</code>、<code>$🐘</code> は、一度 Scheme (Lisp の一種)
+で書いてから PHP に翻訳する形で記述した。</p>
+</div>
+<div class="paragraph">
+<p>なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは)
+ので、 あまりに長い brainf*ck
+プログラムを書くとスタックオーバーフローする。</p>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 第2問 riddle.php
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="o">&lt;?</span><span class="n">php</span>
+
+<span class="cd">/*********************************************************
+ * 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 class="k">const</span> <span class="no">N</span> <span class="o">=</span> <span class="mi">0</span> <span class="cm">/* Change it to your answer. */</span><span class="p">;</span>
+<span class="nb">assert</span><span class="p">(</span><span class="mi">0</span> <span class="o">&lt;=</span> <span class="nc">N</span> <span class="o">&amp;&amp;</span> <span class="nc">N</span> <span class="o">&lt;=</span> <span class="mb">0b11111_11111_11111_11111_11111</span><span class="p">);</span>
+
+<span class="nv">$token</span> <span class="o">=</span> <span class="p">[</span>
+ <span class="mh">0x14B499C</span><span class="p">,</span>
+ <span class="mh">0x0BE34CC</span><span class="p">,</span> <span class="mh">0x01C9C69</span><span class="p">,</span>
+ <span class="mh">0x0ECA069</span><span class="p">,</span> <span class="mh">0x01C2449</span><span class="p">,</span> <span class="mh">0x0FDB166</span><span class="p">,</span> <span class="mh">0x01C9C69</span><span class="p">,</span>
+ <span class="mh">0x01C1C66</span><span class="p">,</span> <span class="mh">0x0FC1C47</span><span class="p">,</span> <span class="mh">0x01C1C66</span><span class="p">,</span>
+ <span class="mh">0x10C5858</span><span class="p">,</span> <span class="mh">0x1E4E3B8</span><span class="p">,</span> <span class="mh">0x1A2F2F8</span><span class="p">,</span>
+<span class="p">];</span>
+<span class="k">foreach</span> <span class="p">(</span><span class="nv">$token</span> <span class="k">as</span> <span class="nv">$x</span><span class="p">)</span> <span class="p">{</span>
+ <span class="nv">$x</span> <span class="o">=</span> <span class="nv">$x</span> <span class="o">^</span> <span class="nc">N</span><span class="p">;</span>
+
+ <span class="nv">$x</span> <span class="o">=</span> <span class="nb">sprintf</span><span class="p">(</span><span class="s1">'%025b'</span><span class="p">,</span> <span class="nv">$x</span><span class="p">);</span>
+ <span class="nv">$x</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="n">search</span><span class="o">:</span> <span class="p">[</span><span class="s1">'0'</span><span class="p">,</span> <span class="s1">'1'</span><span class="p">],</span> <span class="n">replace</span><span class="o">:</span> <span class="p">[</span><span class="s1">' '</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">],</span> <span class="n">subject</span><span class="o">:</span> <span class="nv">$x</span><span class="p">);</span>
+ <span class="nv">$x</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nb">str_split</span><span class="p">(</span><span class="nv">$x</span><span class="p">,</span> <span class="n">length</span><span class="o">:</span> <span class="mi">5</span><span class="p">));</span>
+ <span class="k">echo</span> <span class="s2">"</span><span class="si">{</span><span class="nv">$x</span><span class="si">}</span><span class="se">\n\n</span><span class="s2">"</span><span class="p">;</span>
+<span class="p">}</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。
+トークンを得るためには、ソースコードを読み、定数 <code>N</code>
+を特定する必要がある。</p>
+</div>
+<div class="paragraph">
+<p>ここでは、私の想定解を解説する。</p>
+</div>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 読解
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>まずはソースコードを読んでいく。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nv">$token</span> <span class="o">=</span> <span class="p">[</span>
+ <span class="c1">// 略</span>
+<span class="p">];</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>数値からなる <code>$token</code> があり、各要素をループしている。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"> <span class="nv">$x</span> <span class="o">=</span> <span class="nv">$x</span> <span class="o">^</span> <span class="nc">N</span><span class="p">;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>まずは排他的論理和 (xor) を取り、</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"> <span class="nv">$x</span> <span class="o">=</span> <span class="nb">sprintf</span><span class="p">(</span><span class="s1">'%025b'</span><span class="p">,</span> <span class="nv">$x</span><span class="p">);</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>二進数に変換して、</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"> <span class="nv">$x</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="n">search</span><span class="o">:</span> <span class="p">[</span><span class="s1">'0'</span><span class="p">,</span> <span class="s1">'1'</span><span class="p">],</span> <span class="n">replace</span><span class="o">:</span> <span class="p">[</span><span class="s1">' '</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">],</span> <span class="n">subject</span><span class="o">:</span> <span class="nv">$x</span><span class="p">);</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>0 を空白に、1 を <code>#</code> にし、</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"> <span class="nv">$x</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nb">str_split</span><span class="p">(</span><span class="nv">$x</span><span class="p">,</span> <span class="n">length</span><span class="o">:</span> <span class="mi">5</span><span class="p">));</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>5文字ごとに区切ったあと、改行で結合している。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ ヒント
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>次に、ソースコードに書いてあるヒントを読んでいく。</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><code>N</code> それ自体は、42 や 8128
+といったような特別な意味を持たず、ランダムに決められている</p>
+</li>
+<li>
+<p><code>$token</code> の各要素は、1文字を表す</p>
+</li>
+<li>
+<p>1文字は 5x5 のセルからなる</p>
+</li>
+<li>
+<p>出力されるのは、完全な PHPer トークンである</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>ここで、PHPer トークンは必ず <code><mark></code> 記号から始まることを思いだすと、
+<code>$token</code> の最初の数字 <code>0x14B499C</code> は、変換の結果 <code></mark></code>
+になるのではないかと予想される (なお、このことは、リポジトリの README
+ファイルに追加ヒントとして書かれている)。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 解く
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>ここまでわかれば、あと一歩で解ける。すなわち、<code>0x14B499C</code> が <code>#</code>
+に変換されるような <code>N</code> を見つければよい。</p>
+</div>
+<div class="paragraph">
+<p><code>N</code> は高々</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nb">assert</span><span class="p">(</span><span class="mi">0</span> <span class="o">&lt;=</span> <span class="nc">N</span> <span class="o">&amp;&amp;</span> <span class="nc">N</span> <span class="o">&lt;=</span> <span class="mb">0b11111_11111_11111_11111_11111</span><span class="p">);</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="o">&lt;?</span><span class="n">php</span>
+
+<span class="nv">$x</span> <span class="o">=</span> <span class="mh">0x14B499C</span><span class="p">;</span>
+
+<span class="nv">$x</span> <span class="o">=</span> <span class="nv">$x</span> <span class="o">^</span> <span class="nc">N</span><span class="p">;</span>
+
+<span class="nv">$x</span> <span class="o">=</span> <span class="nb">sprintf</span><span class="p">(</span><span class="s1">'%025b'</span><span class="p">,</span> <span class="nv">$x</span><span class="p">);</span>
+<span class="nv">$x</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="n">search</span><span class="o">:</span> <span class="p">[</span><span class="s1">'0'</span><span class="p">,</span> <span class="s1">'1'</span><span class="p">],</span> <span class="n">replace</span><span class="o">:</span> <span class="p">[</span><span class="s1">' '</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">],</span> <span class="n">subject</span><span class="o">:</span> <span class="nv">$x</span><span class="p">);</span>
+<span class="nv">$x</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nb">str_split</span><span class="p">(</span><span class="nv">$x</span><span class="p">,</span> <span class="n">length</span><span class="o">:</span> <span class="mi">5</span><span class="p">));</span>
+
+<span class="nb">assert</span><span class="p">(</span><span class="nv">$x</span> <span class="o">===</span>
+ <span class="s2">" # # </span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span>
+ <span class="s2">"#####</span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span>
+ <span class="s2">" # # </span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span>
+ <span class="s2">"#####</span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span>
+ <span class="s2">" # # "</span><span class="p">);</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>この一連の変換に対する逆変換を考えると、次のようになる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="o">&lt;?</span><span class="n">php</span>
+
+<span class="nv">$x</span> <span class="o">=</span>
+ <span class="s2">" # # </span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span>
+ <span class="s2">"#####</span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span>
+ <span class="s2">" # # </span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span>
+ <span class="s2">"#####</span><span class="se">\n</span><span class="s2">"</span> <span class="mf">.</span>
+ <span class="s2">" # # "</span><span class="p">;</span>
+
+<span class="nv">$x</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="s1">''</span><span class="p">,</span> <span class="nb">explode</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nv">$x</span><span class="p">));</span>
+<span class="nv">$x</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="n">search</span><span class="o">:</span> <span class="p">[</span><span class="s1">' '</span><span class="p">,</span> <span class="s1">'#'</span><span class="p">],</span> <span class="n">replace</span><span class="o">:</span> <span class="p">[</span><span class="s1">'0'</span><span class="p">,</span> <span class="s1">'1'</span><span class="p">],</span> <span class="n">subject</span><span class="o">:</span> <span class="nv">$x</span><span class="p">);</span>
+<span class="nv">$x</span> <span class="o">=</span> <span class="nb">bindec</span><span class="p">(</span><span class="nv">$x</span><span class="p">);</span>
+
+<span class="nv">$n</span> <span class="o">=</span> <span class="nv">$x</span> <span class="o">^</span> <span class="mh">0x14B499C</span><span class="p">;</span>
+
+<span class="k">echo</span> <span class="s2">"N = </span><span class="nv">$n</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>これを実行すると、<code>N</code> が得られる。</p>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 第3問 toquine.php
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>ソースコードはこちら。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="o">&lt;?</span><span class="n">php</span>
+
+<span class="c1">// License: https://creativecommons.org/publicdomain/zero/1.0/</span>
+<span class="c1">// This is a quine-like program to generate a PHPer token.</span>
+<span class="c1">// Execute it like this: php toquine.php | php | php | php | ...</span>
+
+<span class="nv">$s</span> <span class="o">=</span> <span class="sh">&lt;&lt;&lt;'Q'
+&lt;?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 &lt;= 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) =&gt; vzcybqr(', ', $j), neenl_puhax(neenl_znc(sa($k) =&gt; fcevags('0k' . pue(37) . '07K', $k), $kf), 10));
+cevags($f, $g, fge_ebg13("&lt;&lt;&lt;'Q'\a{$f}\aQ"), vzcybqr(",\a", $jf));
+Q;</span>
+<span class="nv">$s</span> <span class="o">=</span> <span class="nb">str_rot13</span><span class="p">(</span><span class="nv">$s</span><span class="p">);</span> <span class="nv">$xs</span> <span class="o">=</span> <span class="p">[</span>
+<span class="mh">0x0AFABEA</span><span class="p">,</span> <span class="mh">0x1F294A7</span><span class="p">,</span> <span class="mh">0x1F2109F</span><span class="p">,</span> <span class="mh">0x1F294A7</span><span class="p">,</span> <span class="mh">0x0002800</span><span class="p">,</span> <span class="mh">0x1F2109F</span><span class="p">,</span> <span class="mh">0x0117041</span><span class="p">,</span> <span class="mh">0x1F294A7</span><span class="p">,</span> <span class="mh">0x1FAD6B5</span><span class="p">,</span> <span class="mh">0x1F295B7</span><span class="p">,</span>
+<span class="mh">0x010FC21</span><span class="p">,</span> <span class="mh">0x1FAD6B5</span><span class="p">,</span> <span class="mh">0x1151151</span><span class="p">,</span> <span class="mh">0x010FC21</span><span class="p">,</span> <span class="mh">0x1F294A7</span><span class="p">,</span> <span class="mh">0x1F295B7</span><span class="p">,</span> <span class="mh">0x1FAD6B5</span><span class="p">,</span> <span class="mh">0x1F294A7</span><span class="p">,</span> <span class="mh">0x1F295B7</span><span class="p">,</span> <span class="mh">0x1F8C63F</span><span class="p">,</span>
+<span class="mh">0x1F8C631</span><span class="p">,</span> <span class="mh">0x1FAD6B5</span><span class="p">,</span> <span class="mh">0x17AD6BD</span><span class="p">,</span> <span class="mh">0x17AD6BD</span><span class="p">,</span> <span class="mh">0x1F8C63F</span><span class="p">,</span> <span class="mh">0x1F295B7</span><span class="p">,</span>
+<span class="p">];</span>
+<span class="nv">$t</span> <span class="o">=</span> <span class="kc">null</span><span class="mf">.</span><span class="kc">false</span><span class="p">;</span> <span class="k">for</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nv">$i</span> <span class="o">&lt;=</span> <span class="nb">intdiv</span><span class="p">(</span><span class="k">__LINE__</span><span class="o">-</span><span class="mo">035</span><span class="p">,</span><span class="mi">6</span><span class="p">);</span> <span class="o">++</span><span class="nv">$i</span><span class="p">)</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="k">isset</span><span class="p">(</span><span class="nv">$xs</span><span class="p">[</span><span class="nv">$i</span><span class="p">]))</span> <span class="k">break</span><span class="p">;</span> <span class="k">else</span>
+<span class="nv">$t</span> <span class="mf">.</span><span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nb">str_split</span><span class="p">(</span><span class="nb">str_replace</span><span class="p">([</span><span class="s1">'0'</span><span class="p">,</span><span class="s1">'1'</span><span class="p">],</span> <span class="p">[</span><span class="s1">' '</span><span class="p">,</span><span class="s1">'##'</span><span class="p">],</span> <span class="nb">sprintf</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="mi">37</span><span class="p">)</span> <span class="mf">.</span> <span class="s1">'025b'</span><span class="p">,</span> <span class="nv">$xs</span><span class="p">[</span><span class="nv">$i</span><span class="p">])),</span> <span class="mo">012</span><span class="p">))</span> <span class="mf">.</span> <span class="s2">"</span><span class="se">\n\n</span><span class="s2">"</span><span class="p">;</span>
+<span class="nv">$ws</span> <span class="o">=</span> <span class="nb">array_map</span><span class="p">(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$w</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nb">implode</span><span class="p">(</span><span class="s1">', '</span><span class="p">,</span> <span class="nv">$w</span><span class="p">),</span> <span class="nb">array_chunk</span><span class="p">(</span><span class="nb">array_map</span><span class="p">(</span><span class="k">fn</span><span class="p">(</span><span class="nv">$x</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nb">sprintf</span><span class="p">(</span><span class="s1">'0x'</span> <span class="mf">.</span> <span class="nb">chr</span><span class="p">(</span><span class="mi">37</span><span class="p">)</span> <span class="mf">.</span> <span class="s1">'07X'</span><span class="p">,</span> <span class="nv">$x</span><span class="p">),</span> <span class="nv">$xs</span><span class="p">),</span> <span class="mi">10</span><span class="p">));</span>
+<span class="nb">printf</span><span class="p">(</span><span class="nv">$s</span><span class="p">,</span> <span class="nv">$t</span><span class="p">,</span> <span class="nb">str_rot13</span><span class="p">(</span><span class="s2">"&lt;&lt;&lt;'D'</span><span class="se">\n</span><span class="si">{</span><span class="nv">$s</span><span class="si">}</span><span class="se">\n</span><span class="s2">D"</span><span class="p">),</span> <span class="nb">implode</span><span class="p">(</span><span class="s2">",</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nv">$ws</span><span class="p">));</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>コメントにもあるとおり、次のようにして実行すれば答えがでてくる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>php toquine.php | php | php | php | ...</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>実際にはもう少しパイプで繋げなければならない。</p>
+</div>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 解説
+
+ </h3>
+ <div class="section-body">
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ プログラム全体
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>コメントにもあるとおり、これは quine (風) のプログラムになっている。
+Quine
+とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。</p>
+</div>
+<div class="paragraph">
+<p>このプログラムは、実行すると自身とほとんど同じプログラムを出力する。
+異なるのはトークンになっている部分のみである。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ トークン
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p><code>$xs</code> がトークンに対応している。変換のロジックは <code>riddle.php</code>
+とほぼ同じなので省略する。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ 状態保持
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>トークンの何文字目まで出力したかを、ソースコードを変えずに (quine
+なので) 覚えておく必要がある。
+このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、<code><em>LINE</em></code>
+から情報を取得している。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-3">
+ <h4 id="" class="section-header">
+
+ ROT 13
+
+ </h4>
+ <div class="section-body">
+ <div class="paragraph">
+<p>Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。
+これがあまり美しくないので、<code>toquine.php</code> では、ROT 13
+変換を使って難読化した。</p>
+</div>
+<div class="paragraph">
+<p>それにしてもなぜこんなものが標準ライブラリに……。</p>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ おわりに
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。</p>
+</div>
+<div class="paragraph">
+<p>今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、
+来年は 5問、より面白い問題を持っていきます。</p>
+</div>
+<div class="paragraph">
+<p>実はもう作りはじめているので、どうか来年もありますように……。</p>
+</div>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html b/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html
new file mode 100644
index 0000000..628d3f8
--- /dev/null
+++ b/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html
@@ -0,0 +1,222 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。">
+ <meta name="keywords" content="">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>term-banner: ターミナルにバナーを表示するツールを書いた | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">term-banner: ターミナルにバナーを表示するツールを書いた</h1>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2022-04-24">2022-04-24</time>: 公開
+ </li>
+
+ <li class="revision">
+ <time datetime="2022-04-27">2022-04-27</time>: -f オプションについて追記
+ </li>
+
+ </ol>
+ </section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ はじめに
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>こんなものを作った。</p>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre>$ term-banner 'Hello, World!' 'こんにちは、' '世界!'</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>image::https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png[term-banner
+のスクリーンショット]</p>
+</div>
+<div class="paragraph">
+<p>コマンドライン引数として渡した文字列をターミナルに大きく表示する。</p>
+</div>
+<div class="paragraph">
+<p>リポジトリはこちら: <a href="https://github.com/nsfisis/term-banner" class="bare">https://github.com/nsfisis/term-banner</a></p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ Motivation
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>以前、https://github.com/nsfisis/big-clock-mode[big-clock-mode]
+という似たようなプログラムを書いた。 これは tmux の <code>:clock-mode</code>
+コマンドに着想を得たもので、<code>:clock-mode</code>
+よりも大きく現在時刻を表示する。</p>
+</div>
+<div class="paragraph">
+<p><code>big-clock-mode</code>
+を開発したのは、次のようなシチュエーションで使うためである。
+弊社では現在リモートワークが基本だが、web
+会議などで画面共有しているときに、休憩を挟んで特定の時刻から再開する、ということがある。
+こういったケースで、画面上に現在の時刻を大きめに表示しておくと、モニタから離れても遠くから時刻がわかるので便利である。</p>
+</div>
+<div class="paragraph">
+<p>それこそタイマアプリか何かを使えばいいのだが、ターミナルに棲むいきものとしては、住処から離れたくないわけだ。</p>
+</div>
+<div class="paragraph">
+<p>しばらく便利に使っていたのだが、ひとつ不満点が出てきた。それは、再開する時刻がいつだったかを覚えておかなければならないということだ。
+どこかにメモしておいてもいいが、せっかくなら現在時刻とともに表示させておきたい。</p>
+</div>
+<div class="paragraph">
+<p>そんなわけで、「任意の文字列をターミナルに表示する」プログラムを書く運びとなった。
+まあ、作らなくても探せばあると思うが、作りたいものは作りたいので知ったことではない。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ プログラム
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>全体の流れは次のようになっている。</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>フォントファイルを読み込む</p>
+</li>
+<li>
+<p>コマンドライン引数を Shift-JIS に変換する (フォントが Shift-JIS
+基準で並んでいるため)</p>
+</li>
+<li>
+<p>1文字ずつレンダリングしていく</p>
+</li>
+</ol>
+</div>
+<div class="paragraph">
+<p><code>big-clock-mode</code> が Go 製なので、今回も Go で書いた。 PNG
+が標準ライブラリにあったり、Shift-JIS
+のエンコーディングが準標準ライブラリにあったりしたのは助かった。</p>
+</div>
+<div class="paragraph">
+<p>フォントファイルは <code>go:embed</code>
+で実行ファイルに埋め込んでいるので、ビルド後はワンバイナリで動く。
+仕事ではスクリプト言語ばかり書いているが、やはりコンパイル言語はいい。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ フォント
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>フリーの 8x8
+ビットマップフォントである、https://littlelimit.net/misaki.htm[美咲フォント
+2021-05-05a 版] を使わせていただいた。</p>
+</div>
+<div class="paragraph">
+<p>はじめは自分でポチポチ打っていたのだが、「き」くらいまでやって挫折した。
+同じく 8x8
+で作っていたのだが、平仮名でさえも、この小さなキャンバスにはとても収められない。</p>
+</div>
+<div class="paragraph">
+<p>美咲フォントは、平仮名・片仮名に留まらず、JIS
+第一・第二水準の漢字までサポートしている。
+第二水準ともなると一生お目にかかることのない字の方が多いくらいだが、これをこの大きさで書くというのは、もはや芸術の域である。</p>
+</div>
+<div class="paragraph">
+<p>さらに言うと、実のところ美咲フォントは実サイズ 7x7
+で作られており、余白が設けられている。
+これは、単純にそのまま並べても字間・行間を確保できるようにという配慮である。
+おかげでコーディングまで楽になった。</p>
+</div>
+<div class="paragraph">
+<p>ゴシック体と明朝体があったが、私の好みで明朝体の方にした。
+ただ、ゴシック体の方が見やすい気がするので、フォントを選べるように後ほど拡張するかもしれない。</p>
+</div>
+<div class="paragraph">
+<p>2022-04-27 追記: <code>-f</code> オプションで選べるようにした。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ おわりに
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>あなたもターミナルに住んでみませんか?</p>
+</div>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2022-05-01/phperkaigi-2022/index.html b/public/posts/2022-05-01/phperkaigi-2022/index.html
new file mode 100644
index 0000000..4168136
--- /dev/null
+++ b/public/posts/2022-05-01/phperkaigi-2022/index.html
@@ -0,0 +1,324 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。">
+ <meta name="keywords" content="カンファレンス,PHP,PHPerKaigi">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHPerKaigi 2022 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHPerKaigi 2022</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/conference/">カンファレンス</a>
+ </li>
+
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+
+ <li class="tag">
+ <a href="/tags/phperkaigi/">PHPerKaigi</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2022-05-01">2022-05-01</time>: 公開
+ </li>
+
+ </ol>
+ </section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ はじめに
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>2022-04-09 から 2022-04-11
+にかけて開催された、https://phperkaigi.jp/2022/[PHPerKaigi 2022]
+に、一般参加者として参加した。
+弊社https://www.dgcircus.com/[デジタルサーカス株式会社]
+はダイヤモンドスポンサーとなっており、スポンサー枠のチケットを使わせていただいた。</p>
+</div>
+<div class="paragraph">
+<p>昨年のレポートは<a href="/posts/2021-03-30/phperkaigi-2021">こちら</a>。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 感想
+
+ </h2>
+ <div class="section-body">
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 厳選おすすめトーク
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>多くの素晴らしいトークの中から、特におすすめのものを
+5つ選んだ。是非聞いてほしい。引用部分は、リンク先プロポーザルから引用している。</p>
+</div>
+<div class="paragraph">
+<p><a href="https://fortee.jp/phperkaigi-2022/proposal/ef8cf4ed-63fe-42f8-8145-b3e70054458b">予防に勝る防御なし
+- 堅牢なコードを導く様々な設計のヒント</a></p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>PHP
+はバージョンを追う毎に型宣言、例外、表明、列挙型などの機能が大幅に強化され、堅牢なコードを書くための機能が充実してきました。それらの機能はどう使うと効果的なのでしょうか。</p>
+</div>
+<div class="paragraph">
+<p>本講演では PHP 8.1
+をベースにして、誤りを想定してチェックするのではなく、そもそも誤りにくい設計とはどのようなものか、つまり「予防」の観点を軸足に、堅牢なコードを導くための様々な設計のヒントをご紹介します。</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p><a href="https://fortee.jp/phperkaigi-2022/proposal/db00d49e-0dd6-453f-b54b-f731d112f10e">PHPのエラーを理解して適切なエラーハンドリングを学ぼう</a></p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>PHPを使ってるとよく遭遇する Fatal error / Parse error / Warning / Notice
+理解していますか?<br>
+これらのエラー文を理解することで、すぐにエラーの原因に気付き適切に対象できる様になります!<br>
+またそれらを理解した上でのエラーハンドリングを学びましょう。</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p><a href="https://fortee.jp/phperkaigi-2022/proposal/4a7e3ded-9134-4919-955c-ec7bf4491c0d">エラー監視とテスト体制への改善作戦</a></p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>毎日流れてくるエラーに皆さんはどう向き合ってますか?<br>
+エラーを出さない事が一番ですが、完全に塞ぐ事は難しいと考えます。<br>
+サービス運用の中で本番環境から発生するエラー(サーバー・クライアントサイド・サードパーティ起因のエラー)への監視体制と、<br>
+エラー・バグ防御のためチームで行っているテストコード文化づくりの話をします。</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p><a href="https://fortee.jp/phperkaigi-2022/proposal/6f47daf8-c78f-4fb1-9b99-e9656e6fe7f7">ISUCON11のPHP実装は、何を考え、どのようにして作られていたのか</a></p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>昨年開催されたISUCON11にて問題(参考実装)のPHPへの移植を担当させていただきました。</p>
+</div>
+<div class="paragraph">
+<p>最終的なソースコードこそシンプルなWebアプリケーションではありますが、その裏には<br>
+・「(私の思う)良い設計」を実現するための意思決定<br>
+・「ISUCONの問題」という位置付けに由来する取捨選択<br>
+・移植中に遭遇したトラブルとその解決策<br>
+といった文脈や葛藤が存在しています。</p>
+</div>
+<div class="paragraph">
+<p>本発表はそれらを共有することで<br>
+・PHPアプリケーションの設計、実装事例として役立ててもらう<br>
+・ISUCONの言語移植に興味を持ってもらう<br>
+・ISUCON問題移植の「実装や設計の練習をする教材」としての可能性を知ってもらう<br>
+ことを目的とします。</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p><a href="https://fortee.jp/phperkaigi-2022/proposal/5a260e4e-542d-4d82-849d-ef3d6cb7c854">チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた</a></p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>サイボウズの大企業向けグループウェアのGaroon(ガルーン)は、PHPで開発されている20年目の製品です。ガルーン開発チームは日本で40名、ベトナムで50名の計90名ほどのチームになっています。また、コロナ禍でフルリモートでの活動がこの2年ほど継続してきました。</p>
+</div>
+<div class="paragraph">
+<p>フルリモートになっても仕事はまわっており、継続的にリリースはしていましたが、一方でお互いの考えていることや感じている問題意識が見えづらくなり、モヤモヤを抱えているメンバーが増えていました。</p>
+</div>
+<div class="paragraph">
+<p>このセッションでは、そういう状況で私がチーム外からジョインし、聴き役に徹しながら見える化することで状況を改善していった取り組みを紹介します。同じように大きなチームやリモートワークで難しさを感じている人に、難しさの原因への気づきや取り組みへのヒントがあれば幸いです。</p>
+</div>
+</blockquote>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ トークン問題の作成
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>今回は、PHPer チャレンジ用に弊社のトークン問題を
+3題作成した。こちらについては<a href="/posts/2022-04-09/phperkaigi-2022-tokens">別途記事にしている</a>ので、そちらを参照されたい。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ PHPer チャレンジ
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p><a href="https://fortee.jp/phperkaigi-2022/challenge">1位</a>になった。<br>
+また、賞品として <a href="https://www.amazon.co.jp/dp/B08MQNJC9Z">Echo Show 15</a>
+をいただいた。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ カンファレンス全体への感想
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p><a href="/posts/2021-03-30/phperkaigi-2021">去年の参加レポ</a>
+では、こんなことを書いた。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>1つ個人的な反省点としては、(中略) Discord
+しかりアンカンファレンスしかり「このイベントのこの瞬間にしかないコンテンツ」に触れずに、後から見返せる発表やスライドに注力してしまった、ということだ。発表の詳細な見直しはあとからできるのだから、今しかできないことを考えるべきだった。<br>
+まあ初カンファレンスだし、とお茶を濁しておこう。</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>この反省を踏まえ、今年は積極的にほかの場 (公式の Discord
+サーバや、アンカンファレンス) にも参加した。<br>
+これにより、参加体験の質がはるかに向上した。特に Discord
+に関しては、登壇者ご本人による補足や、質問への回答などがおこなわれる
+(ことが多い)
+ため、特別な理由のない限り、発言はしないまでも参加はしておいたほうが良いと思われる。</p>
+</div>
+<div class="paragraph">
+<p>なお、アンカンファレンスについては、1日目の終わりにhttps://fortee.jp/phperkaigi-2022/unconference/view/d332797a-8921-4706-a7e2-ee72640c9b5e[トークン問題の解説放送]もおこなった。</p>
+</div>
+<div class="paragraph">
+<p>また、今年はオフラインとオンラインのハイブリッド開催であったが、去年の全オンラインと比べて、オンライン参加の体験が落ちていなかったのは、特筆すべきであろう。
+今年は
+3回目のワクチン接種が間に合わなかったこともあり現地参加は見送ったのだが、来年は是非オフラインで参加したい。</p>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ そして来年へ……?
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>PHPerKaigi 2023 があるかどうか存じ上げないが、あるとすれば、次の
+4つを目標としたい。</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>プロポーザルを出す</p>
+</li>
+<li>
+<p>PHPer チャレンジのトークン問題を 5題作成する</p>
+</li>
+<li>
+<p>現地に行く</p>
+</li>
+<li>
+<p>PHPer チャレンジで圧勝する</p>
+</li>
+</ul>
+</div>
+<hr>
+<div class="paragraph">
+<p>最後になりましたが、PHPerKaigi
+のスタッフ、スポンサー、スピーカーのみなさん、素敵な時間をありがとうございました。</p>
+</div>
+<div class="paragraph">
+<p>ではまた来年。</p>
+</div>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html b/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html
new file mode 100644
index 0000000..471678a
--- /dev/null
+++ b/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html
@@ -0,0 +1,276 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。">
+ <meta name="keywords" content="カンファレンス,PHP,PHP カンファレンス">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/conference/">カンファレンス</a>
+ </li>
+
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+
+ <li class="tag">
+ <a href="/tags/phpcon/">PHP カンファレンス</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2022-08-27">2022-08-27</time>: 公開
+ </li>
+
+ </ol>
+ </section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ はじめに
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>本日 <a href="https://phpcon.okinawa.jp/">PHP カンファレンス沖縄 2022</a>
+が開催された (らしい)。</p>
+</div>
+<div class="paragraph">
+<p>カンファレンスには参加できなかったものの、懇親会の LT
+で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。</p>
+</div>
+<div class="paragraph">
+<p>ツイート: <a href="https://twitter.com/m3m0r7/status/1563397620231712772" class="bare">https://twitter.com/m3m0r7/status/1563397620231712772</a><br>
+スライド:
+<a href="https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3" class="bare">https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3</a></p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 解
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>細かいレギュレーションは不明だったので、勝手に定めた。</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>コマンドライン引数の第1引数で受けとる</p>
+</li>
+<li>
+<p>結果は標準出力に出す</p>
+</li>
+<li>
+<p>コンマの直後にはスペースを1つ置く</p>
+</li>
+<li>
+<p>末尾コンマは禁止</p>
+</li>
+<li>
+<p>数字でないものは入ってこないものとする</p>
+</li>
+<li>
+<p>負数は入ってこないものとする</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>書いたものがこちら:</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="p">[</span><span class="o">&lt;?</span><span class="n">php</span> <span class="nv">$n</span><span class="o">=</span><span class="nv">$argv</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span><span class="k">foreach</span><span class="p">([</span><span class="mi">1</span><span class="n">e4</span><span class="p">,</span><span class="mi">5</span><span class="n">e3</span><span class="p">,</span><span class="mi">2</span><span class="n">e3</span><span class="p">,</span><span class="mi">1</span><span class="n">e3</span><span class="p">,</span><span class="mi">500</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">50</span><span class="p">,</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">1</span><span class="p">]</span><span class="k">as</span><span class="nv">$x</span><span class="p">)</span><span class="k">for</span><span class="p">(;</span><span class="nv">$n</span><span class="o">&gt;=</span><span class="nv">$x</span><span class="p">;</span><span class="nv">$n</span><span class="o">-=</span><span class="nv">$x</span><span class="p">)</span><span class="nv">$r</span><span class="p">[]</span><span class="o">=</span><span class="nv">$x</span><span class="p">;</span><span class="k">echo</span> <span class="nb">implode</span><span class="p">(</span><span class="s1">', '</span><span class="p">,</span><span class="nv">$r</span><span class="o">??</span><span class="p">[]);</span><span class="cp">?&gt;</span>]</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>しめて 123 バイトとなった (末尾改行を含めずにカウント)。</p>
+</div>
+<div class="paragraph">
+<p>こちらは改行とスペースを追加したバージョン:</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="p">[</span><span class="o">&lt;?</span><span class="n">php</span>
+
+<span class="nv">$n</span> <span class="o">=</span> <span class="nv">$argv</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
+<span class="k">foreach</span> <span class="p">([</span><span class="mi">1</span><span class="n">e4</span><span class="p">,</span> <span class="mi">5</span><span class="n">e3</span><span class="p">,</span> <span class="mi">2</span><span class="n">e3</span><span class="p">,</span> <span class="mi">1</span><span class="n">e3</span><span class="p">,</span> <span class="mi">500</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">50</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> <span class="k">as</span> <span class="nv">$x</span><span class="p">)</span>
+ <span class="k">for</span> <span class="p">(;</span> <span class="nv">$n</span> <span class="o">&gt;=</span> <span class="nv">$x</span><span class="p">;</span> <span class="nv">$n</span> <span class="o">-=</span> <span class="nv">$x</span><span class="p">)</span>
+ <span class="nv">$r</span><span class="p">[]</span> <span class="o">=</span> <span class="nv">$x</span><span class="p">;</span>
+<span class="k">echo</span> <span class="nb">implode</span><span class="p">(</span><span class="s1">', '</span><span class="p">,</span> <span class="nv">$r</span> <span class="o">??</span> <span class="p">[]);</span>
+
+<span class="cp">?&gt;</span>]</code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 使用したテクニック
+
+ </h2>
+ <div class="section-body">
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 指数表記
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>割と多くの言語のゴルフで使えるテクニック。<code>e</code>
+を用いた指数表記で、大きな数を短く表す。このコードでは
+<code>10000</code>、<code>5000</code>、<code>2000</code>、<code>1000</code> を指数表記している。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ foreach や for の中身を1つの文に
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p><code>foreach</code>、<code>for</code>、<code>if</code> などの後ろには、通常 <code>{</code>
+を続けて複数の文を連ねるが、中身の文を1つにしてしまえば、<code>{</code> と <code>}</code>
+を省略できる。C言語などでも使える。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ $r に初期値を入れない
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>PHP では、<code>$r[] = &#8230;&#8203;</code>
+のような配列の末尾に追加する式を実行したとき、<code>$r</code> が未定義だった場合は
+<code>$r</code>
+を勝手に定義して空の配列で初期化してくれる。これを利用すると、<code>$r = [];</code>
+のような初期化が不要になる。</p>
+</div>
+<div class="paragraph">
+<p>ただし、プログラムに 0 が渡されるとループを一度も回らないので、<code>$r</code>
+が未定義になってしまい、<code>implode()</code>
+に渡すところでエラーになる。それを防ぐために <code>$r ?? []</code> を使っている。</p>
+</div>
+<div class="paragraph">
+<p>もし 0 が渡されたケースを無視するなら、これが不要になるので 4
+バイト縮む。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ PHP タグの外に文字列を置く
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>PHP では、<code>&lt;?php</code> <code>?&gt;</code>
+で囲われた部分の外側にある文字列は、そのまま出力される。今回のケースでは、先頭と末尾に必ず
+<code>[</code> と <code>]</code> を出力するので、そのまま書いてやればよい。</p>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ おわりに
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>最後になりましたが、https://twitter.com/m3m0r7[めもりー]
+さん、楽しい問題をありがとうございました。</p>
+</div>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html b/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html
new file mode 100644
index 0000000..e452599
--- /dev/null
+++ b/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html
@@ -0,0 +1,140 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="先日、私の勤めるデジタルサーカス株式会社が、PHP Foundation へ寄付をおこないました。 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。">
+ <meta name="keywords" content="">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>弊社の PHP Foundation への寄付に寄せて | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">弊社の PHP Foundation への寄付に寄せて</h1>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2022-08-31">2022-08-31</time>: 公開
+ </li>
+
+ </ol>
+ </section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ はじめに
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p><strong>注:
+これは私個人の意見であり、所属する組織を代表するものではありません。</strong></p>
+</div>
+<div class="paragraph">
+<p>先日、私の勤める <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a> が
+<a href="https://opencollective.com/phpfoundation">PHP Foundation</a> へ $2,000
+の寄付をおこないました。</p>
+</div>
+<div class="paragraph">
+<p>記事: <a href="https://www.dgcircus.com/news/581" class="bare">https://www.dgcircus.com/news/581</a></p>
+</div>
+<div class="paragraph">
+<p>本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ なぜ?
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>組織としての寄付理由は前掲した記事に譲るとして、ここでは、私が社内でこの件を推進した理由について書くことにします。</p>
+</div>
+<div class="paragraph">
+<p>当時の考えを端的にまとめた社内チャットの投稿があったので、それを引用します:</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="paragraph">
+<p>結局これを通したい (私の中での)
+最大の理由が、「自分の勤める会社が、これをやる会社であってほしい」というのがあり、↑にしても、感情ベースの理由しか出せていないというのが説得力に欠けている理由なのだと思いますが、寄付の報告が流れてきたり、OSS
+のフリーライドの話が流れてきたりするたびに、自尊心が毀損される、というか
+(これは大袈裟すぎる表現で、実際にはそこまで明確に傷ついているわけではありませんが)。</p>
+</div>
+<div class="paragraph">
+<p>追記: 「肩身が狭くなる」というのがより適切でした。</p>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>※文中の「↑にしても」は、ここに載せていない別の投稿を指しています。</p>
+</div>
+<div class="paragraph">
+<p>OSS を金銭的に支援したり、技術カンファレンスへ協賛したり (あるいは
+<a href="https://twitter.com/tomzoh">CTO</a> がカンファレンスを年2で主催したり:
+<a href="https://iosdc.jp">iOSDC</a> <a href="https://phperkaigi.jp">PHPerKaigi</a>)
+といった行為は、コミュニティへの貢献であると同時に、社員に対する精神的福利厚生でもあると言えるでしょう
+(知らんけど)。これらは、技術や技術者を大切にする組織である、ということの、対外的にも対内的にも強力なメッセージなのです。</p>
+</div>
+<div class="paragraph">
+<p>以上が、私が社内で寄付の件を進めた (かなり私的な) 理由です。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ おわりに
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>最終的に社としての寄付まで漕ぎ着けられたのは、もちろん私の力ではなく役員の方々の決定によるものです。この場を借りて感謝申し上げます。</p>
+</div>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html
new file mode 100644
index 0000000..c2dc8ab
--- /dev/null
+++ b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html
@@ -0,0 +1,929 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。">
+ <meta name="keywords" content="PHP">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【PHP】fizzbuzz を書く。1行あたり2文字で。 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【PHP】fizzbuzz を書く。1行あたり2文字で。</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2022-09-28">2022-09-28</time>: 公開
+ </li>
+
+ <li class="revision">
+ <time datetime="2022-09-29">2022-09-29</time>: 小さな文言の修正・変更
+ </li>
+
+ </ol>
+ </section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 記事の構成について
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>この記事は、普通の fizzbuzz
+を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、
+<a href="https://gist.github.com/nsfisis/04c227d5a419867472a0b23a83ad2919#file-fizzbuzz-php-2-letters-per-line-and-supports-php-8-x-without-warnings">このページ</a>
+にソースコードがあるので、そちらを先に見てほしい。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ レギュレーション
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>PHP で、次のような制約の下に fizzbuzz を書いた。</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p>1行あたりの文字数は2文字までに収めること (ただし <code>&lt;?php</code> タグは除く)</p>
+<div class="ulist">
+<ul>
+<li>
+<p>厳密な定義: <code>&lt;?php</code> タグ以降のソースコードが、2 byte ごとに
+ラインフィード (LF) で区切られること</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>スペースやタブを使用しないこと</p>
+</li>
+<li>
+<p>ループのアンロールをしないこと</p>
+<div class="ulist">
+<ul>
+<li>
+<p>100 回ループの代わりに 100 回コードをコピペ、というのは禁止</p>
+</li>
+</ul>
+</div>
+</li>
+<li>
+<p>PHP 7.4〜8.1 で動作すること</p>
+</li>
+<li>
+<p>実行時に Notice や Warning が出ないこと</p>
+</li>
+<li>
+<p>標準的なインストール構成の PHP で実現できること
+(デフォルトで有効になっていない拡張等を使わないこと)</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>備考: PHP には <code>short_open_tag</code>
+というオプションがあり、これを有効にするとファイル冒頭の <code>&lt;?php</code>
+の代わりに <code>&lt;?</code>
+を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト
+off になっている環境が多いようなので、今回は使わないことにした。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 主な障害
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>1行あたりの文字数など、適当に改行を挟めばいいだけではないのか?</p>
+</div>
+<div class="paragraph">
+<p>特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="c"><span class="cp">#\
+i\
+n\
+c\
+l\
+u\
+d\
+e\
+&lt;\
+s\
+t\
+d\
+i\
+o\
+.\
+h\
+&gt;\
+</span><span class="cm">/*
+*/</span><span class="cp">
+</span><span class="n">i</span>\
+<span class="n">n</span>\
+<span class="n">t</span>\
+<span class="cm">/*
+*/</span>
+<span class="n">m</span>\
+<span class="n">a</span>\
+<span class="n">i</span>\
+<span class="n">n</span><span class="p">(</span>
+<span class="p">){</span>
+<span class="n">f</span>\
+<span class="n">o</span>\
+<span class="n">r</span><span class="p">(</span>
+<span class="n">i</span>\
+<span class="n">n</span>\
+<span class="n">t</span>\
+<span class="cm">/*
+*/</span>
+<span class="n">i</span><span class="o">=</span>
+<span class="mi">1</span><span class="p">;</span>
+<span class="n">i</span><span class="o">&lt;</span>
+<span class="mi">1</span>\
+<span class="mi">0</span>\
+<span class="mi">0</span><span class="p">;</span>
+<span class="n">i</span>\
+<span class="o">+</span>\
+<span class="o">+</span><span class="p">)</span>
+<span class="k">if</span>
+<span class="p">(</span><span class="n">i</span>
+<span class="o">%</span>\
+<span class="mi">15</span>
+<span class="o">==</span>
+<span class="mi">0</span><span class="p">)</span>
+<span class="n">p</span>\
+<span class="n">r</span>\
+<span class="n">i</span>\
+<span class="n">n</span>\
+<span class="n">t</span>\
+<span class="n">f</span><span class="p">(</span>
+<span class="s">"\
+F\
+i\
+z\
+z\
+B\
+u\
+z\
+z\
+%\
+c\
+"</span><span class="p">,</span>
+<span class="mi">10</span>
+<span class="p">);</span>
+
+<span class="cm">/* あとは同じように普通のプログラムを変形するだけなので省略 */</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。</p>
+</div>
+<div class="paragraph">
+<p>さて、PHP
+ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、<code>echo</code>
+で出力することや、<code>for</code> でループすること、<code>new</code>
+でインスタンスを生成することができない。特に、出力は fizzbuzz
+をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。</p>
+</div>
+<div class="paragraph">
+<p>当然、名前が3文字以上ある関数も使えない。なお、標準 PHP
+の範囲内において、名前が 2文字以下の関数は以下のとおりである:</p>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><code>_</code>: <code>gettext</code> のエイリアス</p>
+</li>
+<li>
+<p><code>dl</code>: 拡張モジュールをロードする</p>
+</li>
+<li>
+<p><code>pi</code>: 円周率を返す</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>(環境によって多少は変わるかも)</p>
+</div>
+<div class="paragraph">
+<p>2文字の関数を定義しまくった拡張モジュールを用意しておいて <code>dl()</code>
+で読み込む行為は、レギュレーションで定めた</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="ulist">
+<ul>
+<li>
+<p>標準的なインストール構成の PHP で実現できること
+(デフォルトで有効になっていない拡張等を使わないこと)</p>
+</li>
+</ul>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>に反する
+(というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。</p>
+</div>
+<div class="paragraph">
+<p>また、2文字だと文字列がまともに書けないのも辛い。<code>''</code> だけで
+2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP
+では文字列リテラル中に生の改行が書けるので</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nv">$a</span>
+<span class="o">=</span><span class="s1">'
+a'</span>
+<span class="p">;;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>とすると <code>$a</code> は <code>"\na"</code> になるのだが、余計な改行が入ってしまう。</p>
+</div>
+<div class="paragraph">
+<p>これらの障害をどのように乗り越えるのか、次節から見ていく。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 解説
+
+ </h2>
+ <div class="section-body">
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 普通の (?) fizzbuzz
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>まずは普通に書くとしよう。</p>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre>&lt;?php
+
+for ($i = 1; $i &lt; 100; $i++) {
+ echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n";
+}</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>素直に書いた fizzbuzz
+とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ <code>for</code> の排除
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p><code>for</code>
+は、3文字もある長いキーワードである。こんなものは使えない。<code>array_</code>
+系の関数を使って、適当に置き換えるとしよう。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="o">&lt;?</span><span class="n">php</span>
+
+<span class="nv">$s</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">);</span>
+<span class="nb">array_walk</span><span class="p">(</span>
+ <span class="nv">$s</span><span class="p">,</span>
+ <span class="k">fn</span><span class="p">(</span><span class="nv">$i</span><span class="p">)</span> <span class="o">=&gt;</span>
+ <span class="nb">printf</span><span class="p">(((</span><span class="nv">$i</span> <span class="o">%</span> <span class="mi">3</span> <span class="o">?</span> <span class="s1">''</span> <span class="o">:</span> <span class="s1">'Fizz'</span><span class="p">)</span> <span class="mf">.</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">%</span> <span class="mi">5</span> <span class="o">?</span> <span class="s1">''</span> <span class="o">:</span> <span class="s1">'Buzz'</span><span class="p">)</span> <span class="o">?:</span> <span class="nv">$i</span><span class="p">)</span> <span class="mf">.</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">),</span>
+<span class="p">);</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><code>array_walk</code> や <code>range</code>、<code>printf</code> といった <code>for</code>
+よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、<code>echo</code>
+は文 (statement) であり式 (expression) ではないので、式である <code>printf</code>
+に置き換えた。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 関数呼び出しの短縮
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p><code>range</code>、<code>array_walk</code>、<code>printf</code>
+は長すぎるのでどうにかせねばならない。ここで、PHP
+の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="o">&lt;?</span><span class="n">php</span>
+
+<span class="nv">$r</span> <span class="o">=</span> <span class="s1">'range'</span><span class="p">;</span>
+<span class="nv">$w</span> <span class="o">=</span> <span class="s1">'array_walk'</span><span class="p">;</span>
+<span class="nv">$p</span> <span class="o">=</span> <span class="s1">'printf'</span><span class="p">;</span>
+
+<span class="nv">$s</span> <span class="o">=</span> <span class="nv">$r</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">);</span>
+<span class="nv">$w</span><span class="p">(</span>
+ <span class="nv">$s</span><span class="p">,</span>
+ <span class="k">fn</span><span class="p">(</span><span class="nv">$i</span><span class="p">)</span> <span class="o">=&gt;</span>
+ <span class="nv">$p</span><span class="p">(((</span><span class="nv">$i</span> <span class="o">%</span> <span class="mi">3</span> <span class="o">?</span> <span class="s1">''</span> <span class="o">:</span> <span class="s1">'Fizz'</span><span class="p">)</span> <span class="mf">.</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">%</span> <span class="mi">5</span> <span class="o">?</span> <span class="s1">''</span> <span class="o">:</span> <span class="s1">'Buzz'</span><span class="p">)</span> <span class="o">?:</span> <span class="nv">$i</span><span class="p">)</span> <span class="mf">.</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">),</span>
+<span class="p">);</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>これで関数を呼び出している所は短くなった。では、<code>$r</code> や <code>$w</code> や
+<code>$p</code>、また <code>'Fizz'</code> や <code>'Buzz'</code> はどうやって
+1行2文字に収めるのか。次のテクニックへ移ろう。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 余談: PHP 8.x で動作しなくてもいいなら
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="ulist">
+<ul>
+<li>
+<p>PHP 7.4〜8.1 で動作すること</p>
+</li>
+</ul>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という
+PHP 7.x までの仕様が利用できる。例えば、 <code>Fizz</code>
+という文字列が欲しければ、次のようにする。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nv">$f</span>
+<span class="o">=</span><span class="nc">F</span>
+<span class="mf">.</span><span class="n">i</span>
+<span class="mf">.</span><span class="n">z</span>
+<span class="mf">.</span><span class="n">z</span>
+<span class="p">;;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>こうして簡単に文字列を作れる。なお、この仕様は 7.x
+時点でも警告を受けるので、<code>@</code> 演算子を使って抑制してやるとよい。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nv">$f</span>
+<span class="o">=@</span>
+<span class="nc">F</span><span class="mf">.</span>
+<span class="o">@</span><span class="n">i</span>
+<span class="mf">.</span><span class="c1">#</span>
+<span class="o">@</span><span class="n">z</span>
+<span class="mf">.</span><span class="c1">#</span>
+<span class="o">@</span><span class="n">z</span>
+<span class="p">;;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>むしろ、このことがわかっていたからこそ PHP 8.x
+での動作を要件に課したところがある。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 文字列リテラルの短縮
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>実際に使った手法の説明に移る。</p>
+</div>
+<div class="paragraph">
+<p>ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算
+(<code>&amp;</code>、<code>|</code>、<code>^</code>)
+をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nv">$a</span> <span class="o">=</span> <span class="s2">"12345"</span><span class="p">;</span>
+<span class="nv">$b</span> <span class="o">=</span> <span class="s2">"world"</span><span class="p">;</span>
+
+<span class="c1">// $a ^ $b は次のコードと同じ</span>
+<span class="nv">$result</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span>
+<span class="k">for</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nv">$i</span> <span class="o">&lt;</span> <span class="nb">min</span><span class="p">(</span><span class="nb">strlen</span><span class="p">(</span><span class="nv">$a</span><span class="p">),</span> <span class="nb">strlen</span><span class="p">(</span><span class="nv">$b</span><span class="p">));</span> <span class="nv">$i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
+ <span class="nv">$result</span> <span class="mf">.</span><span class="o">=</span> <span class="nv">$a</span><span class="p">[</span><span class="nv">$i</span><span class="p">]</span> <span class="o">^</span> <span class="nv">$b</span><span class="p">[</span><span class="nv">$i</span><span class="p">];</span>
+<span class="p">}</span>
+
+<span class="k">echo</span> <span class="nv">$result</span><span class="p">;</span>
+<span class="c1">// =&gt; F]AXQ</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>これを踏まえ、次のコードを見てみよう。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nv">$x</span> <span class="o">=</span> <span class="s2">"x</span><span class="se">\n</span><span class="s2">Om</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span>
+<span class="nv">$y</span> <span class="o">=</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">k!</span><span class="se">\n</span><span class="s2">o"</span><span class="p">;</span>
+<span class="nv">$r</span> <span class="o">=</span> <span class="nv">$x</span> <span class="o">^</span> <span class="nv">$y</span><span class="p">;</span>
+<span class="k">echo</span> <span class="s2">"</span><span class="nv">$r</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>実行すると、<code>range</code> が表示される。さて、PHP
+では文字列リテラル中に生の改行を直接書いてもよいのだった
+(「主な障害」の節を参照のこと)。書きかえてみよう。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nv">$x</span>
+<span class="o">=</span><span class="s1">'x
+Om
+'</span><span class="p">;</span>
+<span class="nv">$y</span>
+<span class="o">=</span><span class="s1">'
+k!
+o'</span>
+<span class="p">;</span>
+
+<span class="nv">$r</span> <span class="o">=</span> <span class="nv">$x</span> <span class="o">^</span> <span class="nv">$y</span><span class="p">;</span>
+<span class="k">echo</span> <span class="s2">"</span><span class="nv">$r</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>さらに <code>#</code> を使って適当に調整すると、次のようになる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nv">$x</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="s1">'x
+Om
+'</span><span class="p">;</span>
+<span class="nv">$y</span>
+<span class="o">=</span><span class="s1">'
+k!
+o'</span>
+<span class="p">;</span><span class="c1">#</span>
+<span class="nv">$r</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="nv">$x</span>
+<span class="o">^</span><span class="c1">#</span>
+<span class="nv">$y</span>
+<span class="p">;</span><span class="c1">#</span>
+
+<span class="k">echo</span> <span class="s2">"</span><span class="nv">$r</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>1行あたり2文字で、<code>range</code>
+という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。</p>
+</div>
+<div class="paragraph">
+<p>備考: <code>Buzz</code> 中にある小文字の <code>u</code> は、このロジックだと non-printable
+な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。</p>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 完成系
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>完成したものがこちら。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="o">&lt;?</span><span class="n">php</span>
+
+<span class="nv">$x</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="s1">'i
+S'</span>
+<span class="p">;;</span>
+<span class="nv">$y</span>
+<span class="o">=</span><span class="s1">'
+b!
+'</span><span class="p">;</span>
+<span class="nv">$c</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="nv">$x</span>
+<span class="o">^</span><span class="c1">#</span>
+<span class="nv">$y</span>
+<span class="p">;</span><span class="c1">#</span>
+<span class="nv">$x</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="s1">'x
+Om
+'</span><span class="p">;</span>
+<span class="nv">$y</span>
+<span class="o">=</span><span class="s1">'
+k!
+o'</span>
+<span class="p">;</span><span class="c1">#</span>
+<span class="nv">$r</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="nv">$x</span>
+<span class="o">^</span><span class="c1">#</span>
+<span class="nv">$y</span>
+<span class="p">;</span><span class="c1">#</span>
+<span class="nv">$x</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="s1">'k
+Sk
+~}
+Ma
+'</span><span class="p">;</span>
+<span class="nv">$y</span>
+<span class="o">=</span><span class="s1">'
+x!
+s!
+k!
+'</span><span class="p">;</span>
+<span class="nv">$w</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="nv">$x</span>
+<span class="o">^</span><span class="c1">#</span>
+<span class="nv">$y</span>
+<span class="p">;</span><span class="c1">#</span>
+<span class="nv">$x</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="s1">'z
+Hd
+G'</span>
+<span class="p">;</span><span class="c1">#</span>
+<span class="nv">$y</span>
+<span class="o">=</span><span class="s1">'
+x!
+~!
+'</span><span class="p">;</span>
+<span class="nv">$p</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="nv">$x</span>
+<span class="o">^</span><span class="c1">#</span>
+<span class="nv">$y</span>
+<span class="p">;</span><span class="c1">#</span>
+<span class="nv">$x</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="s1">'L
+[p
+'</span><span class="p">;</span>
+<span class="nv">$y</span>
+<span class="o">=</span><span class="s1">'
+c!
+'</span><span class="p">;</span>
+<span class="nv">$f</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="nv">$x</span>
+<span class="o">^</span><span class="c1">#</span>
+<span class="nv">$y</span>
+<span class="p">;</span><span class="c1">#</span>
+<span class="nv">$x</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="s1">'H
+[p
+'</span><span class="p">;</span>
+<span class="nv">$y</span>
+<span class="o">=</span><span class="s1">'
+_!
+'</span><span class="p">;</span>
+<span class="nv">$b</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="nv">$x</span>
+<span class="o">^</span><span class="c1">#</span>
+<span class="nv">$y</span>
+<span class="p">;</span><span class="c1">#</span>
+<span class="nv">$b</span>
+<span class="p">[</span><span class="mi">1</span>
+<span class="p">]</span><span class="o">=</span>
+<span class="nv">$c</span>
+<span class="p">(</span><span class="c1">#</span>
+<span class="mi">13</span>
+<span class="o">*</span><span class="mi">9</span>
+<span class="p">);</span>
+<span class="nv">$s</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="nv">$r</span>
+<span class="p">(</span><span class="mi">1</span>
+<span class="p">,(</span>
+<span class="mi">10</span>
+<span class="o">**</span>
+<span class="mi">2</span><span class="p">)</span>
+<span class="p">);</span>
+<span class="nv">$w</span>
+<span class="p">(</span><span class="c1">#</span>
+<span class="nv">$s</span>
+<span class="p">,</span><span class="c1">#</span>
+<span class="k">fn</span>
+<span class="p">(</span><span class="c1">#</span>
+<span class="nv">$i</span>
+<span class="p">)</span><span class="c1">#</span>
+<span class="o">=&gt;</span>
+<span class="nv">$p</span>
+<span class="p">((</span>
+<span class="p">(</span><span class="c1">#</span>
+<span class="nv">$i</span>
+<span class="o">%</span><span class="mi">3</span>
+<span class="o">?</span><span class="c1">#</span>
+<span class="s1">''</span>
+<span class="o">:</span><span class="c1">#</span>
+<span class="nv">$f</span>
+<span class="p">)</span><span class="mf">.</span>
+<span class="p">(</span><span class="c1">#</span>
+<span class="nv">$i</span>
+<span class="o">%</span><span class="mi">5</span>
+<span class="o">?</span><span class="c1">#</span>
+<span class="s1">''</span>
+<span class="o">:</span><span class="c1">#</span>
+<span class="nv">$b</span>
+<span class="p">)</span><span class="o">?</span>
+<span class="o">:</span><span class="c1">#</span>
+<span class="nv">$i</span>
+<span class="p">)</span><span class="c1">#</span>
+<span class="mf">.</span><span class="s1">'
+'</span><span class="p">)</span>
+<span class="p">);</span></code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 感想など
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>PHP は、スクリプト言語の中だとシンタックスシュガーが少ない
+(体感)。この挑戦は不可能に思われたが、PHP
+マニュアルとにらめっこしていたらなんとかなった。</p>
+</div>
+<div class="paragraph">
+<p>みんなもプログラムを細長くしよう。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 余談2: 別解
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>PHP では、バッククォートを使ってシェルを呼び出せる。これは <code>shell_exec</code>
+関数と等価である。さて、PHP
+ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える
+(当然だが、呼び出されるシェルに依存する。Bash
+なら大丈夫だろう。知らんけど)。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="o">&lt;?</span><span class="n">php</span>
+
+<span class="nb">printf</span><span class="p">(</span><span class="err">`</span>
+<span class="n">e</span><span class="err">\</span>
+<span class="n">c</span><span class="err">\</span>
+<span class="n">h</span><span class="err">\</span>
+<span class="n">o</span><span class="err">\</span>
+ <span class="err">\</span>
+<span class="mi">1</span><span class="err">\</span>
+<span class="mi">2</span><span class="err">\</span>
+<span class="mi">3</span><span class="err">\</span>
+<span class="err">`</span><span class="p">);</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>なお、ここでは簡単のため出力に <code>printf</code> をそのまま使っているが、実際には
+<code>printf</code> という文字列を合成して可変関数で呼び出す。</p>
+</div>
+<div class="paragraph">
+<p>ただし、これでは</p>
+</div>
+<div class="quoteblock">
+<blockquote>
+<div class="ulist">
+<ul>
+<li>
+<p>スペースやタブを使用しないこと</p>
+</li>
+</ul>
+</div>
+</blockquote>
+</div>
+<div class="paragraph">
+<p>に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。</p>
+</div>
+<div class="paragraph">
+<p>もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="o">&lt;?</span><span class="n">php</span>
+
+<span class="nv">$c</span> <span class="o">=</span> <span class="s1">'chr'</span><span class="p">;</span>
+
+<span class="err">$</span><span class="p">{</span>
+<span class="s1">'_
+'</span><span class="p">}</span>
+<span class="o">=</span><span class="c1">#</span>
+<span class="nv">$c</span>
+<span class="p">(</span><span class="c1">#</span>
+<span class="mi">32</span>
+<span class="p">)</span><span class="mf">.</span>
+<span class="nv">$c</span>
+<span class="p">(</span><span class="c1">#</span>
+<span class="mi">92</span>
+<span class="p">);</span>
+
+<span class="nb">printf</span><span class="p">(</span><span class="err">`</span>
+<span class="n">e</span><span class="err">\</span>
+<span class="n">c</span><span class="err">\</span>
+<span class="n">h</span><span class="err">\</span>
+<span class="n">o</span><span class="err">\</span>
+<span class="err">$</span><span class="p">{</span>
+<span class="s1">'_
+'</span><span class="p">}</span>
+<span class="mi">1</span><span class="err">\</span>
+<span class="mi">2</span><span class="err">\</span>
+<span class="mi">3</span><span class="err">\</span>
+<span class="err">`</span><span class="p">);</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>先程と同じく、<code>chr</code> や <code>printf</code> を生成する部分は長くなるので省いた。</p>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre>${
+'_
+'}</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>は変数で、中にはスペースとエスケープが入っている
+(<code>chr(32) . chr(92)</code>)。シェルに渡されている文字列は次のようになる。</p>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre>e\
+c\
+h\
+o\
+ \
+1\
+2\
+3\</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz
+のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう
+(試してないけど)。</p>
+</div>
+<div class="paragraph">
+<p>ということでこれは別解ということにしておく。</p>
+</div>
+<div class="paragraph">
+<p>ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。</p>
+</div>
+<div class="literalblock">
+<div class="content">
+<pre>${
+'_
+'}</pre>
+</div>
+</div>
+<div class="paragraph">
+<p>最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。</p>
+</div>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html b/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html
new file mode 100644
index 0000000..efb7239
--- /dev/null
+++ b/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html
@@ -0,0 +1,291 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、 ボツになった問題を公開する (その 1)。">
+ <meta name="keywords" content="PHP,PHPerKaigi">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHPerKaigi 2023: ボツになったトークン問題 その 1 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">PHPerKaigi 2023: ボツになったトークン問題 その 1</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/php/">PHP</a>
+ </li>
+
+ <li class="tag">
+ <a href="/tags/phperkaigi/">PHPerKaigi</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2022-10-23">2022-10-23</time>: 公開
+ </li>
+
+ </ol>
+ </section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ はじめに
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>2023 年 3 月 23 日から 25 日にかけて開催予定 (記事執筆時点)
+の、 <a href="https://phperkaigi.jp/2023/">PHPerKaigi 2023</a>
+において、昨年と同様に、弊社 <a href="https://www.dgcircus.com/">デジタルサーカス株式会社</a>
+から、トークン問題を出題予定である。</p>
+</div>
+<div class="paragraph">
+<p>昨年のトークン問題の記事はこちら:
+<a href="/posts/2022-04-09/phperkaigi-2022-tokens">PHPerKaigi 2022
+トークン問題の解説</a></p>
+</div>
+<div class="paragraph">
+<p>すでに 2023
+年用の問題は作成済みであるが、その制作過程の中でいくつかボツ問ができた。せっかくなので、PHPerKaigi
+開催を待つ間に紹介しようと思う。</p>
+</div>
+<div class="paragraph">
+<p>10 月から 2 月まで、毎月 1 記事ずつ公開していく予定 (忘れていなければ)。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 問題
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>注意: これはボツ問なので、得られたトークンを PHPerKaigi
+で入力してもポイントにはならない。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="o">&lt;?</span><span class="n">php</span>
+
+<span class="nv">$π</span> <span class="o">=</span> <span class="nv">$argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">??</span> <span class="kc">null</span><span class="p">;</span>
+<span class="k">if</span> <span class="p">(</span><span class="nv">$π</span> <span class="o">===</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">exit</span><span class="p">(</span><span class="s1">'No input.'</span><span class="p">);</span>
+<span class="p">}</span>
+<span class="nv">$π</span> <span class="o">=</span> <span class="nb">trim</span><span class="p">(</span><span class="nv">$π</span><span class="p">);</span>
+<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">is_numeric</span><span class="p">(</span><span class="nv">$π</span><span class="p">))</span> <span class="p">{</span>
+ <span class="k">exit</span><span class="p">(</span><span class="s1">'Invalid input.'</span><span class="p">);</span>
+<span class="p">}</span>
+
+<span class="nv">$s</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="nb">array_map</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="mf">...</span><span class="p">),</span> <span class="nb">str_split</span><span class="p">(</span><span class="nv">$π</span><span class="p">,</span> <span class="mi">2</span><span class="p">)));</span>
+
+<span class="nb">preg_match</span><span class="p">(</span><span class="s1">'/(\x23.+?) /'</span><span class="p">,</span> <span class="nv">$s</span><span class="p">,</span> <span class="nv">$m</span><span class="p">);</span>
+<span class="nv">$t</span> <span class="o">=</span> <span class="nv">$m</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">;</span>
+
+<span class="k">if</span> <span class="p">(</span><span class="nb">md5</span><span class="p">(</span><span class="nv">$t</span><span class="p">)</span> <span class="o">===</span> <span class="s1">'056e831a4146bf123e8ea16613303d2e'</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">echo</span> <span class="s2">"Token: </span><span class="si">{</span><span class="nv">$t</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span>
+<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
+ <span class="k">echo</span> <span class="s2">"Failed.</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span>
+<span class="p">}</span></code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ トークン入手方法
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>ソースを見るとわかるとおり、<code>$argv[1]</code> を参照している。それを <code>$π</code>
+なる変数に代入しているので、円周率を渡してみる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>php Q.php 3.14
+<span class="go">Failed.</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>失敗してしまった。精度を上げてみる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>php Q.php 3.1415
+<span class="go">Failed.</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>だめだった。これを成功するまで繰り返す。</p>
+</div>
+<div class="paragraph">
+<p>最初にトークンが得られるのは、小数点以下 16
+桁目まで入力したときで、こうなる。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>php Q.php 3.1415926535897932
+<span class="gp">Token: #</span>YO</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>めでたくトークン「#YO」が手に入った。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 解説
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>短いので頭から追っていく。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nv">$π</span> <span class="o">=</span> <span class="nv">$argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">??</span> <span class="kc">null</span><span class="p">;</span>
+<span class="k">if</span> <span class="p">(</span><span class="nv">$π</span> <span class="o">===</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">exit</span><span class="p">(</span><span class="s1">'No input.'</span><span class="p">);</span>
+<span class="p">}</span>
+<span class="nv">$π</span> <span class="o">=</span> <span class="nb">trim</span><span class="p">(</span><span class="nv">$π</span><span class="p">);</span>
+<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">is_numeric</span><span class="p">(</span><span class="nv">$π</span><span class="p">))</span> <span class="p">{</span>
+ <span class="k">exit</span><span class="p">(</span><span class="s1">'Invalid input.'</span><span class="p">);</span>
+<span class="p">}</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>入力のバリデーション部分。数値のみ受け付ける。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nv">$s</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="nb">array_map</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="mf">...</span><span class="p">),</span> <span class="nb">str_split</span><span class="p">(</span><span class="nv">$π</span><span class="p">,</span> <span class="mi">2</span><span class="p">)));</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><code>$π</code> を 2 文字ごとに区切り (<code>str_split</code>)、数値を ASCII
+コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。</p>
+</div>
+<div class="paragraph">
+<p>例えば、<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>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nv">$π</span> <span class="o">=</span> <span class="s1">'656667'</span><span class="p">;</span>
+<span class="nv">$s</span> <span class="o">=</span> <span class="nb">implode</span><span class="p">(</span><span class="nb">array_map</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="mf">...</span><span class="p">),</span> <span class="nb">str_split</span><span class="p">(</span><span class="nv">$π</span><span class="p">,</span> <span class="mi">2</span><span class="p">)));</span>
+<span class="k">echo</span> <span class="nv">$s</span><span class="p">;</span>
+<span class="c1">// =&gt; ABC</span></code></pre>
+</div>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="nb">preg_match</span><span class="p">(</span><span class="s1">'/(\x23.+?) /'</span><span class="p">,</span> <span class="nv">$s</span><span class="p">,</span> <span class="nv">$m</span><span class="p">);</span>
+<span class="nv">$t</span> <span class="o">=</span> <span class="nv">$m</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">;</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>正規表現でマッチングしている。<code>\x23</code> は <code>#</code>
+と同じであることに留意すると、この正規表現は「<code>#</code> から始まる 2
+以上の長さ (含 <code>#</code>)
+の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi
+におけるトークンである。</p>
+</div>
+<div class="paragraph">
+<p>なお、<code>#</code> を直接書いていないのは、<code>/#.+?) /</code> と書くと、<code>#.+?)</code>
+という意図せぬトークンが登録されてしまうからである。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="php"><span class="k">if</span> <span class="p">(</span><span class="nb">md5</span><span class="p">(</span><span class="nv">$t</span><span class="p">)</span> <span class="o">===</span> <span class="s1">'056e831a4146bf123e8ea16613303d2e'</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">echo</span> <span class="s2">"Token: </span><span class="si">{</span><span class="nv">$t</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span>
+<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
+ <span class="k">echo</span> <span class="s2">"Failed.</span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span>
+<span class="p">}</span></code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>最後にトークンのハッシュ値を見て、想定解かどうかを確認する。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ おわりに
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>円周率を何桁も計算して ASCII
+コード経由で文字列化すれば、トークンっぽいものがどこかで出てくるのではないか、と考えて生まれた作品。</p>
+</div>
+<div class="paragraph">
+<p>最初は真面目に円周率の計算プログラムを組んでいたのだが、いざ動かしてみるとやけに浅いところにあったので驚いた
+(ちなみに、それでも <code>M_PI</code> や <code>pi()</code>
+では精度が足りない)。見つけたときは狂喜したものの、冷静になってみると大して面白くなかったのでボツになった。むしろ、100
+万桁目くらいに埋まっていてくれたほうがよかったかもしれない。</p>
+</div>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/2022-10-28/setup-server-for-this-site/index.html b/public/posts/2022-10-28/setup-server-for-this-site/index.html
new file mode 100644
index 0000000..c070c03
--- /dev/null
+++ b/public/posts/2022-10-28/setup-server-for-this-site/index.html
@@ -0,0 +1,630 @@
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; nsfisis">
+ <meta name="description" content="GitHub Pages でホストしていたこのサイトを VPS へ移行したので、 そのときにやったことのメモ。99 % 自分用。">
+ <meta name="keywords" content="備忘録">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>【備忘録】このサイト用の VPS をセットアップしたときのメモ | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title">【備忘録】このサイト用の VPS をセットアップしたときのメモ</h1>
+
+ <ul class="post-tags">
+
+ <li class="tag">
+ <a href="/tags/note-to-self/">備忘録</a>
+ </li>
+
+ </ul>
+
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+
+ <li class="revision">
+ <time datetime="2022-10-28">2022-10-28</time>: 公開
+ </li>
+
+ </ol>
+ </section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ はじめに
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>これまでこの blog は GitHub Pages でホストしていたのだが、先日 VPS
+に移行した。そのときにおこなったサーバのセットアップ作業を書き残しておく。99
+% 自分用の備忘録。別のベンダに移したりしたくなったら見に来る。</p>
+</div>
+<div class="paragraph">
+<p>未来の自分へ: 特に自動化してないので、せいぜい苦しんでくれ。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ VPS
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p><a href="https://vps.sakura.ad.jp/">さくらの VPS</a> の 2 GB
+プラン。そこまで真面目に選定していないので、困ったら移動するかも。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 事前準備
+
+ </h2>
+ <div class="section-body">
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ サーバのホスト名を決める
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>モチベーションが上がるという効能がある。今回は藤原定家から取って
+``teika''
+にした。たいていいつも源氏物語の帖か小倉百人一首の歌人から選んでいる。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ SSH の鍵生成
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>ローカルマシンで鍵を生成する。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-b</span> 521 <span class="nt">-f</span> ~/.ssh/teika.key
+<span class="gp">$</span><span class="w"> </span>ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-b</span> 521 <span class="nt">-f</span> ~/.ssh/github2teika.key</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><code>teika.key</code> はローカルからサーバへの接続用、<code>github2teika.key</code>
+は、GitHub Actions からサーバへのデプロイ用。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ SSH の設定
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p><code>.ssh/config</code> に設定しておく。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="ssh_config">Host teika
+ HostName **********
+ User **********
+ Port **********
+ IdentityFile ~/.ssh/teika.key</code></pre>
+</div>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 基本のセットアップ
+
+ </h2>
+ <div class="section-body">
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ SSH 接続
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>VPS 契約時に設定した管理者ユーザとパスワードを使ってログインする。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ ユーザを作成する
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。<code>sudo</code>
+グループに追加して <code>sudo</code> できるようにし、<code>su</code> で切り替え。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>adduser <span class="k">**********</span>
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>adduser <span class="k">**********</span> <span class="nb">sudo</span>
+<span class="gp">$</span><span class="w"> </span>su <span class="k">**********</span>
+<span class="gp">$</span><span class="w"> </span><span class="nb">cd</span></code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ ホスト名を変える
+
+ </h3>
+ <div class="section-body">
+ <div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo hostname </span>teika</code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 公開鍵を置く
+
+ </h3>
+ <div class="section-body">
+ <div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">mkdir</span> ~/.ssh
+<span class="gp">$</span><span class="w"> </span><span class="nb">chmod </span>700 ~/.ssh
+<span class="gp">$</span><span class="w"> </span>vi ~/.ssh/authorized_keys</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><code>authorized_keys</code> には、ローカルで生成した <code>~/.ssh/teika.key.pub</code> と
+<code>~/.ssh/github2teika.key.pub</code> の内容をコピーする。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ SSH の設定
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>SSH の設定を変更し、少しでも安全にしておく。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo cp</span> /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>vi /etc/ssh/sshd_config</code></pre>
+</div>
+</div>
+<div class="ulist">
+<ul>
+<li>
+<p><code>Port</code> を変更</p>
+</li>
+<li>
+<p><code>PermitRootLogin</code> を <code>no</code> に</p>
+</li>
+<li>
+<p><code>PasswordAuthentication</code> を <code>no</code> に</p>
+</li>
+</ul>
+</div>
+<div class="paragraph">
+<p>そして設定を反映。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>systemctl restart sshd
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>systemctl status sshd</code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ SSH で接続確認
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>今の SSH
+セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH
+の設定に不備があった場合に締め出しをくらう。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>ssh teika</code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ ポートの遮断
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>デフォルトの 22 番を閉じ、設定したポートだけ空ける。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw deny ssh
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw allow <span class="k">*******</span>
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw <span class="nb">enable</span>
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw reload
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw status</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>ここでもう一度 SSH の接続確認を挟む。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ GitHub 用の SSH 鍵
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>GitHub に置いてある private リポジトリをサーバから clone したいので、SSH
+鍵を生成して置いておく。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-b</span> 521 <span class="nt">-f</span> ~/.ssh/github.key
+<span class="gp">$</span><span class="w"> </span><span class="nb">cat</span> ~/.ssh/github.key.pub</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p><a href="https://github.com/settings/ssh">GitHub の設定画面</a>
+から、この公開鍵を追加する。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>vi ~/.ssh/config</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>設定はこう。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="ssh_config">Host github.com
+ HostName github.com
+ User git
+ IdentityFile ~/.ssh/github.key</code></pre>
+</div>
+</div>
+<div class="paragraph">
+<p>最後に接続できるか確認しておく。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="go">ssh -T github.com</span></code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ パッケージの更新
+
+ </h3>
+ <div class="section-body">
+ <div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt update
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt upgrade
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt update
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt upgrade
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt autoremove</code></pre>
+</div>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ サイトホスティング用のセットアップ
+
+ </h2>
+ <div class="section-body">
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ DNS に IP アドレスを登録する
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>このサーバは固定の IP アドレスがあるので、<code>A</code>
+レコードに直接入れるだけで済んだ。</p>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ 使うソフトウェアのインストール
+
+ </h3>
+ <div class="section-body">
+ <div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>apt <span class="nb">install </span>docker docker-compose git make</code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ メインユーザが Docker を使えるように
+
+ </h3>
+ <div class="section-body">
+ <div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="go">sudo adduser ********** docker</span></code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ HTTP/HTTPS を通す
+
+ </h3>
+ <div class="section-body">
+ <div class="paragraph">
+<p>80 番と 443 番を空ける。</p>
+</div>
+<div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw allow 80/tcp
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw allow 443/tcp
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw reload
+<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>ufw status</code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ リポジトリのクローン
+
+ </h3>
+ <div class="section-body">
+ <div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span><span class="nb">cd</span>
+<span class="gp">$</span><span class="w"> </span>git clone git@github.com:nsfisis/nsfisis.dev.git
+<span class="gp">$</span><span class="w"> </span><span class="nb">cd </span>nsfisis.dev
+<span class="gp">$</span><span class="w"> </span>git submodule update <span class="nt">--init</span></code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ certbot で証明書取得
+
+ </h3>
+ <div class="section-body">
+ <div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>docker-compose up <span class="nt">-d</span> acme-challenge
+<span class="gp">$</span><span class="w"> </span>make setup</code></pre>
+</div>
+</div>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-2">
+ <h3 id="" class="section-header">
+
+ サーバを稼動させる
+
+ </h3>
+ <div class="section-body">
+ <div id="source." class="listingblock">
+<div class="content">
+<pre class="rouge highlight"><code data-lang="shell-session"><span class="gp">$</span><span class="w"> </span>make serve</code></pre>
+</div>
+</div>
+ </div>
+</section>
+ </div>
+</section>
+
+
+
+
+
+<section class="section-1">
+ <h2 id="" class="section-header">
+
+ 感想
+
+ </h2>
+ <div class="section-body">
+ <div class="paragraph">
+<p>(業務でなく)
+個人だと数年ぶりのサーバセットアップで、これだけでも割と時間を食ってしまった。とはいえ式年遷宮は楽しいので、これからも定期的にやっていきたい。コンテナデプロイにしたい気持ちもあるのだが、色々実験したい関係上、本物のサーバも欲しくはある。次の式年遷宮では、手順の一部だけでも自動化したいところ。</p>
+</div>
+ </div>
+</section>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/posts/index.html b/public/posts/index.html
new file mode 100644
index 0000000..029251b
--- /dev/null
+++ b/public/posts/index.html
@@ -0,0 +1,315 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>Posts | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>Posts</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2022-10-28/setup-server-for-this-site/">
+ <header class="entry-header">
+ <h2>【備忘録】このサイト用の VPS をセットアップしたときのメモ</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ GitHub Pages でホストしていたこのサイトを VPS へ移行したので、 そのときにやったことのメモ。99 % 自分用。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-10-28">2022-10-28</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2023: ボツになったトークン問題 その 1</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、 ボツになった問題を公開する (その 1)。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-10-23">2022-10-23</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/">
+ <header class="entry-header">
+ <h2>【PHP】fizzbuzz を書く。1行あたり2文字で。</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-09-28">2022-09-28</time>, updated on <time datetime="2022-09-29">2022-09-29</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-08-31/support-for-communty-is-employee-benefits/">
+ <header class="entry-header">
+ <h2>弊社の PHP Foundation への寄付に寄せて</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 先日、私の勤めるデジタルサーカス株式会社が、PHP Foundation へ寄付をおこないました。 本件を社内でしつこく推進した1人として、推進の理由等を書き残しておきます。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-08-31">2022-08-31</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-08-27/php-conference-okinawa-code-golf/">
+ <header class="entry-header">
+ <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-08-27">2022-08-27</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-05-01/phperkaigi-2022/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2022</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-05-01">2022-05-01</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/">
+ <header class="entry-header">
+ <h2>term-banner: ターミナルにバナーを表示するツールを書いた</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ ターミナルに任意の文字のバナーを表示するためのツールを Go で書いた。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-04-24">2022-04-24</time>, updated on <time datetime="2022-04-27">2022-04-27</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-04-09/phperkaigi-2022-tokens/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2022 トークン問題の解説</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-04-09">2022-04-09</time>, updated on <time datetime="2022-04-16">2022-04-16</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/vim-swap-order-of-selected-lines/">
+ <header class="entry-header">
+ <h2>Vimで選択した行の順番を入れ替える</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Vim で選択した行の順番を入れ替える方法。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/">
+ <header class="entry-header">
+ <h2>【Vim】autocmd events の BufWrite/BufWritePre の違い</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、 違いはないことがわかった。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/rust-where-are-primitive-types-from/">
+ <header class="entry-header">
+ <h2>Rust のプリミティブ型はどこからやって来るか</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Rust のプリミティブ型は予約語ではなく普通の識別子である。 どのようにこれが名前解決されるのかを調べた。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/ruby-then-keyword-and-case-in/">
+ <header class="entry-header">
+ <h2>【Ruby】then キーワードと case in</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Ruby 3.0 で追加される case in 構文と、then キーワードについて。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/ruby-detect-running-implementation/">
+ <header class="entry-header">
+ <h2>【Ruby】自身を実行している処理系の種類を判定する</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Ruby には複数の実装があるが、自身を実行している処理系の種類を スクリプト上からどのように判定すればよいだろうか。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/python-unbound-local-error/">
+ <header class="entry-header">
+ <h2>【Python】クロージャとUnboundLocalError: local variable 'x' referenced before assignment</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Python における UnboundLocalError の理由と対処法。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/">
+ <header class="entry-header">
+ <h2>【C++】属性構文の属性名にはキーワードが使える</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ C++ の属性構文の属性名には、キーワードが使える。ネタ記事。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-03-30/phperkaigi-2021/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2021</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-03-30">2021-03-30</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-03-05/my-first-post/">
+ <header class="entry-header">
+ <h2>My First Post</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ これはテスト投稿です。これはテスト投稿です。これはテスト投稿です。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-03-05">2021-03-05</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/docs/style.css b/public/style.css
index 3666589..ef2dea5 100644
--- a/docs/style.css
+++ b/public/style.css
@@ -24,7 +24,6 @@
--tertiary: rgba(0, 0, 0, 0.16);
--content: rgba(0, 0, 0, 0.88);
- --hljs-bg: #1c1d21;
--code-bg: #f5f5f5;
--border: #eee;
}
@@ -359,7 +358,6 @@ img {
margin-left: calc(var(--gap) * -1);
margin-right: calc(var(--gap) * -1);
margin-bottom: 32px;
- background: var(--hljs-bg) !important;
border-radius: var(--radius);
overflow-x: auto;
}
@@ -406,7 +404,6 @@ img {
margin-left: 0;
margin-right: 0;
padding: var(--gap);
- color: rgba(255, 255, 255, 0.8);
background: transparent;
border-radius: 0;
}
diff --git a/public/tags/conference/index.html b/public/tags/conference/index.html
new file mode 100644
index 0000000..4423eee
--- /dev/null
+++ b/public/tags/conference/index.html
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="タグ「カンファレンス」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>カンファレンス | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>カンファレンス</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2022-08-27/php-conference-okinawa-code-golf/">
+ <header class="entry-header">
+ <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-08-27">2022-08-27</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-05-01/phperkaigi-2022/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2022</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-05-01">2022-05-01</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-04-09/phperkaigi-2022-tokens/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2022 トークン問題の解説</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-04-09">2022-04-09</time>, updated on <time datetime="2022-04-16">2022-04-16</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-03-30/phperkaigi-2021/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2021</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-03-30">2021-03-30</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/tags/cpp/index.html b/public/tags/cpp/index.html
new file mode 100644
index 0000000..5cc157b
--- /dev/null
+++ b/public/tags/cpp/index.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="タグ「C++」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>C++ | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>C++</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/">
+ <header class="entry-header">
+ <h2>【C++】属性構文の属性名にはキーワードが使える</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ C++ の属性構文の属性名には、キーワードが使える。ネタ記事。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/tags/cpp17/index.html b/public/tags/cpp17/index.html
new file mode 100644
index 0000000..5585a26
--- /dev/null
+++ b/public/tags/cpp17/index.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="タグ「C++ 17」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>C++ 17 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>C++ 17</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/">
+ <header class="entry-header">
+ <h2>【C++】属性構文の属性名にはキーワードが使える</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ C++ の属性構文の属性名には、キーワードが使える。ネタ記事。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/tags/note-to-self/index.html b/public/tags/note-to-self/index.html
new file mode 100644
index 0000000..4cdabd6
--- /dev/null
+++ b/public/tags/note-to-self/index.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2022 nsfisis">
+ <meta name="description" content="タグ「備忘録」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>備忘録 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>備忘録</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2022-10-28/setup-server-for-this-site/">
+ <header class="entry-header">
+ <h2>【備忘録】このサイト用の VPS をセットアップしたときのメモ</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ GitHub Pages でホストしていたこのサイトを VPS へ移行したので、 そのときにやったことのメモ。99 % 自分用。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-10-28">2022-10-28</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/tags/php/index.html b/public/tags/php/index.html
new file mode 100644
index 0000000..cd9a853
--- /dev/null
+++ b/public/tags/php/index.html
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="タグ「PHP」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHP | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>PHP</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2023: ボツになったトークン問題 その 1</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、 ボツになった問題を公開する (その 1)。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-10-23">2022-10-23</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/">
+ <header class="entry-header">
+ <h2>【PHP】fizzbuzz を書く。1行あたり2文字で。</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHP で、fizzbuzz を書いた。ただし、1行あたりに使える文字数は2文字まで。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-09-28">2022-09-28</time>, updated on <time datetime="2022-09-29">2022-09-29</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-08-27/php-conference-okinawa-code-golf/">
+ <header class="entry-header">
+ <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-08-27">2022-08-27</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-05-01/phperkaigi-2022/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2022</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-05-01">2022-05-01</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-04-09/phperkaigi-2022-tokens/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2022 トークン問題の解説</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-04-09">2022-04-09</time>, updated on <time datetime="2022-04-16">2022-04-16</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-03-30/phperkaigi-2021/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2021</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-03-30">2021-03-30</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/tags/phpcon/index.html b/public/tags/phpcon/index.html
new file mode 100644
index 0000000..45fe74f
--- /dev/null
+++ b/public/tags/phpcon/index.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2022 nsfisis">
+ <meta name="description" content="タグ「PHP カンファレンス」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHP カンファレンス | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>PHP カンファレンス</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2022-08-27/php-conference-okinawa-code-golf/">
+ <header class="entry-header">
+ <h2>PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHP カンファレンス沖縄の懇親会 LT で出題されたコードゴルフの問題を解いてみた。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-08-27">2022-08-27</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/tags/phperkaigi/index.html b/public/tags/phperkaigi/index.html
new file mode 100644
index 0000000..e59c245
--- /dev/null
+++ b/public/tags/phperkaigi/index.html
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="タグ「PHPerKaigi」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>PHPerKaigi | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>PHPerKaigi</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2023: ボツになったトークン問題 その 1</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 来年の PHPerKaigi 2023 でデジタルサーカス株式会社から出題予定のトークン問題のうち、 ボツになった問題を公開する (その 1)。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-10-23">2022-10-23</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-05-01/phperkaigi-2022/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2022</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 2022-04-09 から 2022-04-11 にかけて開催された、PHPerKaigi 2022 に参加した。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-05-01">2022-05-01</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2022-04-09/phperkaigi-2022-tokens/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2022 トークン問題の解説</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ PHPerKaigi 2022 で私が作成した PHPer チャレンジ問題を解説する。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2022-04-09">2022-04-09</time>, updated on <time datetime="2022-04-16">2022-04-16</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-03-30/phperkaigi-2021/">
+ <header class="entry-header">
+ <h2>PHPerKaigi 2021</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ 2021-03-26 から 2021-03-28 にかけて開催された、PHPerKaigi 2021 に参加した。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-03-30">2021-03-30</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/tags/python/index.html b/public/tags/python/index.html
new file mode 100644
index 0000000..b15dfb6
--- /dev/null
+++ b/public/tags/python/index.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="タグ「Python」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>Python | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>Python</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/python-unbound-local-error/">
+ <header class="entry-header">
+ <h2>【Python】クロージャとUnboundLocalError: local variable 'x' referenced before assignment</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Python における UnboundLocalError の理由と対処法。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/tags/python3/index.html b/public/tags/python3/index.html
new file mode 100644
index 0000000..2824a04
--- /dev/null
+++ b/public/tags/python3/index.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="タグ「Python 3」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>Python 3 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>Python 3</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/python-unbound-local-error/">
+ <header class="entry-header">
+ <h2>【Python】クロージャとUnboundLocalError: local variable 'x' referenced before assignment</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Python における UnboundLocalError の理由と対処法。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/tags/ruby/index.html b/public/tags/ruby/index.html
new file mode 100644
index 0000000..40c7b4f
--- /dev/null
+++ b/public/tags/ruby/index.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="タグ「Ruby」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>Ruby | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>Ruby</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/ruby-then-keyword-and-case-in/">
+ <header class="entry-header">
+ <h2>【Ruby】then キーワードと case in</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Ruby 3.0 で追加される case in 構文と、then キーワードについて。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/ruby-detect-running-implementation/">
+ <header class="entry-header">
+ <h2>【Ruby】自身を実行している処理系の種類を判定する</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Ruby には複数の実装があるが、自身を実行している処理系の種類を スクリプト上からどのように判定すればよいだろうか。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/tags/ruby3/index.html b/public/tags/ruby3/index.html
new file mode 100644
index 0000000..47a47b7
--- /dev/null
+++ b/public/tags/ruby3/index.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="タグ「Ruby 3」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>Ruby 3 | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>Ruby 3</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/ruby-then-keyword-and-case-in/">
+ <header class="entry-header">
+ <h2>【Ruby】then キーワードと case in</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Ruby 3.0 で追加される case in 構文と、then キーワードについて。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/tags/rust/index.html b/public/tags/rust/index.html
new file mode 100644
index 0000000..da5efee
--- /dev/null
+++ b/public/tags/rust/index.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="タグ「Rust」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>Rust | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>Rust</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/rust-where-are-primitive-types-from/">
+ <header class="entry-header">
+ <h2>Rust のプリミティブ型はどこからやって来るか</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Rust のプリミティブ型は予約語ではなく普通の識別子である。 どのようにこれが名前解決されるのかを調べた。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/public/tags/vim/index.html b/public/tags/vim/index.html
new file mode 100644
index 0000000..e76b079
--- /dev/null
+++ b/public/tags/vim/index.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+<!DOCTYPE html>
+<html lang="ja-JP">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="nsfisis">
+ <meta name="copyright" content="&copy; 2021 nsfisis">
+ <meta name="description" content="タグ「Vim」のついた記事一覧">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title>Vim | REPL: Rest-Eat-Program Loop</title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1>Vim</h1>
+ </header>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/vim-swap-order-of-selected-lines/">
+ <header class="entry-header">
+ <h2>Vimで選択した行の順番を入れ替える</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Vim で選択した行の順番を入れ替える方法。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ <article class="post-entry">
+ <a href="/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/">
+ <header class="entry-header">
+ <h2>【Vim】autocmd events の BufWrite/BufWritePre の違い</h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ Vim の autocmd events における BufWrite/BufWritePre がどう違うのかを調べた結果、 違いはないことがわかった。
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="2021-10-02">2021-10-02</time>
+ </footer>
+ </a>
+ </article>
+
+ </main>
+ <footer class="footer">
+ &copy; 2021 nsfisis
+ </footer>
+ </body>
+</html>
diff --git a/themes/mypaper/static/custom.css b/static/custom.css
index f492b95..d3b1672 100644
--- a/themes/mypaper/static/custom.css
+++ b/static/custom.css
@@ -18,9 +18,12 @@
padding-right: 0.3rem;
}
-.post-content h1::before { content: '#'; }
-.post-content h2::before { content: '##'; }
-.post-content h3::before { content: '###'; }
-.post-content h4::before { content: '####'; }
-.post-content h5::before { content: '#####'; }
-.post-content h6::before { content: '######'; }
+.post-content h2::before { content: '#'; }
+.post-content h3::before { content: '##'; }
+.post-content h4::before { content: '###'; }
+.post-content h5::before { content: '####'; }
+.post-content h6::before { content: '#####'; }
+
+li.revision {
+ list-style: inside;
+}
diff --git a/themes/mypaper/static/favicon.svg b/static/favicon.svg
index d122ea1..d122ea1 100644
--- a/themes/mypaper/static/favicon.svg
+++ b/static/favicon.svg
diff --git a/static/hl.css b/static/hl.css
new file mode 100644
index 0000000..fabe9de
--- /dev/null
+++ b/static/hl.css
@@ -0,0 +1,214 @@
+/* ruby -rrouge -e 'puts Rouge::Themes::Github.render(scope: ".highlight")' */
+.highlight table td { padding: 5px; }
+.highlight table pre { margin: 0; }
+.highlight .cm {
+ color: #999988;
+ font-style: italic;
+}
+.highlight .cp {
+ color: #999999;
+ font-weight: bold;
+}
+.highlight .c1 {
+ color: #999988;
+ font-style: italic;
+}
+.highlight .cs {
+ color: #999999;
+ font-weight: bold;
+ font-style: italic;
+}
+.highlight .c, .highlight .ch, .highlight .cd, .highlight .cpf {
+ color: #999988;
+ font-style: italic;
+}
+.highlight .err {
+ color: #a61717;
+ background-color: #e3d2d2;
+}
+.highlight .gd {
+ color: #000000;
+ background-color: #ffdddd;
+}
+.highlight .ge {
+ color: #000000;
+ font-style: italic;
+}
+.highlight .gr {
+ color: #aa0000;
+}
+.highlight .gh {
+ color: #999999;
+}
+.highlight .gi {
+ color: #000000;
+ background-color: #ddffdd;
+}
+.highlight .go {
+ color: #888888;
+}
+.highlight .gp {
+ color: #555555;
+}
+.highlight .gs {
+ font-weight: bold;
+}
+.highlight .gu {
+ color: #aaaaaa;
+}
+.highlight .gt {
+ color: #aa0000;
+}
+.highlight .kc {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .kd {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .kn {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .kp {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .kr {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .kt {
+ color: #445588;
+ font-weight: bold;
+}
+.highlight .k, .highlight .kv {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .mf {
+ color: #009999;
+}
+.highlight .mh {
+ color: #009999;
+}
+.highlight .il {
+ color: #009999;
+}
+.highlight .mi {
+ color: #009999;
+}
+.highlight .mo {
+ color: #009999;
+}
+.highlight .m, .highlight .mb, .highlight .mx {
+ color: #009999;
+}
+.highlight .sa {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .sb {
+ color: #d14;
+}
+.highlight .sc {
+ color: #d14;
+}
+.highlight .sd {
+ color: #d14;
+}
+.highlight .s2 {
+ color: #d14;
+}
+.highlight .se {
+ color: #d14;
+}
+.highlight .sh {
+ color: #d14;
+}
+.highlight .si {
+ color: #d14;
+}
+.highlight .sx {
+ color: #d14;
+}
+.highlight .sr {
+ color: #009926;
+}
+.highlight .s1 {
+ color: #d14;
+}
+.highlight .ss {
+ color: #990073;
+}
+.highlight .s, .highlight .dl {
+ color: #d14;
+}
+.highlight .na {
+ color: #008080;
+}
+.highlight .bp {
+ color: #999999;
+}
+.highlight .nb {
+ color: #0086B3;
+}
+.highlight .nc {
+ color: #445588;
+ font-weight: bold;
+}
+.highlight .no {
+ color: #008080;
+}
+.highlight .nd {
+ color: #3c5d5d;
+ font-weight: bold;
+}
+.highlight .ni {
+ color: #800080;
+}
+.highlight .ne {
+ color: #990000;
+ font-weight: bold;
+}
+.highlight .nf, .highlight .fm {
+ color: #990000;
+ font-weight: bold;
+}
+.highlight .nl {
+ color: #990000;
+ font-weight: bold;
+}
+.highlight .nn {
+ color: #555555;
+}
+.highlight .nt {
+ color: #000080;
+}
+.highlight .vc {
+ color: #008080;
+}
+.highlight .vg {
+ color: #008080;
+}
+.highlight .vi {
+ color: #008080;
+}
+.highlight .nv, .highlight .vm {
+ color: #008080;
+}
+.highlight .ow {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .o {
+ color: #000000;
+ font-weight: bold;
+}
+.highlight .w {
+ color: #bbbbbb;
+}
+.highlight {
+ background-color: #f8f8f8;
+} \ No newline at end of file
diff --git a/themes/mypaper/static/style.css b/static/style.css
index 3666589..ef2dea5 100644
--- a/themes/mypaper/static/style.css
+++ b/static/style.css
@@ -24,7 +24,6 @@
--tertiary: rgba(0, 0, 0, 0.16);
--content: rgba(0, 0, 0, 0.88);
- --hljs-bg: #1c1d21;
--code-bg: #f5f5f5;
--border: #eee;
}
@@ -359,7 +358,6 @@ img {
margin-left: calc(var(--gap) * -1);
margin-right: calc(var(--gap) * -1);
margin-bottom: 32px;
- background: var(--hljs-bg) !important;
border-radius: var(--radius);
overflow-x: auto;
}
@@ -406,7 +404,6 @@ img {
margin-left: 0;
margin-right: 0;
padding: var(--gap);
- color: rgba(255, 255, 255, 0.8);
background: transparent;
border-radius: 0;
}
diff --git a/templates/document.html.erb b/templates/document.html.erb
new file mode 100644
index 0000000..9d93696
--- /dev/null
+++ b/templates/document.html.erb
@@ -0,0 +1,69 @@
+<% _main_stylesheet = '/style.css' %>
+<% _author = attr 'author' %>
+<% _description = attr 'description' %>
+<% _lang = attr 'lang' %>
+<% _site_copyright_year = attr 'site-copyright-year' %>
+<% _copyright_year = attr 'copyright-year' %>
+<% _revisions = attr 'revision-history' %>
+<% _site_name = attr 'site-name' %>
+<% _tags = attr 'tags' %>
+<% _doctitle = doctitle %>
+<% _header_title = header.title %>
+<% _content = content %>
+<!DOCTYPE html>
+<html lang="<%= _lang %>">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="<%= _author %>">
+ <meta name="copyright" content="&copy; <%= _copyright_year %> <%= _author %>">
+ <meta name="description" content="<%= _description %>">
+ <meta name="keywords" content="<%= _tags.map(&:label).join(',') %>">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title><%= _doctitle %> | <%= _site_name %></title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="<%= _main_stylesheet %>">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="single">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/"><%= _site_name %></a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <article class="post-single">
+ <header class="post-header">
+ <h1 class="post-title"><%= _header_title %></h1>
+ <% if not _tags.empty? %>
+ <ul class="post-tags">
+ <% for tag in _tags %>
+ <li class="tag">
+ <a href="/tags/<%= tag.slug %>/"><%= tag.label %></a>
+ </li>
+ <% end %>
+ </ul>
+ <% end %>
+ </header>
+ <div class="post-content">
+ <section>
+ <h2 id="changelog">更新履歴</h2>
+ <ol>
+ <% for revision in _revisions %>
+ <li class="revision">
+ <time datetime="<%= revision.date %>"><%= revision.date %></time>: <%= revision.remark %>
+ </li>
+ <% end %>
+ </ol>
+ </section>
+ <%= _content %>
+ </div>
+ </article>
+ </main>
+ <footer class="footer">
+ &copy; <%= _site_copyright_year %> <%= _author %>
+ </footer>
+ </body>
+</html>
diff --git a/templates/feed.xml.erb b/templates/feed.xml.erb
new file mode 100644
index 0000000..7ebd1ba
--- /dev/null
+++ b/templates/feed.xml.erb
@@ -0,0 +1,27 @@
+<% _feed_title = feed_title %>
+<% _link = link %>
+<% _description = description %>
+<% _lang = lang %>
+<% _last_build_date = last_build_date %>
+<% _feed_link = feed_link %>
+<% _posts = posts %>
+<?xml version="1.0" encoding="utf-8"?>
+<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
+ <channel>
+ <title><%= _feed_title %></title>
+ <link><%= _link %></link>
+ <description><%= _description %></description>
+ <language><%= _lang %></language>
+ <lastBuildDate><%= _last_build_date %></lastBuildDate>
+ <atom:link href="<%= _feed_link %>" rel="self" type="application/rss+xml" />
+ <% for post in _posts %>
+ <item>
+ <title><%= post.title %></title>
+ <link><%= post.href %></link>
+ <pubDate><%= post.updated_on %></pubDate>
+ <guid><%= post.href %></guid>
+ <description><![CDATA[<%= post %>]]></description>
+ </item>
+ <% end %>
+ </channel>
+</rss>
diff --git a/templates/posts_list.html.erb b/templates/posts_list.html.erb
new file mode 100644
index 0000000..2227241
--- /dev/null
+++ b/templates/posts_list.html.erb
@@ -0,0 +1,59 @@
+<% _main_stylesheet = '/style.css' %>
+<% _author = author %>
+<% _description = description %>
+<% _lang = lang %>
+<% _site_copyright_year = site_copyright_year %>
+<% _copyright_year = copyright_year %>
+<% _site_name = site_name %>
+<% _doctitle = doctitle %>
+<% _header_title = header_title %>
+<% _posts = posts %>
+<!DOCTYPE html>
+<html lang="<%= _lang %>">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="<%= _author %>">
+ <meta name="copyright" content="&copy; <%= _copyright_year %> <%= _author %>">
+ <meta name="description" content="<%= _description %>">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title><%= _doctitle %> | <%= _site_name %></title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="<%= _main_stylesheet %>">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1><%= _header_title %></h1>
+ </header>
+ <% for post in _posts %>
+ <article class="post-entry">
+ <a href="<%= post.attributes['href'] %>">
+ <header class="entry-header">
+ <h2><%= post.doctitle %></h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ <%= post.attributes['description'] %>
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="<%= post.attributes['revision-history'].first.date %>"><%= post.attributes['revision-history'].first.date %></time><% if post.attributes['revision-history'].length > 1 %>, updated on <time datetime="<%= post.attributes['revision-history'].last.date %>"><%= post.attributes['revision-history'].last.date %></time><% end %>
+ </footer>
+ </a>
+ </article>
+ <% end %>
+ </main>
+ <footer class="footer">
+ &copy; <%= _site_copyright_year %> <%= _author %>
+ </footer>
+ </body>
+</html>
diff --git a/templates/section.html.erb b/templates/section.html.erb
new file mode 100644
index 0000000..1510595
--- /dev/null
+++ b/templates/section.html.erb
@@ -0,0 +1,19 @@
+<% _level = level %>
+<% _role = role %>
+<% _id = id %>
+<% _title = caption ? captioned_title : title %>
+<% _content = content %>
+<section class="section-<%= _level %><%= _role ? " #{role}" : '' %>">
+ <h<%= _level + 1 %> id="<%= _id %>" class="section-header">
+ <% if _id %>
+ <a href="#<%= _id %>">
+ <%= _title %>
+ </a>
+ <% else %>
+ <%= _title %>
+ <% end %>
+ </h<%= _level + 1 %>>
+ <div class="section-body">
+ <%= _content %>
+ </div>
+</section>
diff --git a/templates/sitemap.xml.erb b/templates/sitemap.xml.erb
new file mode 100644
index 0000000..304b1c6
--- /dev/null
+++ b/templates/sitemap.xml.erb
@@ -0,0 +1,11 @@
+<% _base_url = base_url %>
+<% _pages = pages %>
+<?xml version="1.0" encoding="utf-8"?>
+<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" >
+ <% for page in _pages %>
+ <url>
+ <loc><%= _base_url %><%= page.href %></loc>
+ <lastmod><%= page.updated_on %></lastmod>
+ </url>
+ <% end %>
+</urlset>
diff --git a/templates/tag.html.erb b/templates/tag.html.erb
new file mode 100644
index 0000000..7fd23cd
--- /dev/null
+++ b/templates/tag.html.erb
@@ -0,0 +1,59 @@
+<% _main_stylesheet = '/style.css' %>
+<% _author = author %>
+<% _description = description %>
+<% _lang = lang %>
+<% _site_copyright_year = site_copyright_year %>
+<% _copyright_year = copyright_year %>
+<% _site_name = site_name %>
+<% _doctitle = tag.label %>
+<% _header_title = tag.label %>
+<% _posts = posts %>
+<!DOCTYPE html>
+<html lang="<%= _lang %>">
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="author" content="<%= _author %>">
+ <meta name="copyright" content="&copy; <%= _copyright_year %> <%= _author %>">
+ <meta name="description" content="<%= _description %>">
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
+ <title><%= _doctitle %> | <%= _site_name %></title>
+ <link rel="stylesheet" href="/hl.css">
+ <link rel="stylesheet" href="<%= _main_stylesheet %>">
+ <link rel="stylesheet" href="/custom.css">
+ </head>
+ <body class="list">
+ <header class="header">
+ <nav class="nav">
+ <p class="logo">
+ <a href="/">REPL: Rest-Eat-Program Loop</a>
+ </p>
+ </nav>
+ </header>
+ <main class="main">
+ <header class="page-header">
+ <h1><%= _header_title %></h1>
+ </header>
+ <% for post in _posts %>
+ <article class="post-entry">
+ <a href="<%= post.attributes['href'] %>">
+ <header class="entry-header">
+ <h2><%= post.doctitle %></h2>
+ </header>
+ <section class="entry-content">
+ <p>
+ <%= post.attributes['description'] %>
+ </p>
+ </section>
+ <footer class="entry-footer">
+ Posted on <time datetime="<%= post.attributes['revision-history'].first.date %>"><%= post.attributes['revision-history'].first.date %></time><% if post.attributes['revision-history'].length > 1 %>, updated on <time datetime="<%= post.attributes['revision-history'].last.date %>"><%= post.attributes['revision-history'].last.date %></time><% end %>
+ </footer>
+ </a>
+ </article>
+ <% end %>
+ </main>
+ <footer class="footer">
+ &copy; <%= _site_copyright_year %> <%= _author %>
+ </footer>
+ </body>
+</html>
diff --git a/themes/mypaper/README.md b/themes/mypaper/README.md
deleted file mode 100644
index a90ab3d..0000000
--- a/themes/mypaper/README.md
+++ /dev/null
@@ -1 +0,0 @@
-This is my modified version of [paper](https://github.com/nanxiaobei/hugo-paper/) theme.
diff --git a/themes/mypaper/i18n/ja.yaml b/themes/mypaper/i18n/ja.yaml
deleted file mode 100644
index 30b412d..0000000
--- a/themes/mypaper/i18n/ja.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-- id: prev_page
- translation: "前のページ"
-
-- id: next_page
- translation: "次のページ"
diff --git a/themes/mypaper/layouts/404.html b/themes/mypaper/layouts/404.html
deleted file mode 100644
index ab966ff..0000000
--- a/themes/mypaper/layouts/404.html
+++ /dev/null
@@ -1,3 +0,0 @@
-{{- partial "header.html" . }}
-<div class="not-found">404</div>
-{{- partial "footer.html" . }}
diff --git a/themes/mypaper/layouts/_default/list.html b/themes/mypaper/layouts/_default/list.html
deleted file mode 100644
index 053951f..0000000
--- a/themes/mypaper/layouts/_default/list.html
+++ /dev/null
@@ -1,45 +0,0 @@
-{{- partial "header.html" . }}
-
-{{- $scope := .Site }}
-{{- if .Title }}
-<header class="page-header"><h1>{{ .Title }}</h1></header>{{ $scope = . }}
-{{ end }}
-
-{{- $paginator := .Paginate (where $scope.RegularPages ".Params.type" "!=" "page") }}
-
-{{- range $index, $page := $paginator.Pages }}
-
-{{- $class := "post-entry" }}
-{{- if .Data.Term }}
-{{- $class = "post-entry tag-entry" }}
-{{- end }}
-<article class="{{ $class }}">
- <header class="entry-header">
- <h2>{{ .Title }}</h2>
- </header>
- <section class="entry-content">
- <p>{{ .Summary | plainify | htmlUnescape }}</p>
- </section>
- <footer class="entry-footer">
- {{- $date := .Date.Format "2006-01-02" }}
- {{- $lastmod := .Lastmod.Format "2006-01-02" }}
- Posted on <time>{{ $date }}</time>{{ if ne $date $lastmod }}, updated on <time>{{ $lastmod }}</time>{{ end }}
- </footer>
- <a class="entry-link" href="{{ .Permalink }}"></a>
-</article>
-{{- end }}
-
-{{- if gt $paginator.TotalPages 1 }}
-<footer class="page-footer">
- <nav class="pagination">
- {{- if $paginator.HasPrev }}
- <a class="prev" href="{{ $paginator.Prev.URL }}">← {{ i18n "prev_page" }}</a>
- {{- end }}
- {{- if $paginator.HasNext }}
- <a class="next" href="{{ $paginator.Next.URL }}">{{ i18n "next_page" }} →</a>
- {{- end }}
- </nav>
-</footer>
-{{- end }}
-
-{{- partial "footer.html" . }}
diff --git a/themes/mypaper/layouts/_default/rss.xml b/themes/mypaper/layouts/_default/rss.xml
deleted file mode 100644
index 8626dca..0000000
--- a/themes/mypaper/layouts/_default/rss.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-{{- $pctx := . -}}
-{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}}
-{{- $pages := slice -}}
-{{- if or $.IsHome $.IsSection -}}
-{{- $pages = $pctx.RegularPages -}}
-{{- else -}}
-{{- $pages = $pctx.Pages -}}
-{{- end -}}
-{{- $limit := .Site.Config.Services.RSS.Limit -}}
-{{- if ge $limit 1 -}}
-{{- $pages = $pages | first $limit -}}
-{{- end -}}
-{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>{{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }}</title>
- <link>{{ .Permalink }}</link>
- <description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }}</description>
- <generator>Hugo -- gohugo.io</generator>{{ with .Site.LanguageCode }}
- <language>{{.}}</language>{{end}}{{ with .Site.Author.email }}
- <managingEditor>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</managingEditor>{{end}}{{ with .Site.Author.email }}
- <webMaster>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }}
- <copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }}
- <lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
- {{- with .OutputFormats.Get "RSS" -}}
- {{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}
- {{- end -}}
- {{ range $pages }}
- <item>
- <title>{{ .Title }}</title>
- <link>{{ .Permalink }}</link>
- <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
- {{ with .Site.Author.email }}<author>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}}
- <guid>{{ .Permalink }}</guid>
- <description>{{ "<![CDATA[" | safeHTML }} {{ .Content }}]]></description>
- </item>
- {{ end }}
- </channel>
-</rss>
diff --git a/themes/mypaper/layouts/_default/single.html b/themes/mypaper/layouts/_default/single.html
deleted file mode 100644
index 2156f37..0000000
--- a/themes/mypaper/layouts/_default/single.html
+++ /dev/null
@@ -1,30 +0,0 @@
-{{- partial "header.html" . }}
-
-<article class="post-single">
- <header class="post-header">
- <h1 class="post-title">{{ .Title }}</h1>
- {{- if .Params.tags }}
- <ul class="post-tags">
- {{- range .Params.tags }}
- {{- $href := print (absURL "tags/") (urlize .) }}
- <li><a href="{{ $href }}">{{ . }}</a></li>
- {{- end }}
- </ul>
- {{- end }}
- </header>
- <div class="post-content">
- {{- if .Params.changelog }}
- <section>
- <h1>更新履歴</h1>
- <ul>
- {{- range $date, $remark := .Params.changelog }}
- <li>{{ $date }}: {{ $remark }}</li>
- {{- end }}
- </ul>
- </section>
- {{- end }}
- {{ .Content }}
- </div>
-</article>
-
-{{- partial "footer.html" . }}
diff --git a/themes/mypaper/layouts/partials/footer.html b/themes/mypaper/layouts/partials/footer.html
deleted file mode 100644
index a7798d7..0000000
--- a/themes/mypaper/layouts/partials/footer.html
+++ /dev/null
@@ -1,12 +0,0 @@
-</main>
-<footer class="footer">
- <span>&copy; {{ now.Year }} <a href="{{ "" | absURL }}">{{ .Site.Title }}</a></span>
- <span>&middot;</span>
- <span>Powered by <a href="https://gohugo.io/" rel="noopener" target="_blank">Hugo️️</a>️</span>
-</footer>
-<script src="{{ "highlight.min.js" | absURL }}"></script>
-<script>
- hljs.initHighlightingOnLoad();
-</script>
-</body>
-</html>
diff --git a/themes/mypaper/layouts/partials/header.html b/themes/mypaper/layouts/partials/header.html
deleted file mode 100644
index 830acd5..0000000
--- a/themes/mypaper/layouts/partials/header.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<html lang="{{ .Site.LanguageCode }}">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
- <!-- Title -->
- <title>{{ if .Title }}{{ .Title }} | {{ end }}{{ .Site.Title }}</title>
- <!-- Meta -->
- {{- if eq .Kind "page" }}
- <meta name="description" content="{{ .Summary }}">
- <meta name="author" content="{{ .Params.Author | default .Site.Author.name }}">
- {{- else }}
- <meta name="description" content="{{ .Site.Params.description }}">
- <meta name="author" content="{{ .Site.Author.name }}">
- {{- end }}
- <!-- Styles -->
- <link href="{{ "an-old-hope.min.css" | absURL }}" rel="stylesheet">
- <link href="{{ "style.css" | absURL }}" rel="stylesheet">
- <link href="{{ "custom.css" | absURL }}" rel="stylesheet">
- <!-- Favicons -->
- <link rel="icon" href="{{ "favicon.svg" | absURL }}">
- <!-- Generator -->
- {{- hugo.Generator }}
- <!-- RSS -->
- {{ range .AlternativeOutputFormats -}}
- {{ printf `<link rel="%s" type="%s" href="%s" title="%s" />` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML }}
- {{ end -}}
- <!-- Misc -->
- {{- if eq (getenv "HUGO_ENV") "production" | or (eq .Site.Params.env "production") }}
- {{- template "_internal/google_analytics_async.html" . }}
- {{- template "_internal/opengraph.html" . }}
- {{- end }}
- </head>
- <body class="{{ if eq .Kind `page` }}single{{ else }}list{{ if .IsHome }} home{{ end }}{{ end }}">
- <header class="header">
- <nav class="nav">
- {{- if .IsHome }}
- <h1 class="logo"><a href="{{ "" | absURL }}">{{ .Site.Title }}</a></h1>
- {{- else }}
- <p class="logo"><a href="{{ "" | absURL }}">{{ .Site.Title }}</a></p>
- {{- end }}
- {{- if .Site.Menus.main }}
- <ul class="menu">
- {{- range .Site.Menus.main }}
- <li>
- <a href="{{ .URL }}">{{ .Name }}</a>
- </li>
- {{- end }}
- </ul>
- {{- end }}
- </nav>
- </header>
- <main class="main">
diff --git a/themes/mypaper/layouts/shortcodes/collapse.html b/themes/mypaper/layouts/shortcodes/collapse.html
deleted file mode 100644
index b92ad01..0000000
--- a/themes/mypaper/layouts/shortcodes/collapse.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{{ if .Get "content" }}
-{{ if .Get "summary" }}
-{{ else }}
-{{ warnf "missing value for param 'summary': %s" .Position }}
-{{ end }}
-{{ else }}
-{{ errorf "missing value for param 'content': %s" .Position }}
-{{ end }}
-<p><details {{ if (eq (.Get "openByDefault") true) }} open=true {{ end }}>
- <summary markdown="span">{{ .Get "summary" | markdownify }}</summary>
- {{ .Get "content" | markdownify }}
-</details></p>
diff --git a/themes/mypaper/layouts/sitemap.xml b/themes/mypaper/layouts/sitemap.xml
deleted file mode 100644
index 74851b5..0000000
--- a/themes/mypaper/layouts/sitemap.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-{{ printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
-<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
- xmlns:xhtml="http://www.w3.org/1999/xhtml">
- {{ range .Data.Pages }}
- {{- if .Permalink -}}
- <url>
- <loc>{{ .Permalink }}</loc>{{ if not .Lastmod.IsZero }}
- <lastmod>{{ safeHTML ( .Lastmod.Format "2006-01-02-07:00" ) }}</lastmod>{{ end }}
- </url>
- {{- end -}}
- {{ end }}
-</urlset>
diff --git a/themes/mypaper/static/an-old-hope.min.css b/themes/mypaper/static/an-old-hope.min.css
deleted file mode 100644
index 936fba3..0000000
--- a/themes/mypaper/static/an-old-hope.min.css
+++ /dev/null
@@ -1 +0,0 @@
-.hljs-comment,.hljs-quote{color:#B6B18B}.hljs-variable,.hljs-template-variable,.hljs-tag,.hljs-name,.hljs-selector-id,.hljs-selector-class,.hljs-regexp,.hljs-deletion{color:#EB3C54}.hljs-number,.hljs-built_in,.hljs-builtin-name,.hljs-literal,.hljs-type,.hljs-params,.hljs-meta,.hljs-link{color:#E7CE56}.hljs-attribute{color:#EE7C2B}.hljs-string,.hljs-symbol,.hljs-bullet,.hljs-addition{color:#4FB4D7}.hljs-title,.hljs-section{color:#78BB65}.hljs-keyword,.hljs-selector-tag{color:#B45EA4}.hljs{display:block;overflow-x:auto;background:#1C1D21;color:#c0c5ce;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold} \ No newline at end of file
diff --git a/themes/mypaper/static/highlight.min.js b/themes/mypaper/static/highlight.min.js
deleted file mode 100644
index ce50ad7..0000000
--- a/themes/mypaper/static/highlight.min.js
+++ /dev/null
@@ -1,1122 +0,0 @@
-/*!
- Highlight.js v11.0.0-beta1 (git: bc7ef3d912)
- (c) 2006-2021 Ivan Sagalaev and other contributors
- License: BSD-3-Clause
- */
-var hljs=function(){"use strict";var e={exports:{}};function n(e){
-return e instanceof Map?e.clear=e.delete=e.set=()=>{
-throw Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=()=>{
-throw Error("set is read-only")
-}),Object.freeze(e),Object.getOwnPropertyNames(e).forEach((t=>{var a=e[t]
-;"object"!=typeof a||Object.isFrozen(a)||n(a)})),e}
-e.exports=n,e.exports.default=n;var t=e.exports;class a{constructor(e){
-void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}
-ignoreMatch(){this.isMatchIgnored=!0}}function i(e){
-return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")
-}function s(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n]
-;return n.forEach((e=>{for(const n in e)t[n]=e[n]})),t}const r=e=>!!e.kind
-;class o{constructor(e,n){
-this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){
-this.buffer+=i(e)}openNode(e){if(!r(e))return;let n=e.kind
-;n=e.sublanguage?"language-"+n:((e,{prefix:n})=>{if(e.includes(".")){
-const t=e.split(".")
-;return[`${n}${t.shift()}`,...t.map(((e,n)=>`${e}${"_".repeat(n+1)}`))].join(" ")
-}return`${n}${e}`})(n,{prefix:this.classPrefix}),this.span(n)}closeNode(e){
-r(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){
-this.buffer+=`<span class="${e}">`}}class l{constructor(){this.rootNode={
-children:[]},this.stack=[this.rootNode]}get top(){
-return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
-this.top.children.push(e)}openNode(e){const n={kind:e,children:[]}
-;this.add(n),this.stack.push(n)}closeNode(){
-if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){
-for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}
-walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){
-return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),
-n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){
-"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
-l._collapse(e)})))}}class c extends l{constructor(e){super(),this.options=e}
-addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}
-addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root
-;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){
-return new o(this,this.options).value()}finalize(){return!0}}function d(e){
-return e?"string"==typeof e?e:e.source:null}function g(e){return b("(?=",e,")")}
-function u(e){return b("(?:",e,")?")}function b(...e){
-return e.map((e=>d(e))).join("")}function m(...e){return"("+((e=>{
-const n=e[e.length-1]
-;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{}
-})(e).capture?"":"?:")+e.map((e=>d(e))).join("|")+")"}function p(e){
-return RegExp(e.toString()+"|").exec("").length-1}
-const _=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./
-;function f(e,{joinWith:n}){let t=0;return e.map((e=>{t+=1;const n=t
-;let a=d(e),i="";for(;a.length>0;){const e=_.exec(a);if(!e){i+=a;break}
-i+=a.substring(0,e.index),
-a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+(Number(e[1])+n):(i+=e[0],
-"("===e[0]&&t++)}return i})).map((e=>`(${e})`)).join(n)}
-const h="[a-zA-Z]\\w*",E="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",N="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",v={
-begin:"\\\\[\\s\\S]",relevance:0},O={scope:"string",begin:"'",end:"'",
-illegal:"\\n",contains:[v]},M={scope:"string",begin:'"',end:'"',illegal:"\\n",
-contains:[v]},x=(e,n,t={})=>{const a=s({scope:"comment",begin:e,end:n,
-contains:[]},t);a.contains.push({scope:"doctag",
-begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",
-end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0})
-;const i=m("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/)
-;return a.contains.push({begin:b(/[ ]+/,"(",i,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),a
-},S=x("//","$"),k=x("/\\*","\\*/"),A=x("#","$");var C=Object.freeze({
-__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:h,UNDERSCORE_IDENT_RE:E,
-NUMBER_RE:y,C_NUMBER_RE:N,BINARY_NUMBER_RE:w,
-RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
-SHEBANG:(e={})=>{const n=/^#![ ]*\//
-;return e.binary&&(e.begin=b(n,/.*\b/,e.binary,/\b.*/)),s({scope:"meta",begin:n,
-end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},
-BACKSLASH_ESCAPE:v,APOS_STRING_MODE:O,QUOTE_STRING_MODE:M,PHRASAL_WORDS_MODE:{
-begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
-},COMMENT:x,C_LINE_COMMENT_MODE:S,C_BLOCK_COMMENT_MODE:k,HASH_COMMENT_MODE:A,
-NUMBER_MODE:{scope:"number",begin:y,relevance:0},C_NUMBER_MODE:{scope:"number",
-begin:N,relevance:0},BINARY_NUMBER_MODE:{scope:"number",begin:w,relevance:0},
-REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{scope:"regexp",begin:/\//,
-end:/\/[gimuy]*/,illegal:/\n/,contains:[v,{begin:/\[/,end:/\]/,relevance:0,
-contains:[v]}]}]},TITLE_MODE:{scope:"title",begin:h,relevance:0},
-UNDERSCORE_TITLE_MODE:{scope:"title",begin:E,relevance:0},METHOD_GUARD:{
-begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:e=>Object.assign(e,{
-"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{
-n.data._beginMatch!==e[1]&&n.ignoreMatch()}})});function T(e,n){
-"."===e.input[e.index-1]&&n.ignoreMatch()}function R(e,n){
-void 0!==e.className&&(e.scope=e.className,delete e.className)}function D(e,n){
-n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
-e.__beforeBegin=T,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
-void 0===e.relevance&&(e.relevance=0))}function I(e,n){
-Array.isArray(e.illegal)&&(e.illegal=m(...e.illegal))}function B(e,n){
-if(e.match){
-if(e.begin||e.end)throw Error("begin & end are not supported with match")
-;e.begin=e.match,delete e.match}}function L(e,n){
-void 0===e.relevance&&(e.relevance=1)}const $=(e,n)=>{if(!e.beforeMatch)return
-;if(e.starts)throw Error("beforeMatch cannot be used with starts")
-;const t=Object.assign({},e);Object.keys(e).forEach((n=>{delete e[n]
-})),e.keywords=t.keywords,e.begin=b(t.beforeMatch,g(t.begin)),e.starts={
-relevance:0,contains:[Object.assign(t,{endsParent:!0})]
-},e.relevance=0,delete t.beforeMatch
-},z=["of","and","for","in","not","or","if","then","parent","list","value"]
-;function F(e,n,t="keyword"){const a=Object.create(null)
-;return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach((t=>{
-Object.assign(a,F(e[t],n,t))})),a;function i(e,t){
-n&&(t=t.map((e=>e.toLowerCase()))),t.forEach((n=>{const t=n.split("|")
-;a[t[0]]=[e,j(t[0],t[1])]}))}}function j(e,n){
-return n?Number(n):(e=>z.includes(e.toLowerCase()))(e)?0:1}const U={},P=e=>{
-console.error(e)},K=(e,...n)=>{console.log("WARN: "+e,...n)},q=(e,n)=>{
-U[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),U[`${e}/${n}`]=!0)
-},H=Error();function Z(e,n,{key:t}){let a=0;const i=e[t],s={},r={}
-;for(let e=1;e<=n.length;e++)r[e+a]=i[e],s[e+a]=!0,a+=p(n[e-1])
-;e[t]=r,e[t]._emit=s,e[t]._multi=!0}function G(e){(e=>{
-e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,
-delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={
-_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope
-}),(e=>{if(Array.isArray(e.begin)){
-if(e.skip||e.excludeBegin||e.returnBegin)throw P("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),
-H
-;if("object"!=typeof e.beginScope||null===e.beginScope)throw P("beginScope must be object"),
-H;Z(e,e.begin,{key:"beginScope"}),e.begin=f(e.begin,{joinWith:""})}})(e),(e=>{
-if(Array.isArray(e.end)){
-if(e.skip||e.excludeEnd||e.returnEnd)throw P("skip, excludeEnd, returnEnd not compatible with endScope: {}"),
-H
-;if("object"!=typeof e.endScope||null===e.endScope)throw P("endScope must be object"),
-H;Z(e,e.end,{key:"endScope"}),e.end=f(e.end,{joinWith:""})}})(e)}function W(e){
-function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}
-class t{constructor(){
-this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
-addRule(e,n){
-n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),
-this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null)
-;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(f(e,{joinWith:"|"
-}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex
-;const n=this.matcherRe.exec(e);if(!n)return null
-;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),a=this.matchIndexes[t]
-;return n.splice(0,t),Object.assign(n,a)}}class a{constructor(){
-this.rules=[],this.multiRegexes=[],
-this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
-if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t
-;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))),
-n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){
-return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){
-this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){
-const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex
-;let t=n.exec(e)
-;if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{
-const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)}
-return t&&(this.regexIndex+=t.position+1,
-this.regexIndex===this.count&&this.considerAll()),t}}
-if(e.compilerExtensions||(e.compilerExtensions=[]),
-e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.")
-;return e.classNameAliases=s(e.classNameAliases||{}),function t(i,r){const o=i
-;if(i.isCompiled)return o
-;[R,B,G,$].forEach((e=>e(i,r))),e.compilerExtensions.forEach((e=>e(i,r))),
-i.__beforeBegin=null,[D,I,L].forEach((e=>e(i,r))),i.isCompiled=!0;let l=null
-;return"object"==typeof i.keywords&&i.keywords.$pattern&&(i.keywords=Object.assign({},i.keywords),
-l=i.keywords.$pattern,
-delete i.keywords.$pattern),l=l||/\w+/,i.keywords&&(i.keywords=F(i.keywords,e.case_insensitive)),
-o.keywordPatternRe=n(l,!0),
-r&&(i.begin||(i.begin=/\B|\b/),o.beginRe=n(i.begin),i.end||i.endsWithParent||(i.end=/\B|\b/),
-i.end&&(o.endRe=n(i.end)),
-o.terminatorEnd=d(i.end)||"",i.endsWithParent&&r.terminatorEnd&&(o.terminatorEnd+=(i.end?"|":"")+r.terminatorEnd)),
-i.illegal&&(o.illegalRe=n(i.illegal)),
-i.contains||(i.contains=[]),i.contains=[].concat(...i.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((n=>s(e,{
-variants:null},n)))),e.cachedVariants?e.cachedVariants:Q(e)?s(e,{
-starts:e.starts?s(e.starts):null
-}):Object.isFrozen(e)?s(e):e))("self"===e?i:e)))),i.contains.forEach((e=>{t(e,o)
-})),i.starts&&t(i.starts,r),o.matcher=(e=>{const n=new a
-;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin"
-}))),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end"
-}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n})(o),o}(e)}function Q(e){
-return!!e&&(e.endsWithParent||Q(e.starts))}const X=i,V=s,J=Symbol("nomatch")
-;var Y=(e=>{const n=Object.create(null),i=Object.create(null),s=[];let r=!0
-;const o="Could not find the language '{}', did you forget to load/include a language module?",l={
-disableAutodetect:!0,name:"Plain text",contains:[]};let d={
-ignoreUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,
-languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
-cssSelector:"pre code",languages:null,__emitter:c};function g(e){
-return d.noHighlightRe.test(e)}function u(e,n,t,a){let i="",s=""
-;"object"==typeof n?(i=e,
-t=n.ignoreIllegals,s=n.language,a=void 0):(q("10.7.0","highlight(lang, code, ...args) has been deprecated."),
-q("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),
-s=e,i=n),void 0===t&&(t=!0);const r={code:i,language:s};N("before:highlight",r)
-;const o=r.result?r.result:b(r.language,r.code,t,a)
-;return o.code=r.code,N("after:highlight",o),o}function b(e,t,i,s){
-const l=Object.create(null);function c(){if(!M.keywords)return void S.addText(k)
-;let e=0;M.keywordPatternRe.lastIndex=0;let n=M.keywordPatternRe.exec(k),t=""
-;for(;n;){t+=k.substring(e,n.index)
-;const i=w.case_insensitive?n[0].toLowerCase():n[0],s=(a=i,M.keywords[a]);if(s){
-const[e,a]=s
-;if(S.addText(t),t="",l[i]=(l[i]||0)+1,l[i]<=7&&(A+=a),e.startsWith("_"))t+=n[0];else{
-const t=w.classNameAliases[e]||e;S.addKeyword(n[0],t)}}else t+=n[0]
-;e=M.keywordPatternRe.lastIndex,n=M.keywordPatternRe.exec(k)}var a
-;t+=k.substr(e),S.addText(t)}function g(){null!=M.subLanguage?(()=>{
-if(""===k)return;let e=null;if("string"==typeof M.subLanguage){
-if(!n[M.subLanguage])return void S.addText(k)
-;e=b(M.subLanguage,k,!0,x[M.subLanguage]),x[M.subLanguage]=e._top
-}else e=m(k,M.subLanguage.length?M.subLanguage:null)
-;M.relevance>0&&(A+=e.relevance),S.addSublanguage(e._emitter,e.language)
-})():c(),k=""}function u(e,n){let t=1;for(;void 0!==n[t];){if(!e._emit[t]){t++
-;continue}const a=w.classNameAliases[e[t]]||e[t],i=n[t]
-;a?S.addKeyword(i,a):(k=i,c(),k=""),t++}}function p(e,n){
-return e.scope&&"string"==typeof e.scope&&S.openNode(w.classNameAliases[e.scope]||e.scope),
-e.beginScope&&(e.beginScope._wrap?(S.addKeyword(k,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),
-k=""):e.beginScope._multi&&(u(e.beginScope,n),k="")),M=Object.create(e,{parent:{
-value:M}}),M}function _(e,n,t){let i=((e,n)=>{const t=e&&e.exec(n)
-;return t&&0===t.index})(e.endRe,t);if(i){if(e["on:end"]){const t=new a(e)
-;e["on:end"](n,t),t.isMatchIgnored&&(i=!1)}if(i){
-for(;e.endsParent&&e.parent;)e=e.parent;return e}}
-if(e.endsWithParent)return _(e.parent,n,t)}function f(e){
-return 0===M.matcher.regexIndex?(k+=e[0],1):(R=!0,0)}function E(e){
-const n=e[0],a=t.substr(e.index),i=_(M,e,a);if(!i)return J;const s=M
-;M.endScope&&M.endScope._wrap?(g(),
-S.addKeyword(n,M.endScope._wrap)):M.endScope&&M.endScope._multi?(g(),
-u(M.endScope,e)):s.skip?k+=n:(s.returnEnd||s.excludeEnd||(k+=n),
-g(),s.excludeEnd&&(k=n));do{
-M.scope&&!M.isMultiClass&&S.closeNode(),M.skip||M.subLanguage||(A+=M.relevance),
-M=M.parent}while(M!==i.parent)
-;return i.starts&&p(i.starts,e),s.returnEnd?0:n.length}let y={};function N(n,s){
-const o=s&&s[0];if(k+=n,null==o)return g(),0
-;if("begin"===y.type&&"end"===s.type&&y.index===s.index&&""===o){
-if(k+=t.slice(s.index,s.index+1),!r){const n=Error(`0 width match regex (${e})`)
-;throw n.languageName=e,n.badRule=y.rule,n}return 1}
-if(y=s,"begin"===s.type)return(e=>{
-const n=e[0],t=e.rule,i=new a(t),s=[t.__beforeBegin,t["on:begin"]]
-;for(const t of s)if(t&&(t(e,i),i.isMatchIgnored))return f(n)
-;return t.skip?k+=n:(t.excludeBegin&&(k+=n),
-g(),t.returnBegin||t.excludeBegin||(k=n)),p(t,e),t.returnBegin?0:n.length})(s)
-;if("illegal"===s.type&&!i){
-const e=Error('Illegal lexeme "'+o+'" for mode "'+(M.scope||"<unnamed>")+'"')
-;throw e.mode=M,e}if("end"===s.type){const e=E(s);if(e!==J)return e}
-if("illegal"===s.type&&""===o)return 1
-;if(T>1e5&&T>3*s.index)throw Error("potential infinite loop, way more iterations than matches")
-;return k+=o,o.length}const w=h(e)
-;if(!w)throw P(o.replace("{}",e)),Error('Unknown language: "'+e+'"')
-;const v=W(w);let O="",M=s||v;const x={},S=new d.__emitter(d);(()=>{const e=[]
-;for(let n=M;n!==w;n=n.parent)n.scope&&e.unshift(n.scope)
-;e.forEach((e=>S.openNode(e)))})();let k="",A=0,C=0,T=0,R=!1;try{
-for(M.matcher.considerAll();;){
-T++,R?R=!1:M.matcher.considerAll(),M.matcher.lastIndex=C
-;const e=M.matcher.exec(t);if(!e)break;const n=N(t.substring(C,e.index),e)
-;C=e.index+n}return N(t.substr(C)),S.closeAllNodes(),S.finalize(),O=S.toHTML(),{
-language:e,value:O,relevance:A,illegal:!1,_emitter:S,_top:M}}catch(n){
-if(n.message&&n.message.includes("Illegal"))return{language:e,value:X(t),
-illegal:!0,relevance:0,_illegalBy:{message:n.message,index:C,
-context:t.slice(C-100,C+100),mode:n.mode,resultSoFar:O},_emitter:S};if(r)return{
-language:e,value:X(t),illegal:!1,relevance:0,errorRaised:n,_emitter:S,_top:M}
-;throw n}}function m(e,t){t=t||d.languages||Object.keys(n);const a=(e=>{
-const n={value:X(e),illegal:!1,relevance:0,_top:l,_emitter:new d.__emitter(d)}
-;return n._emitter.addText(e),n})(e),i=t.filter(h).filter(y).map((n=>b(n,e,!1)))
-;i.unshift(a);const s=i.sort(((e,n)=>{
-if(e.relevance!==n.relevance)return n.relevance-e.relevance
-;if(e.language&&n.language){if(h(e.language).supersetOf===n.language)return 1
-;if(h(n.language).supersetOf===e.language)return-1}return 0})),[r,o]=s,c=r
-;return c.secondBest=o,c}function p(e){let n=null;const t=(e=>{
-let n=e.className+" ";n+=e.parentNode?e.parentNode.className:""
-;const t=d.languageDetectRe.exec(n);if(t){const n=h(t[1])
-;return n||(K(o.replace("{}",t[1])),
-K("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"}
-return n.split(/\s+/).find((e=>g(e)||h(e)))})(e);if(g(t))return
-;N("before:highlightElement",{el:e,language:t
-}),!d.ignoreUnescapedHTML&&e.children.length>0&&(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),
-console.warn("https://github.com/highlightjs/highlight.js/issues/2886"),
-console.warn(e)),n=e;const a=n.textContent,s=t?u(a,{language:t,ignoreIllegals:!0
-}):m(a);N("after:highlightElement",{el:e,result:s,text:a
-}),e.innerHTML=s.value,((e,n,t)=>{const a=n&&i[n]||t
-;e.classList.add("hljs"),e.classList.add("language-"+a)
-})(e,t,s.language),e.result={language:s.language,re:s.relevance,
-relevance:s.relevance},s.secondBest&&(e.secondBest={
-language:s.secondBest.language,relevance:s.secondBest.relevance})}let _=!1
-;function f(){
-"loading"!==document.readyState?document.querySelectorAll(d.cssSelector).forEach(p):_=!0
-}function h(e){return e=(e||"").toLowerCase(),n[e]||n[i[e]]}
-function E(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{
-i[e.toLowerCase()]=n}))}function y(e){const n=h(e)
-;return n&&!n.disableAutodetect}function N(e,n){const t=e;s.forEach((e=>{
-e[t]&&e[t](n)}))}
-"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{
-_&&f()}),!1),Object.assign(e,{highlight:u,highlightAuto:m,highlightAll:f,
-highlightElement:p,
-highlightBlock:e=>(q("10.7.0","highlightBlock will be removed entirely in v12.0"),
-q("10.7.0","Please use highlightElement now."),p(e)),configure:e=>{d=V(d,e)},
-initHighlighting:()=>{
-f(),q("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")},
-initHighlightingOnLoad:()=>{
-f(),q("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")
-},registerLanguage:(t,a)=>{let i=null;try{i=a(e)}catch(e){
-if(P("Language definition for '{}' could not be registered.".replace("{}",t)),
-!r)throw e;P(e),i=l}
-i.name||(i.name=t),n[t]=i,i.rawDefinition=a.bind(null,e),i.aliases&&E(i.aliases,{
-languageName:t})},unregisterLanguage:e=>{delete n[e]
-;for(const n of Object.keys(i))i[n]===e&&delete i[n]},
-listLanguages:()=>Object.keys(n),getLanguage:h,registerAliases:E,
-autoDetection:y,inherit:V,addPlugin:e=>{(e=>{
-e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{
-e["before:highlightBlock"](Object.assign({block:n.el},n))
-}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{
-e["after:highlightBlock"](Object.assign({block:n.el},n))})})(e),s.push(e)}
-}),e.debugMode=()=>{r=!1},e.safeMode=()=>{r=!0},e.versionString="11.0.0-beta1"
-;for(const e in C)"object"==typeof C[e]&&t(C[e]);return Object.assign(e,C),e
-})({});const ee=e=>({IMPORTANT:{scope:"meta",begin:"!important"},HEXCOLOR:{
-scope:"number",begin:"#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})"},
-ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",
-contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{
-scope:"number",
-begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",
-relevance:0}
-}),ne=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],te=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],ae=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],ie=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],se=["align-content","align-items","align-self","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","auto","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","clip-path","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-variant","font-variant-ligatures","font-variation-settings","font-weight","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inherit","initial","justify-content","left","letter-spacing","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","mask","max-height","max-width","min-height","min-width","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","perspective","perspective-origin","pointer-events","position","quotes","resize","right","src","tab-size","table-layout","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-indent","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","white-space","widows","width","word-break","word-spacing","word-wrap","z-index"].reverse(),re=ae.concat(ie)
-;var oe="\\.([0-9](_*[0-9])*)",le="[0-9a-fA-F](_*[0-9a-fA-F])*",ce={
-className:"number",variants:[{
-begin:`(\\b([0-9](_*[0-9])*)((${oe})|\\.)?|(${oe}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`
-},{begin:`\\b([0-9](_*[0-9])*)((${oe})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{
-begin:`(${oe})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{
-begin:`\\b0[xX]((${le})\\.?|(${le})?\\.(${le}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b`
-},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${le})[lL]?\\b`},{
-begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],
-relevance:0};function de(e,n,t){return-1===t?"":e.replace(n,(a=>de(e,n,t-1)))}
-const ge="[A-Za-z$_][0-9A-Za-z$_]*",ue=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],be=["true","false","null","undefined","NaN","Infinity"],me=["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer","BigInt64Array","BigUint64Array","BigInt"],pe=["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],_e=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],fe=["arguments","this","super","console","window","document","localStorage","module","global"],he=[].concat(_e,me,pe)
-;function Ee(e){const n=ge,t={begin:/<[A-Za-z0-9\\._:-]+/,
-end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{
-const t=e[0].length+e.index,a=e.input[t];"<"!==a?">"===a&&(((e,{after:n})=>{
-const t="</"+e[0].slice(1);return-1!==e.input.indexOf(t,n)})(e,{after:t
-})||n.ignoreMatch()):n.ignoreMatch()}},a={$pattern:ge,keyword:ue,literal:be,
-built_in:he,"variable.language":fe
-},i="\\.([0-9](_?[0-9])*)",s="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",r={
-className:"number",variants:[{
-begin:`(\\b(${s})((${i})|\\.)?|(${i}))[eE][+-]?([0-9](_?[0-9])*)\\b`},{
-begin:`\\b(${s})\\b((${i})\\b|\\.)?|(${i})\\b`},{
-begin:"\\b(0|[1-9](_?[0-9])*)n\\b"},{
-begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b"},{
-begin:"\\b0[bB][0-1](_?[0-1])*n?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*n?\\b"},{
-begin:"\\b0[0-7]+n?\\b"}],relevance:0},o={className:"subst",begin:"\\$\\{",
-end:"\\}",keywords:a,contains:[]},l={begin:"html`",end:"",starts:{end:"`",
-returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,o],subLanguage:"xml"}},c={
-begin:"css`",end:"",starts:{end:"`",returnEnd:!1,
-contains:[e.BACKSLASH_ESCAPE,o],subLanguage:"css"}},d={className:"string",
-begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE,o]},u={className:"comment",
-variants:[e.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{
-begin:"(?=@[A-Za-z]+)",relevance:0,contains:[{className:"doctag",
-begin:"@[A-Za-z]+"},{className:"type",begin:"\\{",end:"\\}",excludeEnd:!0,
-excludeBegin:!0,relevance:0},{className:"variable",begin:n+"(?=\\s*(-)|$)",
-endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]
-}),e.C_BLOCK_COMMENT_MODE,e.C_LINE_COMMENT_MODE]
-},m=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,l,c,d,r,e.REGEXP_MODE]
-;o.contains=m.concat({begin:/\{/,end:/\}/,keywords:a,contains:["self"].concat(m)
-});const p=[].concat(u,o.contains),_=p.concat([{begin:/\(/,end:/\)/,keywords:a,
-contains:["self"].concat(p)}]),f={className:"params",begin:/\(/,end:/\)/,
-excludeBegin:!0,excludeEnd:!0,keywords:a,contains:_},h={variants:[{
-match:[/class/,/\s+/,n],scope:{1:"keyword",3:"title.class"}},{
-match:[/extends/,/\s+/,b(n,"(",b(/\./,n),")*")],scope:{1:"keyword",
-3:"title.class.inherited"}}]},E={relevance:0,
-match:/\b[A-Z][a-z]+([A-Z][a-z]+)*/,className:"title.class",keywords:{
-_:[...me,...pe]}},y={variants:[{match:[/function/,/\s+/,n,/(?=\s*\()/]},{
-match:[/function/,/\s*(?=\()/]}],className:{1:"keyword",3:"title.function"},
-label:"func.def",contains:[f],illegal:/%/},N={
-match:b(/\b/,(w=[..._e,"super"],b("(?!",w.join("|"),")")),n,g(/\(/)),
-className:"title.function",relevance:0};var w;const v={
-begin:b(/\./,g(b(n,/(?![0-9A-Za-z$_(])/))),end:n,excludeBegin:!0,
-keywords:"prototype",className:"property",relevance:0},O={
-match:[/get|set/,/\s+/,n,/(?=\()/],className:{1:"keyword",3:"title.function"},
-contains:[{begin:/\(\)/},f]
-},M="(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+e.UNDERSCORE_IDENT_RE+")\\s*=>",x={
-match:[/const|var|let/,/\s+/,n,/\s*/,/=\s*/,g(M)],className:{1:"keyword",
-3:"title.function"},contains:[f]};return{name:"Javascript",
-aliases:["js","jsx","mjs","cjs"],keywords:a,exports:{PARAMS_CONTAINS:_},
-illegal:/#(?![$_A-z])/,contains:[e.SHEBANG({label:"shebang",binary:"node",
-relevance:5}),{label:"use_strict",className:"meta",relevance:10,
-begin:/^\s*['"]use (strict|asm)['"]/
-},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,l,c,d,u,r,E,{className:"attr",
-begin:n+g(":"),relevance:0},x,{
-begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",
-keywords:"return throw case",relevance:0,contains:[u,e.REGEXP_MODE,{
-className:"function",begin:M,returnBegin:!0,end:"\\s*=>",contains:[{
-className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{
-className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,
-excludeEnd:!0,keywords:a,contains:_}]}]},{begin:/,/,relevance:0},{match:/\s+/,
-relevance:0},{variants:[{begin:"<>",end:"</>"},{begin:t.begin,
-"on:begin":t.isTrulyOpeningTag,end:t.end}],subLanguage:"xml",contains:[{
-begin:t.begin,end:t.end,skip:!0,contains:["self"]}]}]},y,{
-beginKeywords:"while if switch catch for"},{
-begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",
-returnBegin:!0,label:"func.def",contains:[f,e.inherit(e.TITLE_MODE,{begin:n,
-className:"title.function"})]},{match:/\.\.\./,relevance:0},v,{match:"\\$"+n,
-relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"},
-contains:[f]},N,{relevance:0,match:/\b[A-Z][A-Z_]+\b/,
-className:"variable.constant"},h,O,{match:/\$[(.]/}]}}
-const ye=e=>b(/\b/,e,/\w$/.test(e)?/\b/:/\B/),Ne=["Protocol","Type"].map(ye),we=["init","self"].map(ye),ve=["Any","Self"],Oe=["actor","associatedtype","async","await",/as\?/,/as!/,"as","break","case","catch","class","continue","convenience","default","defer","deinit","didSet","do","dynamic","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","lazy","let","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],Me=["false","nil","true"],xe=["assignment","associativity","higherThan","left","lowerThan","none","right"],Se=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warn_unqualified_access","#warning"],ke=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],Ae=m(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),Ce=m(Ae,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),Te=b(Ae,Ce,"*"),Re=m(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),De=m(Re,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Ie=b(Re,De,"*"),Be=b(/[A-Z]/,De,"*"),Le=["autoclosure",b(/convention\(/,m("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",b(/objc\(/,Ie,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","testable","UIApplicationMain","unknown","usableFromInline"],$e=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"]
-;var ze=Object.freeze({__proto__:null,grmr_bash:e=>{const n={},t={begin:/\$\{/,
-end:/\}/,contains:["self",{begin:/:-/,contains:[n]}]};Object.assign(n,{
-className:"variable",variants:[{
-begin:b(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},t]});const a={
-className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},i={
-begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,
-end:/(\w+)/,className:"string"})]}},s={className:"string",begin:/"/,end:/"/,
-contains:[e.BACKSLASH_ESCAPE,n,a]};a.contains.push(s);const r={begin:/\$\(\(/,
-end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,n]
-},o=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10
-}),l={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,
-contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{
-name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z._-]+\b/,
-keyword:["if","then","else","elif","fi","for","while","in","do","done","case","esac","function"],
-literal:["true","false"],
-built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp"
-},contains:[o,e.SHEBANG(),l,r,e.HASH_COMMENT_MODE,i,s,{className:"",begin:/\\"/
-},{className:"string",begin:/'/,end:/'/},n]}},grmr_c:e=>{
-const n=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]
-}),t="[a-zA-Z_]\\w*::",a="(decltype\\(auto\\)|"+u(t)+"[a-zA-Z_]\\w*"+u("<[^<>]+>")+")",i={
-className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{
-match:/\batomic_[a-z]{3,6}\b/}]},s={className:"string",variants:[{
-begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{
-begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",
-end:"'",illegal:"."},e.END_SAME_AS_BEGIN({
-begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},r={
-className:"number",variants:[{begin:"\\b(0b[01']+)"},{
-begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)"
-},{
-begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"
-}],relevance:0},o={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{
-keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"
-},contains:[{begin:/\\\n/,relevance:0},e.inherit(s,{className:"string"}),{
-className:"string",begin:/<.*?>/},n,e.C_BLOCK_COMMENT_MODE]},l={
-className:"title",begin:u(t)+e.IDENT_RE,relevance:0
-},c=u(t)+e.IDENT_RE+"\\s*\\(",d={
-keyword:["asm","auto","break","case","const","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","static","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"],
-type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","complex","bool","imaginary"],
-literal:"true false NULL",
-built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr"
-},g=[o,i,n,e.C_BLOCK_COMMENT_MODE,r,s],b={variants:[{begin:/=/,end:/;/},{
-begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],
-keywords:d,contains:g.concat([{begin:/\(/,end:/\)/,keywords:d,
-contains:g.concat(["self"]),relevance:0}]),relevance:0},m={
-begin:"("+a+"[\\*&\\s]+)+"+c,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,
-keywords:d,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:"decltype\\(auto\\)",
-keywords:d,relevance:0},{begin:c,returnBegin:!0,contains:[e.inherit(l,{
-className:"title.function"})],relevance:0},{relevance:0,match:/,/},{
-className:"params",begin:/\(/,end:/\)/,keywords:d,relevance:0,
-contains:[n,e.C_BLOCK_COMMENT_MODE,s,r,i,{begin:/\(/,end:/\)/,keywords:d,
-relevance:0,contains:["self",n,e.C_BLOCK_COMMENT_MODE,s,r,i]}]
-},i,n,e.C_BLOCK_COMMENT_MODE,o]};return{name:"C",aliases:["h"],keywords:d,
-disableAutodetect:!0,illegal:"</",contains:[].concat(b,m,g,[o,{
-begin:e.IDENT_RE+"::",keywords:d},{className:"class",
-beginKeywords:"enum class struct union",end:/[{;:<>=]/,contains:[{
-beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:o,
-strings:s,keywords:d}}},grmr_cpp:e=>{const n=e.COMMENT("//","$",{contains:[{
-begin:/\\\n/}]
-}),t="[a-zA-Z_]\\w*::",a="(?!struct)(decltype\\(auto\\)|"+u(t)+"[a-zA-Z_]\\w*"+u("<[^<>]+>")+")",i={
-className:"type",begin:"\\b[a-z\\d_]*_t\\b"},s={className:"string",variants:[{
-begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{
-begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",
-end:"'",illegal:"."},e.END_SAME_AS_BEGIN({
-begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},r={
-className:"number",variants:[{begin:"\\b(0b[01']+)"},{
-begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)"
-},{
-begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"
-}],relevance:0},o={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{
-keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"
-},contains:[{begin:/\\\n/,relevance:0},e.inherit(s,{className:"string"}),{
-className:"string",begin:/<.*?>/},n,e.C_BLOCK_COMMENT_MODE]},l={
-className:"title",begin:u(t)+e.IDENT_RE,relevance:0
-},c=u(t)+e.IDENT_RE+"\\s*\\(",d={
-type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","any","array","async","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","function","future","imaginary","initializer_list","istringstream","jthread","latch","list","lock_guard","map","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"],
-keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","signed","sizeof","static","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","unsigned","using","virtual","volatile","while","xor","xor_eq,"],
-built_in:["_Bool","_Complex","_Imaginary"],
-literal:["NULL","false","nullopt","nullptr","true"]},m={
-className:"function.dispatch",relevance:0,keywords:{
-_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"]
-},
-begin:b(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!while)/,e.IDENT_RE,g(/(<[^<>]+>|)\s*\(/))
-},p=[m,o,i,n,e.C_BLOCK_COMMENT_MODE,r,s],_={variants:[{begin:/=/,end:/;/},{
-begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],
-keywords:d,contains:p.concat([{begin:/\(/,end:/\)/,keywords:d,
-contains:p.concat(["self"]),relevance:0}]),relevance:0},f={className:"function",
-begin:"("+a+"[\\*&\\s]+)+"+c,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,
-keywords:d,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:"decltype\\(auto\\)",
-keywords:d,relevance:0},{begin:c,returnBegin:!0,contains:[l],relevance:0},{
-begin:/::/,relevance:0},{begin:/:/,endsWithParent:!0,contains:[s,r]},{
-relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,keywords:d,
-relevance:0,contains:[n,e.C_BLOCK_COMMENT_MODE,s,r,i,{begin:/\(/,end:/\)/,
-keywords:d,relevance:0,contains:["self",n,e.C_BLOCK_COMMENT_MODE,s,r,i]}]
-},i,n,e.C_BLOCK_COMMENT_MODE,o]};return{name:"C++",
-aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:d,illegal:"</",
-classNameAliases:{"function.dispatch":"built_in"},
-contains:[].concat(_,f,m,p,[o,{
-begin:"\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array|tuple|optional|variant|function)\\s*<",
-end:">",keywords:d,contains:["self",i]},{begin:e.IDENT_RE+"::",keywords:d},{
-match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/],
-className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={
-keyword:["abstract","as","base","break","case","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]),
-built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"],
-literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{
-begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{
-begin:"\\b(0b[01']+)"},{
-begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{
-begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"
-}],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]
-},s=e.inherit(i,{illegal:/\n/}),r={className:"subst",begin:/\{/,end:/\}/,
-keywords:n},o=e.inherit(r,{illegal:/\n/}),l={className:"string",begin:/\$"/,
-end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/
-},e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{
-begin:/\{\{/},{begin:/\}\}/},{begin:'""'},r]},d=e.inherit(c,{illegal:/\n/,
-contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]})
-;r.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE],
-o.contains=[d,l,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{
-illegal:/\n/})];const g={variants:[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]
-},u={begin:"<",end:">",contains:[{beginKeywords:"in out"},t]
-},b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={
-begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],
-keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,
-contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{
-begin:"\x3c!--|--\x3e"},{begin:"</?",end:">"}]}]
-}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",
-end:"$",keywords:{
-keyword:"if else elif endif define undef warning error line region endregion pragma checksum"
-}},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/,
-illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"
-},t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",
-relevance:0,end:/[{;=]/,illegal:/[^\s:]/,
-contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{
-beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/,
-contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",
-begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{
-className:"string",begin:/"/,end:/"/}]},{
-beginKeywords:"new return throw await else",relevance:0},{className:"function",
-begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<.+>\\s*)?\\(",returnBegin:!0,
-end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{
-beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial",
-relevance:0},{begin:e.IDENT_RE+"\\s*(<.+>\\s*)?\\(",returnBegin:!0,
-contains:[e.TITLE_MODE,u],relevance:0},{className:"params",begin:/\(/,end:/\)/,
-excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,
-contains:[g,a,e.C_BLOCK_COMMENT_MODE]
-},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{
-const n=ee(e),t=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{name:"CSS",
-case_insensitive:!0,illegal:/[=|'\$]/,keywords:{keyframePosition:"from to"},
-classNameAliases:{keyframePosition:"selector-tag"},
-contains:[e.C_BLOCK_COMMENT_MODE,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/
-},n.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0
-},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0
-},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{
-begin:":("+ae.join("|")+")"},{begin:"::("+ie.join("|")+")"}]},{
-className:"attribute",begin:"\\b("+se.join("|")+")\\b"},{begin:":",end:"[;}]",
-contains:[n.HEXCOLOR,n.IMPORTANT,n.CSS_NUMBER_MODE,...t,{
-begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri"
-},contains:[{className:"string",begin:/[^)]/,endsWithParent:!0,excludeEnd:!0}]
-},{className:"built_in",begin:/[\w-]+(?=\()/}]},{begin:g(/@/),end:"[{;]",
-relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/
-},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{
-$pattern:/[a-z-]+/,keyword:"and or not only",attribute:te.join(" ")},contains:[{
-begin:/[a-z-]+(?=:)/,className:"attribute"},...t,n.CSS_NUMBER_MODE]}]},{
-className:"selector-tag",begin:"\\b("+ne.join("|")+")\\b"}]}},grmr_diff:e=>({
-name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,
-match:m(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)
-},{className:"comment",variants:[{
-begin:m(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),
-end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{
-className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,
-end:/$/}]}),grmr_go:e=>{const n={
-keyword:["break","default","func","interface","select","case","map","struct","chan","else","goto","package","switch","const","fallthrough","if","range","type","continue","for","import","return","var","go","defer","bool","byte","complex64","complex128","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"],
-literal:["true","false","iota","nil"],
-built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"]
-};return{name:"Go",aliases:["golang"],keywords:n,illegal:"</",
-contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"string",
-variants:[e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{begin:"`",end:"`"}]},{
-className:"number",variants:[{begin:e.C_NUMBER_RE+"[i]",relevance:1
-},e.C_NUMBER_MODE]},{begin:/:=/},{className:"function",beginKeywords:"func",
-end:"\\s*(\\{|$)",excludeEnd:!0,contains:[e.TITLE_MODE,{className:"params",
-begin:/\(/,end:/\)/,keywords:n,illegal:/["']/}]}]}},grmr_ini:e=>{const n={
-className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{
-begin:e.NUMBER_RE}]},t=e.COMMENT();t.variants=[{begin:/;/,end:/$/},{begin:/#/,
-end:/$/}];const a={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{
-begin:/\$\{(.*?)\}/}]},i={className:"literal",
-begin:/\bon|off|true|false|yes|no\b/},s={className:"string",
-contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{
-begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]
-},r={begin:/\[/,end:/\]/,contains:[t,i,a,s,n,"self"],relevance:0
-},o=m(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{name:"TOML, also INI",
-aliases:["toml"],case_insensitive:!0,illegal:/\S/,contains:[t,{
-className:"section",begin:/\[+/,end:/\]+/},{
-begin:b(o,"(\\s*\\.\\s*",o,")*",g(/\s*=\s*[^#\s]/)),className:"attr",starts:{
-end:/$/,contains:[t,r,i,a,s,n]}}]}},grmr_java:e=>{
-const n="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",t=n+de("(?:<"+n+"~~~(?:\\s*,\\s*"+n+"~~~)*>)?",/~~~/g,2),a={
-keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do"],
-literal:["false","true","null"],
-type:["char","boolean","long","float","int","byte","short","double"],
-built_in:["super","this"]},i={className:"meta",begin:"@"+n,contains:[{
-begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/,
-end:/\)/,keywords:a,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0}
-;return{name:"Java",aliases:["jsp"],keywords:a,illegal:/<\/|#/,
-contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,
-relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{
-begin:/import java\.[a-z]+\./,keywords:"import",relevance:2
-},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{
-match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,n],className:{
-1:"keyword",3:"title.class"}},{begin:[n,/\s+/,n,/\s+/,/=/],className:{1:"type",
-3:"variable",5:"operator"}},{begin:[/record/,/\s+/,n],className:{1:"keyword",
-3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{
-beginKeywords:"new throw return else",relevance:0},{
-begin:["(?:"+t+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{
-2:"title.function"},keywords:a,contains:[{className:"params",begin:/\(/,
-end:/\)/,keywords:a,relevance:0,
-contains:[i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,ce,e.C_BLOCK_COMMENT_MODE]
-},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},ce,i]}},grmr_javascript:Ee,
-grmr_json:e=>({name:"JSON",contains:[{className:"attr",
-begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{match:/[{}[\],:]/,
-className:"punctuation",relevance:0},e.QUOTE_STRING_MODE,{
-beginKeywords:"true false null"
-},e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],illegal:"\\S"}),
-grmr_kotlin:e=>{const n={
-keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual",
-built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",
-literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"
-},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={
-className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},s={className:"string",
-variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'",
-illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,
-contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(s);const r={
-className:"meta",
-begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"
-},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,
-end:/\)/,contains:[e.inherit(s,{className:"string"})]}]
-},l=ce,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={
-variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,
-contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g],
-{name:"Kotlin",aliases:["kt","kts"],keywords:n,
-contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",
-begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",
-begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",
-begin:/@\w+/}]}},t,r,o,{className:"function",beginKeywords:"fun",end:"[(]|$",
-returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{
-begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,
-contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin:/</,end:/>/,
-keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,
-endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,
-endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0
-},e.C_LINE_COMMENT_MODE,c,r,o,s,e.C_NUMBER_MODE]},c]},{className:"class",
-beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,
-illegal:"extends implements",contains:[{
-beginKeywords:"public protected internal private constructor"
-},e.UNDERSCORE_TITLE_MODE,{className:"type",begin:/</,end:/>/,excludeBegin:!0,
-excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,
-excludeBegin:!0,returnEnd:!0},r,o]},s,{className:"meta",begin:"^#!/usr/bin/env",
-end:"$",illegal:"\n"},l]}},grmr_less:e=>{
-const n=ee(e),t=re,a="([\\w-]+|@\\{[\\w-]+\\})",i=[],s=[],r=e=>({
-className:"string",begin:"~?"+e+".*?"+e}),o=(e,n,t)=>({className:e,begin:n,
-relevance:t}),l={$pattern:/[a-z-]+/,keyword:"and or not only",
-attribute:te.join(" ")},c={begin:"\\(",end:"\\)",contains:s,keywords:l,
-relevance:0}
-;s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,r("'"),r('"'),n.CSS_NUMBER_MODE,{
-begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",
-excludeEnd:!0}
-},n.HEXCOLOR,c,o("variable","@@?[\\w-]+",10),o("variable","@\\{[\\w-]+\\}"),o("built_in","~?`[^`]*?`"),{
-className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0
-},n.IMPORTANT);const d=s.concat({begin:/\{/,end:/\}/,contains:i}),g={
-beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"
-}].concat(s)},u={begin:a+"\\s*:",returnBegin:!0,end:/[;}]/,relevance:0,
-contains:[{begin:/-(webkit|moz|ms|o)-/},{className:"attribute",
-begin:"\\b("+se.join("|")+")\\b",end:/(?=:)/,starts:{endsWithParent:!0,
-illegal:"[<=$]",relevance:0,contains:s}}]},b={className:"keyword",
-begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",
-starts:{end:"[;{}]",keywords:l,returnEnd:!0,contains:s,relevance:0}},m={
-className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{
-begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:d}},p={variants:[{
-begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:a,end:/\{/}],returnBegin:!0,
-returnEnd:!0,illegal:"[<='$\"]",relevance:0,
-contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,o("keyword","all\\b"),o("variable","@\\{[\\w-]+\\}"),{
-begin:"\\b("+ne.join("|")+")\\b",className:"selector-tag"
-},o("selector-tag",a+"%?",0),o("selector-id","#"+a),o("selector-class","\\."+a,0),o("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{
-className:"selector-pseudo",begin:":("+ae.join("|")+")"},{
-className:"selector-pseudo",begin:"::("+ie.join("|")+")"},{begin:/\(/,end:/\)/,
-relevance:0,contains:d},{begin:"!important"}]},_={
-begin:`[\\w-]+:(:)?(${t.join("|")})`,returnBegin:!0,contains:[p]}
-;return i.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,b,m,_,u,p),{
-name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:i}},grmr_lua:e=>{
-const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"]
-},i=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[",t,{contains:[a],
-relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE,
-literal:"true false nil",
-keyword:"and break do else elseif end for goto if in local not or repeat return then until while",
-built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"
-},contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)",
-contains:[e.inherit(e.TITLE_MODE,{
-begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",
-begin:"\\(",endsWithParent:!0,contains:i}].concat(i)
-},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",
-begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={
-className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",
-contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%<?\^\+\*]/}]},t={className:"string",
-begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,n]},a={className:"variable",
-begin:/\$\([\w-]+\s/,end:/\)/,keywords:{
-built_in:"subst patsubst strip findstring filter filter-out sort word wordlist firstword lastword dir notdir suffix basename addsuffix addprefix join wildcard realpath abspath error warning shell origin flavor foreach if or and call eval file value"
-},contains:[n]},i={begin:"^"+e.UNDERSCORE_IDENT_RE+"\\s*(?=[:+?]?=)"},s={
-className:"section",begin:/^[^\s]+:/,end:/$/,contains:[n]};return{
-name:"Makefile",aliases:["mk","mak","make"],keywords:{$pattern:/[\w-]+/,
-keyword:"define endef undefine ifdef ifndef ifeq ifneq else endif include -include sinclude override export unexport private vpath"
-},contains:[e.HASH_COMMENT_MODE,n,t,a,i,{className:"meta",begin:/^\.PHONY:/,
-end:/$/,keywords:{$pattern:/[\.\w]+/,keyword:".PHONY"}},s]}},grmr_xml:e=>{
-const n=b(/[A-Z_]/,u(/[A-Z0-9_.-]*:/),/[A-Z0-9_.-]*/),t={className:"symbol",
-begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},a={begin:/\s/,contains:[{
-className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},i=e.inherit(a,{
-begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{className:"string"
-}),r=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),o={endsWithParent:!0,
-illegal:/</,relevance:0,contains:[{className:"attr",begin:/[A-Za-z0-9._:-]+/,
-relevance:0},{begin:/=\s*/,relevance:0,contains:[{className:"string",
-endsParent:!0,variants:[{begin:/"/,end:/"/,contains:[t]},{begin:/'/,end:/'/,
-contains:[t]},{begin:/[^\s"'=<>`]+/}]}]}]};return{name:"HTML, XML",
-aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],
-case_insensitive:!0,contains:[{className:"meta",begin:/<![a-z]/,end:/>/,
-relevance:10,contains:[a,r,s,i,{begin:/\[/,end:/\]/,contains:[{className:"meta",
-begin:/<![a-z]/,end:/>/,contains:[a,i,r,s]}]}]},e.COMMENT(/<!--/,/-->/,{
-relevance:10}),{begin:/<!\[CDATA\[/,end:/\]\]>/,relevance:10},t,{
-className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",
-begin:/<style(?=\s|>)/,end:/>/,keywords:{name:"style"},contains:[o],starts:{
-end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",
-begin:/<script(?=\s|>)/,end:/>/,keywords:{name:"script"},contains:[o],starts:{
-end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{
-className:"tag",begin:/<>|<\/>/},{className:"tag",
-begin:b(/</,g(b(n,m(/\/>/,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name",
-begin:n,relevance:0,starts:o}]},{className:"tag",begin:b(/<\//,g(b(n,/>/))),
-contains:[{className:"name",begin:n,relevance:0},{begin:/>/,relevance:0,
-endsParent:!0}]}]}},grmr_markdown:e=>{const n={begin:/<\/?[A-Za-z_]/,end:">",
-subLanguage:"xml",relevance:0},t={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0
-},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,
-relevance:2},{begin:b(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/),
-relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{
-begin:/\[.+?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{
-className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,
-returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",
-excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",
-end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[],
-variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},i={
-className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{
-begin:/_(?!_)/,end:/_/,relevance:0}]};a.contains.push(i),i.contains.push(a)
-;let s=[n,t]
-;return a.contains=a.contains.concat(s),i.contains=i.contains.concat(s),
-s=s.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{
-className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:s},{
-begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",
-contains:s}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",
-end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:s,
-end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{
-begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{
-begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",
-contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{
-begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{
-className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{
-className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}},grmr_objectivec:e=>{
-const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n,
-keyword:["@interface","@class","@protocol","@implementation"]};return{
-name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"],
-keywords:{$pattern:n,
-keyword:["int","float","while","char","export","sizeof","typedef","const","struct","for","union","unsigned","long","volatile","static","bool","mutable","if","do","return","goto","void","enum","else","break","extern","asm","case","short","default","double","register","explicit","signed","typename","this","switch","continue","wchar_t","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","super","unichar","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"],
-literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"],
-built_in:["BOOL","dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"]
-},illegal:"</",contains:[{className:"built_in",
-begin:"\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\w+"
-},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.C_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{
-className:"string",variants:[{begin:'@"',end:'"',illegal:"\\n",
-contains:[e.BACKSLASH_ESCAPE]}]},{className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,
-keywords:{
-keyword:"if else elif endif define undef warning error line pragma ifdef ifndef include"
-},contains:[{begin:/\\\n/,relevance:0},e.inherit(e.QUOTE_STRING_MODE,{
-className:"string"}),{className:"string",begin:/<.*?>/,end:/$/,illegal:"\\n"
-},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",
-begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t,
-contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,
-relevance:0}]}},grmr_perl:e=>{const n=/[dualxmsipngr]{0,12}/,t={
-$pattern:/[\w.]+/,
-keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0"
-},a={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:t},i={begin:/->\{/,
-end:/\}/},s={variants:[{begin:/\$\d/},{
-begin:b(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])")
-},{begin:/[$%@][^\s\w{]/,relevance:0}]
-},r=[e.BACKSLASH_ESCAPE,a,s],o=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],l=(e,t,a="\\1")=>{
-const i="\\1"===a?a:b(a,t)
-;return b(b("(?:",e,")"),t,/(?:\\.|[^\\\/])*?/,i,/(?:\\.|[^\\\/])*?/,a,n)
-},c=(e,t,a)=>b(b("(?:",e,")"),t,/(?:\\.|[^\\\/])*?/,a,n),d=[s,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{
-endsWithParent:!0}),i,{className:"string",contains:r,variants:[{
-begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",
-end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{
-begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">",
-relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",
-contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",
-contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{
-begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number",
-begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",
-relevance:0},{
-begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",
-keywords:"split return print reverse grep",relevance:0,
-contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{
-begin:l("s|tr|y",m(...o,{capture:!0}))},{begin:l("s|tr|y","\\(","\\)")},{
-begin:l("s|tr|y","\\[","\\]")},{begin:l("s|tr|y","\\{","\\}")}],relevance:2},{
-className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{
-begin:c("(?:m|qr)?",/\//,/\//)},{begin:c("m|qr",m(...o,{capture:!0}),/\1/)},{
-begin:c("m|qr",/\(/,/\)/)},{begin:c("m|qr",/\[/,/\]/)},{
-begin:c("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub",
-end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{
-begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",
-subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]
-}];return a.contains=d,i.contains=d,{name:"Perl",aliases:["pl","pm"],keywords:t,
-contains:d}},grmr_php:e=>{const n={className:"variable",
-begin:"\\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?![A-Za-z0-9])(?![$])"},t={
-className:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{
-begin:/\?>/}]},a={className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,
-end:/\}/}]},i=e.inherit(e.APOS_STRING_MODE,{illegal:null
-}),s=e.inherit(e.QUOTE_STRING_MODE,{illegal:null,
-contains:e.QUOTE_STRING_MODE.contains.concat(a)}),r=e.END_SAME_AS_BEGIN({
-begin:/<<<[ \t]*(\w+)\n/,end:/[ \t]*(\w+)\b/,
-contains:e.QUOTE_STRING_MODE.contains.concat(a)}),o={className:"string",
-contains:[e.BACKSLASH_ESCAPE,t],variants:[e.inherit(i,{begin:"b'",end:"'"
-}),e.inherit(s,{begin:'b"',end:'"'}),s,i,r]},l={className:"number",variants:[{
-begin:"\\b0b[01]+(?:_[01]+)*\\b"},{begin:"\\b0o[0-7]+(?:_[0-7]+)*\\b"},{
-begin:"\\b0x[\\da-f]+(?:_[\\da-f]+)*\\b"},{
-begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:e[+-]?\\d+)?"
-}],relevance:0},c={
-keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile enum eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list match|0 mixed new object or private protected public real return string switch throw trait try unset use var void while xor yield",
-literal:"false null true",
-built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException UnhandledMatchError ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Stringable Throwable Traversable WeakReference WeakMap Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"
-};return{case_insensitive:!0,keywords:c,
-contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t]
-}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]
-}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,
-keywords:"__halt_compiler"}),t,{className:"keyword",begin:/\$this\b/},n,{
-begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",
-relevance:0,beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,
-illegal:"[$%\\[]",contains:[{beginKeywords:"use"},e.UNDERSCORE_TITLE_MODE,{
-begin:"=>",endsParent:!0},{className:"params",begin:"\\(",end:"\\)",
-excludeBegin:!0,excludeEnd:!0,keywords:c,
-contains:["self",n,e.C_BLOCK_COMMENT_MODE,o,l]}]},{className:"class",variants:[{
-beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait",
-illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{
-beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{
-beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/,
-contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",relevance:0,end:";",
-contains:[e.UNDERSCORE_TITLE_MODE]},o,l]}},grmr_php_template:e=>({
-name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,
-subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',
-end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},e.inherit(e.APOS_STRING_MODE,{
-illegal:null,className:null,contains:null,skip:!0
-}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,
-skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text",aliases:["text","txt"],
-disableAutodetect:!0}),grmr_python:e=>{const n={$pattern:/[A-Za-z]\w+|__\w+__/,
-keyword:["and","as","assert","async","await","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],
-built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"],
-literal:["__debug__","Ellipsis","False","None","NotImplemented","True"],
-type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"]
-},t={className:"meta",begin:/^(>>>|\.\.\.) /},a={className:"subst",begin:/\{/,
-end:/\}/,keywords:n,illegal:/#/},i={begin:/\{\{/,relevance:0},s={
-className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{
-begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/,
-contains:[e.BACKSLASH_ESCAPE,t],relevance:10},{
-begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/,
-contains:[e.BACKSLASH_ESCAPE,t],relevance:10},{
-begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/,
-contains:[e.BACKSLASH_ESCAPE,t,i,a]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/,
-end:/"""/,contains:[e.BACKSLASH_ESCAPE,t,i,a]},{begin:/([uU]|[rR])'/,end:/'/,
-relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{
-begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/,
-end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/,
-contains:[e.BACKSLASH_ESCAPE,i,a]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/,
-contains:[e.BACKSLASH_ESCAPE,i,a]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]
-},r="[0-9](_?[0-9])*",o=`(\\b(${r}))?\\.(${r})|\\b(${r})\\.`,l={
-className:"number",relevance:0,variants:[{
-begin:`(\\b(${r})|(${o}))[eE][+-]?(${r})[jJ]?\\b`},{begin:`(${o})[jJ]?`},{
-begin:"\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?\\b"},{
-begin:"\\b0[bB](_?[01])+[lL]?\\b"},{begin:"\\b0[oO](_?[0-7])+[lL]?\\b"},{
-begin:"\\b0[xX](_?[0-9a-fA-F])+[lL]?\\b"},{begin:`\\b(${r})[jJ]\\b`}]},c={
-className:"comment",begin:g(/# type:/),end:/$/,keywords:n,contains:[{
-begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},d={
-className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/,
-end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,
-contains:["self",t,l,s,e.HASH_COMMENT_MODE]}]};return a.contains=[s,l,t],{
-name:"Python",aliases:["py","gyp","ipython"],keywords:n,
-illegal:/(<\/|->|\?)|=>/,contains:[t,l,{begin:/\bself\b/},{beginKeywords:"if",
-relevance:0},s,c,e.HASH_COMMENT_MODE,{match:[/def/,/\s+/,h],scope:{1:"keyword",
-3:"title.function"},contains:[d]},{variants:[{
-match:[/class/,/\s+/,h,/\s*/,/\(\s*/,h,/\s*\)/]},{match:[/class/,/\s+/,h]}],
-scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{
-className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[l,d,s]}]}},
-grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta",starts:{
-end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{
-begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{
-const n=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/;return{name:"R",
-illegal:/->/,keywords:{$pattern:n,
-keyword:"function if in break next repeat else for while",
-literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10",
-built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm"
-},contains:[e.COMMENT(/#'/,/$/,{contains:[{className:"doctag",begin:"@examples",
-starts:{contains:[{begin:/\n/},{begin:/#'\s*(?=@[a-zA-Z]+)/,endsParent:!0},{
-begin:/#'/,end:/$/,excludeBegin:!0}]}},{className:"doctag",begin:"@param",
-end:/$/,contains:[{className:"variable",variants:[{begin:n},{
-begin:/`(?:\\.|[^`\\])+`/}],endsParent:!0}]},{className:"doctag",
-begin:/@[a-zA-Z]+/},{className:"keyword",begin:/\\[a-zA-Z]+/}]
-}),e.HASH_COMMENT_MODE,{className:"string",contains:[e.BACKSLASH_ESCAPE],
-variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/
-}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/
-}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/
-}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/
-}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/
-}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"',
-relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,className:{
-2:"number"},variants:[{
-match:[/[^a-zA-Z0-9._]/,/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/]},{
-match:[/[^a-zA-Z0-9._]/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/]},{
-match:[/[^a-zA-Z0-9._]/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/]}]},{
-begin:"%",end:"%"},{begin:b(/[a-zA-Z][a-zA-Z_0-9]*/,"\\s+<-\\s+")},{begin:"`",
-end:"`",contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{
-const n="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",t={
-keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor __FILE__",
-built_in:"proc lambda",literal:"true false nil"},a={className:"doctag",
-begin:"@[A-Za-z]+"},i={begin:"#<",end:">"},s=[e.COMMENT("#","$",{contains:[a]
-}),e.COMMENT("^=begin","^=end",{contains:[a],relevance:10
-}),e.COMMENT("^__END__","\\n$")],r={className:"subst",begin:/#\{/,end:/\}/,
-keywords:t},o={className:"string",contains:[e.BACKSLASH_ESCAPE,r],variants:[{
-begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/,
-end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{
-begin:/%[qQwWx]?</,end:/>/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/,
-end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{
-begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{
-begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{
-begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{
-begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{
-begin:b(/<<[-~]?'?/,g(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)),
-contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,
-contains:[e.BACKSLASH_ESCAPE,r]})]}]},l="[0-9](_?[0-9])*",c={className:"number",
-relevance:0,variants:[{
-begin:`\\b([1-9](_?[0-9])*|0)(\\.(${l}))?([eE][+-]?(${l})|r)?i?\\b`},{
-begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b"
-},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{
-begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{
-begin:"\\b0(_?[0-7])+r?i?\\b"}]},d={className:"params",begin:"\\(",end:"\\)",
-endsParent:!0,keywords:t},u=[o,{className:"class",beginKeywords:"class module",
-end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{
-begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|!)?"}),{begin:"<\\s*",contains:[{
-begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE,relevance:0}]}].concat(s)},{
-className:"function",begin:b(/def\s+/,g(n+"\\s*(\\(|;|$)")),relevance:0,
-keywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:n
-}),d].concat(s)},{begin:e.IDENT_RE+"::"},{className:"symbol",
-begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",
-begin:":(?!\\s)",contains:[o,{begin:n}],relevance:0},c,{className:"variable",
-begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{
-className:"params",begin:/\|/,end:/\|/,relevance:0,keywords:t},{
-begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{
-className:"regexp",contains:[e.BACKSLASH_ESCAPE,r],illegal:/\n/,variants:[{
-begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(",
-end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]
-}].concat(i,s),relevance:0}].concat(i,s);r.contains=u,d.contains=u;const m=[{
-begin:/^\s*=>/,starts:{end:"$",contains:u}},{className:"meta",
-begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])",
-starts:{end:"$",contains:u}}];return s.unshift(i),{name:"Ruby",
-aliases:["rb","gemspec","podspec","thor","irb"],keywords:t,illegal:/\/\*/,
-contains:[e.SHEBANG({binary:"ruby"})].concat(m).concat(s).concat(u)}},
-grmr_rust:e=>{const n={className:"title.function.invoke",relevance:0,
-begin:b(/\b/,/(?!let\b)/,e.IDENT_RE,g(/\s*\(/))
-},t="([ui](8|16|32|64|128|size)|f(32|64))?",a=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","panic!","file!","format!","format_args!","include_bin!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"]
-;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",
-type:["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"],
-keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","unsafe","unsized","use","virtual","where","while","yield"],
-literal:["true","false","Some","None","Ok","Err"],built_in:a},illegal:"</",
-contains:[e.C_LINE_COMMENT_MODE,e.COMMENT("/\\*","\\*/",{contains:["self"]
-}),e.inherit(e.QUOTE_STRING_MODE,{begin:/b?"/,illegal:null}),{
-className:"string",variants:[{begin:/b?r(#*)"(.|\n)*?"\1(?!#)/},{
-begin:/b?'\\?(x\w{2}|u\w{4}|U\w{8}|.)'/}]},{className:"symbol",
-begin:/'[a-zA-Z_][a-zA-Z0-9_]*/},{className:"number",variants:[{
-begin:"\\b0b([01_]+)"+t},{begin:"\\b0o([0-7_]+)"+t},{
-begin:"\\b0x([A-Fa-f0-9_]+)"+t},{
-begin:"\\b(\\d[\\d_]*(\\.[0-9_]+)?([eE][+-]?[0-9_]+)?)"+t}],relevance:0},{
-begin:[/fn/,/\s+/,e.UNDERSCORE_IDENT_RE],className:{1:"keyword",
-3:"title.function"}},{className:"meta",begin:"#!?\\[",end:"\\]",contains:[{
-className:"string",begin:/"/,end:/"/}]},{
-begin:[/let/,/\s+/,/(?:mut\s+)?/,e.UNDERSCORE_IDENT_RE],className:{1:"keyword",
-3:"keyword",4:"variable"}},{
-begin:[/for/,/\s+/,e.UNDERSCORE_IDENT_RE,/\s+/,/in/],className:{1:"keyword",
-3:"variable",5:"keyword"}},{begin:[/type/,/\s+/,e.UNDERSCORE_IDENT_RE],
-className:{1:"keyword",3:"title.class"}},{
-begin:[/(?:trait|enum|struct|union|impl|for)/,/\s+/,e.UNDERSCORE_IDENT_RE],
-className:{1:"keyword",3:"title.class"}},{begin:e.IDENT_RE+"::",keywords:{
-keyword:"Self",built_in:a}},{className:"punctuation",begin:"->"},n]}},
-grmr_scss:e=>{const n=ee(e),t=ie,a=ae,i="@[a-z-]+",s={className:"variable",
-begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b"};return{name:"SCSS",case_insensitive:!0,
-illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{
-className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{
-className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0
-},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag",
-begin:"\\b("+ne.join("|")+")\\b",relevance:0},{className:"selector-pseudo",
-begin:":("+a.join("|")+")"},{className:"selector-pseudo",
-begin:"::("+t.join("|")+")"},s,{begin:/\(/,end:/\)/,contains:[n.CSS_NUMBER_MODE]
-},{className:"attribute",begin:"\\b("+se.join("|")+")\\b"},{
-begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"
-},{begin:":",end:";",
-contains:[s,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT]
-},{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{
-begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/,
-keyword:"and or not only",attribute:te.join(" ")},contains:[{begin:i,
-className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute"
-},s,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE]}]}},
-grmr_shell:e=>({name:"Shell Session",aliases:["console","shellsession"],
-contains:[{className:"meta",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{
-end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]}),grmr_sql:e=>{
-const n=e.COMMENT("--","$"),t=["true","false","unknown"],a=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],i=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],r=i,o=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!i.includes(e))),l={
-begin:b(/\b/,m(...r),/\s*\(/),relevance:0,keywords:{built_in:r}};return{
-name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{
-$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t
-;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e))
-})(o,{when:e=>e.length<3}),literal:t,type:a,
-built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"]
-},contains:[{begin:m(...s),relevance:0,keywords:{$pattern:/[\w\.]+/,
-keyword:o.concat(s),literal:t,type:a}},{className:"type",
-begin:m("double precision","large object","with timezone","without timezone")
-},l,{className:"variable",begin:/@[a-z0-9]+/},{className:"string",variants:[{
-begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/,contains:[{
-begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,n,{className:"operator",
-begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/,relevance:0}]}},
-grmr_swift:e=>{const n={match:/\s+/,relevance:0},t=e.COMMENT("/\\*","\\*/",{
-contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={match:[/\./,m(...Ne,...we)],
-className:{2:"keyword"}},s={match:b(/\./,m(...Oe)),relevance:0
-},r=Oe.filter((e=>"string"==typeof e)).concat(["_|0"]),o={variants:[{
-className:"keyword",
-match:m(...Oe.filter((e=>"string"!=typeof e)).concat(ve).map(ye),...we)}]},l={
-$pattern:m(/\b\w+/,/#\w+/),keyword:r.concat(Se),literal:Me},c=[i,s,o],d=[{
-match:b(/\./,m(...ke)),relevance:0},{className:"built_in",
-match:b(/\b/,m(...ke),/(?=\()/)}],u={match:/->/,relevance:0},p=[u,{
-className:"operator",relevance:0,variants:[{match:Te},{match:`\\.(\\.|${Ce})+`}]
-}],_="([0-9a-fA-F]_*)+",f={className:"number",relevance:0,variants:[{
-match:"\\b(([0-9]_*)+)(\\.(([0-9]_*)+))?([eE][+-]?(([0-9]_*)+))?\\b"},{
-match:`\\b0x(${_})(\\.(${_}))?([pP][+-]?(([0-9]_*)+))?\\b`},{
-match:/\b0o([0-7]_*)+\b/},{match:/\b0b([01]_*)+\b/}]},h=(e="")=>({
-className:"subst",variants:[{match:b(/\\/,e,/[0\\tnr"']/)},{
-match:b(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}]}),E=(e="")=>({className:"subst",
-match:b(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/)}),y=(e="")=>({className:"subst",
-label:"interpol",begin:b(/\\/,e,/\(/),end:/\)/}),N=(e="")=>({begin:b(e,/"""/),
-end:b(/"""/,e),contains:[h(e),E(e),y(e)]}),w=(e="")=>({begin:b(e,/"/),
-end:b(/"/,e),contains:[h(e),y(e)]}),v={className:"string",
-variants:[N(),N("#"),N("##"),N("###"),w(),w("#"),w("##"),w("###")]},O={
-match:b(/`/,Ie,/`/)},M=[O,{className:"variable",match:/\$\d+/},{
-className:"variable",match:`\\$${De}+`}],x=[{match:/(@|#)available/,
-className:"keyword",starts:{contains:[{begin:/\(/,end:/\)/,keywords:$e,
-contains:[...p,f,v]}]}},{className:"keyword",match:b(/@/,m(...Le))},{
-className:"meta",match:b(/@/,Ie)}],S={match:g(/\b[A-Z]/),relevance:0,contains:[{
-className:"type",
-match:b(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,De,"+")
-},{className:"type",match:Be,relevance:0},{match:/[?!]+/,relevance:0},{
-match:/\.\.\./,relevance:0},{match:b(/\s+&\s+/,g(Be)),relevance:0}]},k={
-begin:/</,end:/>/,keywords:l,contains:[...a,...c,...x,u,S]};S.contains.push(k)
-;const A={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{
-match:b(Ie,/\s*:/),keywords:"_|0",relevance:0
-},...a,...c,...d,...p,f,v,...M,...x,S]},C={begin:/</,end:/>/,contains:[...a,S]
-},T={begin:/\(/,end:/\)/,keywords:l,contains:[{
-begin:m(g(b(Ie,/\s*:/)),g(b(Ie,/\s+/,Ie,/\s*:/))),end:/:/,relevance:0,
-contains:[{className:"keyword",match:/\b_\b/},{className:"params",match:Ie}]
-},...a,...c,...p,f,v,...x,S,A],endsParent:!0,illegal:/["']/},R={
-match:[/func/,/\s+/,m(O.match,Ie,Te)],className:{1:"keyword",3:"title.function"
-},contains:[C,T,n],illegal:[/\[/,/%/]},D={
-match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"},
-contains:[C,T,n],illegal:/\[|%/},I={match:[/operator/,/\s+/,Te],className:{
-1:"keyword",3:"title"}},B={begin:[/precedencegroup/,/\s+/,Be],className:{
-1:"keyword",3:"title"},contains:[S],keywords:[...xe,...Me],end:/}/}
-;for(const e of v.variants){const n=e.contains.find((e=>"interpol"===e.label))
-;n.keywords=l;const t=[...c,...d,...p,f,v,...M];n.contains=[...t,{begin:/\(/,
-end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:l,
-contains:[...a,R,D,{beginKeywords:"struct protocol class extension enum actor",
-end:"\\{",excludeEnd:!0,keywords:l,contains:[e.inherit(e.TITLE_MODE,{
-className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...c]
-},I,B,{beginKeywords:"import",end:/$/,contains:[...a],relevance:0
-},...c,...d,...p,f,v,...M,...x,S,A]}},grmr_typescript:e=>{const n={$pattern:ge,
-keyword:ue.concat(["type","namespace","typedef","interface","public","private","protected","implements","declare","abstract","readonly"]),
-literal:be,
-built_in:he.concat(["any","void","number","boolean","string","object","never","enum"]),
-"variable.language":fe},t={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"
-},a=(e,n,t)=>{const a=e.contains.findIndex((e=>e.label===n))
-;if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)
-},i=Ee(e)
-;return Object.assign(i.keywords,n),i.exports.PARAMS_CONTAINS.push(t),i.contains=i.contains.concat([t,{
-beginKeywords:"namespace",end:/\{/,excludeEnd:!0},{beginKeywords:"interface",
-end:/\{/,excludeEnd:!0,keywords:"interface extends"
-}]),a(i,"shebang",e.SHEBANG()),a(i,"use_strict",{className:"meta",relevance:10,
-begin:/^\s*['"]use strict['"]/
-}),i.contains.find((e=>"func.def"===e.label)).relevance=0,Object.assign(i,{
-name:"TypeScript",aliases:["ts","tsx"]}),i},grmr_vbnet:e=>{
-const n=/\d{1,2}\/\d{1,2}\/\d{4}/,t=/\d{4}-\d{1,2}-\d{1,2}/,a=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,i=/\d{1,2}(:\d{1,2}){1,2}/,s={
-className:"literal",variants:[{begin:b(/# */,m(t,n),/ *#/)},{
-begin:b(/# */,i,/ *#/)},{begin:b(/# */,a,/ *#/)},{
-begin:b(/# */,m(t,n),/ +/,m(a,i),/ *#/)}]},r=e.COMMENT(/'''/,/$/,{contains:[{
-className:"doctag",begin:/<\/?/,end:/>/}]}),o=e.COMMENT(null,/$/,{variants:[{
-begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]});return{name:"Visual Basic .NET",
-aliases:["vb"],case_insensitive:!0,classNameAliases:{label:"symbol"},keywords:{
-keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield",
-built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort",
-type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort",
-literal:"true false nothing"},
-illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{
-className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/,
-end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0,
-variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/
-},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{
-begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{
-className:"label",begin:/^\w+:/},r,o,{className:"meta",
-begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/,
-end:/$/,keywords:{
-keyword:"const disable else elseif enable end externalsource if region then"},
-contains:[o]}]}},grmr_yaml:e=>{
-const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={
-className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/
-},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",
-variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{
-variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),s={
-end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},r={begin:/\{/,
-end:/\}/,contains:[s],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]",
-contains:[s],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{
-begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{
-begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$",
-relevance:10},{className:"string",
-begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{
-begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,
-relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type",
-begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t
-},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",
-begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)",
-relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{
-className:"number",
-begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"
-},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},r,o,a],c=[...l]
-;return c.pop(),c.push(i),s.contains=c,{name:"YAML",case_insensitive:!0,
-aliases:["yml"],contains:l}}});const Fe=Y;for(const e of Object.keys(ze)){
-const n=e.replace("grmr_","");Fe.registerLanguage(n,ze[e])}return Fe}()
-;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); \ No newline at end of file
diff --git a/themes/mypaper/theme.toml b/themes/mypaper/theme.toml
deleted file mode 100644
index d755a43..0000000
--- a/themes/mypaper/theme.toml
+++ /dev/null
@@ -1,25 +0,0 @@
-# theme.toml template for a Hugo theme
-# See https://github.com/gohugoio/hugoThemes#themetoml for an example
-
-name = "Mypaper"
-license = "MIT"
-licenselink = "https://github.com/nsfisis/nsfisis.github.io/blob/main/themes/mypaper/LICENSE"
-description = "My modified version of paper theme"
-homepage = "https://github.com/nsfisis/nsfisis.github.io/tree/main/themes/mypaper"
-tags = ["Responsive", "Simple", "Clean", "Light", "White", "Blog"]
-features = ["Responsive", "One Column", "Blog"]
-min_version = "0.57.1"
-
-[[authors]]
- name = "nanxiaobei"
- homepage = "https://mrlee.me/"
-
-[[authors]]
- name = "nsfisis"
- homepage = "https://blog.nsfisis.dev"
-
-# If porting an existing theme
-[original]
- name = "paper"
- homepage = "https://github.com/nanxiaobei/hugo-paper/"
- repo = "https://github.com/nanxiaobei/hugo-paper/"