commonmeta-ruby 3.7.2 → 3.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/publish.yml +23 -0
  3. data/Gemfile.lock +23 -23
  4. data/bin/commonmeta +1 -1
  5. data/docs/.gitignore +1 -0
  6. data/docs/_publish.yml +4 -0
  7. data/docs/_quarto.yml +46 -0
  8. data/docs/_site/favicon.ico +0 -0
  9. data/docs/_site/images/icon.png +0 -0
  10. data/docs/_site/index.html +947 -0
  11. data/docs/_site/readers/bibtex_reader.html +802 -0
  12. data/docs/_site/search.json +74 -0
  13. data/docs/_site/site_libs/bootstrap/bootstrap-dark.min.css +9 -0
  14. data/docs/_site/site_libs/bootstrap/bootstrap-icons.css +2078 -0
  15. data/docs/_site/site_libs/bootstrap/bootstrap-icons.woff +0 -0
  16. data/docs/_site/site_libs/bootstrap/bootstrap.min.css +9 -0
  17. data/docs/_site/site_libs/bootstrap/bootstrap.min.js +7 -0
  18. data/docs/_site/site_libs/clipboard/clipboard.min.js +7 -0
  19. data/docs/_site/site_libs/quarto-html/anchor.min.js +9 -0
  20. data/docs/_site/site_libs/quarto-html/popper.min.js +6 -0
  21. data/docs/_site/site_libs/quarto-html/quarto-syntax-highlighting-dark.css +179 -0
  22. data/docs/_site/site_libs/quarto-html/quarto-syntax-highlighting.css +179 -0
  23. data/docs/_site/site_libs/quarto-html/quarto.js +889 -0
  24. data/docs/_site/site_libs/quarto-html/tippy.css +1 -0
  25. data/docs/_site/site_libs/quarto-html/tippy.umd.min.js +2 -0
  26. data/docs/_site/site_libs/quarto-nav/headroom.min.js +7 -0
  27. data/docs/_site/site_libs/quarto-nav/quarto-nav.js +288 -0
  28. data/docs/_site/site_libs/quarto-search/autocomplete.umd.js +3 -0
  29. data/docs/_site/site_libs/quarto-search/fuse.min.js +9 -0
  30. data/docs/_site/site_libs/quarto-search/quarto-search.js +1241 -0
  31. data/docs/_site/utils/doi_utils.html +787 -0
  32. data/docs/_site/writers/bibtex_writer.html +803 -0
  33. data/docs/favicon.ico +0 -0
  34. data/docs/images/icon.png +0 -0
  35. data/docs/index.qmd +83 -0
  36. data/docs/readers/bibtex_reader.ipynb +37 -0
  37. data/docs/theme.scss +7 -0
  38. data/docs/utils/doi_utils.ipynb +28 -0
  39. data/docs/writers/bibtex_writer.ipynb +39 -0
  40. data/lib/commonmeta/cli.rb +5 -5
  41. data/lib/commonmeta/readers/json_feed_reader.rb +4 -4
  42. data/lib/commonmeta/version.rb +1 -1
  43. data/spec/cli_spec.rb +2 -2
  44. data/spec/fixtures/vcr_cassettes/Commonmeta_CLI/json_feed/json_feed_blog_slug.yml +71 -0
  45. data/spec/readers/json_feed_reader_spec.rb +2 -2
  46. metadata +40 -3
@@ -0,0 +1,947 @@
1
+ <!DOCTYPE html>
2
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
3
+
4
+ <meta charset="utf-8">
5
+ <meta name="generator" content="quarto-1.4.504">
6
+
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
8
+
9
+
10
+ <title>commonmeta-ruby - Guide</title>
11
+ <style>
12
+ code{white-space: pre-wrap;}
13
+ span.smallcaps{font-variant: small-caps;}
14
+ div.columns{display: flex; gap: min(4vw, 1.5em);}
15
+ div.column{flex: auto; overflow-x: auto;}
16
+ div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
17
+ ul.task-list{list-style: none;}
18
+ ul.task-list li input[type="checkbox"] {
19
+ width: 0.8em;
20
+ margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
21
+ vertical-align: middle;
22
+ }
23
+ </style>
24
+
25
+
26
+ <script src="site_libs/quarto-nav/quarto-nav.js"></script>
27
+ <script src="site_libs/quarto-nav/headroom.min.js"></script>
28
+ <script src="site_libs/clipboard/clipboard.min.js"></script>
29
+ <script src="site_libs/quarto-search/autocomplete.umd.js"></script>
30
+ <script src="site_libs/quarto-search/fuse.min.js"></script>
31
+ <script src="site_libs/quarto-search/quarto-search.js"></script>
32
+ <meta name="quarto:offset" content="./">
33
+ <link href="./favicon.ico" rel="icon">
34
+ <script src="site_libs/quarto-html/quarto.js"></script>
35
+ <script src="site_libs/quarto-html/popper.min.js"></script>
36
+ <script src="site_libs/quarto-html/tippy.umd.min.js"></script>
37
+ <script src="site_libs/quarto-html/anchor.min.js"></script>
38
+ <link href="site_libs/quarto-html/tippy.css" rel="stylesheet">
39
+ <link href="site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" class="quarto-color-scheme" id="quarto-text-highlighting-styles">
40
+ <link href="site_libs/quarto-html/quarto-syntax-highlighting-dark.css" rel="prefetch" class="quarto-color-scheme quarto-color-alternate" id="quarto-text-highlighting-styles">
41
+ <script src="site_libs/bootstrap/bootstrap.min.js"></script>
42
+ <link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
43
+ <link href="site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" class="quarto-color-scheme" id="quarto-bootstrap" data-mode="light">
44
+ <link href="site_libs/bootstrap/bootstrap-dark.min.css" rel="prefetch" class="quarto-color-scheme quarto-color-alternate" id="quarto-bootstrap" data-mode="dark">
45
+ <script id="quarto-search-options" type="application/json">{
46
+ "location": "navbar",
47
+ "copy-button": false,
48
+ "collapse-after": 3,
49
+ "panel-placement": "end",
50
+ "type": "overlay",
51
+ "limit": 50,
52
+ "keyboard-shortcut": [
53
+ "f",
54
+ "/",
55
+ "s"
56
+ ],
57
+ "show-item-context": false,
58
+ "language": {
59
+ "search-no-results-text": "No results",
60
+ "search-matching-documents-text": "matching documents",
61
+ "search-copy-link-title": "Copy link to search",
62
+ "search-hide-matches-text": "Hide additional matches",
63
+ "search-more-match-text": "more match in this document",
64
+ "search-more-matches-text": "more matches in this document",
65
+ "search-clear-button-title": "Clear",
66
+ "search-detached-cancel-button-title": "Cancel",
67
+ "search-submit-button-title": "Submit",
68
+ "search-label": "Search"
69
+ }
70
+ }</script>
71
+
72
+
73
+ </head>
74
+
75
+ <body class="nav-sidebar floating nav-fixed">
76
+
77
+ <div id="quarto-search-results"></div>
78
+ <header id="quarto-header" class="headroom fixed-top">
79
+ <nav class="navbar navbar-expand-lg " data-bs-theme="dark">
80
+ <div class="navbar-container container-fluid">
81
+ <div class="navbar-brand-container mx-auto">
82
+ <a href="./index.html" class="navbar-brand navbar-brand-logo">
83
+ <img src="./images/icon.png" alt="commonmeta-py" class="navbar-logo">
84
+ </a>
85
+ <a class="navbar-brand" href="./index.html">
86
+ <span class="navbar-title">commonmeta-ruby</span>
87
+ </a>
88
+ </div>
89
+ <div id="quarto-search" class="" title="Search"></div>
90
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
91
+ <span class="navbar-toggler-icon"></span>
92
+ </button>
93
+ <div class="collapse navbar-collapse" id="navbarCollapse">
94
+ <ul class="navbar-nav navbar-nav-scroll ms-auto">
95
+ <li class="nav-item compact">
96
+ <a class="nav-link" href="https://github.com/front-matter/commonmeta-ruby"> <i class="bi bi-github" role="img">
97
+ </i>
98
+ <span class="menu-text"></span></a>
99
+ </li>
100
+ </ul>
101
+ </div> <!-- /navcollapse -->
102
+ <div class="quarto-navbar-tools">
103
+ <a href="" class="quarto-color-scheme-toggle quarto-navigation-tool px-1" onclick="window.quartoToggleColorScheme(); return false;" title="Toggle dark mode"><i class="bi"></i></a>
104
+ </div>
105
+ </div> <!-- /container-fluid -->
106
+ </nav>
107
+ <nav class="quarto-secondary-nav">
108
+ <div class="container-fluid d-flex">
109
+ <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
110
+ <i class="bi bi-layout-text-sidebar-reverse"></i>
111
+ </button>
112
+ <a class="flex-grow-1 no-decor" role="button" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }">
113
+ <h1 class="quarto-secondary-nav-title">Guide</h1>
114
+ </a>
115
+ </div>
116
+ </nav>
117
+ </header>
118
+ <!-- content -->
119
+ <div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar">
120
+ <!-- sidebar -->
121
+ <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal quarto-sidebar-collapse-item sidebar-navigation floating overflow-auto">
122
+ <div class="sidebar-menu-container">
123
+ <ul class="list-unstyled mt-1">
124
+ <li class="sidebar-item">
125
+ <div class="sidebar-item-container">
126
+ <a href="./index.html" class="sidebar-item-text sidebar-link active">
127
+ <span class="menu-text">Guide</span></a>
128
+ </div>
129
+ </li>
130
+ <li class="sidebar-item sidebar-item-section">
131
+ <div class="sidebar-item-container">
132
+ <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="true">
133
+ <span class="menu-text">Readers</span></a>
134
+ <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="true" aria-label="Toggle section">
135
+ <i class="bi bi-chevron-right ms-2"></i>
136
+ </a>
137
+ </div>
138
+ <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 show">
139
+ <li class="sidebar-item">
140
+ <div class="sidebar-item-container">
141
+ <a href="./readers/bibtex_reader.html" class="sidebar-item-text sidebar-link">
142
+ <span class="menu-text">BibTex Reader</span></a>
143
+ </div>
144
+ </li>
145
+ </ul>
146
+ </li>
147
+ <li class="sidebar-item sidebar-item-section">
148
+ <div class="sidebar-item-container">
149
+ <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true">
150
+ <span class="menu-text">Writers</span></a>
151
+ <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true" aria-label="Toggle section">
152
+ <i class="bi bi-chevron-right ms-2"></i>
153
+ </a>
154
+ </div>
155
+ <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show">
156
+ <li class="sidebar-item">
157
+ <div class="sidebar-item-container">
158
+ <a href="./writers/bibtex_writer.html" class="sidebar-item-text sidebar-link">
159
+ <span class="menu-text">BibTex Writer</span></a>
160
+ </div>
161
+ </li>
162
+ </ul>
163
+ </li>
164
+ <li class="sidebar-item sidebar-item-section">
165
+ <div class="sidebar-item-container">
166
+ <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="true">
167
+ <span class="menu-text">Utils</span></a>
168
+ <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="true" aria-label="Toggle section">
169
+ <i class="bi bi-chevron-right ms-2"></i>
170
+ </a>
171
+ </div>
172
+ <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth1 show">
173
+ <li class="sidebar-item">
174
+ <div class="sidebar-item-container">
175
+ <a href="./utils/doi_utils.html" class="sidebar-item-text sidebar-link">
176
+ <span class="menu-text">doi_utils</span></a>
177
+ </div>
178
+ </li>
179
+ </ul>
180
+ </li>
181
+ </ul>
182
+ </div>
183
+ </nav>
184
+ <div id="quarto-sidebar-glass" class="quarto-sidebar-collapse-item" data-bs-toggle="collapse" data-bs-target=".quarto-sidebar-collapse-item"></div>
185
+ <!-- margin-sidebar -->
186
+ <div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
187
+ <nav id="TOC" role="doc-toc" class="toc-active">
188
+ <h2 id="toc-title">On this page</h2>
189
+
190
+ <ul>
191
+ <li><a href="#installation" id="toc-installation" class="nav-link active" data-scroll-target="#installation">Installation</a></li>
192
+ <li><a href="#commands" id="toc-commands" class="nav-link" data-scroll-target="#commands">Commands</a></li>
193
+ <li><a href="#errors" id="toc-errors" class="nav-link" data-scroll-target="#errors">Errors</a></li>
194
+ <li><a href="#supported-metadata-formats" id="toc-supported-metadata-formats" class="nav-link" data-scroll-target="#supported-metadata-formats">Supported Metadata Formats</a></li>
195
+ </ul>
196
+ </nav>
197
+ </div>
198
+ <!-- main -->
199
+ <main class="content" id="quarto-document-content">
200
+
201
+ <header id="title-block-header" class="quarto-title-block default">
202
+ <div class="quarto-title">
203
+ <h1 class="title d-none d-lg-block">Guide</h1>
204
+ </div>
205
+
206
+
207
+
208
+ <div class="quarto-title-meta">
209
+
210
+
211
+
212
+
213
+ </div>
214
+
215
+
216
+
217
+ </header>
218
+
219
+
220
+ <p><a href="https://doi.org/10.5281/zenodo.5785519"><img src="https://zenodo.org/badge/DOI/10.5281/zenodo.5785519.svg" class="img-fluid" alt="DOI"></a> <a href="https://badge.fury.io/rb/commonmeta-ruby"><img src="https://badge.fury.io/rb/commonmeta-ruby.svg" class="img-fluid" alt="Gem Version"></a> <img src="https://img.shields.io/github/license/front-matter/commonmeta-ruby?logo=MIT.png" class="img-fluid" alt="GitHub"></p>
221
+ <p>commonmeta-ruby is a Ruby gem and command-line utility for the conversion of scholarly metadata, including <a href="https://schema.org">schema.org</a>. Based on the <a href="https://github.com/datacite/bolognese">bolognese</a> gem, but using <a href="https://commonmeta.org">commonmeta</a> as the intermediate format, and supporting additional metadata formats. A Python version is available at <a href="https://github.com/front-matter/commonmeta-py">commonmeta-py</a>.</p>
222
+ <section id="installation" class="level2">
223
+ <h2 class="anchored" data-anchor-id="installation">Installation</h2>
224
+ <p>Requires Ruby 3.0 or later (Ruby 2.x <a href="https://endoflife.date/ruby">has reached its end of life</a> March 2023). Then add the following to your <code>Gemfile</code> to install the latest version:</p>
225
+ <pre><code>gem 'commonmeta-ruby'</code></pre>
226
+ <p>Then run <code>bundle install</code> to install into your environment.</p>
227
+ <p>You can also install the gem system-wide in the usual way:</p>
228
+ <pre><code>gem install commonmeta-ruby</code></pre>
229
+ </section>
230
+ <section id="commands" class="level2">
231
+ <h2 class="anchored" data-anchor-id="commands">Commands</h2>
232
+ <p>Run the <code>commonmeta</code> command with either an identifier (DOI or URL) or filename:</p>
233
+ <pre><code>commonmeta https://doi.org/10.7554/elife.01567</code></pre>
234
+ <pre><code>commonmeta example.xml</code></pre>
235
+ <p>commonmeta can read BibTeX files (file extension <code>.bib</code>), RIS files (file extension <code>.ris</code>), Crossref files (file extension <code>.xml</code>), DataCite files and CSL-JSON files.</p>
236
+ <p>The input format (e.g.&nbsp;Crossref or BibteX) is automatically detected, but you can also provide the format with the <code>--from</code> or <code>-f</code> flag. The supported input formats are listed in the table above.</p>
237
+ <p>The output format is determined by the <code>--to</code> or <code>-t</code> flag, and defaults to <code>schema_org</code>.</p>
238
+ <p>Show all commands with <code>commonmeta help</code>:</p>
239
+ <pre><code>Commands:
240
+ commonmeta # convert metadata
241
+ commonmeta --version, -v # print the version
242
+ commonmeta help [COMMAND] # Describe available commands or one specific command</code></pre>
243
+ </section>
244
+ <section id="errors" class="level2">
245
+ <h2 class="anchored" data-anchor-id="errors">Errors</h2>
246
+ <p>Errors are returned to STDOUT.</p>
247
+ <p>All input is validated against the commonmeta JSON schema.</p>
248
+ </section>
249
+ <section id="supported-metadata-formats" class="level2">
250
+ <h2 class="anchored" data-anchor-id="supported-metadata-formats">Supported Metadata Formats</h2>
251
+ <p>commonmeta-ruby reads and/or writes these metadata formats:</p>
252
+ <table class="table">
253
+ <thead>
254
+ <tr class="header">
255
+ <th>Format</th>
256
+ <th>Name</th>
257
+ <th>Content Type</th>
258
+ <th>Read</th>
259
+ <th>Write</th>
260
+ </tr>
261
+ </thead>
262
+ <tbody>
263
+ <tr class="odd">
264
+ <td><a href="https://commonmeta.org">Commonmeta</a></td>
265
+ <td>commonmeta</td>
266
+ <td>application/vnd.commonmeta+json</td>
267
+ <td>yes</td>
268
+ <td>yes</td>
269
+ </tr>
270
+ <tr class="even">
271
+ <td><a href="https://www.crossref.org/schema/documentation/unixref1.1/unixref1.1.html">CrossRef Unixref XML</a></td>
272
+ <td>crossref</td>
273
+ <td>application/vnd.crossref.unixref+xml</td>
274
+ <td>yes</td>
275
+ <td>yes</td>
276
+ </tr>
277
+ <tr class="odd">
278
+ <td><a href="https://api.crossref.org">Crossref</a></td>
279
+ <td>crossref</td>
280
+ <td>application/vnd.crossref+json</td>
281
+ <td>yes</td>
282
+ <td>no</td>
283
+ </tr>
284
+ <tr class="even">
285
+ <td><a href="https://api.datacite.org/">DataCite</a></td>
286
+ <td>datacite</td>
287
+ <td>application/vnd.datacite.datacite+json</td>
288
+ <td>yes</td>
289
+ <td>yes</td>
290
+ </tr>
291
+ <tr class="odd">
292
+ <td><a href="http://schema.org/">Schema.org (in JSON-LD)</a></td>
293
+ <td>schema_org</td>
294
+ <td>application/vnd.schemaorg.ld+json</td>
295
+ <td>yes</td>
296
+ <td>yes</td>
297
+ </tr>
298
+ <tr class="even">
299
+ <td><a href="http://www.w3.org/TR/rdf-syntax-grammar/">RDF XML</a></td>
300
+ <td>rdf_xml</td>
301
+ <td>application/rdf+xml</td>
302
+ <td>no</td>
303
+ <td>yes</td>
304
+ </tr>
305
+ <tr class="odd">
306
+ <td><a href="http://www.w3.org/TeamSubmission/turtle/">RDF Turtle</a></td>
307
+ <td>turtle</td>
308
+ <td>text/turtle</td>
309
+ <td>no</td>
310
+ <td>yes</td>
311
+ </tr>
312
+ <tr class="even">
313
+ <td><a href="https://citationstyles.org/">CSL-JSON</a></td>
314
+ <td>csl</td>
315
+ <td>application/vnd.citationstyles.csl+json</td>
316
+ <td>yes</td>
317
+ <td>yes</td>
318
+ </tr>
319
+ <tr class="odd">
320
+ <td><a href="https://citationstyles.org/">Formatted text citation</a></td>
321
+ <td>citation</td>
322
+ <td>text/x-bibliography</td>
323
+ <td>no</td>
324
+ <td>yes</td>
325
+ </tr>
326
+ <tr class="even">
327
+ <td><a href="https://codemeta.github.io/">Codemeta</a></td>
328
+ <td>codemeta</td>
329
+ <td>application/vnd.codemeta.ld+json</td>
330
+ <td>yes</td>
331
+ <td>yes</td>
332
+ </tr>
333
+ <tr class="odd">
334
+ <td><a href="https://citation-file-format.github.io/">Citation File Format (CFF)</a></td>
335
+ <td>cff</td>
336
+ <td>application/vnd.cff+yaml</td>
337
+ <td>yes</td>
338
+ <td>yes</td>
339
+ </tr>
340
+ <tr class="even">
341
+ <td><a href="https://jats.nlm.nih.gov/">JATS</a></td>
342
+ <td>jats</td>
343
+ <td>application/vnd.jats+xml</td>
344
+ <td>no</td>
345
+ <td>yes</td>
346
+ </tr>
347
+ <tr class="odd">
348
+ <td><a href="https://en.wikipedia.org/wiki/Comma-separated_values">CSV</a></td>
349
+ <td>csv</td>
350
+ <td>text/csv</td>
351
+ <td>no</td>
352
+ <td>yes</td>
353
+ </tr>
354
+ <tr class="even">
355
+ <td><a href="http://en.wikipedia.org/wiki/BibTeX">BibTex</a></td>
356
+ <td>bibtex</td>
357
+ <td>application/x-bibtex</td>
358
+ <td>yes</td>
359
+ <td>yes</td>
360
+ </tr>
361
+ <tr class="odd">
362
+ <td><a href="http://en.wikipedia.org/wiki/RIS_(file_format)">RIS</a></td>
363
+ <td>ris</td>
364
+ <td>application/x-research-info-systems</td>
365
+ <td>yes</td>
366
+ <td>yes</td>
367
+ </tr>
368
+ </tbody>
369
+ </table>
370
+
371
+
372
+ </section>
373
+
374
+ </main> <!-- /main -->
375
+ <script id="quarto-html-after-body" type="application/javascript">
376
+ window.document.addEventListener("DOMContentLoaded", function (event) {
377
+ const toggleBodyColorMode = (bsSheetEl) => {
378
+ const mode = bsSheetEl.getAttribute("data-mode");
379
+ const bodyEl = window.document.querySelector("body");
380
+ if (mode === "dark") {
381
+ bodyEl.classList.add("quarto-dark");
382
+ bodyEl.classList.remove("quarto-light");
383
+ } else {
384
+ bodyEl.classList.add("quarto-light");
385
+ bodyEl.classList.remove("quarto-dark");
386
+ }
387
+ }
388
+ const toggleBodyColorPrimary = () => {
389
+ const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
390
+ if (bsSheetEl) {
391
+ toggleBodyColorMode(bsSheetEl);
392
+ }
393
+ }
394
+ toggleBodyColorPrimary();
395
+ const disableStylesheet = (stylesheets) => {
396
+ for (let i=0; i < stylesheets.length; i++) {
397
+ const stylesheet = stylesheets[i];
398
+ stylesheet.rel = 'prefetch';
399
+ }
400
+ }
401
+ const enableStylesheet = (stylesheets) => {
402
+ for (let i=0; i < stylesheets.length; i++) {
403
+ const stylesheet = stylesheets[i];
404
+ stylesheet.rel = 'stylesheet';
405
+ }
406
+ }
407
+ const manageTransitions = (selector, allowTransitions) => {
408
+ const els = window.document.querySelectorAll(selector);
409
+ for (let i=0; i < els.length; i++) {
410
+ const el = els[i];
411
+ if (allowTransitions) {
412
+ el.classList.remove('notransition');
413
+ } else {
414
+ el.classList.add('notransition');
415
+ }
416
+ }
417
+ }
418
+ const toggleGiscusIfUsed = (isAlternate, darkModeDefault) => {
419
+ const baseTheme = document.querySelector('#giscus-base-theme')?.value ?? 'light';
420
+ const alternateTheme = document.querySelector('#giscus-alt-theme')?.value ?? 'dark';
421
+ let newTheme = '';
422
+ if(darkModeDefault) {
423
+ newTheme = isAlternate ? baseTheme : alternateTheme;
424
+ } else {
425
+ newTheme = isAlternate ? alternateTheme : baseTheme;
426
+ }
427
+ const changeGiscusTheme = () => {
428
+ // From: https://github.com/giscus/giscus/issues/336
429
+ const sendMessage = (message) => {
430
+ const iframe = document.querySelector('iframe.giscus-frame');
431
+ if (!iframe) return;
432
+ iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app');
433
+ }
434
+ sendMessage({
435
+ setConfig: {
436
+ theme: newTheme
437
+ }
438
+ });
439
+ }
440
+ const isGiscussLoaded = window.document.querySelector('iframe.giscus-frame') !== null;
441
+ if (isGiscussLoaded) {
442
+ changeGiscusTheme();
443
+ }
444
+ }
445
+ const toggleColorMode = (alternate) => {
446
+ // Switch the stylesheets
447
+ const alternateStylesheets = window.document.querySelectorAll('link.quarto-color-scheme.quarto-color-alternate');
448
+ manageTransitions('#quarto-margin-sidebar .nav-link', false);
449
+ if (alternate) {
450
+ enableStylesheet(alternateStylesheets);
451
+ for (const sheetNode of alternateStylesheets) {
452
+ if (sheetNode.id === "quarto-bootstrap") {
453
+ toggleBodyColorMode(sheetNode);
454
+ }
455
+ }
456
+ } else {
457
+ disableStylesheet(alternateStylesheets);
458
+ toggleBodyColorPrimary();
459
+ }
460
+ manageTransitions('#quarto-margin-sidebar .nav-link', true);
461
+ // Switch the toggles
462
+ const toggles = window.document.querySelectorAll('.quarto-color-scheme-toggle');
463
+ for (let i=0; i < toggles.length; i++) {
464
+ const toggle = toggles[i];
465
+ if (toggle) {
466
+ if (alternate) {
467
+ toggle.classList.add("alternate");
468
+ } else {
469
+ toggle.classList.remove("alternate");
470
+ }
471
+ }
472
+ }
473
+ // Hack to workaround the fact that safari doesn't
474
+ // properly recolor the scrollbar when toggling (#1455)
475
+ if (navigator.userAgent.indexOf('Safari') > 0 && navigator.userAgent.indexOf('Chrome') == -1) {
476
+ manageTransitions("body", false);
477
+ window.scrollTo(0, 1);
478
+ setTimeout(() => {
479
+ window.scrollTo(0, 0);
480
+ manageTransitions("body", true);
481
+ }, 40);
482
+ }
483
+ }
484
+ const isFileUrl = () => {
485
+ return window.location.protocol === 'file:';
486
+ }
487
+ const hasAlternateSentinel = () => {
488
+ let styleSentinel = getColorSchemeSentinel();
489
+ if (styleSentinel !== null) {
490
+ return styleSentinel === "alternate";
491
+ } else {
492
+ return false;
493
+ }
494
+ }
495
+ const setStyleSentinel = (alternate) => {
496
+ const value = alternate ? "alternate" : "default";
497
+ if (!isFileUrl()) {
498
+ window.localStorage.setItem("quarto-color-scheme", value);
499
+ } else {
500
+ localAlternateSentinel = value;
501
+ }
502
+ }
503
+ const getColorSchemeSentinel = () => {
504
+ if (!isFileUrl()) {
505
+ const storageValue = window.localStorage.getItem("quarto-color-scheme");
506
+ return storageValue != null ? storageValue : localAlternateSentinel;
507
+ } else {
508
+ return localAlternateSentinel;
509
+ }
510
+ }
511
+ const darkModeDefault = false;
512
+ let localAlternateSentinel = darkModeDefault ? 'alternate' : 'default';
513
+ // Dark / light mode switch
514
+ window.quartoToggleColorScheme = () => {
515
+ // Read the current dark / light value
516
+ let toAlternate = !hasAlternateSentinel();
517
+ toggleColorMode(toAlternate);
518
+ setStyleSentinel(toAlternate);
519
+ toggleGiscusIfUsed(toAlternate, darkModeDefault);
520
+ };
521
+ // Ensure there is a toggle, if there isn't float one in the top right
522
+ if (window.document.querySelector('.quarto-color-scheme-toggle') === null) {
523
+ const a = window.document.createElement('a');
524
+ a.classList.add('top-right');
525
+ a.classList.add('quarto-color-scheme-toggle');
526
+ a.href = "";
527
+ a.onclick = function() { try { window.quartoToggleColorScheme(); } catch {} return false; };
528
+ const i = window.document.createElement("i");
529
+ i.classList.add('bi');
530
+ a.appendChild(i);
531
+ window.document.body.appendChild(a);
532
+ }
533
+ // Switch to dark mode if need be
534
+ if (hasAlternateSentinel()) {
535
+ toggleColorMode(true);
536
+ } else {
537
+ toggleColorMode(false);
538
+ }
539
+ const icon = "";
540
+ const anchorJS = new window.AnchorJS();
541
+ anchorJS.options = {
542
+ placement: 'right',
543
+ icon: icon
544
+ };
545
+ anchorJS.add('.anchored');
546
+ const isCodeAnnotation = (el) => {
547
+ for (const clz of el.classList) {
548
+ if (clz.startsWith('code-annotation-')) {
549
+ return true;
550
+ }
551
+ }
552
+ return false;
553
+ }
554
+ const clipboard = new window.ClipboardJS('.code-copy-button', {
555
+ text: function(trigger) {
556
+ const codeEl = trigger.previousElementSibling.cloneNode(true);
557
+ for (const childEl of codeEl.children) {
558
+ if (isCodeAnnotation(childEl)) {
559
+ childEl.remove();
560
+ }
561
+ }
562
+ return codeEl.innerText;
563
+ }
564
+ });
565
+ clipboard.on('success', function(e) {
566
+ // button target
567
+ const button = e.trigger;
568
+ // don't keep focus
569
+ button.blur();
570
+ // flash "checked"
571
+ button.classList.add('code-copy-button-checked');
572
+ var currentTitle = button.getAttribute("title");
573
+ button.setAttribute("title", "Copied!");
574
+ let tooltip;
575
+ if (window.bootstrap) {
576
+ button.setAttribute("data-bs-toggle", "tooltip");
577
+ button.setAttribute("data-bs-placement", "left");
578
+ button.setAttribute("data-bs-title", "Copied!");
579
+ tooltip = new bootstrap.Tooltip(button,
580
+ { trigger: "manual",
581
+ customClass: "code-copy-button-tooltip",
582
+ offset: [0, -8]});
583
+ tooltip.show();
584
+ }
585
+ setTimeout(function() {
586
+ if (tooltip) {
587
+ tooltip.hide();
588
+ button.removeAttribute("data-bs-title");
589
+ button.removeAttribute("data-bs-toggle");
590
+ button.removeAttribute("data-bs-placement");
591
+ }
592
+ button.setAttribute("title", currentTitle);
593
+ button.classList.remove('code-copy-button-checked');
594
+ }, 1000);
595
+ // clear code selection
596
+ e.clearSelection();
597
+ });
598
+ function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
599
+ const config = {
600
+ allowHTML: true,
601
+ maxWidth: 500,
602
+ delay: 100,
603
+ arrow: false,
604
+ appendTo: function(el) {
605
+ return el.parentElement;
606
+ },
607
+ interactive: true,
608
+ interactiveBorder: 10,
609
+ theme: 'quarto',
610
+ placement: 'bottom-start',
611
+ };
612
+ if (contentFn) {
613
+ config.content = contentFn;
614
+ }
615
+ if (onTriggerFn) {
616
+ config.onTrigger = onTriggerFn;
617
+ }
618
+ if (onUntriggerFn) {
619
+ config.onUntrigger = onUntriggerFn;
620
+ }
621
+ window.tippy(el, config);
622
+ }
623
+ const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
624
+ for (var i=0; i<noterefs.length; i++) {
625
+ const ref = noterefs[i];
626
+ tippyHover(ref, function() {
627
+ // use id or data attribute instead here
628
+ let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
629
+ try { href = new URL(href).hash; } catch {}
630
+ const id = href.replace(/^#\/?/, "");
631
+ const note = window.document.getElementById(id);
632
+ return note.innerHTML;
633
+ });
634
+ }
635
+ const xrefs = window.document.querySelectorAll('a.quarto-xref');
636
+ const processXRef = (id, note) => {
637
+ // Strip column container classes
638
+ const stripColumnClz = (el) => {
639
+ el.classList.remove("page-full", "page-columns");
640
+ if (el.children) {
641
+ for (const child of el.children) {
642
+ stripColumnClz(child);
643
+ }
644
+ }
645
+ }
646
+ stripColumnClz(note)
647
+ const typesetMath = (el) => {
648
+ if (window.MathJax) {
649
+ // MathJax Typeset
650
+ window.MathJax.typeset([el]);
651
+ } else if (window.katex) {
652
+ // KaTeX Render
653
+ var mathElements = el.getElementsByClassName("math");
654
+ var macros = [];
655
+ for (var i = 0; i < mathElements.length; i++) {
656
+ var texText = mathElements[i].firstChild;
657
+ if (mathElements[i].tagName == "SPAN") {
658
+ window.katex.render(texText.data, mathElements[i], {
659
+ displayMode: mathElements[i].classList.contains('display'),
660
+ throwOnError: false,
661
+ macros: macros,
662
+ fleqn: false
663
+ });
664
+ }
665
+ }
666
+ }
667
+ }
668
+ if (id === null || id.startsWith('sec-')) {
669
+ // Special case sections, only their first couple elements
670
+ const container = document.createElement("div");
671
+ if (note.children && note.children.length > 2) {
672
+ container.appendChild(note.children[0].cloneNode(true));
673
+ for (let i = 1; i < note.children.length; i++) {
674
+ const child = note.children[i];
675
+ if (child.tagName === "P" && child.innerText === "") {
676
+ continue;
677
+ } else {
678
+ container.appendChild(child.cloneNode(true));
679
+ break;
680
+ }
681
+ }
682
+ typesetMath(container);
683
+ return container.innerHTML
684
+ } else {
685
+ typesetMath(note);
686
+ return note.innerHTML;
687
+ }
688
+ } else {
689
+ // Remove any anchor links if they are present
690
+ const anchorLink = note.querySelector('a.anchorjs-link');
691
+ if (anchorLink) {
692
+ anchorLink.remove();
693
+ }
694
+ typesetMath(note);
695
+ return note.innerHTML;
696
+ }
697
+ }
698
+ for (var i=0; i<xrefs.length; i++) {
699
+ const xref = xrefs[i];
700
+ tippyHover(xref, undefined, function(instance) {
701
+ instance.disable();
702
+ let url = xref.getAttribute('href');
703
+ let hash = undefined;
704
+ if (url.startsWith('#')) {
705
+ hash = url;
706
+ } else {
707
+ try { hash = new URL(url).hash; } catch {}
708
+ }
709
+ if (hash) {
710
+ const id = hash.replace(/^#\/?/, "");
711
+ const note = window.document.getElementById(id);
712
+ if (note !== null) {
713
+ try {
714
+ const html = processXRef(id, note.cloneNode(true));
715
+ instance.setContent(html);
716
+ } finally {
717
+ instance.enable();
718
+ instance.show();
719
+ }
720
+ } else {
721
+ // See if we can fetch this
722
+ fetch(url.split('#')[0])
723
+ .then(res => res.text())
724
+ .then(html => {
725
+ const parser = new DOMParser();
726
+ const htmlDoc = parser.parseFromString(html, "text/html");
727
+ const note = htmlDoc.getElementById(id);
728
+ if (note !== null) {
729
+ const html = processXRef(id, note);
730
+ instance.setContent(html);
731
+ }
732
+ }).finally(() => {
733
+ instance.enable();
734
+ instance.show();
735
+ });
736
+ }
737
+ } else {
738
+ // See if we can fetch a full url (with no hash to target)
739
+ // This is a special case and we should probably do some content thinning / targeting
740
+ fetch(url)
741
+ .then(res => res.text())
742
+ .then(html => {
743
+ const parser = new DOMParser();
744
+ const htmlDoc = parser.parseFromString(html, "text/html");
745
+ const note = htmlDoc.querySelector('main.content');
746
+ if (note !== null) {
747
+ // This should only happen for chapter cross references
748
+ // (since there is no id in the URL)
749
+ // remove the first header
750
+ if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
751
+ note.children[0].remove();
752
+ }
753
+ const html = processXRef(null, note);
754
+ instance.setContent(html);
755
+ }
756
+ }).finally(() => {
757
+ instance.enable();
758
+ instance.show();
759
+ });
760
+ }
761
+ }, function(instance) {
762
+ });
763
+ }
764
+ let selectedAnnoteEl;
765
+ const selectorForAnnotation = ( cell, annotation) => {
766
+ let cellAttr = 'data-code-cell="' + cell + '"';
767
+ let lineAttr = 'data-code-annotation="' + annotation + '"';
768
+ const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
769
+ return selector;
770
+ }
771
+ const selectCodeLines = (annoteEl) => {
772
+ const doc = window.document;
773
+ const targetCell = annoteEl.getAttribute("data-target-cell");
774
+ const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
775
+ const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
776
+ const lines = annoteSpan.getAttribute("data-code-lines").split(",");
777
+ const lineIds = lines.map((line) => {
778
+ return targetCell + "-" + line;
779
+ })
780
+ let top = null;
781
+ let height = null;
782
+ let parent = null;
783
+ if (lineIds.length > 0) {
784
+ //compute the position of the single el (top and bottom and make a div)
785
+ const el = window.document.getElementById(lineIds[0]);
786
+ top = el.offsetTop;
787
+ height = el.offsetHeight;
788
+ parent = el.parentElement.parentElement;
789
+ if (lineIds.length > 1) {
790
+ const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
791
+ const bottom = lastEl.offsetTop + lastEl.offsetHeight;
792
+ height = bottom - top;
793
+ }
794
+ if (top !== null && height !== null && parent !== null) {
795
+ // cook up a div (if necessary) and position it
796
+ let div = window.document.getElementById("code-annotation-line-highlight");
797
+ if (div === null) {
798
+ div = window.document.createElement("div");
799
+ div.setAttribute("id", "code-annotation-line-highlight");
800
+ div.style.position = 'absolute';
801
+ parent.appendChild(div);
802
+ }
803
+ div.style.top = top - 2 + "px";
804
+ div.style.height = height + 4 + "px";
805
+ div.style.left = 0;
806
+ let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
807
+ if (gutterDiv === null) {
808
+ gutterDiv = window.document.createElement("div");
809
+ gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
810
+ gutterDiv.style.position = 'absolute';
811
+ const codeCell = window.document.getElementById(targetCell);
812
+ const gutter = codeCell.querySelector('.code-annotation-gutter');
813
+ gutter.appendChild(gutterDiv);
814
+ }
815
+ gutterDiv.style.top = top - 2 + "px";
816
+ gutterDiv.style.height = height + 4 + "px";
817
+ }
818
+ selectedAnnoteEl = annoteEl;
819
+ }
820
+ };
821
+ const unselectCodeLines = () => {
822
+ const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
823
+ elementsIds.forEach((elId) => {
824
+ const div = window.document.getElementById(elId);
825
+ if (div) {
826
+ div.remove();
827
+ }
828
+ });
829
+ selectedAnnoteEl = undefined;
830
+ };
831
+ // Handle positioning of the toggle
832
+ window.addEventListener(
833
+ "resize",
834
+ throttle(() => {
835
+ elRect = undefined;
836
+ if (selectedAnnoteEl) {
837
+ selectCodeLines(selectedAnnoteEl);
838
+ }
839
+ }, 10)
840
+ );
841
+ function throttle(fn, ms) {
842
+ let throttle = false;
843
+ let timer;
844
+ return (...args) => {
845
+ if(!throttle) { // first call gets through
846
+ fn.apply(this, args);
847
+ throttle = true;
848
+ } else { // all the others get throttled
849
+ if(timer) clearTimeout(timer); // cancel #2
850
+ timer = setTimeout(() => {
851
+ fn.apply(this, args);
852
+ timer = throttle = false;
853
+ }, ms);
854
+ }
855
+ };
856
+ }
857
+ // Attach click handler to the DT
858
+ const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
859
+ for (const annoteDlNode of annoteDls) {
860
+ annoteDlNode.addEventListener('click', (event) => {
861
+ const clickedEl = event.target;
862
+ if (clickedEl !== selectedAnnoteEl) {
863
+ unselectCodeLines();
864
+ const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
865
+ if (activeEl) {
866
+ activeEl.classList.remove('code-annotation-active');
867
+ }
868
+ selectCodeLines(clickedEl);
869
+ clickedEl.classList.add('code-annotation-active');
870
+ } else {
871
+ // Unselect the line
872
+ unselectCodeLines();
873
+ clickedEl.classList.remove('code-annotation-active');
874
+ }
875
+ });
876
+ }
877
+ const findCites = (el) => {
878
+ const parentEl = el.parentElement;
879
+ if (parentEl) {
880
+ const cites = parentEl.dataset.cites;
881
+ if (cites) {
882
+ return {
883
+ el,
884
+ cites: cites.split(' ')
885
+ };
886
+ } else {
887
+ return findCites(el.parentElement)
888
+ }
889
+ } else {
890
+ return undefined;
891
+ }
892
+ };
893
+ var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
894
+ for (var i=0; i<bibliorefs.length; i++) {
895
+ const ref = bibliorefs[i];
896
+ const citeInfo = findCites(ref);
897
+ if (citeInfo) {
898
+ tippyHover(citeInfo.el, function() {
899
+ var popup = window.document.createElement('div');
900
+ citeInfo.cites.forEach(function(cite) {
901
+ var citeDiv = window.document.createElement('div');
902
+ citeDiv.classList.add('hanging-indent');
903
+ citeDiv.classList.add('csl-entry');
904
+ var biblioDiv = window.document.getElementById('ref-' + cite);
905
+ if (biblioDiv) {
906
+ citeDiv.innerHTML = biblioDiv.innerHTML;
907
+ }
908
+ popup.appendChild(citeDiv);
909
+ });
910
+ return popup.innerHTML;
911
+ });
912
+ }
913
+ }
914
+ });
915
+ </script>
916
+ </div> <!-- /content -->
917
+ <footer class="footer">
918
+ <div class="nav-footer">
919
+ <div class="nav-footer-left">
920
+ <p>Copyright ©2023 Front Matter.</p>
921
+ </div>
922
+ <div class="nav-footer-center">
923
+ &nbsp;
924
+ </div>
925
+ <div class="nav-footer-right">
926
+ <ul class="footer-items list-unstyled">
927
+ <li class="nav-item compact">
928
+ <a class="nav-link" href="mailto:info@front-matter.io">
929
+ <i class="bi bi-envelope" role="img">
930
+ </i>
931
+ </a>
932
+ </li>
933
+ <li class="nav-item compact">
934
+ <a class="nav-link" href="https://rogue-scholar.social/@admin">
935
+ <i class="bi bi-mastodon" role="img">
936
+ </i>
937
+ </a>
938
+ </li>
939
+ </ul>
940
+ </div>
941
+ </div>
942
+ </footer>
943
+
944
+
945
+
946
+
947
+ </body></html>