wani 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +262 -0
  4. data/assets/bootstrap.rb +9 -0
  5. data/assets/build.json +6 -0
  6. data/assets/fonts/IBMPlexSansJP-Bold.woff2 +0 -0
  7. data/assets/fonts/IBMPlexSansJP-Regular.woff2 +0 -0
  8. data/assets/highlight.css +117 -0
  9. data/assets/index.html +39 -0
  10. data/assets/rabbit.svg +1 -0
  11. data/assets/rouge.LICENSE +187 -0
  12. data/assets/runtime.LICENSE +21 -0
  13. data/assets/runtime.NOTICE +1292 -0
  14. data/assets/runtime.pr672.js +3143 -0
  15. data/assets/shark.svg +1 -0
  16. data/assets/speaker.html +2 -0
  17. data/assets/style.css +103 -0
  18. data/assets/time-expired.png +0 -0
  19. data/assets/wani.wasm +4 -0
  20. data/exe/wani +3 -0
  21. data/lib/wani/browser/application.rb +189 -0
  22. data/lib/wani/browser/bridge_progress.rb +19 -0
  23. data/lib/wani/browser/fonts.rb +60 -0
  24. data/lib/wani/browser/layout.rb +107 -0
  25. data/lib/wani/browser/presentation_timer.rb +66 -0
  26. data/lib/wani/browser/renderer.rb +80 -0
  27. data/lib/wani/cli.rb +134 -0
  28. data/lib/wani/core/fonts.rb +49 -0
  29. data/lib/wani/core/parser.rb +127 -0
  30. data/lib/wani/core/presentation.rb +15 -0
  31. data/lib/wani/core/safe_html.rb +74 -0
  32. data/lib/wani/core/validator.rb +31 -0
  33. data/lib/wani/fonts/http.rb +45 -0
  34. data/lib/wani/fonts/manager.rb +190 -0
  35. data/lib/wani/server/application.rb +92 -0
  36. data/lib/wani/server/http_server.rb +34 -0
  37. data/lib/wani/version.rb +3 -0
  38. data/lib/wani.rb +4 -0
  39. data/templates/images/workflow.svg +36 -0
  40. data/templates/slides.md +182 -0
  41. data/third_party/gems/kramdown-LICENSE +30 -0
  42. data/third_party/gems/kramdown-parser-gfm-LICENSE +21 -0
  43. data/third_party/gems/rexml-LICENSE +22 -0
  44. data/third_party/ibm-plex-sans-jp/LICENSE.txt +93 -0
  45. data/third_party/ibm-plex-sans-jp/README.md +39 -0
  46. data/third_party/ibm-plex-sans-jp/provenance.json +20 -0
  47. data/third_party/ruby-wasm-loader/LICENSE +21 -0
  48. data/third_party/ruby-wasm-loader/NOTICE +1292 -0
  49. data/third_party/ruby-wasm-loader/README.md +35 -0
  50. data/third_party/ruby-wasm-loader/browser.script.iife.js +3143 -0
  51. data/third_party/ruby-wasm-loader/provenance.json +10 -0
  52. metadata +159 -0
@@ -0,0 +1,92 @@
1
+ require "uri"
2
+ require "json"
3
+ require_relative "../fonts/manager"
4
+ require_relative "../../wani"
5
+
6
+ module Wani
7
+ module Server
8
+ # Only the selected Markdown, images below its directory and fixed gem assets are public.
9
+ class Application
10
+ ASSETS = %w[index.html style.css highlight.css rouge.LICENSE bootstrap.rb speaker.html rabbit.svg shark.svg time-expired.png runtime.pr672.js wani.wasm runtime.LICENSE runtime.NOTICE build.json
11
+ fonts/IBMPlexSansJP-Regular.woff2 fonts/IBMPlexSansJP-Bold.woff2].freeze
12
+ TYPES = { ".html" => "text/html; charset=utf-8", ".css" => "text/css; charset=utf-8", ".rb" => "text/plain; charset=utf-8", ".js" => "text/javascript", ".wasm" => "application/wasm", ".md" => "text/plain; charset=utf-8", ".svg" => "image/svg+xml", ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".webp" => "image/webp", ".json" => "application/json", ".woff2" => "font/woff2" }.freeze
13
+ IMAGES = %w[.png .jpg .jpeg .webp .svg].freeze
14
+
15
+ def initialize(file, assets: File.join(Wani::ROOT, "assets"), diagnostics: nil)
16
+ @file = File.realpath(file)
17
+ raise ArgumentError, "Markdown is not a file: #{file}" unless File.file?(@file)
18
+ @root = File.dirname(@file)
19
+ @assets = File.realpath(assets)
20
+ @diagnostics = diagnostics
21
+ report_font(File.read(@file, encoding: "UTF-8")) if @diagnostics
22
+ end
23
+
24
+ def call(raw_path)
25
+ path = decode(raw_path)
26
+ if path == "/talk/fonts.json"
27
+ return [200, { "Content-Type" => "application/json", "Cache-Control" => "no-store" }, JSON.generate(Fonts::Manager.new(@root).list)]
28
+ end
29
+ file = if path == "/"
30
+ File.join(@assets, "index.html")
31
+ elsif path == "/talk/slides.md"
32
+ @file
33
+ elsif path.start_with?("/assets/") && ASSETS.include?(path.delete_prefix("/assets/"))
34
+ contained(@assets, path.delete_prefix("/assets/"))
35
+ elsif path.start_with?("/talk/fonts/") && Fonts::Manager.new(@root).list.values.any? { |entry| entry.fetch("files").include?(path.delete_prefix("/talk/")) }
36
+ contained(@root, path.delete_prefix("/talk/"))
37
+ elsif path.start_with?("/talk/") && IMAGES.include?(File.extname(path).downcase)
38
+ contained(@root, path.delete_prefix("/talk/"))
39
+ else
40
+ return [404, {}, "Not found"]
41
+ end
42
+ return [404, {}, "Not found"] unless File.file?(file)
43
+ type = TYPES.fetch(File.extname(file).downcase, "text/plain; charset=utf-8")
44
+ headers = { "Content-Type" => type, "X-Content-Type-Options" => "nosniff", "Cache-Control" => "no-store" }
45
+ if type.start_with?("image/")
46
+ headers["Content-Security-Policy"] = "sandbox; default-src 'none'; style-src 'unsafe-inline'"
47
+ else
48
+ headers["Content-Security-Policy"] = "default-src 'self'; script-src 'self' 'unsafe-eval' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' https: http:; connect-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'"
49
+ end
50
+ body = File.binread(file)
51
+ report_font(body.dup.force_encoding(Encoding::UTF_8)) if path == "/talk/slides.md" && @diagnostics
52
+ [200, headers, body]
53
+ rescue ArgumentError, EncodingError
54
+ [403, {}, "Forbidden"]
55
+ rescue Errno::ENOENT, Errno::ENOTDIR
56
+ [404, {}, "Not found"]
57
+ rescue Errno::EACCES
58
+ [403, {}, "Forbidden"]
59
+ end
60
+
61
+ private
62
+
63
+ def report_font(source)
64
+ message = begin
65
+ name = Core::Parser.new.parse(source).fonts["default"]
66
+ if name && !Core::Fonts.resolve(Fonts::Manager.new(@root).list, name)
67
+ "warning: Unregistered font: #{name}; using fallback"
68
+ end
69
+ rescue Core::Parser::Error, ArgumentError => error
70
+ "error: #{error.message}"
71
+ end
72
+ @diagnostics.call(message) if message && message != @last_diagnostic
73
+ @last_diagnostic = message
74
+ end
75
+
76
+ def decode(raw)
77
+ raw = raw.split("?", 2).first
78
+ raise ArgumentError if raw.match?(/%(?![0-9a-fA-F]{2})/)
79
+ path = URI::RFC2396_PARSER.unescape(raw).force_encoding(Encoding::UTF_8)
80
+ raise ArgumentError unless path.valid_encoding? && path.start_with?("/")
81
+ raise ArgumentError if path.match?(/[\x00-\x1f\x7f\\%]/) || path.split("/").any? { |part| part == ".." || part == "." }
82
+ path
83
+ end
84
+
85
+ def contained(root, relative)
86
+ resolved = File.realpath(File.join(root, relative))
87
+ raise ArgumentError unless resolved.start_with?(root + File::SEPARATOR)
88
+ resolved
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,34 @@
1
+ require "webrick"
2
+ require_relative "application"
3
+
4
+ module Wani
5
+ module Server
6
+ class HTTPServer
7
+ def initialize(file, bind: "127.0.0.1", port: 8000, out: $stdout)
8
+ app = Application.new(file, diagnostics: ->(message) { out.puts(message); out.flush })
9
+ @server = WEBrick::HTTPServer.new(BindAddress: bind, Port: port,
10
+ Logger: WEBrick::Log.new($stderr, WEBrick::Log::WARN), AccessLog: [],
11
+ StartCallback: -> { out.puts "Wani: http://#{bind.include?(':') ? "[#{bind}]" : bind}:#{@server.listeners.first.addr[1]}/"; out.flush })
12
+ @server.mount_proc("/") do |request, response|
13
+ if %w[GET HEAD].include?(request.request_method)
14
+ status, headers, body = app.call(request.unparsed_uri)
15
+ response.status = status
16
+ headers.each { |key, value| response[key] = value }
17
+ response.body = body
18
+ else
19
+ response.status = 405
20
+ response["Allow"] = "GET, HEAD"
21
+ end
22
+ end
23
+ end
24
+
25
+ def start
26
+ previous = %w[INT TERM].to_h { |signal| [signal, Signal.trap(signal) { @server.shutdown }] }
27
+ @server.start
28
+ ensure
29
+ previous&.each { |signal, handler| Signal.trap(signal, handler) }
30
+ @server.shutdown
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module Wani
2
+ VERSION = "0.1.8"
3
+ end
data/lib/wani.rb ADDED
@@ -0,0 +1,4 @@
1
+ require_relative "wani/version"
2
+ module Wani
3
+ ROOT = File.expand_path("..", __dir__)
4
+ end
@@ -0,0 +1,36 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="300" viewBox="0 0 1200 300" role="img" aria-labelledby="title desc">
2
+ <title id="title">Markdown から発表と PDF へ</title>
3
+ <desc id="desc">原稿を書く、ブラウザーで発表する、PDF を配布する、という3つの手順を矢印で結んだ図。</desc>
4
+ <defs>
5
+ <marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">
6
+ <path d="M0 0 L10 5 L0 10 Z" fill="#527b65"/>
7
+ </marker>
8
+ </defs>
9
+ <rect width="1200" height="300" rx="24" fill="#f3f6f2"/>
10
+ <g fill="white" stroke="#91af99" stroke-width="3">
11
+ <rect x="35" y="50" width="310" height="200" rx="18"/>
12
+ <rect x="445" y="50" width="310" height="200" rx="18"/>
13
+ <rect x="855" y="50" width="310" height="200" rx="18"/>
14
+ </g>
15
+ <g stroke="#527b65" stroke-width="5" marker-end="url(#arrow)">
16
+ <path d="M365 150 H420"/>
17
+ <path d="M775 150 H830"/>
18
+ </g>
19
+ <g font-family="sans-serif" text-anchor="middle" fill="#20352e">
20
+ <g font-size="20" fill="#527b65">
21
+ <text x="190" y="95">01 / WRITE</text>
22
+ <text x="600" y="95">02 / PRESENT</text>
23
+ <text x="1010" y="95">03 / SHARE</text>
24
+ </g>
25
+ <g font-size="38" font-weight="bold">
26
+ <text x="190" y="158">Markdown</text>
27
+ <text x="600" y="158">Browser</text>
28
+ <text x="1010" y="158">PDF</text>
29
+ </g>
30
+ <g font-size="24" fill="#527b65">
31
+ <text x="190" y="205">slides.md</text>
32
+ <text x="600" y="205">wani serve</text>
33
+ <text x="1010" y="205">Slides + Notes</text>
34
+ </g>
35
+ </g>
36
+ </svg>
@@ -0,0 +1,182 @@
1
+ ---
2
+ time_limit: 5
3
+ ---
4
+
5
+ # はじめての Wani
6
+
7
+ Ruby と Markdown でプレゼンテーション。
8
+
9
+ - 左右キー・Space で移動
10
+ - F で全画面
11
+ - N で発表者ノート
12
+
13
+ <!-- page-footnote: Wani のサンプルへようこそ -->
14
+
15
+ <!-- notes:
16
+ 最初に自己紹介をします。
17
+ ページを進めながら使える記法を紹介します。
18
+ 原稿の先頭にある time_limit は発表時間(分)です。0 にするとタイマーを無効にできます。
19
+ -->
20
+
21
+ ---
22
+
23
+ # 文章を強調する
24
+
25
+ **いちばん伝えたいこと**は太字にします。
26
+
27
+ *強調したい言葉*はアスタリスクで囲みます。
28
+
29
+ コマンドは `wani serve` のように文中に入れられます。
30
+
31
+ 空行を入れると、新しい段落になります。
32
+
33
+ <!-- notes:
34
+ 原稿では **太字**、*強調*、バッククォートで囲むコードを使っています。
35
+ タイトルはプレーンテキストになります。本文で表示の違いを見せます。
36
+ -->
37
+
38
+ ---
39
+
40
+ # リストで整理する
41
+
42
+ - 原稿は Markdown で書く
43
+ - 画像は images フォルダーに置く
44
+ - ブラウザーで見た目を確認する
45
+
46
+ 1. `wani check` で原稿を確認する
47
+ 2. `wani serve` でサーバーを起動する
48
+ 3. 表示された URL を開く
49
+
50
+ <!-- notes:
51
+ 上は箇条書き、下は番号付きリストです。
52
+ 原稿を編集したらブラウザーを再読み込みします。
53
+ -->
54
+
55
+ ---
56
+
57
+ # 引用とリンク
58
+
59
+ > 一枚のスライドでは、一つのメッセージを伝えよう。
60
+
61
+ 参考資料は [Ruby の公式サイト](https://www.ruby-lang.org/ja/) のようにリンクできます。
62
+
63
+ `[表示する文章](URL)` がリンクの書き方です。
64
+
65
+ <!-- page-footnote: リンクはクリックして開けます -->
66
+
67
+ <!-- notes:
68
+ 引用は行頭に > を付けて書きます。
69
+ この引用文は書き方を紹介するためのサンプルです。
70
+ -->
71
+
72
+ ---
73
+
74
+ # コードを見せる
75
+
76
+ ```ruby
77
+ topics = ["Markdown", "Ruby", "WebAssembly"]
78
+
79
+ topics.each do |topic|
80
+ puts "Hello, #{topic}!"
81
+ end
82
+ ```
83
+
84
+ 複数行のコードはバッククォート3つで囲みます。
85
+
86
+ <!-- notes:
87
+ フェンスに ruby と言語名を書けますが、構文ハイライトは行いません。
88
+ コード内の記号や改行はそのまま表示します。
89
+ -->
90
+
91
+ ---
92
+
93
+ # 表で比較する
94
+
95
+ | 書きたいもの | Markdown の記法 |
96
+ | --- | --- |
97
+ | ページのタイトル | `# タイトル` |
98
+ | 太字 | `**太字**` |
99
+ | 文中のコード | バッククォートで囲む |
100
+ | 次のページ | 空行を挟んだ `---` |
101
+
102
+ <!-- notes:
103
+ 表の見出しの次に、ハイフンで区切りの行を書きます。
104
+ 行数が多いときは、スライドを分けて読みやすくします。
105
+ -->
106
+
107
+ ---
108
+
109
+ # 画像で伝える
110
+
111
+ ![Markdown の原稿からブラウザーで発表し、PDF を配布する流れ](images/workflow.svg)
112
+
113
+ `![画像の説明](images/workflow.svg)` で画像を表示します。
114
+
115
+ <!-- page-footnote: サンプル画像は images/workflow.svg にあります -->
116
+
117
+ <!-- notes:
118
+ この図は wani new で原稿と一緒にコピーされる SVG です。
119
+ PNG、JPEG、WebP も使えます。自分の画像を images フォルダーに置いて差し替えてください。
120
+ パスは slides.md の場所を基準に書きます。
121
+ -->
122
+
123
+ ---
124
+
125
+ # 発表者ノートを書く
126
+
127
+ ```markdown
128
+ <!-- notes:
129
+ **デモの前に**、操作の流れを説明します。
130
+ -->
131
+ ```
132
+
133
+ N キーで、このページの実際のノートを確認できます。
134
+ ノートは発表者画面とノート付き PDF に表示します。
135
+
136
+ <!-- notes:
137
+ **デモの前に**、操作の流れを説明します。
138
+ これは発表者向けの補足です。通常のスライド本文には表示されません。
139
+ -->
140
+
141
+ ---
142
+
143
+ # ページに脚注を付ける
144
+
145
+ ```markdown
146
+ <!-- page-footnote: 出典:Wani サンプル資料 -->
147
+ ```
148
+
149
+ このページの下部に、実際の脚注を表示しています。
150
+ 出典や補足を、そのページだけに付けられます。
151
+
152
+ <!-- page-footnote: 出典:Wani サンプル資料 -->
153
+
154
+ <!-- notes:
155
+ コード欄は書き方の見本で、下部の脚注は実際のコメントから表示しています。
156
+ 脚注はプレーンテキストです。PDF にも表示されます。
157
+ -->
158
+
159
+ ---
160
+
161
+ # 発表と配布へ
162
+
163
+ - N キーで、このページの発表者ノートを開く
164
+ - 「PDF」でスライドを保存する
165
+ - 「ノート付き PDF」で説明も一緒に配布する
166
+
167
+ 原稿を自分のテーマに書き換えて、発表を始めましょう。
168
+
169
+ <!-- page-footnote: ご清聴ありがとうございました -->
170
+
171
+ <!-- notes:
172
+ ノートは通常のスライド本文には表示されません。
173
+ 発表者画面とノート付き PDF に表示します。
174
+
175
+ **最後に確認すること**
176
+
177
+ - 質問を受け付ける
178
+ - 参考資料の場所を伝える
179
+
180
+ ページごとの脚注は page-footnote コメントで指定します。
181
+ PDF には脚注とページ番号が残り、兎と鰐の装飾は表示されません。
182
+ -->
@@ -0,0 +1,30 @@
1
+ kramdown - fast, pure-Ruby Markdown-superset converter
2
+ Copyright (C) 2009-2013 Thomas Leitner <t_leitner@gmx.at>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a
5
+ copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included
13
+ in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+
24
+ Some test cases and the benchmark files are based on test cases from
25
+ the MDTest test suite:
26
+
27
+ MDTest
28
+ Copyright (c) 2007 Michel Fortin
29
+ <http://www.michelf.com/>
30
+
@@ -0,0 +1,21 @@
1
+ kramdown-parser-gfm
2
+ Copyright (C) 2019 Thomas Leitner <t_leitner@gmx.at>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a
5
+ copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included
13
+ in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,93 @@
1
+ Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+
5
+ This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,39 @@
1
+ # IBM Plex Sans JP
2
+
3
+ IBM の公式 npm パッケージ [`@ibm/plex-sans-jp@3.0.0`](https://www.npmjs.com/package/@ibm/plex-sans-jp/v/3.0.0)
4
+ から、以下の完成版 WOFF2 を変更せずに同梱する。
5
+
6
+ - `assets/fonts/IBMPlexSansJP-Regular.woff2`(400 / 2,282,284 bytes)
7
+ - `assets/fonts/IBMPlexSansJP-Bold.woff2`(700 / 2,352,756 bytes)
8
+
9
+ 元ファイルは `fonts/complete/woff2/hinted/` にある。サブセット化・改名・フォントデータの加工はしていない。
10
+ 出所・バージョン・配布アーカイブと各ファイルの SHA-256 は `provenance.json` に記録する。
11
+
12
+ Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"。
13
+ SIL Open Font License 1.1 により配布され、著作権表示とライセンス全文を `LICENSE.txt` に保持する。
14
+ アプリの MIT ライセンスとは区別する。
15
+
16
+ ## 取得の再現
17
+
18
+ ```sh
19
+ npm pack @ibm/plex-sans-jp@3.0.0 --pack-destination /tmp
20
+ ```
21
+
22
+ `provenance.json` のアーカイブ SHA-256 と照合して展開し、上記2ファイルとパッケージの `LICENSE.txt` を取り出す。
23
+ Wani の通常利用・ビルド時にフォントのダウンロードや OS インストールは不要。
24
+ 参照元: [IBM 公式リポジトリ](https://github.com/IBM/plex/tree/master/packages/plex-sans-jp)。
25
+
26
+ ## PDF の文字抽出
27
+
28
+ 検証した Chromium の PDF では、同じグリフに対応する文字が互換部首として抽出される場合がある
29
+ (例: `日` → `⽇`)。表示の字形とフォント埋め込みは確認し、内容比較のテストでは NFKC 正規化する。
30
+ PDF のテキストコピーが常に元のコードポイントと一致することまでは保証しない。
31
+
32
+ ## 動作検証 (2026-10-26)
33
+
34
+ Linux / Ruby 4.0.7 / Node.js 24.22.1 / Chrome 156.0.8078.47。
35
+ Ruby は12件・85アサーション、ブラウザーは13件成功(35.8秒)。
36
+ Chrome の実フォント情報で日本語の Regular / Bold と Web フォント使用を確認し、
37
+ 日本語 PDF の文字内容・Regular / Bold と FontFile2 の埋め込みを検査した。
38
+ 太字の取得先を壊すと実描画テストは失敗し、復元後はフォント検証3件が成功(9.2秒)。
39
+ 隔離環境の gem インストールでも2フォントのハッシュ一致、ライセンス同梱、HTTP配信を確認した。
@@ -0,0 +1,20 @@
1
+ {
2
+ "package": "@ibm/plex-sans-jp",
3
+ "version": "3.0.0",
4
+ "repository": "https://github.com/IBM/plex/tree/master/packages/plex-sans-jp",
5
+ "tarball": "https://registry.npmjs.org/@ibm/plex-sans-jp/-/plex-sans-jp-3.0.0.tgz",
6
+ "tarball_sha256": "051484321fcffecc69c3d608b739c5fe0f558b0fd1de7958d96ca360d161de7f",
7
+ "license": "OFL-1.1",
8
+ "files": {
9
+ "IBMPlexSansJP-Bold.woff2": {
10
+ "sha256": "38336fbb169ae1b7b6ca2539332e1d59c9be222227659d23f8eb70ecda60337d",
11
+ "bytes": 2352756,
12
+ "source_path": "fonts/complete/woff2/hinted/IBMPlexSansJP-Bold.woff2"
13
+ },
14
+ "IBMPlexSansJP-Regular.woff2": {
15
+ "sha256": "ec27e9b75cd90a6f7abe96ede49d00b151eb5b1c2c886bfe9b4fc845f40be1ff",
16
+ "bytes": 2282284,
17
+ "source_path": "fonts/complete/woff2/hinted/IBMPlexSansJP-Regular.woff2"
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Yuta Saito
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.