relaton-nist 1.20.4 → 2.0.0.pre.alpha.1
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +1 -1
- data/CLAUDE.md +96 -0
- data/README.adoc +71 -73
- data/grammars/basicdoc.rng +1559 -671
- data/grammars/biblio-standoc.rng +107 -46
- data/grammars/biblio.rng +1010 -375
- data/grammars/relaton-nist.rng +13 -33
- data/lib/relaton/nist/bibdata.rb +7 -0
- data/lib/relaton/nist/bibitem.rb +7 -0
- data/lib/relaton/nist/bibliography.rb +168 -0
- data/lib/relaton/nist/comment_period.rb +15 -0
- data/lib/relaton/nist/data_fetcher.rb +74 -0
- data/lib/relaton/nist/date.rb +7 -0
- data/lib/relaton/nist/doctype.rb +7 -0
- data/lib/relaton/nist/ext.rb +20 -0
- data/lib/relaton/nist/hit.rb +18 -0
- data/lib/relaton/nist/hit_collection.rb +286 -0
- data/lib/relaton/nist/item.rb +17 -0
- data/lib/relaton/nist/item_data.rb +6 -0
- data/lib/relaton/nist/mods_parser.rb +249 -0
- data/lib/relaton/nist/processor.rb +66 -0
- data/lib/relaton/nist/pubs_export.rb +69 -0
- data/lib/relaton/nist/relation.rb +7 -0
- data/lib/relaton/nist/scraper.rb +290 -0
- data/lib/relaton/nist/tech_pubs_parser.rb +321 -0
- data/lib/relaton/nist/util.rb +8 -0
- data/lib/relaton/nist/version.rb +5 -0
- data/lib/relaton/nist.rb +30 -0
- data/relaton_nist.gemspec +9 -7
- metadata +61 -32
- data/lib/relaton_nist/comment_period.rb +0 -49
- data/lib/relaton_nist/data_fetcher.rb +0 -97
- data/lib/relaton_nist/document_relation.rb +0 -5
- data/lib/relaton_nist/document_status.rb +0 -24
- data/lib/relaton_nist/hash_converter.rb +0 -51
- data/lib/relaton_nist/hit.rb +0 -42
- data/lib/relaton_nist/hit_collection.rb +0 -301
- data/lib/relaton_nist/mods_parser.rb +0 -223
- data/lib/relaton_nist/nist_bibliographic_item.rb +0 -128
- data/lib/relaton_nist/nist_bibliography.rb +0 -189
- data/lib/relaton_nist/processor.rb +0 -58
- data/lib/relaton_nist/pubs_export.rb +0 -65
- data/lib/relaton_nist/scrapper.rb +0 -265
- data/lib/relaton_nist/tech_pubs_parser.rb +0 -308
- data/lib/relaton_nist/util.rb +0 -6
- data/lib/relaton_nist/version.rb +0 -3
- data/lib/relaton_nist/xml_parser.rb +0 -51
- data/lib/relaton_nist.rb +0 -29
- /data/lib/{relaton_nist → relaton/nist}/series.yaml +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c03d23fadbcef92134d86d7df992c92c185202d0385d0a788944a281e69dd2c4
|
|
4
|
+
data.tar.gz: 05ea6538b1c9383a3ce1df1636bedfc4b044115d335b09d34b72a8ca60ca858c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7f20c86344e122030a98651429bbf43559b2d0955ebbd5697f071c20421996f2bad161b0967bc6171888251bcbd77d3b8c615803d17b93de08162734a7a79c71
|
|
7
|
+
data.tar.gz: fd93a125142aa2274f8bb0d00825cde4d21ba701529e112c998c61b3f698a36506d44f449b80072dde7270c9dfb01cb1b5fe066df0be8da3edae499abcfd36ec
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
relaton-nist is a Ruby gem that retrieves and manages NIST (National Institute of Standards and Technology) bibliographic metadata as part of the Relaton ecosystem. Data sources include the NIST Cybersecurity Resource Center (CSRC) and the NIST Library (MARC21/MODS XML).
|
|
8
|
+
|
|
9
|
+
## Development Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install dependencies
|
|
13
|
+
bundle install
|
|
14
|
+
|
|
15
|
+
# Run all tests (any of these)
|
|
16
|
+
rake
|
|
17
|
+
rake spec
|
|
18
|
+
bundle exec rspec
|
|
19
|
+
|
|
20
|
+
# Run a single test file
|
|
21
|
+
bundle exec rspec spec/relaton/nist/item_spec.rb
|
|
22
|
+
|
|
23
|
+
# Run a specific test by line number
|
|
24
|
+
bundle exec rspec spec/relaton/nist/item_spec.rb:10
|
|
25
|
+
|
|
26
|
+
# Interactive console with gem loaded
|
|
27
|
+
bin/console
|
|
28
|
+
|
|
29
|
+
# Lint (uses Ribose OSS rubocop config)
|
|
30
|
+
bundle exec rubocop
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Architecture
|
|
34
|
+
|
|
35
|
+
### Module Structure
|
|
36
|
+
|
|
37
|
+
All classes live under `Relaton::Nist` (entry point: `require 'relaton/nist'`).
|
|
38
|
+
|
|
39
|
+
### Lutaml-Model Serialization
|
|
40
|
+
|
|
41
|
+
All data models inherit from `Lutaml::Model::Serializable` and use declarative attribute/mapping DSL for XML and YAML serialization. The base bibliographic types come from `relaton-bib` (aliased as `Bib`).
|
|
42
|
+
|
|
43
|
+
**Core model hierarchy**:
|
|
44
|
+
- `Bib::Item` → `Relaton::Nist::Item` (`model ItemData`)
|
|
45
|
+
- `Relaton::Nist::Bibitem` (includes `Bib::BibitemShared`)
|
|
46
|
+
- `Relaton::Nist::Bibdata` (includes `Bib::BibdataShared`)
|
|
47
|
+
- `Bib::ItemData` → `Relaton::Nist::ItemData`
|
|
48
|
+
|
|
49
|
+
**NIST-specific extensions** (under `lib/relaton/nist/`):
|
|
50
|
+
- `Ext` — extension block holding doctype, comment period (extends `Bib::Ext`)
|
|
51
|
+
- `Date` — adds `abandoned` and `superseded` date types (extends `Bib::Date`)
|
|
52
|
+
- `Relation` — adds `obsoletedBy`, `supersedes`, `supersededBy` relation types (extends `Bib::Relation`)
|
|
53
|
+
- `CommentPeriod` — from/to/extended date ranges (extends `Lutaml::Model::Serializable`)
|
|
54
|
+
- `Doctype` — currently only `standard` (extends `Bib::Doctype`)
|
|
55
|
+
|
|
56
|
+
**Search/retrieval layer** (extends `relaton-core`):
|
|
57
|
+
- `Bibliography` — class methods `search(text, year, opts)` and `get(code, year, opts)`
|
|
58
|
+
- `HitCollection` < `Core::HitCollection` — searches GitHub index + CSRC JSON
|
|
59
|
+
- `Hit` < `Core::Hit` — lazily resolves items via `Scraper`
|
|
60
|
+
- `Processor` < `Core::Processor` — Relaton plugin interface (`get`, `fetch_data`, `from_xml`, `from_yaml`)
|
|
61
|
+
|
|
62
|
+
**Data fetching/parsing**:
|
|
63
|
+
- `DataFetcher` < `Core::DataFetcher` — fetches NIST Tech Pubs MODS XML from GitHub releases
|
|
64
|
+
- `ModsParser` — maps MODS XML (via `loc_mods`) to `ItemData`
|
|
65
|
+
- `Scraper` — fetches items from GitHub YAML or CSRC JSON
|
|
66
|
+
- `PubsExport` — singleton; caches CSRC pubs-export zip with thread-safe daily updates
|
|
67
|
+
|
|
68
|
+
### Serialization Round-Trip Pattern
|
|
69
|
+
|
|
70
|
+
Models support `from_xml`/`to_xml` and `from_yaml`/`to_yaml`. Tests verify round-trip fidelity by parsing a fixture, re-serializing, and comparing output to input.
|
|
71
|
+
|
|
72
|
+
### XML Schema Validation
|
|
73
|
+
|
|
74
|
+
RNG (Relax NG) schemas in `grammars/` validate XML output. Tests use the `jing` gem:
|
|
75
|
+
```ruby
|
|
76
|
+
schema = Jing.new("grammars/relaton-nist-compile.rng")
|
|
77
|
+
errors = schema.validate(file)
|
|
78
|
+
```
|
|
79
|
+
`relaton-nist-compile.rng` is the top-level schema that includes `relaton-nist.rng` and `basicdoc.rng`.
|
|
80
|
+
|
|
81
|
+
### HTTP Recording
|
|
82
|
+
|
|
83
|
+
Tests use VCR with WebMock. Cassettes are stored in `spec/vcr_cassettes/` and re-record every 7 days.
|
|
84
|
+
|
|
85
|
+
## Key Dependencies
|
|
86
|
+
|
|
87
|
+
- `relaton-bib` — base bibliographic models and shared mixins
|
|
88
|
+
- `relaton-core` — base classes for Processor, HitCollection, Hit, DataFetcher
|
|
89
|
+
- `loc_mods` — MODS (Metadata Object Description Schema) XML parsing
|
|
90
|
+
- `pubid` — NIST publication ID parsing
|
|
91
|
+
- `relaton-index` — index/search utilities
|
|
92
|
+
- `mechanize` — HTTP fetching for data sources
|
|
93
|
+
|
|
94
|
+
## Code Style
|
|
95
|
+
|
|
96
|
+
RuboCop config inherits from the Ribose OSS style guide. Target Ruby version is 3.1.
|
data/README.adoc
CHANGED
|
@@ -98,7 +98,7 @@ Or install it yourself as:
|
|
|
98
98
|
|
|
99
99
|
[source,sh]
|
|
100
100
|
----
|
|
101
|
-
$ gem install
|
|
101
|
+
$ gem install relaton-nist
|
|
102
102
|
----
|
|
103
103
|
|
|
104
104
|
== Usage
|
|
@@ -120,19 +120,16 @@ https://www.nist.gov/news-events/news/2021/08/nist-technical-series-publications
|
|
|
120
120
|
====
|
|
121
121
|
[source,ruby]
|
|
122
122
|
----
|
|
123
|
-
|
|
124
|
-
=>
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
[relaton-nist] (NIST IR 8200) Fetching from
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
> item = hit_collection[0].fetch
|
|
134
|
-
=>
|
|
135
|
-
#<RelatonNist::NistBibliographicItem:0x007fc049aa6778
|
|
123
|
+
require 'relaton/nist'
|
|
124
|
+
=> true
|
|
125
|
+
|
|
126
|
+
hit_collection = Relaton::Nist::Bibliography.search("NISTIR 8200")
|
|
127
|
+
[relaton-nist] INFO: (NIST IR 8200) Fetching from csrc.nist.gov ...
|
|
128
|
+
[relaton-nist] INFO: (NIST IR 8200) Fetching from Relaton repository ...
|
|
129
|
+
=> <Relaton::Nist::HitCollection:0x00000000002c10 @ref=NIST IR 8200 @fetched=false>
|
|
130
|
+
|
|
131
|
+
item = hit_collection[0].item
|
|
132
|
+
=> #<Relaton::Nist::ItemData:0x000000012c1d8008
|
|
136
133
|
# ...
|
|
137
134
|
----
|
|
138
135
|
====
|
|
@@ -146,12 +143,11 @@ revisions or editions.
|
|
|
146
143
|
====
|
|
147
144
|
[source,ruby]
|
|
148
145
|
----
|
|
149
|
-
|
|
150
|
-
[relaton-nist] (NIST
|
|
151
|
-
[relaton-nist] (NIST IR 8200
|
|
152
|
-
[relaton-nist] (NIST IR 8200
|
|
153
|
-
=>
|
|
154
|
-
#<RelatonNist::NistBibliographicItem:0x00007fab74a572c0
|
|
146
|
+
Relaton::Nist::Bibliography.get("NIST IR 8200", "2018")
|
|
147
|
+
[relaton-nist] INFO: (NIST IR 8200) Fetching from csrc.nist.gov ...
|
|
148
|
+
[relaton-nist] INFO: (NIST IR 8200) Fetching from Relaton repository ...
|
|
149
|
+
[relaton-nist] INFO: (NIST IR 8200) Found: `NIST IR 8200`
|
|
150
|
+
=> #<Relaton::Nist::ItemData:0x000000012c5e7590
|
|
155
151
|
# ...
|
|
156
152
|
----
|
|
157
153
|
====
|
|
@@ -170,14 +166,14 @@ A NIST PubID can contain these optional parameters `{ptN}{vN}{verN}{rN}{/Add}`:
|
|
|
170
166
|
====
|
|
171
167
|
[source,ruby]
|
|
172
168
|
----
|
|
173
|
-
item =
|
|
174
|
-
[relaton-nist] (NIST SP 800-67r1) Fetching from csrc.nist.gov ...
|
|
175
|
-
[relaton-nist] (NIST SP 800-67r1) Found: `NIST SP 800-
|
|
176
|
-
=> #<
|
|
169
|
+
item = Relaton::Nist::Bibliography.get 'NIST SP 800-67r1'
|
|
170
|
+
[relaton-nist] INFO: (NIST SP 800-67r1) Fetching from csrc.nist.gov ...
|
|
171
|
+
[relaton-nist] INFO: (NIST SP 800-67r1) Found: `NIST SP 800-67r1 fpd`
|
|
172
|
+
=> #<Relaton::Nist::ItemData:0x000000012cf294c8
|
|
177
173
|
...
|
|
178
174
|
|
|
179
|
-
item.docidentifier.first.
|
|
180
|
-
=> "NIST SP 800-
|
|
175
|
+
item.docidentifier.first.content
|
|
176
|
+
=> "NIST SP 800-67r1 fpd"
|
|
181
177
|
----
|
|
182
178
|
====
|
|
183
179
|
|
|
@@ -186,14 +182,14 @@ item.docidentifier.first.id
|
|
|
186
182
|
====
|
|
187
183
|
[source,ruby]
|
|
188
184
|
----
|
|
189
|
-
item =
|
|
190
|
-
[relaton-nist] (NIST SP 800-38A
|
|
191
|
-
[relaton-nist] (NIST SP 800-38A
|
|
192
|
-
=> #<
|
|
185
|
+
item = Relaton::Nist::Bibliography.get 'NIST SP 800-38A/Add'
|
|
186
|
+
[relaton-nist] INFO: (NIST SP 800-38A Add) Fetching from csrc.nist.gov ...
|
|
187
|
+
[relaton-nist] INFO: (NIST SP 800-38A Add) Found: `NIST SP 800-38A fpd Add`
|
|
188
|
+
=> #<Relaton::Nist::ItemData:0x0000000124864190
|
|
193
189
|
...
|
|
194
190
|
|
|
195
|
-
item.docidentifier.first.
|
|
196
|
-
=> "NIST SP 800-38A
|
|
191
|
+
item.docidentifier.first.content
|
|
192
|
+
=> "NIST SP 800-38A fpd Add"
|
|
197
193
|
----
|
|
198
194
|
====
|
|
199
195
|
|
|
@@ -225,11 +221,10 @@ In case the state is "draft" it should be:
|
|
|
225
221
|
====
|
|
226
222
|
[source,ruby]
|
|
227
223
|
----
|
|
228
|
-
|
|
229
|
-
[relaton-nist] (NIST SP 800-205) Fetching from csrc.nist.gov ...
|
|
230
|
-
[relaton-nist] (NIST SP 800-205) Found: `NIST SP 800-205
|
|
231
|
-
=>
|
|
232
|
-
#<RelatonNist::NistBibliographicItem:0x00000001105afdc8
|
|
224
|
+
Relaton::Nist::Bibliography.get("NIST SP 800-205 (February 2019) (IPD)")
|
|
225
|
+
[relaton-nist] INFO: (NIST SP 800-205) Fetching from csrc.nist.gov ...
|
|
226
|
+
[relaton-nist] INFO: (NIST SP 800-205) Found: `NIST SP 800-205 ipd`
|
|
227
|
+
=> #<Relaton::Nist::ItemData:0x000000012494fb40
|
|
233
228
|
# ...
|
|
234
229
|
----
|
|
235
230
|
====
|
|
@@ -247,11 +242,10 @@ The format for FIPS publications is:
|
|
|
247
242
|
====
|
|
248
243
|
[source,ruby]
|
|
249
244
|
----
|
|
250
|
-
|
|
245
|
+
Relaton::Nist::Bibliography.get("NIST FIPS 140-3")
|
|
251
246
|
[relaton-nist] INFO: (NIST FIPS 140-3) Fetching from csrc.nist.gov ...
|
|
252
|
-
[relaton-nist] INFO: (NIST FIPS 140-3) Found: `NIST FIPS 140-3`
|
|
253
|
-
=>
|
|
254
|
-
# #<RelatonNist::NistBibliographicItem:0x000000013b68fb50
|
|
247
|
+
[relaton-nist] INFO: (NIST FIPS 140-3) Found: `NIST FIPS 140-3 2pd`
|
|
248
|
+
=> #<Relaton::Nist::ItemData:0x0000000124d8dfe0
|
|
255
249
|
# ...
|
|
256
250
|
----
|
|
257
251
|
====
|
|
@@ -266,12 +260,16 @@ The format for FIPS publications is:
|
|
|
266
260
|
====
|
|
267
261
|
[source,ruby]
|
|
268
262
|
----
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
263
|
+
item.to_xml
|
|
264
|
+
=> "<bibitem id="NISTSP80038AfpdAdd" type="standard" schema-version="v1.4.1">
|
|
265
|
+
<fetched>2026-02-26</fetched>
|
|
266
|
+
<title language="en" script="Latn">Recommendation for Block Cipher Modes of Operation - Three Variants of Ciphertext Stealing for CBC Mode</title>
|
|
267
|
+
<uri type="src">https://csrc.nist.gov/pubs/sp/800/38/a/sup/final</uri>
|
|
268
|
+
<uri type="doi">https://doi.org/10.6028/NIST.SP.800-38A-Add</uri>
|
|
269
|
+
<docidentifier type="NIST" primary="true">NIST SP 800-38A fpd Add</docidentifier>
|
|
270
|
+
<docidentifier type="DOI">NIST.SP.800-38A-Add</docidentifier>
|
|
271
|
+
...
|
|
272
|
+
</bibitem>"
|
|
275
273
|
----
|
|
276
274
|
====
|
|
277
275
|
|
|
@@ -283,16 +281,20 @@ the `bibdata` element and adds a flavor-specific `ext` element.
|
|
|
283
281
|
====
|
|
284
282
|
[source,ruby]
|
|
285
283
|
----
|
|
286
|
-
|
|
287
|
-
=>
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
284
|
+
item.to_xml bibdata: true
|
|
285
|
+
=> "<bibdata type="standard" schema-version="v1.4.1">
|
|
286
|
+
<fetched>2026-02-26</fetched>
|
|
287
|
+
<title language="en" script="Latn">Recommendation for Block Cipher Modes of Operation - Three Variants of Ciphertext Stealing for CBC Mode</title>
|
|
288
|
+
<uri type="src">https://csrc.nist.gov/pubs/sp/800/38/a/sup/final</uri>
|
|
289
|
+
<uri type="doi">https://doi.org/10.6028/NIST.SP.800-38A-Add</uri>
|
|
290
|
+
<docidentifier type="NIST" primary="true">NIST SP 800-38A fpd Add</docidentifier>
|
|
291
|
+
<docidentifier type="DOI">NIST.SP.800-38A-Add</docidentifier>
|
|
292
|
+
...
|
|
293
|
+
<ext schema-version="v1.0.0">
|
|
294
|
+
<doctype>standard</doctype>
|
|
295
|
+
<flavor>nist</flavor>
|
|
296
|
+
</ext>
|
|
297
|
+
</bibdata>
|
|
296
298
|
----
|
|
297
299
|
====
|
|
298
300
|
|
|
@@ -318,18 +320,16 @@ They can be accessed through the following methods:
|
|
|
318
320
|
NIST publications may have `src` and `doi` links, obtained using the `#link`
|
|
319
321
|
method.
|
|
320
322
|
|
|
321
|
-
.Accessing links of a NIST bibliographic item
|
|
323
|
+
.Accessing source links of a NIST bibliographic item
|
|
322
324
|
[example]
|
|
323
325
|
====
|
|
324
326
|
[source,ruby]
|
|
325
327
|
----
|
|
326
|
-
item.
|
|
327
|
-
=>
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
@type="src">,
|
|
332
|
-
#<RelatonBib::TypedUri:0x00000001110879a8 @content=#<Addressable::URI:0x8d4 URI:https://doi.org/10.6028/NIST.SP.800-38A-Add>, @language=nil, @script=nil, @type="doi">]
|
|
328
|
+
item.source[0].type
|
|
329
|
+
=> "src"
|
|
330
|
+
|
|
331
|
+
item.source[0].content
|
|
332
|
+
=> "https://csrc.nist.gov/pubs/sp/800/38/a/sup/final"
|
|
333
333
|
----
|
|
334
334
|
====
|
|
335
335
|
|
|
@@ -347,12 +347,8 @@ Offline Relaton YAML files can be loaded directly as bibliographic items.
|
|
|
347
347
|
====
|
|
348
348
|
[source,ruby]
|
|
349
349
|
----
|
|
350
|
-
|
|
351
|
-
=>
|
|
352
|
-
...
|
|
353
|
-
|
|
354
|
-
RelatonNist::NistBibliographicItem.from_hash hash
|
|
355
|
-
=> #<RelatonNist::NistBibliographicItem:0x007f8b708505b8
|
|
350
|
+
Relaton::Nist::Item.from_yaml File.read("spec/fixtures/item.yaml")
|
|
351
|
+
=> #<Relaton::Nist::ItemData:0x0000000124d4ab50
|
|
356
352
|
...
|
|
357
353
|
----
|
|
358
354
|
====
|
|
@@ -371,7 +367,9 @@ The following method fetches all the documents from the NIST-Tech-Pubs dataset,
|
|
|
371
367
|
====
|
|
372
368
|
[source,ruby]
|
|
373
369
|
----
|
|
374
|
-
|
|
370
|
+
require "relaton/nist/data_fetcher"
|
|
371
|
+
|
|
372
|
+
Relaton::Nist::DataFetcher.fetch
|
|
375
373
|
Started at: 2021-09-01 18:01:01 +0200
|
|
376
374
|
Stopped at: 2021-09-01 18:01:43 +0200
|
|
377
375
|
Done in: 42 sec.
|
|
@@ -384,7 +382,7 @@ Done in: 42 sec.
|
|
|
384
382
|
====
|
|
385
383
|
[source,ruby]
|
|
386
384
|
----
|
|
387
|
-
>
|
|
385
|
+
> Relaton::Nist::DataFetcher.fetch(output: "data", format: "yaml")
|
|
388
386
|
----
|
|
389
387
|
====
|
|
390
388
|
|