@cosense-toolbox/parser 0.1.0-beta.1 → 0.1.0-beta.3

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 (76) hide show
  1. package/README.md +45 -31
  2. package/dist/{ast-uYWtkHwT.cjs → ast-C0BGz7X2.cjs} +2 -2
  3. package/dist/ast-C0BGz7X2.cjs.map +1 -0
  4. package/dist/{ast-CIKXwSl5.mjs → ast-CMQYawYl.mjs} +2 -2
  5. package/dist/ast-CMQYawYl.mjs.map +1 -0
  6. package/dist/compile.cjs +2 -213
  7. package/dist/compile.cjs.map +1 -1
  8. package/dist/compile.d.cts +2 -129
  9. package/dist/compile.d.cts.map +1 -1
  10. package/dist/compile.d.mts +2 -129
  11. package/dist/compile.d.mts.map +1 -1
  12. package/dist/compile.mjs +3 -207
  13. package/dist/compile.mjs.map +1 -1
  14. package/dist/extensions.cjs +10 -7
  15. package/dist/extensions.cjs.map +1 -1
  16. package/dist/extensions.d.cts +12 -8
  17. package/dist/extensions.d.cts.map +1 -1
  18. package/dist/extensions.d.mts +12 -8
  19. package/dist/extensions.d.mts.map +1 -1
  20. package/dist/extensions.mjs +10 -7
  21. package/dist/extensions.mjs.map +1 -1
  22. package/dist/html.cjs +458 -0
  23. package/dist/html.cjs.map +1 -0
  24. package/dist/html.d.cts +274 -0
  25. package/dist/html.d.cts.map +1 -0
  26. package/dist/html.d.mts +274 -0
  27. package/dist/html.d.mts.map +1 -0
  28. package/dist/html.mjs +447 -0
  29. package/dist/html.mjs.map +1 -0
  30. package/dist/image-url-YcTed8tg.cjs.map +1 -1
  31. package/dist/image-url-eQ6X-oN0.mjs.map +1 -1
  32. package/dist/index-CrIlOW1k.d.mts +78 -0
  33. package/dist/index-CrIlOW1k.d.mts.map +1 -0
  34. package/dist/index-_o1STNhP.d.cts +78 -0
  35. package/dist/index-_o1STNhP.d.cts.map +1 -0
  36. package/dist/index.cjs +188 -35
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +4 -77
  39. package/dist/index.d.mts +4 -77
  40. package/dist/index.mjs +180 -27
  41. package/dist/index.mjs.map +1 -1
  42. package/dist/schema.cjs +1 -0
  43. package/dist/schema.cjs.map +1 -1
  44. package/dist/schema.d.cts +1 -1
  45. package/dist/schema.d.cts.map +1 -1
  46. package/dist/schema.d.mts +1 -1
  47. package/dist/schema.d.mts.map +1 -1
  48. package/dist/schema.mjs +1 -0
  49. package/dist/schema.mjs.map +1 -1
  50. package/dist/{types-CiwPj2R8.d.cts → types-CdiHju1P.d.mts} +15 -12
  51. package/dist/types-CdiHju1P.d.mts.map +1 -0
  52. package/dist/{types-9vAAFHka.d.mts → types-_-ZAyNkz.d.cts} +15 -12
  53. package/dist/types-_-ZAyNkz.d.cts.map +1 -0
  54. package/dist/{types-DmfFumcw.d.cts → types-gWMrsXPX.d.cts} +28 -21
  55. package/dist/{types-DmfFumcw.d.cts.map → types-gWMrsXPX.d.cts.map} +1 -1
  56. package/dist/{types-DmfFumcw.d.mts → types-gWMrsXPX.d.mts} +28 -21
  57. package/dist/{types-DmfFumcw.d.mts.map → types-gWMrsXPX.d.mts.map} +1 -1
  58. package/dist/utils.cjs +1 -1
  59. package/dist/utils.cjs.map +1 -1
  60. package/dist/utils.d.cts +2 -2
  61. package/dist/utils.d.cts.map +1 -1
  62. package/dist/utils.d.mts +2 -2
  63. package/dist/utils.d.mts.map +1 -1
  64. package/dist/utils.mjs +1 -1
  65. package/dist/utils.mjs.map +1 -1
  66. package/package.json +27 -5
  67. package/dist/ast-CIKXwSl5.mjs.map +0 -1
  68. package/dist/ast-uYWtkHwT.cjs.map +0 -1
  69. package/dist/decoration-DODaJKeA.cjs +0 -103
  70. package/dist/decoration-DODaJKeA.cjs.map +0 -1
  71. package/dist/decoration-Dq_5e20j.mjs +0 -68
  72. package/dist/decoration-Dq_5e20j.mjs.map +0 -1
  73. package/dist/index.d.cts.map +0 -1
  74. package/dist/index.d.mts.map +0 -1
  75. package/dist/types-9vAAFHka.d.mts.map +0 -1
  76. package/dist/types-CiwPj2R8.d.cts.map +0 -1
@@ -0,0 +1,274 @@
1
+ import { A as TableCell, C as NodeOfType, D as ProjectLink, M as TextNode, N as TitleBlock, b as InternalLink, c as CodeLine, d as FormulaNode, f as Hashtag, h as InlineCode, j as TableRow, k as TableBlock, l as Decoration, m as ImageNode, p as IconNode, r as AnyNodeType, s as CodeBlock, t as AnyNode, u as ExternalLink, w as Page, x as LineBlock } from "./types-gWMrsXPX.mjs";
2
+ import "./index-CrIlOW1k.mjs";
3
+ import { Element, ElementContent, Root, Text } from "hast";
4
+ //#region src/html/to-hast.d.ts
5
+ /** `href` に入れて安全な URL だけを返す。script が動くスキームなら null。 */
6
+ declare const safeHref: (url: string) => string | null;
7
+ /** `src` に入れて安全な URL だけを返す。script が動くスキームなら null。 */
8
+ declare const safeSrc: (url: string) => string | null;
9
+ /** プロジェクト内のページを指すノード。Cosense Web ではアイコンもユーザーのページへのリンクになる。 */
10
+ type PageRefNode = InternalLink | ProjectLink | Hashtag | IconNode;
11
+ /**
12
+ * 出力する要素に付ける class 名。指定したキーだけが既定を上書きする。
13
+ * 空文字にすると class 属性自体を出さない。
14
+ */
15
+ interface HtmlClassNames {
16
+ readonly page?: string;
17
+ readonly title?: string;
18
+ readonly line?: string;
19
+ /** 引用行の `<blockquote>` */
20
+ readonly quote?: string;
21
+ /** 等幅行の `<code>` */
22
+ readonly monospace?: string;
23
+ /** コードブロックに属する行 (ヘッダ行と本体行の両方) */
24
+ readonly codeBlock?: string;
25
+ /** ヘッダ行の `<code>` */
26
+ readonly codeStart?: string;
27
+ /** ヘッダ行に出るファイル名 */
28
+ readonly codeFilename?: string;
29
+ /** 本体行の `<code>` */
30
+ readonly codeBody?: string;
31
+ /** ハイライタを通した本体に追加で付く class */
32
+ readonly codeHighlight?: string;
33
+ readonly table?: string;
34
+ /** `showPads` のときだけ出る、インデントぶんの余白と中点をまとめる要素 */
35
+ readonly indentMark?: string;
36
+ /** インデント 1 段ぶんの余白 */
37
+ readonly pad?: string;
38
+ /** インデントの右端に置く中点 */
39
+ readonly dot?: string;
40
+ readonly internalLink?: string;
41
+ readonly externalLink?: string;
42
+ readonly projectLink?: string;
43
+ readonly hashtag?: string;
44
+ readonly inlineCode?: string;
45
+ readonly image?: string;
46
+ readonly icon?: string;
47
+ readonly formula?: string;
48
+ readonly decoration?: string;
49
+ }
50
+ /** 既定の class 名。接頭辞を持たないため、利用側の CSS と名前がぶつかりうる。 */
51
+ declare const defaultClassNames: HtmlClassNames;
52
+ /**
53
+ * HTML の文字列をそのまま入れるノード。`toHtml` はそのまま埋め込む (hast-util-to-html の raw ノード)。
54
+ * hast の型には無いので、ここで持つ。hast-util-to-html の型拡張に頼ると、
55
+ * `@types/hast` の版が分かれたときに型が合わなくなるため。
56
+ */
57
+ interface RawNode {
58
+ readonly type: "raw";
59
+ readonly value: string;
60
+ }
61
+ /** ハンドラやハイライタが返せるノード。hast の要素の中身か、raw ノード。 */
62
+ type HastContent = ElementContent | RawNode;
63
+ /**
64
+ * コードブロックの中身を色付けする。
65
+ *
66
+ * `language` はファイル名から推測した名前 (`codeLanguageOf`)。
67
+ * null を返すと色付けせず、1 行ずつのまま出す。知らない言語のときに使う。
68
+ *
69
+ * shiki の `codeToHast` のように `pre > code` を返したときは、code の中身を使い、
70
+ * pre の class と style (テーマの背景色や文字色) をコードブロックの code に移す。
71
+ * 行の要素 (`div.line`) の中に置くので、pre そのものは出さない。
72
+ */
73
+ type HastHighlighter = (code: string, language: string) => Root | HastContent[] | null;
74
+ /**
75
+ * 既定のハンドラの振る舞いを変えるオプション。
76
+ *
77
+ * `pageUrl` / `iconImageUrl` / `highlight` は、**記法に書かれていないので AST から導けない**
78
+ * 情報を外から渡すためのもの。残りは出力の見た目を調整する。
79
+ */
80
+ interface HastRenderOptions {
81
+ /**
82
+ * ページを指す記法 (`[title]` / `[/proj/page]` / `#tag` / `[user.icon]`) の遷移先。
83
+ * アイコンについてはリンク先だけを決め、画像は `iconImageUrl` が決める。
84
+ *
85
+ * `title` は記法に書かれたタイトルそのままで、`[title]` なら `title`、
86
+ * `[/proj/page]` なら `/proj/page`、`#tag` なら `tag`、`[user.icon]` なら `user`。
87
+ *
88
+ * @defaultValue `/{title}`。区切りを含むタイトルは区切りを残して各段を encode する
89
+ */
90
+ readonly pageUrl?: (title: string, node: PageRefNode) => string;
91
+ /**
92
+ * アイコンの画像 URL。null なら `<img>` を出さず、ユーザー名のテキストになる。
93
+ * リンク先のほうは `pageUrl` が決める。
94
+ *
95
+ * @defaultValue 常に null。Cosense Web の画像 URL (`/api/pages/{project}/{user}/icon`) は
96
+ * プロジェクト名を要するが、記法には書かれていないため
97
+ */
98
+ readonly iconImageUrl?: (node: IconNode) => string | null;
99
+ /**
100
+ * コードブロックの中身の色付け。渡すと、本体は 1 行 1 要素ではなく 1 つの要素にまとまる。
101
+ * ハイライタの出力が複数行にまたがる要素を含みうるため。
102
+ */
103
+ readonly highlight?: HastHighlighter;
104
+ /** 出力する要素に付ける class 名。 */
105
+ readonly classNames?: HtmlClassNames;
106
+ /**
107
+ * インデントを Cosense Web と同じ要素として書き出す。深さ 1 段につき `pad` が 1 つ並び、
108
+ * その右端に中点が付く。
109
+ *
110
+ * @defaultValue false。深さは行の `data-indent` 属性だけで表す
111
+ */
112
+ readonly showPads?: boolean;
113
+ }
114
+ /** オプションの既定値を埋めたもの。ハンドラは `ctx.options` でこれを読む。 */
115
+ interface ResolvedHastOptions {
116
+ readonly pageUrl: (title: string, node: PageRefNode) => string;
117
+ readonly iconImageUrl: (node: IconNode) => string | null;
118
+ readonly highlight: HastHighlighter | null;
119
+ /** 既定の class 名に、指定したものを重ねたもの */
120
+ readonly classNames: HtmlClassNames;
121
+ readonly showPads: boolean;
122
+ }
123
+ /** ハンドラの中から再帰的に変換するための入口と、オプション。 */
124
+ interface HastContext {
125
+ /**
126
+ * 今描いているノードの祖先。根 (`toHast` に渡したノード) から親までの順に並ぶ。
127
+ * 「テーブルのセルの中の text だけ」のように、どこにあるかで出力を変えるときに使う。
128
+ */
129
+ readonly ancestors: readonly AnyNode[];
130
+ /** ノード 1 つを変換する (そのノード型のハンドラを通る) */
131
+ readonly node: (node: AnyNode) => ElementContent[];
132
+ /** 子ノードをすべて変換し、平らな配列で返す */
133
+ readonly children: (node: AnyNode) => ElementContent[];
134
+ readonly options: ResolvedHastOptions;
135
+ }
136
+ type HastHandler<K extends AnyNodeType> = (node: NodeOfType<K>, ctx: HastContext) => HastContent | HastContent[];
137
+ /**
138
+ * ノード型 → ハンドラの対応。`AnyNodeMap` から型を導出しているので、
139
+ * ノード型が増えたら (declaration merging を含む) ここも自動で新しいキーを受け入れる。
140
+ */
141
+ type HastHandlers = { readonly [K in AnyNodeType]?: HastHandler<K>; };
142
+ /**
143
+ * 描画の拡張の 1 段。そのノード型の、ここまでの出力 (既定のハンドラか `handlers`、
144
+ * 先に並べた拡張を通したもの) を受け取り、新しい出力を返す。
145
+ * vite の `transform` と同じく、前の段の出力をもらって加工するだけの関数にしている。
146
+ * 出力を一から作るのは `handlers` の役目なので、拡張では作り直さない。
147
+ */
148
+ type RenderTransform<K extends AnyNodeType> = (output: ElementContent[], node: NodeOfType<K>, ctx: HastContext) => HastContent | HastContent[];
149
+ /**
150
+ * 描画の拡張。ノード型ごとに `RenderTransform` を持つ。
151
+ * 行番号 (`codeLineNumbers`) のように、既定の出力に手を加えるものをまとめて配るための形。
152
+ */
153
+ type RenderExtension = { readonly [K in AnyNodeType]?: RenderTransform<K>; };
154
+ interface HastOptions extends HastRenderOptions {
155
+ /**
156
+ * ノード型ごとの出力の置き換え。指定した型だけが差し替わる。
157
+ * 出力を一から作りたいときに使う。できた出力に手を加えるだけなら `extensions` を使う。
158
+ */
159
+ readonly handlers?: HastHandlers;
160
+ /**
161
+ * 描画の拡張。`handlers` の後に、並べた順に出力を加工する。
162
+ * 前の拡張の出力が次の拡張に渡るので、同じノード型に触る拡張どうしも重ねられる。
163
+ */
164
+ readonly extensions?: readonly RenderExtension[];
165
+ }
166
+ /**
167
+ * コードブロックのファイル名から言語名を推測する。拡張子があればそれ、無ければファイル名全体。
168
+ * Cosense では `code:python` のように言語名だけを書くこともできるため。
169
+ * `highlight` に渡る言語名はこれで決めている。
170
+ */
171
+ declare const codeLanguageOf: (filename: string) => string;
172
+ /**
173
+ * `pageUrl` の既定の実装。`/proj/page` のように区切りを含むタイトルは、
174
+ * 区切りを残したまま各段を encode する。
175
+ */
176
+ declare const defaultPageUrl: (title: string) => string;
177
+ /**
178
+ * 既定のハンドラ一式。`toHast` はこれに `handlers` を重ねてから走らせる。
179
+ *
180
+ * cosense-x のように描画を組み立て直すライブラリが、既定の部品 (行の包み方など) を使い回すためのもの。
181
+ * 既定の出力に手を加えるだけなら、これを呼ばずに `extensions` を使う。
182
+ * オプションは `ctx.options` から読むので、呼ぶ側が渡し直さなくてよい。
183
+ */
184
+ declare const defaultHastHandlers: {
185
+ page: (node: Page, ctx: HastContext) => Element[];
186
+ title: (node: TitleBlock, ctx: HastContext) => Element[];
187
+ line: (node: LineBlock, ctx: HastContext) => Element[];
188
+ codeBlock: (node: CodeBlock, ctx: HastContext) => ElementContent[];
189
+ codeLine: (node: CodeLine) => Text[];
190
+ table: (node: TableBlock, ctx: HastContext) => Element[];
191
+ tableRow: (node: TableRow, ctx: HastContext) => Element[];
192
+ tableCell: (node: TableCell, ctx: HastContext) => Element[];
193
+ text: (node: TextNode) => Text[];
194
+ internalLink: (node: InternalLink, ctx: HastContext) => Element[];
195
+ externalLink: (node: ExternalLink, ctx: HastContext) => Element[];
196
+ projectLink: (node: ProjectLink, ctx: HastContext) => Element[];
197
+ hashtag: (node: Hashtag, ctx: HastContext) => Element[];
198
+ inlineCode: (node: InlineCode, ctx: HastContext) => Element[];
199
+ image: (node: ImageNode, ctx: HastContext) => Element[];
200
+ icon: (node: IconNode, ctx: HastContext) => Element[];
201
+ formula: (node: FormulaNode, ctx: HastContext) => Element[];
202
+ decoration: (node: Decoration, ctx: HastContext) => Element[];
203
+ };
204
+ /**
205
+ * ページ (または任意のノード) を hast にする。
206
+ *
207
+ * 1 つのノードは「既定のハンドラ (`handlers` があれば置き換え)」で作り、`extensions` を並べた順に通す。
208
+ * テキストは hast のテキストノードに入れるだけなので、エスケープは文字列にする側 (`toHtml`) が行う。
209
+ * `javascript:` のようなスキームの URL は属性ごと落とす。
210
+ * ハンドラの無いノード型 (拡張が足した独自ノード) は、中身を落とさずに子だけを出す。
211
+ */
212
+ declare const toHast: (node: AnyNode, options?: HastOptions) => Root;
213
+ //#endregion
214
+ //#region src/html/to-html.d.ts
215
+ /**
216
+ * `& < > " '` を実体参照に置き換える。テキストと属性値のどちらにも使える。
217
+ * `highlight` に HTML の文字列を返すハイライタを渡すとき、色付けしない部分のエスケープに使う。
218
+ */
219
+ declare const escapeHtml: (value: string) => string;
220
+ /**
221
+ * コードブロックの中身を色付けする。`toHast` の `highlight` に加えて、HTML の文字列も返せる。
222
+ * **文字列はそのまま埋め込まれる**ため、エスケープは実装側の責任になる。
223
+ * highlight.js や Prism のように HTML の文字列を返すハイライタを、そのまま渡せるようにするため。
224
+ */
225
+ type Highlighter = (code: string, language: string) => string | Root | HastContent[] | null;
226
+ interface HtmlOptions extends Omit<HastOptions, "highlight"> {
227
+ /** コードブロックの中身の色付け。 */
228
+ readonly highlight?: Highlighter;
229
+ /**
230
+ * 出力の先頭に `<style>` 要素として差し込む CSS。
231
+ *
232
+ * @defaultValue undefined。`<style>` を出さない
233
+ */
234
+ readonly style?: string;
235
+ }
236
+ /**
237
+ * ページ (または任意のノード) を HTML 文字列にする。`hast-util-to-html(toHast(node, options))` と同じ。
238
+ *
239
+ * テキストと属性値はエスケープし、`javascript:` のようなスキームの URL は属性ごと落とす。
240
+ * `highlight` が返した文字列と、`handlers` が返した raw ノードはそのまま埋め込むので、
241
+ * そこでのエスケープは書いた人の責任になる。
242
+ */
243
+ declare const toHtml: (node: AnyNode, options?: HtmlOptions) => string;
244
+ //#endregion
245
+ //#region src/html/code-line-numbers.d.ts
246
+ /**
247
+ * コードブロックの本体行に、1 から数えた行番号 (`data-line`) と桁数 (`data-line-digits`) を付ける拡張。
248
+ *
249
+ * ```ts
250
+ * toHtml(page, { extensions: [codeLineNumbers()] })
251
+ * ```
252
+ *
253
+ * 番号を見せるのは CSS の役目 (`@cosense-toolbox/style` は `data-line` を見て行の左に番号を出す)。
254
+ * 色付けしてひと塊にまとめたブロックは、行と番号が対応しないので付けない。
255
+ */
256
+ declare const codeLineNumbers: () => RenderExtension;
257
+ //#endregion
258
+ //#region src/html/table-cell-line-breaks.d.ts
259
+ /**
260
+ * テーブルのセルの中の `marker` を `<br>` にする描画の拡張。
261
+ *
262
+ * 当てるのは、セルの中にある AST の text ノード (記法の外の地の文) だけ。
263
+ * コード・数式・リンクの表示は text ノードではないので、`classNames` や `handlers` で
264
+ * 出力を変えても、その中には当たらない。装飾の中身は text ノードなので当たる。
265
+ * `marker` は文字列そのままで探し (正規表現としては読まない)、区切った文字は通常どおりエスケープされる。
266
+ * `marker` が空文字なら何もしない。
267
+ *
268
+ * @example
269
+ * toHtml(page, { extensions: [tableCellLineBreaks('\\n')] })
270
+ */
271
+ declare const tableCellLineBreaks: (marker: string) => RenderExtension;
272
+ //#endregion
273
+ export { type HastContent, type HastContext, type HastHandler, type HastHandlers, type HastHighlighter, type HastOptions, type HastRenderOptions, type Highlighter, type HtmlClassNames, type HtmlOptions, type PageRefNode, type RawNode, type RenderExtension, type RenderTransform, type ResolvedHastOptions, codeLanguageOf, codeLineNumbers, defaultClassNames, defaultHastHandlers, defaultPageUrl, escapeHtml, safeHref, safeSrc, tableCellLineBreaks, toHast, toHtml };
274
+ //# sourceMappingURL=html.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.mts","names":[],"sources":["../src/html/to-hast.ts","../src/html/to-html.ts","../src/html/code-line-numbers.ts","../src/html/table-cell-line-breaks.ts"],"mappings":";;;;;cA+Ca,WAAY;;cAGZ,UAAW;;KAcZ,cAAc,eAAe,cAAc,UAAU;;;;;UAMhD;WACN;WACA;WACA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;WACA;;WAEA;;WAEA;;WAEA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;;cAIE,mBAAmB;;;;;;UA+Bf;WACN;WACA;;;KAIC,cAAc,iBAAiB;;;;;;;;;;;KAY/B,mBAAmB,cAAc,qBAAqB,OAAO;;;;;;;UAQxD;;;;;;;;;;WAUN,WAAW,eAAe,MAAM;;;;;;;;WAQhC,gBAAgB,MAAM;;;;;WAKtB,YAAY;;WAEZ,aAAa;;;;;;;WAOb;;;UAIM;WACN,UAAU,eAAe,MAAM;WAC/B,eAAe,MAAM;WACrB,WAAW;;WAEX,YAAY;WACZ;;;UAIM;;;;;WAKN,oBAAoB;;WAEpB,OAAO,MAAM,YAAY;;WAEzB,WAAW,MAAM,YAAY;WAC7B,SAAS;;KAGR,YAAY,UAAU,gBAChC,MAAM,WAAW,IACjB,KAAK,gBACF,cAAc;;;;;KAMP,2BACA,KAAK,eAAe,YAAY;;;;;;;KAShC,gBAAgB,UAAU,gBACpC,QAAQ,kBACR,MAAM,WAAW,IACjB,KAAK,gBACF,cAAc;;;;;KAMP,8BACA,KAAK,eAAe,gBAAgB;UAG/B,oBAAoB;;;;;WAK1B,WAAW;;;;;WAKX,sBAAsB;;;;;;;cAQpB,iBAAkB;;;;;cASlB,iBAAkB;;;;;;;;cAoQlB;eAAA;;;EA3DY,YAAA,MAAA,WAAS,KAAO,gBAAc;mBAAA;;;;;;;;;;;;;;;;;;;;;;;cAqN1C,SAAU,MAAM,SAAS,UAAS,gBAAmB;;;;;;;cCjqBrD,aAAc;;;;;;KAQf,eAAe,cAAc,8BAA8B,OAAO;UAE7D,oBAAoB,KAAK;;WAE/B,YAAY;;;;;;WAMZ;;;;;;;;;cAkBE,SAAU,MAAM,SAAS,UAAS;;;;;;;;;;;;;cCVlC,uBAAsB;;;;;;;;;;;;;;;cCItB,sBAAuB,mBAAiB"}