From 6c1cb3049110ea6f0c99cb1394326f53c4ed1af1 Mon Sep 17 00:00:00 2001 From: David McArthur Date: Tue, 12 Dec 2023 15:55:17 +0000 Subject: [PATCH] build release 1.1.69 --- package.json | 2 +- release/cli.js | 106 +++++++++++++++++++++++++++++++++++++++++-- release/cli.js.map | 2 +- release/package.json | 2 +- 4 files changed, 105 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 7e7b9ec..966cd3e 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "compiler", "template" ], - "version": "1.1.68", + "version": "1.1.69", "repository": "https://github.com/UofGAnalytics/build-coursework.git", "author": "David McArthur ", "license": "MIT", diff --git a/release/cli.js b/release/cli.js index 10bd6c6..be54cb4 100755 --- a/release/cli.js +++ b/release/cli.js @@ -183,6 +183,10 @@ const args = { type: 'string', description: 'Specify which environment program to display' }, + envLanguage: { + type: 'string', + description: 'Specify which environment language to display' + }, fileName: { type: 'string', description: 'Specify name of output file' @@ -214,6 +218,7 @@ const options = { verbose: argv.verbose, envPlatform: argv.envPlatform, envProgram: argv.envProgram, + envLanguage: argv.envLanguage, fileName: argv.fileName, output: argv.output }; @@ -3190,14 +3195,16 @@ __webpack_require__.a(module, async (__webpack_handle_async_dependencies__, __we /* harmony import */ var _boxouts__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6112); /* harmony import */ var _move_answers_to_end__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3069); /* harmony import */ var _program_switcher__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3324); -var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([unified__WEBPACK_IMPORTED_MODULE_0__, _boxouts__WEBPACK_IMPORTED_MODULE_1__, _move_answers_to_end__WEBPACK_IMPORTED_MODULE_2__, _program_switcher__WEBPACK_IMPORTED_MODULE_3__]); -([unified__WEBPACK_IMPORTED_MODULE_0__, _boxouts__WEBPACK_IMPORTED_MODULE_1__, _move_answers_to_end__WEBPACK_IMPORTED_MODULE_2__, _program_switcher__WEBPACK_IMPORTED_MODULE_3__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__); +/* harmony import */ var _language_switcher__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(4921); +var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([unified__WEBPACK_IMPORTED_MODULE_0__, _boxouts__WEBPACK_IMPORTED_MODULE_1__, _move_answers_to_end__WEBPACK_IMPORTED_MODULE_2__, _program_switcher__WEBPACK_IMPORTED_MODULE_3__, _language_switcher__WEBPACK_IMPORTED_MODULE_4__]); +([unified__WEBPACK_IMPORTED_MODULE_0__, _boxouts__WEBPACK_IMPORTED_MODULE_1__, _move_answers_to_end__WEBPACK_IMPORTED_MODULE_2__, _program_switcher__WEBPACK_IMPORTED_MODULE_3__, _language_switcher__WEBPACK_IMPORTED_MODULE_4__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__); + async function combinedMdastPhase(mdast, ctx, file, targetPdf) { - const processor = (0,unified__WEBPACK_IMPORTED_MODULE_0__.unified)().use(_program_switcher__WEBPACK_IMPORTED_MODULE_3__/* .programSwitcher */ .D, ctx).use(_boxouts__WEBPACK_IMPORTED_MODULE_1__/* .boxouts */ .q, ctx.refStore); + const processor = (0,unified__WEBPACK_IMPORTED_MODULE_0__.unified)().use(_program_switcher__WEBPACK_IMPORTED_MODULE_3__/* .programSwitcher */ .D, ctx).use(_language_switcher__WEBPACK_IMPORTED_MODULE_4__/* .languageSwitcher */ .v, ctx).use(_boxouts__WEBPACK_IMPORTED_MODULE_1__/* .boxouts */ .q, ctx.refStore); if (targetPdf) { processor.use(_move_answers_to_end__WEBPACK_IMPORTED_MODULE_2__/* .moveAnswersToEnd */ .w); } @@ -3645,6 +3652,97 @@ __webpack_async_result__(); /***/ }), +/***/ 4921: +/***/ ((module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try { +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ v: () => (/* binding */ languageSwitcher) +/* harmony export */ }); +/* harmony import */ var mdast_util_to_hast__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1037); +/* harmony import */ var unist_util_visit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6016); +var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([mdast_util_to_hast__WEBPACK_IMPORTED_MODULE_0__, unist_util_visit__WEBPACK_IMPORTED_MODULE_1__]); +([mdast_util_to_hast__WEBPACK_IMPORTED_MODULE_0__, unist_util_visit__WEBPACK_IMPORTED_MODULE_1__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__); + + +const languages = ['r', 'python']; +const titleCase = ['R', 'Python']; +function languageSwitcher(ctx) { + const languageFlag = ctx.options.envLanguage; + if (languageFlag !== undefined && !languages.includes(languageFlag)) { + throw new Error(`[environment]: envLanguage ${languageFlag} should be one of ${languages}`); + } + return tree => { + (0,unist_util_visit__WEBPACK_IMPORTED_MODULE_1__.visit)(tree, 'containerDirective', node => { + if (node.name === 'language-switcher') { + const children = []; + if (languageFlag === undefined) { + children.push(processMenu(node)); + } + children.push(...processChildren(node, languageFlag)); + node.data = { + hProperties: { + className: 'language-switcher' + }, + hChildren: children + }; + } + }); + }; +} +function processMenu(parent) { + const children = parent.children; + return { + type: 'element', + tagName: 'ul', + properties: {}, + children: children.map(node => { + const element = { + type: 'element', + tagName: 'li', + properties: { + 'data-language': node.name + }, + children: [{ + type: 'text', + value: titleCase[languages.indexOf(node.name)] + }] + }; + return element; + }) + }; +} +function processChildren(parent, languageFlag) { + const children = parent.children.map(node => { + const parent = node; + if (languages.includes(parent.name)) { + node.data = { + hProperties: { + 'data-language': parent.name, + className: ['language', languageFlag === parent.name ? 'show' : ''] + } + }; + } + return node; + }); + let filtered = children; + if (languageFlag !== undefined) { + filtered = filtered.filter(node => { + const parent = node; + return languageFlag === parent.name; + }); + } + const parentHast = (0,mdast_util_to_hast__WEBPACK_IMPORTED_MODULE_0__.toHast)({ + type: 'root', + children: filtered + }); + return parentHast.children; +} +__webpack_async_result__(); +} catch(e) { __webpack_async_result__(e); } }); + +/***/ }), + /***/ 3069: /***/ ((module, __webpack_exports__, __webpack_require__) => { @@ -4570,7 +4668,7 @@ var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([chal const repo = 'UofGAnalytics/build-coursework'; async function checkForLatestVersion() { if (false) {} - const currentVersion = "1.1.68"; + const currentVersion = "1.1.69"; try { const tags = await listRemoteGitTags(); const latestTag = parseLatestTag(tags); diff --git a/release/cli.js.map b/release/cli.js.map index fa090fa..8aab923 100644 --- a/release/cli.js.map +++ b/release/cli.js.map @@ -1 +1 @@ -{"version":3,"file":"cli.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AACA;AAEA;AACA;;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAMA;AAEA;AACA;AAOA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAIA;AAEA;AAOA;AACA;AAMA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;;;;;;;;;;;;;;;;;;ACpHA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;ACpJA;AAOA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;ACvDA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;AC7CA;AAEA;AA+CA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;AC9DA;AAEA;AACA;AAEA;AACA;AACA;AAUA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AAKA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;AC9DA;AAEA;AACA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;AC9CA;AAEA;AACA;AAEA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;AC3BA;AACA;AACA;AAIA;AACA;AAEA;AAMA;AACA;AAAA;AAIA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1BA;AAEA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAKA;AAEA;AAEA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAMA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;ACvNA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;AC9BA;AAGA;AAEA;AACA;AACA;AACA;AAKA;AACA;AACA;AAEA;AAQA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AClEA;AACA;AACA;AAEA;AACA;AACA;AAKA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;AC3BA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;AC5BA;AAEA;AACA;AAGA;AAEA;AAKA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAIA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;AC5GA;AACA;AAEA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;;;;;;;;;;;;;;;;;AChFA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AAEA;AACA;;AC1HA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;ACpDA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;AC5CA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7EA;AACA;AACA;AACA;AAEA;AACA;AACA;AAIA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAIA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAKA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAIA;;AAEA;AACA;AACA;;AAEA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;AC/TA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;ACpCA;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAIA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;;AAEA;AAAA;AAEA;AACA;AAKA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AAEA;;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAIA;AAEA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;AC7KA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AC3BA;AAGA;AAEA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;ACpCA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACjBA;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;ACvBA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;ACzBA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AChCA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AC9BA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;ACnCA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAKA;AASA;AAAA;;AAIA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;;;;;;;;;;;;;;;;ACxEA;AAIA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;ACjFA;AACA;AAKA;AAmBA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;AC5GA;AAGA;AAEA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAKA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AAEA;AAIA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AAAA;AAGA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAIA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;ACvNA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;ACtJA;AAEA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;ACnHA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;ACzDA;AAIA;AACA;AACA;AAEA;AAMA;AAIA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;ACxBA;AAGA;AACA;AAKA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;AChGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AASA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;AC/HA;AAGA;AAGA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpJA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAOA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAgBA;AACA;AACA;AACA;;;;;;;;;;;;;;;;ACzDA;AAEA;AACA;AACA;AAIA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;AC7CA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;ACfA;AAEA;AAIA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;AChGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AChBA;AAIA;AAEA;AACA;AACA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAIA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;;;;;;;;;;;;;;;;AChFA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;ACtEA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;ACnIA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACvCA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;ACXA;AAEA;AACA;AAIA;AAEA;AACA;AAGA;AAIA;AACA;AACA;AACA;AAEA;;;;;;;;;;;ACtBA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;ACRA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAIA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;AClEA;AACA;AAIA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;ACxCA;AAEA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAKA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;ACzIA;AAEA;AAGA;AAUA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;ACzDA;AAEA;AACA;AAEA;AAEA;AACA;AAIA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACtDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;ACdA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;AChBA;AAEA;AAEA;;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;AC9CA;AACA;AACA;AAQA;AACA;AAIA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;ACtEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA;AAKA;AACA;AACA;AAEA;AAKA;AACA;AACA;AAEA;AAKA;AACA;AACA;AAEA;AAMA;AACA;AACA;AACA;AACA;;;;;;;;;;ACnDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZA;AACA;AAEA;AACA;AACA;AAGA;;AAEA;AACA;AAAA;AAGA;AAIA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;AC9EA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;ACvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;AChEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;ACPA;;;;;AEAA;AACA;AACA;AACA","sources":["webpack://compiler/./src/build-unit.ts","webpack://compiler/./src/cli/cli.ts","webpack://compiler/./src/code/alias-directive-to-code.ts","webpack://compiler/./src/code/code-to-alias-directive.ts","webpack://compiler/./src/context.ts","webpack://compiler/./src/course/index.ts","webpack://compiler/./src/course/load-course.ts","webpack://compiler/./src/course/load-unit.ts","webpack://compiler/./src/hast/index.ts","webpack://compiler/./src/hast/inline-files.ts","webpack://compiler/./src/hast/responsive-tables.ts","webpack://compiler/./src/html/index.ts","webpack://compiler/./src/html/pdf.ts","webpack://compiler/./src/html/wrapper/index.ts","webpack://compiler/./src/html/wrapper/main.ts","webpack://compiler/./src/html/wrapper/sidebar.ts","webpack://compiler/./src/html/wrapper/view-options/readability.ts","webpack://compiler/./src/html/wrapper/view-options/theme.ts","webpack://compiler/./src/html/wrapper/view-options/index.ts","webpack://compiler/./src/index.ts","webpack://compiler/./src/knitr/knitr.ts","webpack://compiler/./src/latex/directive-to-svg.ts","webpack://compiler/./src/latex/mathjax-tex.ts","webpack://compiler/./src/latex/tex-to-directive.ts","webpack://compiler/./src/linter/assert-asset-exists.ts","webpack://compiler/./src/linter/assert-columns.ts","webpack://compiler/./src/linter/assert-no-h1.ts","webpack://compiler/./src/linter/assert-no-image-attributes.ts","webpack://compiler/./src/linter/assert-no-tex-tabular.ts","webpack://compiler/./src/linter/assert-program-switcher.ts","webpack://compiler/./src/linter/assert-task-answer.ts","webpack://compiler/./src/linter/assert-video-attributes.ts","webpack://compiler/./src/linter/assert-weblink-target.ts","webpack://compiler/./src/linter/index.ts","webpack://compiler/./src/linter/lint-latex.ts","webpack://compiler/./src/linter/report.ts","webpack://compiler/./src/mdast/boxouts.ts","webpack://compiler/./src/mdast/browser-window.ts","webpack://compiler/./src/mdast/code-blocks.ts","webpack://compiler/./src/mdast/columns.ts","webpack://compiler/./src/mdast/combined.ts","webpack://compiler/./src/mdast/embed-asset-url.ts","webpack://compiler/./src/mdast/gitgraph.ts","webpack://compiler/./src/mdast/images.ts","webpack://compiler/./src/mdast/index.ts","webpack://compiler/./src/mdast/move-answers-to-end.ts","webpack://compiler/./src/mdast/pagebreaks.ts","webpack://compiler/./src/mdast/program-switcher.ts","webpack://compiler/./src/mdast/remove-empty-paragraphs.ts","webpack://compiler/./src/mdast/styled-terminal.ts","webpack://compiler/./src/mdast/text-file.ts","webpack://compiler/./src/mdast/youtube-videos.ts","webpack://compiler/./src/pdf/index.ts","webpack://compiler/./src/pre-parse/allow-no-whitespace-before-heading.ts","webpack://compiler/./src/pre-parse/convert-block-tex.ts","webpack://compiler/./src/pre-parse/convert-inline-tex.ts","webpack://compiler/./src/pre-parse/convert-macro-to-directive.ts","webpack://compiler/./src/pre-parse/index.ts","webpack://compiler/./src/pre-parse/reformat-pandoc-simple-tables.ts","webpack://compiler/./src/utils/cache-to-file.ts","webpack://compiler/./src/utils/check-for-latest-version.ts","webpack://compiler/./src/utils/counter.ts","webpack://compiler/./src/utils/get-asset-hast.ts","webpack://compiler/./src/utils/get-svg-hast.ts","webpack://compiler/./src/utils/icons.ts","webpack://compiler/./src/utils/message.ts","webpack://compiler/./src/utils/timer.ts","webpack://compiler/./src/utils/utils.ts","webpack://compiler/./assets/crest.svg","webpack://compiler/./assets/dag-logo.svg","webpack://compiler/./assets/hamburger-icon.svg","webpack://compiler/./assets/hexagons.svg","webpack://compiler/./assets/link-icon.svg","webpack://compiler/./assets/uofg.svg","webpack://compiler/external module \"@double-great/remark-lint-alt-text\"","webpack://compiler/external module \"@mapbox/remark-lint-link-text\"","webpack://compiler/external module \"ansicolor\"","webpack://compiler/external module \"base64-arraybuffer\"","webpack://compiler/external module \"chalk\"","webpack://compiler/external module \"figures\"","webpack://compiler/external module \"hash-sum\"","webpack://compiler/external module \"image-size\"","webpack://compiler/external module \"js-yaml\"","webpack://compiler/external module \"lodash/cloneDeep.js\"","webpack://compiler/external module \"lodash/kebabCase.js\"","webpack://compiler/external module \"lodash/startCase.js\"","webpack://compiler/external module \"markdown-table\"","webpack://compiler/external module \"mathjax-full/js/adaptors/liteAdaptor.js\"","webpack://compiler/external module \"mathjax-full/js/core/MathItem.js\"","webpack://compiler/external module \"mathjax-full/js/core/MmlTree/SerializedMmlVisitor.js\"","webpack://compiler/external module \"mathjax-full/js/handlers/html.js\"","webpack://compiler/external module \"mathjax-full/js/handlers/html/HTMLDocument.js\"","webpack://compiler/external module \"mathjax-full/js/input/mathml.js\"","webpack://compiler/external module \"mathjax-full/js/input/tex.js\"","webpack://compiler/external module \"mathjax-full/js/input/tex/AllPackages.js\"","webpack://compiler/external module \"mathjax-full/js/mathjax.js\"","webpack://compiler/external module \"mathjax-full/js/output/svg.js\"","webpack://compiler/external module \"mdast-util-to-hast\"","webpack://compiler/external module \"mdast-util-toc\"","webpack://compiler/external module \"mime\"","webpack://compiler/external module \"node-fetch\"","webpack://compiler/external module \"puppeteer\"","webpack://compiler/external module \"refractor/lib/all.js\"","webpack://compiler/external module \"rehype-autolink-headings\"","webpack://compiler/external module \"rehype-document\"","webpack://compiler/external module \"rehype-format\"","webpack://compiler/external module \"rehype-parse\"","webpack://compiler/external module \"rehype-raw\"","webpack://compiler/external module \"rehype-slug\"","webpack://compiler/external module \"rehype-stringify\"","webpack://compiler/external module \"remark-directive\"","webpack://compiler/external module \"remark-frontmatter\"","webpack://compiler/external module \"remark-gfm\"","webpack://compiler/external module \"remark-parse\"","webpack://compiler/external module \"remark-rehype\"","webpack://compiler/external module \"speech-rule-engine\"","webpack://compiler/external module \"to-vfile\"","webpack://compiler/external module \"unified\"","webpack://compiler/external module \"unist-util-remove\"","webpack://compiler/external module \"unist-util-visit\"","webpack://compiler/external module \"vfile\"","webpack://compiler/external module \"yargs\"","webpack://compiler/external module \"yargs/helpers\"","webpack://compiler/external module \"yup\"","webpack://compiler/external node-commonjs \"child_process\"","webpack://compiler/external node-commonjs \"fs\"","webpack://compiler/external node-commonjs \"os\"","webpack://compiler/external node-commonjs \"path\"","webpack://compiler/external node-commonjs \"url\"","webpack://compiler/webpack/bootstrap","webpack://compiler/webpack/runtime/async module","webpack://compiler/webpack/runtime/compat get default export","webpack://compiler/webpack/runtime/define property getters","webpack://compiler/webpack/runtime/hasOwnProperty shorthand","webpack://compiler/webpack/before-startup","webpack://compiler/webpack/startup","webpack://compiler/webpack/after-startup"],"sourcesContent":["import { EOL } from 'os';\n\nimport { Parent as HastParent } from 'hast';\nimport { Parent as MdastParent, Root } from 'mdast';\nimport { VFile } from 'vfile';\n\nimport { Context } from './context';\nimport { Unit } from './course/types';\nimport { hastPhase } from './hast';\nimport { htmlPhase } from './html';\nimport { knitr } from './knitr/knitr';\nimport { texToAliasDirective } from './latex/tex-to-directive';\nimport { createReport, reportErrors } from './linter';\nimport { assertNoImageAttributes } from './linter/assert-no-image-attributes';\nimport { mdastPhase } from './mdast';\nimport { combinedMdastPhase } from './mdast/combined';\nimport { convertToPdf } from './pdf';\nimport { preParsePhase } from './pre-parse';\nimport { codeToAliasDirective } from './code/code-to-alias-directive';\n\nexport type BuiltUnit = {\n unit: Unit;\n md: string;\n files: VFile[];\n html?: {\n mdast: MdastParent;\n hast: HastParent;\n html: string;\n };\n pdf?: {\n mdast: MdastParent;\n hast: HastParent;\n html: string;\n pdf: Buffer;\n };\n};\n\nexport async function buildUnit(unit: Unit, ctx: Context) {\n const unifiedFile = await knitr(unit, ctx);\n\n const mdast = (await inSituTransforms(unifiedFile, ctx)) as Root;\n // console.log(mdast);\n\n await createReport(unifiedFile, mdast, ctx);\n\n const result: BuiltUnit = {\n unit,\n md: combineMdFiles(unifiedFile),\n files: [unifiedFile],\n };\n\n if (!ctx.options.noHtml) {\n result.html = await syntaxTreeTransforms(\n mdast,\n unifiedFile,\n unit,\n ctx,\n );\n }\n\n if (!ctx.options.noPdf) {\n const transformed = await syntaxTreeTransforms(\n mdast,\n unifiedFile,\n unit,\n ctx,\n true,\n );\n result.pdf = {\n ...transformed,\n pdf: await convertToPdf(transformed.html),\n };\n }\n\n if (!ctx.options.noReport) {\n reportErrors(result.files, ctx);\n }\n\n return result;\n}\n\nasync function inSituTransforms(file: VFile, ctx: Context) {\n assertNoImageAttributes(file);\n preParsePhase(file);\n await codeToAliasDirective(file, ctx);\n texToAliasDirective(file, ctx);\n return mdastPhase(file, ctx);\n}\n\nfunction combineMdFiles(file: VFile) {\n return removeDirectoryLines(file.value as string);\n}\n\nfunction removeDirectoryLines(md: string) {\n return md\n .split(EOL)\n .filter((line) => !/^::directory\\[.+\\]$/.test(line))\n .join(EOL);\n}\n\nasync function syntaxTreeTransforms(\n _mdast: Root,\n file: VFile,\n unit: Unit,\n ctx: Context,\n targetPdf?: boolean,\n) {\n const mdast = await combinedMdastPhase(_mdast, ctx, file, targetPdf);\n const hast = (await hastPhase(\n mdast,\n ctx,\n file,\n targetPdf,\n )) as HastParent;\n const html = await htmlPhase(hast, mdast, file, unit, ctx, targetPdf);\n return { mdast, hast, html };\n}\n","import chalk from 'chalk';\nimport figures from 'figures';\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\n\nimport { Options } from '../context';\nimport { reportHasFatalErrors } from '../linter/report';\nimport { rMarkdown } from '..';\n\nconst args = {\n week: {\n type: 'number',\n description: 'Build specific week (1-based index)',\n },\n watch: {\n type: 'boolean',\n description: 'Watch coursework for changes',\n },\n noDoc: {\n type: 'boolean',\n description: 'Only compile content HTML',\n },\n noHtml: {\n type: 'boolean',\n description: \"Don't create HTML file\",\n },\n noPdf: {\n type: 'boolean',\n description: \"Don't create PDF file\",\n },\n noSyntaxHighlight: {\n type: 'boolean',\n description: 'No syntax highlighting',\n },\n noReport: {\n type: 'boolean',\n description: 'Bypass linter',\n },\n noEmbedAssets: {\n type: 'boolean',\n description: \"Don't embed assets\",\n },\n noEmbedAssetUrl: {\n type: 'boolean',\n description: \"Don't complete asset Url\",\n },\n noCache: {\n type: 'boolean',\n description: 'No cache',\n },\n noTexSvg: {\n type: 'boolean',\n description: 'No Tex Svg',\n },\n noHexagons: {\n type: 'boolean',\n description: 'No cover hexagons',\n },\n spelling: {\n type: 'boolean',\n description: 'Check spelling',\n },\n pythonBin: {\n type: 'string',\n description: 'Custom path to python binary',\n },\n force: {\n type: 'boolean',\n description: 'Compile even with fatal errors',\n },\n verbose: {\n type: 'boolean',\n description: 'Show error stack',\n },\n envPlatform: {\n type: 'string',\n description: 'Specify which environment platform to display',\n },\n envProgram: {\n type: 'string',\n description: 'Specify which environment program to display',\n },\n fileName: {\n type: 'string',\n description: 'Specify name of output file',\n },\n output: {\n type: 'string',\n description: 'output to stdout',\n choices: ['md', 'html'],\n },\n} as const;\n\nconst argv = yargs(hideBin(process.argv)).options(args).parseSync();\n\nconst dirPath = String(argv._[0] || '.');\n\nconst options: Options = {\n week: argv.week,\n watch: argv.watch,\n noDoc: argv.noDoc,\n noHtml: argv.noHtml,\n noPdf: argv.noPdf,\n noSyntaxHighlight: argv.noSyntaxHighlight,\n noReport: argv.noReport,\n noEmbedAssets: argv.noEmbedAssets,\n noEmbedAssetUrl: argv.noEmbedAssetUrl,\n noCache: argv.noCache,\n noTexSvg: argv.noTexSvg,\n noHexagons: argv.noHexagons,\n spelling: argv.spelling,\n pythonBin: argv.pythonBin,\n force: argv.force,\n verbose: argv.verbose,\n envPlatform: argv.envPlatform,\n envProgram: argv.envProgram,\n fileName: argv.fileName,\n output: argv.output as 'md' | 'html',\n};\n\nasync function run() {\n try {\n const weeks = await rMarkdown(dirPath, options);\n for (const week of weeks) {\n if (options.output === 'html') {\n console.log((week.html?.html || '').trim());\n }\n if (options.output === 'md') {\n console.log(week.md.trim());\n }\n }\n\n // correct exit code even when using --force\n for (const week of weeks) {\n if (reportHasFatalErrors(week.files)) {\n process.exit(1);\n }\n }\n } catch (err: any) {\n console.log(chalk.red(figures.cross + ' ' + err.message));\n if (options.verbose) {\n console.error(err);\n }\n process.exit(1);\n }\n process.exit(0);\n}\n\nrun();\n","import { visit } from 'unist-util-visit';\nimport { LeafDirective, TextDirective } from 'mdast-util-directive';\nimport { Literal, Node } from 'hast';\nimport { Parent } from 'mdast';\n\nimport { CodeBlock, Context } from '../context';\n\nexport function aliasDirectiveToCode(ctx: Context) {\n return (tree: Node) => {\n visit(tree, (node: Node) => {\n if (\n node.type === 'leafDirective' &&\n (node as LeafDirective).name === 'codeBlock'\n ) {\n const idx = getStoreIdx(node as Parent);\n if (ctx.codeStore === undefined) {\n return;\n }\n const stored = ctx.codeStore[idx] as CodeBlock;\n if (!stored) {\n return;\n }\n Object.assign(node, {\n type: 'code',\n name: undefined,\n lang: stored.lang,\n meta: stored.meta,\n value: stored.value,\n children: [],\n });\n }\n if (\n node.type === 'textDirective' &&\n (node as TextDirective).name === 'codeBlock'\n ) {\n const idx = getStoreIdx(node as Parent);\n if (ctx.codeStore === undefined) {\n return;\n }\n const stored = ctx.codeStore[idx] as CodeBlock;\n if (!stored) {\n return;\n }\n Object.assign(node, {\n type: 'inlineCode',\n name: undefined,\n value: stored.value,\n children: [],\n });\n }\n });\n };\n}\n\nfunction getStoreIdx(node: Parent) {\n const firstChild = node.children[0] as Literal;\n return Number(firstChild.value || 0);\n}\n","import { VFile } from 'vfile';\nimport { Context, CodeBlock } from '../context';\nimport { EOL } from 'os';\n\n// The reason for replacing all fenced code blocks with aliases\n// temporarily is because of MathJax. MathJax is designed to look\n// for TeX code inside HTML files, and in our case we need to make it\n// look inside a Markdown file. This leads to MathJax looking for TeX\n// inside code blocks, which can causes problems (especially with SAS\n// code syntax). So this function replaces code blocks with an alias,\n// allows MathJax to do it's thing, then adds it back in with\n// `aliasDirectiveToCode`.\n\nexport async function codeToAliasDirective(file: VFile, ctx: Context) {\n const store: CodeBlock[] = [];\n file.value = codeBlocksToAlias(file.value as string, store);\n file.value = inlineCodeToAlias(file.value as string, store);\n ctx.codeStore = store;\n return file;\n}\n\nfunction codeBlocksToAlias(md: string, store: CodeBlock[]) {\n const verbatimStore: string[] = [];\n return md\n .replace(/^(~~~.+?^~~~)$/gms, (_, match) => {\n verbatimStore.push(match);\n return `::verbatimStore[${verbatimStore.length - 1}]`;\n })\n .replace(/^```(.+?)^```$/gms, (_, match) => {\n const lines = match.split(EOL);\n const lang = lines[0];\n const value = lines.slice(1).join(EOL);\n store.push({ lang, value });\n return `::codeBlock[${store.length - 1}]`;\n })\n .replace(/::verbatimStore\\[(\\d+)\\]/g, (_, match) => {\n return verbatimStore[Number(match)];\n });\n}\n\nfunction inlineCodeToAlias(md: string, store: CodeBlock[]) {\n return md.replace(/`([^\\n`]+?)`/g, (_, value) => {\n store.push({ value });\n return `:codeBlock[${store.length - 1}]`;\n });\n}\n","import { collectCoursework } from './course';\nimport { Course } from './course/types';\nimport { getBuildDir, getCacheDir } from './utils/utils';\n\nexport type Options = {\n noDoc?: boolean;\n noHtml?: boolean;\n noPdf?: boolean;\n noSyntaxHighlight?: boolean;\n noReport?: boolean;\n reportOnlyErrors?: boolean;\n noEmbedAssets?: boolean;\n noEmbedAssetUrl?: boolean;\n noCache?: boolean;\n noTexSvg?: boolean;\n noHexagons?: boolean;\n week?: number;\n watch?: boolean;\n shouldFail?: boolean;\n spelling?: boolean;\n force?: boolean;\n noWrite?: boolean;\n format?: boolean;\n pythonBin?: string;\n verbose?: boolean;\n envPlatform?: string;\n envProgram?: string;\n fileName?: string;\n output?: 'md' | 'html';\n};\n\nexport type CodeBlock = {\n lang?: string | null;\n meta?: string | null;\n value: string;\n};\n\nexport type Context = {\n dirPath: string;\n buildDir: string;\n cacheDir: string;\n course: Course;\n options: Options;\n mmlStore?: string[];\n codeStore?: CodeBlock[];\n refStore: Record;\n figureCounter: number;\n};\n\nexport async function createContext(\n dirPath: string,\n options: Options = {},\n): Promise {\n return {\n course: await collectCoursework(dirPath),\n dirPath,\n buildDir: getBuildDir(dirPath),\n cacheDir: getCacheDir(dirPath),\n options,\n refStore: {},\n figureCounter: 0,\n };\n}\n","import path from 'path';\n\nimport kebabCase from 'lodash/kebabCase.js';\nimport { read as readVfile } from 'to-vfile';\n\nimport { checkLocalFileExists } from '../utils/utils';\nimport { loadCourseYaml } from './load-course';\nimport { loadUnitYaml } from './load-unit';\nimport {\n Course,\n CourseYaml,\n Unit,\n UnitTitles,\n UnitTitlesInput,\n} from './types';\nimport { FileRef } from './types';\n\nexport async function collectCoursework(dirPath: string): Promise {\n const course = await loadCourseYaml(dirPath);\n const coursePath = path.join(process.cwd(), dirPath);\n const units = await Promise.all(\n course.units.map((unit) => collectUnit(unit, course, dirPath)),\n );\n return { ...course, coursePath, units };\n}\n\nasync function collectUnit(\n unit: FileRef,\n course: CourseYaml,\n dirPath: string,\n): Promise {\n const { content, ...yaml } = await loadUnitYaml(dirPath, unit.src);\n const unitPath = path.join(process.cwd(), dirPath, unit.src);\n const files = await Promise.all(\n content.map(async (c) => {\n const filePath = path.resolve(dirPath, unit.src, '..', c.src);\n if (!(await checkLocalFileExists(filePath))) {\n throw new Error(`No Rmd file exists at ${filePath}`);\n }\n return readVfile(filePath, 'utf-8');\n }),\n );\n const titles = getUnitTitles({\n courseTitle: course.title,\n unitName: yaml.name,\n unitTitle: yaml.title,\n });\n return { ...yaml, unitPath, parts: content, files, titles };\n}\n\nexport function getUnitTitles({\n courseTitle,\n unitName,\n unitTitle,\n}: UnitTitlesInput): UnitTitles {\n return {\n courseTitle,\n unitTitle: `${unitName}: ${unitTitle}`,\n unitName,\n docTitle: `${unitTitle} | ${courseTitle}`,\n fileName: kebabCase(unitName),\n };\n}\n","import path from 'path';\n\nimport yaml from 'js-yaml';\nimport * as yup from 'yup';\n\nimport { checkLocalFileExists, readFile } from '../utils/utils';\nimport { CourseYaml } from './types';\n\n// export const validCatalogValues = [\n// 'STATS5077',\n// 'STATS5078',\n// 'STATS5075',\n// 'STATS5084',\n// 'STATS5074',\n// 'STATS5081',\n// 'STATS5080',\n// 'STATS5073',\n// 'STATS5076',\n// 'STATS5079',\n// 'STATS5082',\n// 'STATS5094',\n// 'STATS5083',\n// ];\n\nconst courseSchema = yup.object().shape({\n title: yup.string().required(),\n units: yup.array().of(\n yup.object().shape({\n src: yup.string().required(),\n })\n ),\n catalog: yup.string(),\n authors: yup.string().required(),\n academic_year: yup.string().required(),\n});\n\nexport async function loadCourseYaml(dirPath: string) {\n const courseYamlPath = path.join(dirPath, 'course.yaml');\n if (!(await checkLocalFileExists(courseYamlPath))) {\n throw Error(\n `No course.yaml file exists in ${path.join(process.cwd(), dirPath)}`\n );\n }\n const fileContents = await readFile(courseYamlPath);\n const course = yaml.load(fileContents);\n return courseSchema.validateSync(course) as CourseYaml;\n}\n","import path from 'path';\n\nimport yaml from 'js-yaml';\nimport * as yup from 'yup';\n\nimport { checkLocalFileExists, readFile } from '../utils/utils';\nimport { UnitYaml } from './types';\n\nconst unitSchema = yup.object().shape({\n name: yup.string().required(),\n title: yup.string().required(),\n content: yup.array().of(\n yup.object().shape({\n src: yup.string().required(),\n })\n ),\n});\n\nexport async function loadUnitYaml(dirPath: string, src: string) {\n const contentsPath = path.join(dirPath, src);\n if (!(await checkLocalFileExists(contentsPath))) {\n throw Error(\n `No yaml file exists at ${path.join(process.cwd(), contentsPath)}`\n );\n }\n const fileContents = await readFile(contentsPath);\n const unit = yaml.load(fileContents);\n return unitSchema.validateSync(unit) as UnitYaml;\n}\n","import { Root } from 'mdast';\nimport rehypeRaw from 'rehype-raw';\nimport remark2rehype from 'remark-rehype';\nimport { unified } from 'unified';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { inlineRelativeAssets } from './inline-files';\nimport { responsiveTables } from './responsive-tables';\n\nexport async function hastPhase(\n mdast: Root,\n ctx: Context,\n file: VFile,\n targetPdf?: boolean,\n) {\n const processor = unified()\n .use(remark2rehype, { allowDangerousHtml: true })\n .use(rehypeRaw)\n .use(responsiveTables);\n\n if (!ctx.options.noEmbedAssets) {\n processor.use(inlineRelativeAssets, ctx);\n }\n\n return processor.run(mdast, file);\n}\n","import path from 'path';\n\nimport { encode as base46Encode } from 'base64-arraybuffer';\nimport { Element, Properties } from 'hast';\nimport sizeOf from 'image-size';\nimport mimes from 'mime';\nimport fetch from 'node-fetch';\nimport { toVFile } from 'to-vfile';\n// import { optimize } from 'svgo';\nimport { Parent } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\n// import { pdfToSvg } from '../pdf/pdf-to-svg';\nimport { cacheToFile } from '../utils/cache-to-file';\nimport { getSvgHast } from '../utils/get-svg-hast';\nimport { failMessage } from '../utils/message';\nimport { readFile, rehypeParser } from '../utils/utils';\n\nexport function inlineRelativeAssets(ctx: Context) {\n return async (tree: Element, file: VFile) => {\n const transformations: Promise[] = [];\n const loadedScripts: string[] = [];\n\n visit(tree, 'element', (node, index, parent) => {\n if (node.tagName === 'img') {\n transformations.push(embedFile(node, file, ctx));\n }\n if (node.tagName === 'script' && node.properties?.src) {\n transformations.push(\n embedScript(node, index, parent, loadedScripts),\n );\n }\n });\n\n await Promise.all(transformations);\n };\n}\n\nasync function embedFile(node: Element, file: VFile, ctx: Context) {\n const src = getImageSrc(node);\n const parsed = path.parse(src);\n try {\n switch (parsed.ext) {\n case '.png':\n case '.jpg':\n case '.jpeg':\n case '.gif':\n return await embedImage(node, ctx, file);\n case '.svg':\n return await embedSvg(node, ctx);\n case '.pdf':\n // return await embedPdfSvg(node);\n throw new Error(\n `Unhandled file extension: .pdf (convert to .svg)`,\n );\n case '.html':\n return await embedHtml(node);\n default:\n throw new Error(`Unhandled file extension: ${parsed.ext}`);\n }\n } catch (_err) {\n console.log(_err);\n const err = _err as Error;\n failMessage(file, err?.message || '', node.position);\n }\n}\n\nasync function embedImage(node: Element, ctx: Context, file: VFile) {\n const src = getImageSrc(node);\n const mime = mimes.getType(path.extname(src));\n try {\n const image = await getImage(src, ctx);\n const { width } = sizeOf(Buffer.from(image, 'base64'));\n node.properties = {\n ...node.properties,\n src: `data:${mime};base64,${image}`,\n style: [`max-width: ${width}px`],\n };\n } catch (err) {\n console.log(err);\n failMessage(file, `Image not found: ${src}`);\n }\n}\n\nasync function embedSvg(imgNode: Element, ctx: Context) {\n const src = getImageSrc(imgNode);\n const contents = await readFile(src);\n const idx = contents.indexOf(' String(x)).filter((s) => s !== removeClass);\n }\n return [];\n}\n\nfunction getImageSrc(node: Element) {\n const properties = (node.properties || {}) as { src: string };\n if (!properties.src) {\n throw new Error('Image has no src');\n }\n return properties.src;\n}\n\nasync function getImage(src: string, ctx: Context) {\n if (src.startsWith('http')) {\n return cacheToFile({\n ctx,\n prefix: 'youtube',\n key: src,\n execFn: getImageDataFromWeb,\n });\n }\n return readFile(src, 'base64');\n}\n\nasync function getImageDataFromWeb(src: string) {\n const response = await fetch(src);\n const buffer = await response.arrayBuffer();\n return base46Encode(buffer);\n}\n\n// async function embedPdfSvg(imgNode: Element) {\n// const src = getImageSrc(imgNode);\n// const svgNode = (await pdfToSvg(src)) as Element;\n// console.log('hey!');\n// console.log(svgNode);\n\n// const properties = {\n// ...imgNode.properties,\n// ...svgNode.properties,\n// } as Properties;\n\n// delete properties.src;\n\n// Object.assign(imgNode, svgNode, { properties });\n// }\n\nasync function embedHtml(imgNode: Element) {\n const src = getImageSrc(imgNode);\n const value = await readFile(src);\n const vfile = toVFile({ value });\n const parsed = rehypeParser().parse(vfile) as Parent;\n\n Object.assign(imgNode, {\n tagName: 'div',\n properties: {\n className: 'interactive-element',\n },\n children: parsed.children,\n });\n}\n\nasync function embedScript(\n node: Element,\n index: number | undefined,\n parent: Parent | undefined,\n loadedScripts: string[],\n) {\n if (!node.properties?.src) {\n return;\n }\n\n const src = node.properties.src as string;\n\n if (loadedScripts.includes(src)) {\n // script already inlined, remove tag\n const parentChildren = parent?.children || [];\n parentChildren.splice(index || 0, 1);\n return;\n }\n\n loadedScripts.push(src);\n\n delete node.properties.src;\n const response = await fetch(src);\n const value = await response.text();\n\n node.children = [\n {\n type: 'text',\n value: `// ${src}\\n${value}\\n`,\n },\n ];\n}\n","import { Root, Element } from 'hast';\nimport cloneDeep from 'lodash/cloneDeep.js';\nimport { visit } from 'unist-util-visit';\n\ntype ParentProps = {\n className: string[];\n};\n\nexport function responsiveTables() {\n return function (tree: Root) {\n visit(tree, 'element', (node, idx, _parent) => {\n if (node.tagName !== 'table') {\n return;\n }\n\n const parent = _parent as Element;\n const properties = (parent?.properties || {}) as ParentProps;\n const className = properties.className || [];\n\n if (!className.includes('table-wrapper')) {\n Object.assign(node, {\n tagName: 'div',\n properties: {\n className: 'table-wrapper',\n },\n children: [cloneDeep(node)],\n });\n }\n });\n };\n}\n","import path from 'path';\n\nimport { Parent as HastParent } from 'hast';\nimport startCase from 'lodash/startCase.js';\nimport { Parent as MdastParent } from 'mdast';\nimport doc, { Options } from 'rehype-document';\nimport format from 'rehype-format';\nimport stringify from 'rehype-stringify';\nimport { unified } from 'unified';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { Unit } from '../course/types';\nimport { getTemplateDir, readFile } from '../utils/utils';\nimport { pdfWrapper } from './pdf';\nimport { htmlWrapper } from './wrapper';\n\nexport async function htmlPhase(\n hast: HastParent,\n mdast: MdastParent,\n file: VFile,\n unit: Unit,\n ctx: Context,\n targetPdf?: boolean,\n) {\n const processor = unified().use(stringify, { allowDangerousHtml: true });\n\n if (ctx.options.format) {\n // hangs in some scenarios so off by default, useful in tests\n processor.use(format);\n }\n\n if (!ctx.options.noDoc) {\n const cssPath = path.join(getTemplateDir(), 'template.css');\n const docOptions: Options = {\n title: unit.titles.docTitle,\n style: `\\n${await readFile(cssPath)}\\n`,\n };\n\n if (!targetPdf) {\n const jsPath = path.join(getTemplateDir(), 'template.js2');\n docOptions.script = `\\n${await readFile(jsPath)}\\n`;\n processor.use(htmlWrapper, unit, mdast, ctx);\n } else {\n processor.use(pdfWrapper, unit, ctx);\n }\n\n processor.use(doc, docOptions);\n }\n\n const transformed = await processor.run(hast, file);\n\n const result = processor.stringify(transformed as any, file);\n\n return postTransforms(result, ctx);\n}\n\nfunction postTransforms(html: string, ctx: Context) {\n let result = '';\n result = referenceTransform(html, ctx.refStore);\n return result;\n}\n\nfunction referenceTransform(html: string, refStore: Context['refStore']) {\n return html.replace(/ref:\\/\\/(\\w+)/gms, (...match) => {\n const key = match[1];\n const link = refStore[key];\n const name = startCase(link);\n return `${name}`;\n });\n}\n","import { Node, Parent } from 'unist';\n\nimport { Context } from '../context';\nimport { Unit } from '../course/types';\n// import { UnitTitles } from '../course/types';\nimport { createDefs } from '../utils/icons';\nimport { createMain } from './wrapper/main';\n\nexport function pdfWrapper(unit: Unit, ctx: Context) {\n return async (tree: Node) => {\n const main = await createMain(\n unit.titles,\n ctx,\n (tree as Parent).children\n );\n const iconDefs = createDefs();\n return {\n type: 'root',\n children: [\n {\n type: 'element',\n tagName: 'div',\n properties: {\n id: 'root',\n className: ['hide-sidebar', 'font-default', 'pdf'],\n },\n children: [iconDefs, main],\n },\n ],\n };\n };\n}\n","import { Parent } from 'mdast';\n\nimport { Context } from '../../context';\nimport { Unit } from '../../course/types';\nimport { createDefs, createSvg } from '../../utils/icons';\nimport { createMain } from './main';\nimport { createSidebar } from './sidebar';\n\nexport function htmlWrapper(unit: Unit, mdast: Parent, ctx: Context) {\n return async (tree: Parent) => {\n const hamburgerIcon = createSvg('hamburger-icon');\n const sidebar = await createSidebar(mdast);\n const main = await createMain(unit.titles, ctx, tree.children);\n const iconDefs = createDefs();\n return {\n type: 'root',\n children: [\n {\n type: 'element',\n tagName: 'div',\n properties: {\n id: 'root',\n className: ['hide-sidebar'],\n },\n children: [iconDefs, main, hamburgerIcon, sidebar],\n },\n ],\n };\n };\n}\n","import { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nimport dagLogoSvg from '../../../assets/dag-logo.svg';\nimport coverSvg from '../../../assets/hexagons.svg';\nimport { Context } from '../../context';\nimport { Course, UnitTitles } from '../../course/types';\nimport { getAssetHast } from '../../utils/get-asset-hast';\n\nexport async function createMain(\n titles: UnitTitles,\n ctx: Context,\n content: Node[]\n) {\n const children = [];\n\n if (ctx.options.noHexagons) {\n children.push(createH1(titles));\n } else {\n children.push(createCover(titles, ctx.course));\n }\n\n children.push(...content);\n\n return {\n type: 'element',\n tagName: 'main',\n children: [\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'wrapper',\n },\n children,\n },\n ],\n };\n}\n\nfunction createCover(titles: UnitTitles, course: Course) {\n return {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'cover',\n },\n children: [\n createH1(titles),\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'logos',\n },\n children: [\n createCoverHexagons(course.catalog || ''),\n getAssetHast(dagLogoSvg),\n ],\n },\n ],\n };\n}\n\nfunction createH1(titles: UnitTitles) {\n return {\n type: 'element',\n tagName: 'h1',\n children: [\n {\n type: 'text',\n value: titles.courseTitle,\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'unit',\n },\n children: [\n {\n type: 'text',\n value: titles.unitTitle,\n },\n ],\n },\n ],\n };\n}\n\nfunction createCoverHexagons(catalog: string) {\n const hexagons = getAssetHast(coverSvg);\n\n if (catalog !== '') {\n visit(hexagons, 'element', (node) => {\n if (node.tagName === 'g') {\n const properties = node.properties || {};\n const [className] = (properties.className || []) as string[];\n if (catalog === className) {\n properties.className = ['active'];\n } else {\n properties.className = [];\n }\n node.properties = properties;\n }\n });\n }\n\n return hexagons;\n}\n","import { List, Nodes, Parent } from 'mdast';\nimport { toHast } from 'mdast-util-to-hast';\nimport { toc as getToc } from 'mdast-util-toc';\n\nimport crestSvg from '../../../assets/crest.svg';\nimport uOfGSvg from '../../../assets/uofg.svg';\nimport { getAssetHast } from '../../utils/get-asset-hast';\nimport { createSvg } from '../../utils/icons';\nimport {\n createViewOptions,\n createViewOptionsButton,\n} from './view-options';\n\nexport async function createSidebar(mdast: Parent) {\n const logo = await createLogo();\n const toc = getToc(mdast as Nodes, { maxDepth: 3 }).map;\n const tocChildren = toc === undefined ? [] : [toHast(toc)];\n\n printTableOfContents(toc);\n\n return {\n type: 'element',\n tagName: 'aside',\n children: [\n logo,\n createViewOptionsButton(),\n {\n type: 'element',\n tagName: 'nav',\n properties: {\n id: 'toc',\n },\n children: tocChildren,\n },\n {\n type: 'element',\n tagName: 'div',\n properties: {\n id: 'view-options',\n },\n children: createViewOptions(),\n },\n ],\n };\n}\n\nasync function createLogo() {\n const crest = getAssetHast(crestSvg);\n const uofg = getAssetHast(uOfGSvg);\n const hamburgerIcon = createSvg('hamburger-icon');\n return {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'logo',\n },\n children: [\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'logo-wrapper',\n },\n children: [crest, uofg],\n },\n hamburgerIcon,\n ],\n };\n}\n\nfunction printTableOfContents(toc: List | undefined) {\n // toc?.children.forEach((a) => {\n // a.children.forEach((b) => {\n // if (b.type === 'paragraph') {\n // // @ts-ignore\n // console.log(`- [ ] ${b.children[0].children[0].value}`);\n // }\n // if (b.type === 'list') {\n // b.children.forEach((c) => {\n // c.children.forEach((d) => {\n // if (d.type === 'paragraph') {\n // // @ts-ignore\n // console.log(` - [ ] ${d.children[0].children[0].value}`);\n // }\n // });\n // });\n // }\n // });\n // });\n}\n","import { Item } from './shared';\n\ntype ReadabilityItem = Item & {\n min: number;\n max: number;\n increment: number;\n};\n\nconst options: ReadabilityItem[] = [\n {\n value: 'fontSize',\n label: 'Font-size',\n min: 0.6,\n max: 2,\n increment: 0.1,\n },\n {\n value: 'lineSpacing',\n label: 'Line spacing',\n min: 0.6,\n max: 2,\n increment: 0.1,\n },\n {\n value: 'letterSpacing',\n label: 'Letter spacing',\n min: -0.1,\n max: 0.2,\n increment: 0.05,\n },\n {\n value: 'lineWidth',\n label: 'Line width',\n min: 0.6,\n max: 1.2,\n increment: 0.05,\n },\n];\n\nexport function createReadabilityList() {\n return {\n type: 'element',\n tagName: 'ul',\n properties: {\n id: 'readability',\n },\n children: options.map(createOption),\n };\n}\n\nfunction createOption(item: ReadabilityItem) {\n return {\n type: 'element',\n tagName: 'li',\n properties: {\n className: [item.value],\n 'data-min': item.min,\n 'data-max': item.max,\n 'data-increment': item.increment,\n },\n children: [\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['label'],\n },\n children: [\n {\n type: 'text',\n value: item.label,\n },\n ],\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['actions'],\n },\n children: [\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['btn', 'minus'],\n },\n children: [\n {\n type: 'text',\n value: '−',\n },\n ],\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['btn', 'plus'],\n },\n children: [\n {\n type: 'text',\n value: '+',\n },\n ],\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['btn', 'reset'],\n },\n children: [\n {\n type: 'text',\n value: 'Reset',\n },\n ],\n },\n ],\n },\n ],\n };\n}\n","import { Item } from './shared';\n\nconst themes: Item[] = [\n {\n value: 'light',\n label: 'Light',\n },\n {\n value: 'dark',\n label: 'Dark',\n },\n {\n value: 'yellow-on-black',\n label: 'Yellow on Black',\n },\n {\n value: 'black-on-yellow',\n label: 'Black on Yellow',\n },\n {\n value: 'black-on-red',\n label: 'Black on Red',\n },\n {\n value: 'black-on-blue',\n label: 'Black on Blue',\n },\n];\n\nexport function createThemeList() {\n return {\n type: 'element',\n tagName: 'ul',\n properties: {\n id: 'themes',\n },\n children: themes.map(createThemeButton),\n };\n}\n\nfunction createThemeButton(theme: Item) {\n return {\n type: 'element',\n tagName: 'li',\n properties: {\n className: [theme.value],\n },\n children: [\n {\n type: 'text',\n value: theme.label,\n },\n ],\n };\n}\n","import { Node } from 'unist';\n\n// import { createFontList } from './font';\nimport { createReadabilityList } from './readability';\nimport { createThemeList } from './theme';\n\nexport function createViewOptionsButton() {\n return {\n type: 'element',\n tagName: 'div',\n properties: {\n id: 'view-options-toggle',\n },\n children: [\n {\n type: 'text',\n value: 'View options',\n },\n ],\n };\n}\n\nexport function createViewOptions(): Node[] {\n return [\n createTitle('Theme'),\n createThemeList(),\n // createTitle('Font'),\n // createFontList(),\n createTitle('Readability'),\n createReadabilityList(),\n ];\n}\n\nfunction createTitle(value: string) {\n return {\n type: 'element',\n tagName: 'h3',\n children: [\n {\n type: 'text',\n value,\n },\n ],\n };\n}\n","import path from 'path';\n\nimport chalk from 'chalk';\n\nimport { BuiltUnit, buildUnit } from './build-unit';\nimport { Context, Options, createContext } from './context';\nimport { checkForLatestVersion } from './utils/check-for-latest-version';\nimport { Timer, createTimer } from './utils/timer';\nimport { mkdir, writeFile } from './utils/utils';\n\nexport async function rMarkdown(dirPath: string, options: Options = {}) {\n if (!options.output) {\n await checkForLatestVersion();\n }\n\n const timer = createTimer();\n const ctx = await createContext(dirPath, options);\n\n const result = [];\n\n if (ctx.options.week) {\n // write single week\n const idx = ctx.options.week - 1;\n const input = ctx.course.units[idx];\n\n if (input === undefined) {\n const courseYaml = path.join(ctx.dirPath, 'course.yaml');\n throw new Error(\n `Week ${ctx.options.week} not found in ${courseYaml}`,\n );\n }\n\n const built = await buildUnit(input, ctx);\n await writeUnit(built, ctx, timer);\n result.push(built);\n } else {\n // write full course\n for (const input of ctx.course.units) {\n const built = await buildUnit(input, ctx);\n await writeUnit(built, ctx, timer);\n result.push(built);\n }\n }\n return result;\n}\n\nasync function writeUnit(built: BuiltUnit, ctx: Context, timer: Timer) {\n if (ctx.options.noWrite) {\n return;\n }\n\n await mkdir(ctx.buildDir);\n const fileName = ctx.options.fileName\n ? ctx.options.fileName\n : built.unit.titles.fileName;\n const filePath = path.join(ctx.buildDir, fileName);\n\n if (built.html) {\n await writeFile(filePath + '.html', built.html.html);\n\n if (!ctx.options.output) {\n const status = chalk.green.bold(`Complete in ${timer.seconds()}s`);\n console.log(`✨ ${status} ${filePath}.html`);\n }\n }\n\n if (built.pdf) {\n await writeFile(filePath + '.pdf', built.pdf.pdf);\n\n // debug\n // await writeFile(filePath + '.pdf.html', built.pdf.html);\n\n if (!ctx.options.output) {\n const status = chalk.green.bold(`Complete in ${timer.seconds()}s`);\n console.log(`✨ ${status} ${filePath}.pdf`);\n }\n }\n}\n","import { exec } from 'child_process';\nimport { EOL } from 'os';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nimport chalk from 'chalk';\nimport hashSum from 'hash-sum';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { Unit } from '../course/types';\nimport { failMessage, infoMessage, warnMessage } from '../utils/message';\nimport { mkdir, rmFile, writeFile } from '../utils/utils';\n\n// bypass knitr for debugging\n// export async function knitr(unit: Unit, ctx: Context) {\n// const file = new VFile();\n// file.value = unit.files.reduce((acc, o) => {\n// return acc + EOL + EOL + o.value;\n// }, '');\n// return file;\n// }\n\nexport async function knitr(unit: Unit, ctx: Context) {\n const parentFile = await createParentFile(unit, ctx);\n // console.log(parentFile.value);\n\n const result = await execKnitr(parentFile, ctx, unit.unitPath);\n // console.log(result);\n parentFile.value = result;\n return parentFile;\n}\n\n// creating a temporary file which includes all child files allows\n// R/Python state to be shared across multiple .Rmd files\n// https://yihui.org/knitr/options/#child-documents\nasync function createParentFile(unit: Unit, ctx: Context) {\n const file = new VFile();\n\n let value = '';\n\n // pass path to custom python binary to reticulate\n // https://rstudio.github.io/reticulate/articles/r_markdown.html\n if (ctx.options.pythonBin) {\n const reticulate = `reticulate::use_python(\"${ctx.options.pythonBin}\")`;\n value += `\\`\\`\\`{r, echo=FALSE}${EOL}${reticulate}${EOL}\\`\\`\\`${EOL}${EOL}`;\n }\n\n value += unit.files.reduce((acc, o) => {\n const [filePath] = o.history;\n\n // directory directive is used to ensure external assets\n // can have relative paths to the .Rmd document.\n // used in embed-asset-url mdast transform\n const fileDir = path.parse(filePath).dir;\n const directive = `::directory[${fileDir}]`;\n\n // child document\n // convert all file paths to forward slash (windows anaconda/knitr bug)\n const formattedPath = path\n .relative(ctx.cacheDir, filePath)\n .replace(/\\\\/g, '/');\n\n const childCodeBlock = `\\`\\`\\`{r, child='${formattedPath}'}${EOL}\\`\\`\\``;\n return acc + directive + EOL + EOL + childCodeBlock + EOL + EOL;\n }, '');\n\n // console.log(value);\n\n file.value = value;\n return file;\n}\n\nasync function execKnitr(file: VFile, ctx: Context, unitPath: string) {\n const md = file.value as string;\n const uniqueId = getUniqueId(md);\n const cachedFile = path.join(ctx.cacheDir, `${uniqueId}.Rmd`);\n const cacheDir = path.join(ctx.cacheDir, uniqueId);\n await mkdir(cacheDir);\n await writeFile(cachedFile, md);\n\n return new Promise((resolve, reject) => {\n const cmd = createKnitrCommand(ctx, uniqueId, unitPath);\n\n exec(cmd, async (err, response, stdErr) => {\n if (stdErr) {\n if (!ctx.options.output) {\n console.log(chalk.grey(`[knitr] ${stdErr.trim()}`));\n }\n if (isFailingStdErr(stdErr)) {\n failMessage(file, stdErr);\n }\n }\n\n if (err) {\n console.error('ERROR', err);\n reject(err);\n } else {\n reportErrors(response, file, ctx);\n resolve(formatResponse(response));\n }\n await rmFile(cachedFile);\n });\n });\n}\n\nfunction getUniqueId(md: string) {\n const hash = hashSum(md);\n const ts = new Date().getTime().toString();\n return `knitr-${hash}-${ts}`;\n}\n\nfunction createKnitrCommand(\n ctx: Context,\n uniqueId: string,\n unitPath: string,\n) {\n const rFileDir = getKnitrFileDir();\n const rFile = path.join(rFileDir, 'knitr.R');\n const baseDir = path.parse(unitPath).dir;\n const cachedFile = path.join(ctx.cacheDir, `${uniqueId}.Rmd`);\n const cacheDir = path.join(ctx.cacheDir, uniqueId);\n\n // spawn args\n // return [rFile, cachedFile, baseDir, cacheDir];\n\n return `Rscript \"${rFile}\" \"${cachedFile}\" \"${baseDir}\" \"${cacheDir}\"`;\n}\n\nfunction getKnitrFileDir() {\n // temporary hack until this PR is merged\n // https://github.com/webpack/webpack/pull/15246\n if (process.env.NODE_ENV === 'production') {\n return __dirname;\n }\n return path.dirname(fileURLToPath(import.meta.url));\n}\n\nfunction isFailingStdErr(stdErr: string) {\n // console.log({ stdErr });\n return /status 1\\d*$/.test(stdErr.trim());\n}\n\nfunction reportErrors(response: string, file: VFile, ctx: Context) {\n const lines = response\n .split(EOL)\n .filter((s) => !s.startsWith(':directory'));\n\n const trimmed = lines.join(EOL).trim();\n\n // Warning at the start of a document\n if (trimmed.startsWith('WARNING -')) {\n const match = trimmed.match(/^WARNING - (.+?)[\\r\\n]{2,}/ms);\n\n // Check the original file doesn't start with WARNING\n const original = String(ctx.course.units[0].files[0].value)\n .split(EOL)\n .filter((s) => !s.startsWith(':directory'))\n .join(EOL)\n .trim();\n\n if (match !== null && !original.startsWith('WARNING -')) {\n warnMessage(file, match[1], {\n start: {\n line: 1,\n column: 0,\n },\n end: {\n line: 1,\n column: lines[0].length,\n },\n });\n }\n\n // Python binary path\n } else if (trimmed.startsWith('$python [1]')) {\n const match = trimmed.match(/^\\$python\\s\\[1\\]\\s(\"\\S+\")/);\n if (match !== null) {\n infoMessage(file, match[1], {\n start: {\n line: 1,\n column: 0,\n },\n end: {\n line: 1,\n column: lines[0].length,\n },\n });\n }\n }\n\n // Errors throughout document\n lines.forEach((line, idx) => {\n const trimmedLine = line.trim();\n if (trimmedLine.startsWith('## Error')) {\n warnMessage(file, trimmedLine.replace('## ', ''), {\n start: {\n line: idx + 1,\n column: 0,\n },\n end: {\n line: idx + 1,\n column: line.length,\n },\n });\n }\n });\n}\n\nasync function formatResponse(response: string) {\n let md = response;\n md = removeCustomPythonBinNotice(md);\n md = removePythonWarningMessage(md);\n md = addErrorCodeBlock(md);\n md = removeHashSigns(md);\n md = removeEmptyLog(md);\n md = addNewLineAfterKable(md);\n return md;\n}\n\nfunction removeCustomPythonBinNotice(md: string) {\n return md.replace(/^\\$python\\s\\[1\\]\\s\"\\S+\"/, '');\n}\n\nfunction removePythonWarningMessage(md: string) {\n return md.replace(/^WARNING - .+?[\\r\\n]+/m, '');\n}\n\nfunction removeHashSigns(md: string) {\n let insideCodeResponse = false;\n let openingLine = '';\n return md\n .split('\\n')\n .reduce((acc: string[], line) => {\n if (line.startsWith('```')) {\n insideCodeResponse = !insideCodeResponse;\n openingLine = insideCodeResponse ? line : '';\n }\n if (insideCodeResponse && openingLine.endsWith('-output}')) {\n acc.push(line.replace(/^##\\s+/, ''));\n } else {\n acc.push(line);\n }\n return acc;\n }, [])\n .join('\\n');\n}\n\nfunction removeEmptyLog(md: string) {\n return md.replace(/\\[1\\]\\s\"\"$/gm, '').trim();\n}\n\nfunction addErrorCodeBlock(md: string) {\n return md\n .split('\\n')\n .reduce((acc: string[], line, idx) => {\n if (idx > 0 && acc[idx - 1].startsWith('```')) {\n if (line.startsWith('## Error') || line.startsWith('## fatal')) {\n acc[acc.length - 1] = `\\`\\`\\`{.error-output}`;\n }\n }\n acc.push(line);\n return acc;\n }, [])\n .join('\\n');\n}\n\nfunction addNewLineAfterKable(md: string) {\n return md\n .split('\\n')\n .reduce((acc: string[], line, idx) => {\n if (acc[idx - 1]?.startsWith('|') && !line.startsWith('|')) {\n acc.push('', line);\n } else {\n acc.push(line);\n }\n return acc;\n }, [])\n .join('\\n');\n}\n\n// experimental streaming output\n// async function spawnKnitr(file: VFile, ctx: Context, unitPath: string) {\n// const md = file.value as string;\n// const uniqueId = getUniqueId(md);\n// const cachedFile = path.join(ctx.cacheDir, `${uniqueId}.Rmd`);\n// const cacheDir = path.join(ctx.cacheDir, uniqueId);\n// await mkdir(cacheDir);\n// await writeFile(cachedFile, md);\n\n// return new Promise((resolve, reject) => {\n// const args = createKnitrCommand(ctx, uniqueId, unitPath);\n// const knitr = spawn('Rscript', args);\n// const result: string[] = [];\n\n// knitr.stdout.on('data', (data) => {\n// const str = data.toString();\n// console.log(str);\n// result.push(str);\n// });\n\n// knitr.stdout.on('end', () => {\n// console.log('STDOUT END');\n// const end = result.join('');\n// console.log('END', end);\n// reportErrors(end, file);\n// resolve(formatResponse(end));\n// });\n\n// knitr.stdout.on('error', (err) => {\n// console.log('STDOUT ERROR', err, err.toString());\n// reject();\n// });\n\n// knitr.stderr.on('data', (data) => {\n// const str = data.toString();\n// console.log('STDERR ERROR', str);\n// });\n// }).then(async (result) => {\n// await rmFile(cachedFile);\n// return result;\n// });\n// }\n","import { Element, Literal } from 'hast';\nimport { Parent, Root } from 'mdast';\nimport { TextDirective } from 'mdast-util-directive';\nimport { visit } from 'unist-util-visit';\n\nimport { Context } from '../context';\nimport { rehypeParser } from '../utils/utils';\nimport { mmlToSpeech, mmlToSvg } from './mathjax-tex';\n\nexport function aliasDirectiveToLatexSvg(ctx: Context) {\n return (tree: Root) => {\n visit(tree, 'textDirective', (node: TextDirective) => {\n if (!ctx.mmlStore || ctx.options.noTexSvg) {\n return;\n }\n switch (node.name) {\n case 'inlineMath':\n case 'blockMath': {\n const idx = getTexIdx(node as TextDirective);\n const mml = ctx.mmlStore[idx];\n const svg = renderSvg(mml);\n const properties = {\n ...svg.properties,\n className:\n node.name === 'inlineMath' ? 'inline-math' : 'block-math',\n id: getRefId(mml),\n };\n node.data = {\n hName: svg.tagName,\n hProperties: properties,\n hChildren: svg.children,\n };\n }\n }\n });\n };\n}\n\nfunction getTexIdx(node: Parent) {\n const firstChild = node.children[0] as Literal;\n return Number(firstChild.value || 0);\n}\n\nfunction getRefId(mml: string) {\n const match = mml.match(/;\n\n const newProperties: Record = {\n width: properties.width,\n height: properties.height,\n viewBox: properties.viewBox,\n role: 'img',\n };\n\n if (label !== '') {\n const uniqueId = `math-${Math.random().toString(16).slice(2)}`;\n newProperties['aria-labelledby'] = uniqueId;\n svg.children.unshift({\n type: 'element',\n tagName: 'title',\n properties: {\n id: uniqueId,\n },\n children: [\n {\n type: 'text',\n value: label,\n },\n ],\n });\n }\n\n svg.properties = newProperties;\n return svg;\n}\n","import { liteAdaptor } from 'mathjax-full/js/adaptors/liteAdaptor.js';\nimport { STATE } from 'mathjax-full/js/core/MathItem.js';\nimport { SerializedMmlVisitor } from 'mathjax-full/js/core/MmlTree/SerializedMmlVisitor.js';\nimport { RegisterHTMLHandler } from 'mathjax-full/js/handlers/html.js';\nimport { HTMLDocument } from 'mathjax-full/js/handlers/html/HTMLDocument.js';\nimport { MathML } from 'mathjax-full/js/input/mathml.js';\nimport { TeX } from 'mathjax-full/js/input/tex.js';\nimport { AllPackages } from 'mathjax-full/js/input/tex/AllPackages.js';\nimport { mathjax } from 'mathjax-full/js/mathjax.js';\nimport { SVG } from 'mathjax-full/js/output/svg.js';\n// @ts-expect-error\nimport SRE from 'speech-rule-engine';\n\nexport function texToMml(tex: string = '') {\n const adaptor = liteAdaptor();\n // Busproofs requires an output jax, which we aren't using\n const packages = AllPackages.filter((name) => name !== 'bussproofs');\n const input = new TeX({ packages });\n const doc = new HTMLDocument('', adaptor, { InputJax: input });\n const node = doc.convert(tex, { end: STATE.CONVERT });\n const visitor = new SerializedMmlVisitor();\n return visitor.visitTree(node);\n}\n\nexport function mmlToSvg(mml: string) {\n const adaptor = liteAdaptor();\n RegisterHTMLHandler(adaptor);\n const input = new MathML();\n const output = new SVG({ fontCache: 'local' });\n const doc = mathjax.document('', { InputJax: input, OutputJax: output });\n const node = doc.convert(mml, { em: 25 });\n return adaptor.outerHTML(node);\n}\n\nexport function mmlToSpeech(mml: string) {\n return SRE.toSpeech(mml);\n}\n","import { liteAdaptor } from 'mathjax-full/js/adaptors/liteAdaptor.js';\nimport { MathDocument } from 'mathjax-full/js/core/MathDocument.js';\nimport * as MathItem from 'mathjax-full/js/core/MathItem.js';\nimport { SerializedMmlVisitor } from 'mathjax-full/js/core/MmlTree/SerializedMmlVisitor.js';\nimport { RegisterHTMLHandler } from 'mathjax-full/js/handlers/html.js';\nimport { TeX } from 'mathjax-full/js/input/tex.js';\nimport { AllPackages } from 'mathjax-full/js/input/tex/AllPackages.js';\nimport { mathjax } from 'mathjax-full/js/mathjax.js';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { assertNoTexTabular } from '../linter/assert-no-tex-tabular';\nimport { failMessage } from '../utils/message';\n\n// This custom MathJax implementation has had to diverge from the provided demos found\n// here: https://github.com/mathjax/MathJax-demos-node, because they are all focused on\n// either converting LaTeX on its own or (referencing \"page\" demos) LaTeX embedded in\n// HTML, whereas at this stage in the processor we're dealing with LaTeX embedded in\n// Markdown. Due to TeX/LaTeX making heavy use of the backslash (\\) character, we need\n// to deal with it early as it conflicts with other libraries used later.\n\n// I use the MathJax \"page\" process as it will pick up LaTeX even without delimiters\n// and stores context required for numbered references (based on direct/tex2mml-page).\n// However this has a naive HTML handler which will munge HTML (and Python) in some\n// cases so I am careful to only mutate TeX and leave the rest of the Markdown alone.\n\n// I replace the TeX with a placeholder formatted as a Markdown directive, for example\n// :inlineMath[21] or :blockMath[42].\n\n// I convert the TeX to MathML and store it memory for use later (in directive-to-svg.ts).\n\nexport function texToAliasDirective(file: VFile, ctx: Context) {\n // simple regex tests\n assertNoTexTabular(file);\n\n const md = file.value as string;\n const store: string[] = [];\n const adaptor = liteAdaptor();\n const visitor = new SerializedMmlVisitor();\n RegisterHTMLHandler(adaptor);\n\n const doc = mathjax.document(md, {\n InputJax: new TeX({\n // Bussproofs requires an output jax\n packages: AllPackages.filter((name) => name !== 'bussproofs'),\n // Allow numbered references\n tags: 'ams',\n // Allow single $ delimiters\n inlineMath: [\n ['$', '$'],\n ['\\\\(', '\\\\)'],\n ],\n displayMath: [\n ['$$', '$$'],\n [`\\\\[`, `\\\\]`],\n ],\n }),\n // wrap verbatim latex with
\n ignoreHtmlClass: 'mathjax-ignore',\n renderActions: {\n typeset: [\n MathItem.STATE.TYPESET,\n ({ math }: MathDocument) => {\n for (const item of Array.from(math)) {\n let newMarkdown = '';\n\n // convert to MathML\n const mml = visitor.visitTree(item.root);\n assertNoMmlError(mml, file);\n\n // escaped dollar sign...\n if (item.math === '$') {\n newMarkdown = '$';\n }\n\n // double backslash...\n else if (item.math === '\\\\') {\n newMarkdown = '\\\\\\\\';\n }\n\n // reference link...\n else if (isReferenceLink(item.math)) {\n const refNum = extractRefNumFromMml(mml, item.math, file);\n const anchor = extractAnchorLinkFromMml(\n mml,\n item.math,\n file,\n );\n newMarkdown = `[${refNum}](${anchor})`;\n }\n\n // normal use case (math notation)...\n else {\n store.push(mml);\n const type = item.display ? 'blockMath' : 'inlineMath';\n newMarkdown = `:${type}[${store.length - 1}]`;\n }\n\n const tree = adaptor.parse(newMarkdown, 'text/html');\n item.typesetRoot = adaptor.firstChild(adaptor.body(tree));\n }\n },\n ],\n },\n });\n\n // add store to ctx\n ctx.mmlStore = store;\n\n doc.render();\n\n // replace md in VFile\n const result = adaptor.innerHTML(adaptor.body(doc.document));\n file.value = postParse(result);\n\n return file;\n}\n\nfunction assertNoMmlError(mml: string, file: VFile) {\n const match = mml.match(/(.+)<\\/mtext>/);\n if (match === null) {\n failMessage(file, `Invalid reference: ${tex}`);\n return;\n }\n if (match[1] === '???') {\n failMessage(\n file,\n `Invalid reference: ${tex}. You may only reference numbered sections.`,\n );\n }\n return match[1] as string;\n}\n\nfunction extractAnchorLinkFromMml(mml: string, tex: string, file: VFile) {\n const match = mml.match(//);\n if (match === null) {\n failMessage(file, `Reference has no anchor link: ${tex}`);\n return;\n }\n return decodeURIComponent(match[1] || '') as string;\n}\n\nfunction postParse(html: string) {\n let result = html.trim();\n result = unprotectHtml(result);\n result = removeUnresolvedLabels(result);\n result = removeHTMLClosingTags(result);\n return result;\n}\n\n// https://github.com/mathjax/MathJax-src/blob/41565a97529c8de57cb170e6a67baf311e61de13/ts/adaptors/lite/Parser.ts#L399-L403\nfunction unprotectHtml(html: string) {\n return html\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n\nfunction removeUnresolvedLabels(html: string) {\n return html.replace(/\\\\label{def:.*?}/gm, '');\n}\n\nfunction removeHTMLClosingTags(html: string) {\n return html.replace(/(<\\/\\S+>)+$/, '');\n}\n","import { Image } from 'mdast';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\nimport { checkLocalFileExists } from '../utils/utils';\n\nexport function assertAssetExists() {\n async function getAssetUrl(node: Image, file: VFile) {\n const url = (node.url || '') as string;\n if (!file.dirname) {\n throw new Error('VFile dirname undefined');\n }\n if (!url.startsWith('http')) {\n const exists = await checkLocalFileExists(url);\n if (!exists) {\n failMessage(file, `No asset found at ${url}`, node.position);\n }\n }\n }\n\n return async (tree: Node, file: VFile) => {\n const transformations: Promise[] = [];\n visit(tree, 'image', (node) => {\n transformations.push(getAssetUrl(node, file));\n });\n await Promise.all(transformations);\n };\n}\n","import { Root } from 'mdast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function assertColumnStructure() {\n return (tree: Root, file: VFile) => {\n visit(\n tree,\n 'containerDirective',\n (node: ContainerDirective, index, _parent) => {\n if (node.name === 'columns') {\n const children = node.children as ContainerDirective[];\n const columns = children.filter((o) => o.name === 'column');\n if (columns.length < 2) {\n failMessage(\n file,\n 'Columns must contain at least 2 columns',\n node.position,\n );\n }\n }\n if (node.name === 'column') {\n const parent = _parent as ContainerDirective;\n if (!parent || parent.name !== 'columns') {\n failMessage(\n file,\n 'Column must be nested inside columns',\n node.position,\n );\n }\n }\n },\n );\n };\n}\n","import { Root } from 'mdast';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function assertNoH1() {\n return (tree: Root, file: VFile) => {\n visit(tree, 'heading', (node) => {\n if (node.depth === 1) {\n failMessage(\n file,\n 'Level 1 heading found. Only one Level 1 heading can be used in the document and it is automatically generated from .yaml file and should not be found in .Rmd file. Please use Level 2 (## Example) and below.',\n node.position,\n );\n return;\n }\n });\n };\n}\n","import { VFile } from 'vfile';\n\nimport { warnMessage } from '../utils/message';\n\nexport function assertNoImageAttributes(file: VFile) {\n const md = file.value as string;\n md.split('\\n').forEach((line, idx) => {\n const match = line.match(/!\\[.*\\]\\(.*\\)({.+})/);\n if (match !== null) {\n warnMessage(\n file,\n `image attributes are not supported: ${match[1]}`,\n {\n start: {\n line: idx + 1,\n column: 0,\n },\n end: {\n line: idx + 1,\n column: line.length,\n },\n }\n );\n }\n });\n}\n","import { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\n// TODO: could possibly try converting to array here\n// https://stackoverflow.com/questions/51803244\n\nexport function assertNoTexTabular(file: VFile) {\n const md = file.value as string;\n md.split('\\n').forEach((line, idx) => {\n if (line.includes('\\\\begin{tabular}')) {\n failMessage(\n file,\n 'LaTeX tables are not allowed, please use Markdown syntax',\n {\n start: {\n line: idx + 1,\n column: 0,\n },\n end: {\n line: idx + 1,\n column: line.length,\n },\n }\n );\n }\n });\n}\n","import { Root } from 'mdast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function assertProgramSwitcherStructure() {\n return (tree: Root, file: VFile) => {\n let count = 0;\n visit(tree, 'containerDirective', (node, index, _parent) => {\n if (node.name === 'task') {\n count++;\n const children = node.children as ContainerDirective[];\n const answers = children.filter((o) => o.name === 'answer');\n if (answers.length < 1) {\n failMessage(file, `Task ${count} has no answer`, node.position);\n }\n if (answers.length > 1) {\n failMessage(file, 'Task has multiple answers', node.position);\n }\n }\n if (node.name === 'answer') {\n const parent = _parent as ContainerDirective;\n if (!parent || parent.name !== 'task') {\n failMessage(\n file,\n 'Answer must be nested inside task',\n node.position,\n );\n }\n }\n });\n };\n}\n","import { Root } from 'mdast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function assertTaskAnswerStructure() {\n return (tree: Root, file: VFile) => {\n let count = 0;\n visit(tree, 'containerDirective', (node, index, _parent) => {\n if (node.name === 'task') {\n count++;\n const children = node.children as ContainerDirective[];\n const answers = children.filter((o) => o.name === 'answer');\n if (answers.length < 1) {\n failMessage(file, `Task ${count} has no answer`, node.position);\n }\n if (answers.length > 1) {\n failMessage(file, 'Task has multiple answers', node.position);\n }\n }\n if (node.name === 'answer') {\n const parent = _parent as ContainerDirective;\n if (!parent || parent.name !== 'task') {\n failMessage(\n file,\n 'Answer must be nested inside task',\n node.position,\n );\n }\n }\n });\n };\n}\n","import { Literal, Parent } from 'mdast';\nimport { Root } from 'mdast';\nimport { LeafDirective } from 'mdast-util-directive';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function assertVideoAttributes() {\n return async (tree: Root, file: VFile) => {\n visit(tree, 'leafDirective', (node: LeafDirective) => {\n if (node.name === 'video') {\n if (!node.attributes?.id) {\n failMessage(file, 'id attribute is required', node.position);\n }\n if (!node.attributes?.duration) {\n failMessage(\n file,\n 'duration attribute is required',\n node.position,\n );\n }\n\n const title = getTitle(node);\n if (!title) {\n failMessage(file, 'title is required', node.position);\n }\n }\n });\n };\n}\n\nfunction getTitle(node: Parent) {\n const children = node.children as Node[];\n const firstChild = children[0] as Literal;\n return (firstChild?.value || '') as string;\n}\n","import { Root } from 'mdast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function assertWeblinkTarget() {\n return (tree: Root, file: VFile) => {\n visit(tree, 'containerDirective', (node: ContainerDirective) => {\n if (node.name === 'weblink') {\n if (node.attributes?.target === undefined) {\n failMessage(\n file,\n 'Weblink has no target attribute',\n node.position,\n );\n }\n }\n });\n };\n}\n","import lintAltText from '@double-great/remark-lint-alt-text';\n// @ts-expect-error\nimport lintLinkText from '@mapbox/remark-lint-link-text';\n// import dictionary from 'dictionary-en-gb';\n// import remark2retext from 'remark-retext';\n// import english from 'retext-english';\n// import spell from 'retext-spell';\nimport { unified } from 'unified';\nimport { Node } from 'unist';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { assertAssetExists } from './assert-asset-exists';\nimport { assertColumnStructure } from './assert-columns';\nimport { assertNoH1 } from './assert-no-h1';\nimport { assertProgramSwitcherStructure } from './assert-program-switcher';\nimport { assertTaskAnswerStructure } from './assert-task-answer';\nimport { assertVideoAttributes } from './assert-video-attributes';\nimport { assertWeblinkTarget } from './assert-weblink-target';\nimport { lintLatex } from './lint-latex';\nimport { printReport, reportHasFatalErrors } from './report';\nimport { Root } from 'mdast';\n\nexport function reportErrors(files: VFile[], ctx: Context) {\n if (!ctx.options.noReport) {\n printReport(files, ctx);\n }\n if (reportHasFatalErrors(files)) {\n if (ctx.options.noReport) {\n printReport(files, {\n ...ctx,\n options: {\n ...ctx.options,\n reportOnlyErrors: true,\n },\n });\n }\n console.log('Report has fatal errors');\n if (ctx.options.force) {\n console.log('Compiling using force option...');\n } else {\n process.exit(1);\n }\n }\n}\n\nexport async function createReport(\n file: VFile,\n mdast: Node,\n ctx: Context,\n) {\n const processor = unified()\n .use(assertAssetExists)\n .use(assertVideoAttributes)\n .use(assertTaskAnswerStructure)\n .use(assertProgramSwitcherStructure)\n .use(assertColumnStructure)\n .use(assertWeblinkTarget)\n .use(assertNoH1)\n .use(lintLatex)\n // @ts-expect-error\n .use(lintAltText)\n .use(lintLinkText);\n\n // if (ctx.options.spelling) {\n // const retextProcessor = unified()\n // .use(english)\n // .use(spell, { dictionary, max: 1 });\n // processor.use(remark2retext, retextProcessor);\n // }\n\n processor.run(mdast as Root, file);\n}\n","import { exec } from 'child_process';\n\nimport { Literal, Root } from 'mdast';\nimport { Position } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nexport function lintLatex() {\n return async (tree: Root, file: VFile) => {\n const transformations: Promise[] = [];\n\n visit(tree, 'math', (node: Literal) => {\n transformations.push(chktex(node, file));\n });\n\n await Promise.all(transformations);\n return tree;\n };\n}\n\nasync function chktex(node: Literal, file: VFile) {\n return new Promise((resolve, reject) => {\n exec(`chktex -q <<< \"${node.value}\"`, (err, response) => {\n if (err) {\n reject(err);\n } else {\n const messages = formatResponse(response);\n const position = node.position as Position;\n messages.forEach(({ line, column, message }) => {\n file.message(message, {\n line: position.start.line + line,\n column: position.start.column + column,\n });\n });\n resolve();\n }\n });\n });\n}\n\ntype Message = {\n line: number;\n column: number;\n message: string;\n};\n\nfunction formatResponse(response: string) {\n if (response.trim() === '') {\n return [];\n }\n\n function formatMessage(message: string) {\n return message.replace(/'/g, '').replace(/`/g, '');\n }\n\n return response\n .split(/Warning \\d+ in stdin line /)\n .filter(Boolean)\n .reduce((acc: Message[], s) => {\n const [key, value] = s.split(':');\n const line = Number(key);\n const trimmed = value.trim();\n\n const match = trimmed.match(/(.*)\\n(.*)\\n(\\s*)\\^/m);\n if (Array.isArray(match)) {\n const message = formatMessage(match[1]);\n acc.push({\n line,\n column: match[3].length,\n message: `${message}\\n\\n${match[2]}\\n${match[3]}^`,\n });\n } else {\n acc.push({\n line,\n column: 0,\n message: formatMessage(trimmed),\n });\n }\n\n return acc;\n }, []);\n}\n","import chalk from 'chalk';\nimport figures from 'figures';\nimport { VFile } from 'vfile';\nimport { VFileMessage } from 'vfile-message';\n\nimport { Context } from '../context';\nimport { MessageStatus } from '../utils/message';\n\nexport type Report = {\n failed: boolean;\n files: ReportFile[];\n};\n\nexport type ReportFile = Omit & {\n messages: ReportMessage[];\n};\n\nexport type ReportMessage = {\n status: MessageStatus;\n position: string;\n reason: string;\n line: number;\n column: number;\n};\n\nexport function printReport(files: VFile[], ctx: Context) {\n const { reportOnlyErrors, shouldFail } = ctx.options;\n\n if (reportOnlyErrors && shouldFail) {\n return;\n }\n\n for (const file of files) {\n // console.log(file.messages);\n const messages = reportOnlyErrors\n ? failingMessages(file.messages as any)\n : file.messages;\n\n if (messages.length !== 0) {\n // if (file.path !== undefined) {\n // console.log(`\\n${getFilePath(file.path)}`);\n // }\n messages.forEach((message) => {\n printMessage(message as any);\n });\n }\n }\n}\n\nexport function reportHasFatalErrors(files: VFile[]) {\n return files.some((file) => {\n const messages = file.messages as unknown as ReportMessage[];\n return messages.some(\n (message) => message.status === MessageStatus.fail,\n );\n });\n}\n\nexport function reportHasWarnings(files: VFile[]) {\n return files.some((file) => {\n const messages = file.messages as unknown as ReportMessage[];\n return messages.some(\n (message) => message.status === MessageStatus.warning,\n );\n });\n}\n\nfunction failingMessages(_messages: VFileMessage[]) {\n const messages = _messages as unknown as ReportMessage[];\n return messages.filter(\n (o) => o.status === MessageStatus.fail,\n ) as unknown as VFileMessage[];\n}\n\nfunction printMessage(_message: VFileMessage) {\n const message = _message as unknown as ReportMessage;\n // console.log(message);\n const status = message.status;\n const position = chalk.grey(`${message.line}:${message.column}`);\n const reason = formatReason(message.reason, status);\n console.log(`${formatStatus(status)} ${position} ${reason}`);\n}\n\n// function getFilePath(filePath: string) {\n// return path.isAbsolute(filePath)\n// ? filePath\n// : path.join(process.cwd(), filePath);\n// }\n\nfunction formatStatus(status: MessageStatus) {\n const statusColour = getStatusColour(status);\n switch (status) {\n case MessageStatus.fail:\n return statusColour(figures.cross);\n default:\n return statusColour(figures.warning);\n // TODO: fail on unsupported status?\n }\n}\n\nfunction formatReason(reason: string, status: MessageStatus) {\n const statusColour = getStatusColour(status);\n const [first, ...rest] = reason.split('\\n');\n const formattedFirst = statusColour(first);\n const formattedRest = rest.map((line) => chalk.grey(line));\n return [formattedFirst, ...formattedRest].join('\\n');\n}\n\nfunction getStatusColour(status: MessageStatus) {\n switch (status) {\n case MessageStatus.fail:\n return chalk.red;\n default:\n return chalk.yellow;\n }\n}\n","import {\n Element,\n ElementContent,\n Parent as HastParent,\n Text,\n Node,\n} from 'hast';\nimport startCase from 'lodash/startCase.js';\nimport { Root } from 'mdast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { toHast } from 'mdast-util-to-hast';\nimport { Parent } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nimport { Context } from '../context';\nimport { createCounter } from '../utils/counter';\n\nexport function boxouts(refStore: Context['refStore']) {\n const counter = createCounter();\n return async (tree: Node) => {\n visit(tree, 'containerDirective', (node: ContainerDirective) => {\n switch (node.name) {\n case 'example':\n case 'error':\n case 'supplement':\n case 'background':\n case 'definition':\n case 'weblink':\n case 'theorem':\n case 'task':\n case 'proposition':\n case 'answer': {\n const name = node.name as string;\n const count = counter.increment(name);\n node.data = {\n hProperties: createAttributes(node, count, refStore),\n hChildren: createBoxout(node, count) as any,\n };\n }\n }\n });\n };\n}\n\nfunction createAttributes(\n node: ContainerDirective,\n count: number,\n refStore: Context['refStore'],\n) {\n const name = node.name as string;\n const id = `${name}-${count}`;\n\n const attributes = node.attributes as Record;\n const className = ['boxout', name];\n if (attributes.icon) {\n className.push(`${attributes.icon}-icon`);\n }\n\n if (\n node.attributes?.label !== undefined &&\n node.attributes?.label !== null\n ) {\n refStore[node.attributes.label] = id;\n }\n\n return { className, id };\n}\n\nexport function createBoxout(\n node: ContainerDirective,\n count: number,\n): Node[] {\n const typeTitle = createBoxoutType(node, count);\n const titles = [typeTitle];\n\n const titleValue = getTitleValue(node);\n if (titleValue.length > 0) {\n const title = createTitle(node);\n titles.push(title);\n }\n\n const children = node.children as ContainerDirective[];\n\n const content = children\n // @ts-expect-error\n .filter((o) => !o.data?.directiveLabel)\n .filter((o) => o.type !== 'containerDirective' && o.name !== 'answer')\n .map((o) => toHast(o, { allowDangerousHtml: true }))\n .filter(Boolean) as HastParent[];\n\n if (node.name === 'task') {\n const answer = children.find(\n (o) => o.type === 'containerDirective' && o.name === 'answer',\n );\n if (answer) {\n const answerHast = createAnswer(answer, count);\n content.push(answerHast as HastParent);\n }\n }\n\n return [...titles, ...content];\n}\n\nfunction createAnswer(node: ContainerDirective, count: number) {\n const { children } = toHast(node) as HastParent;\n return {\n type: 'element',\n tagName: 'div',\n properties: {\n className: ['answer'],\n },\n children: [\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['answer-trigger'],\n 'data-answer-id': count,\n },\n children: [\n {\n type: 'text',\n value: 'Show answer',\n },\n ],\n },\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: ['answer-reveal'],\n id: `answer-${count}`,\n },\n children,\n },\n ],\n };\n}\n\nfunction createBoxoutType(\n node: ContainerDirective,\n count: number,\n): Element {\n const name = node.name as string;\n const label = startCase(name);\n let value = `${label} ${count}`;\n\n if (node.attributes?.optional !== undefined) {\n value += ` (Optional)`;\n }\n\n return {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['type'],\n },\n children: [\n {\n type: 'text',\n value,\n },\n ],\n };\n}\n\nfunction createTitle(node: ContainerDirective): Element {\n return {\n type: 'element',\n tagName: 'h3',\n children: createTitleValue(node) as ElementContent[],\n properties: {},\n };\n}\n\nfunction createTitleValue(node: ContainerDirective) {\n const name = node.name as string;\n const newRoot = {\n type: 'root',\n children: getTitleValue(node),\n };\n const { children = [] } = toHast(newRoot as Root) as Parent;\n if (name !== 'weblink') {\n return children;\n }\n const { target } = node.attributes as Record;\n return [\n {\n type: 'element',\n tagName: 'a',\n properties: {\n href: target,\n target: '_blank',\n className: ['target'],\n },\n children,\n },\n ];\n}\n\nfunction getTitleValue(node: ContainerDirective): Node[] {\n const children = (node.children || []) as Node[];\n const parent = (children[0] || {}) as Parent;\n\n // @ts-expect-error\n if (!parent.data?.directiveLabel) {\n if (node.name === 'weblink') {\n const attributes = node.attributes as Record;\n return [\n {\n type: 'text',\n value: attributes.target,\n } as Text,\n ];\n }\n return [];\n }\n\n return parent.children || [];\n}\n","import { Element } from 'hast';\nimport { Literal } from 'mdast';\nimport { LeafDirective } from 'mdast-util-directive';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function browserWindow() {\n return (tree: Node, file: VFile) => {\n visit(tree, 'leafDirective', (node: LeafDirective) => {\n if (node.name === 'browser') {\n template(node, file);\n }\n });\n };\n}\n\nfunction template(node: LeafDirective, file: VFile) {\n const url = node.attributes?.url || '';\n const alt = node.attributes?.alt || '';\n const imagePath = getImagePath(node, file);\n\n const browser = createBrowserWindow(imagePath, url, alt);\n const caption = createCaption(alt);\n\n Object.assign(node, {\n type: 'browser-window',\n data: {\n hName: 'figure',\n hProperties: {\n className: ['browser'],\n },\n hChildren: [browser, caption],\n },\n });\n}\n\nfunction createBrowserWindow(\n imagePath: string,\n url: string,\n alt: string,\n): Element {\n return {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'browser-window',\n },\n children: [\n {\n type: 'text',\n value: '\\n',\n },\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'browser-window-wrapper',\n },\n children: [\n createBrowserHeader(url),\n {\n type: 'text',\n value: '\\n',\n },\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'browser-window-content',\n },\n children: [\n {\n type: 'element',\n tagName: 'img',\n properties: {\n src: imagePath,\n alt,\n },\n children: [],\n },\n ],\n },\n {\n type: 'text',\n value: '\\n',\n },\n ],\n },\n ],\n };\n}\n\nfunction createBrowserHeader(url: string): Element {\n return {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'browser-window-header',\n },\n children: [\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'browser-window-address-bar',\n },\n children: [\n {\n type: 'text',\n value: url?.trim() || '',\n },\n ],\n },\n ],\n };\n}\n\nfunction createCaption(alt: string): Element | null {\n if (alt.trim() === '') {\n return null;\n }\n return {\n type: 'element',\n tagName: 'figcaption',\n properties: {},\n children: [\n {\n type: 'element',\n tagName: 'a',\n properties: {},\n children: [\n {\n type: 'text',\n value: ` ${alt}`,\n },\n ],\n },\n ],\n };\n}\n\nfunction getImagePath(node: LeafDirective, file: VFile) {\n const children = node.children as Node[];\n const firstChild = children[0] as Literal;\n const title = firstChild?.value || '';\n if (title.trim() === '') {\n failMessage(file, 'Video has no title', node.position);\n }\n return title;\n}\n","import { Properties, Text } from 'hast';\nimport { Code } from 'mdast';\nimport { RefractorElement, refractor } from 'refractor/lib/all.js';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\n\nexport function codeBlocks(ctx: Context) {\n return async (tree: Node, file: VFile) => {\n visit(tree, 'code', (node: Code) => {\n customCode(node, ctx, file);\n });\n };\n}\n\nfunction customCode(node: Code, ctx: Context, file: VFile) {\n const language = parseLanguage(node);\n const klass = parseClass(node);\n\n const codeProps: Properties = {};\n const children: (RefractorElement | Text)[] = [];\n const trimmed = node.value.trim();\n\n if (ctx.options.noSyntaxHighlight || language === '') {\n children.push({\n type: 'text',\n value: trimmed,\n });\n } else {\n const highlighted = refractor.highlight(trimmed, language);\n children.push(...highlighted.children);\n }\n\n Object.assign(node, {\n type: 'custom-code',\n data: {\n hName: 'div',\n hProperties: {\n className: ['code-wrapper', klass],\n },\n hChildren: [\n addConsoleHeading(klass),\n {\n type: 'element',\n tagName: 'pre',\n children: [\n {\n type: 'element',\n tagName: 'code',\n properties: codeProps,\n children,\n },\n ],\n },\n ],\n },\n });\n}\n\nfunction addConsoleHeading(klass: string) {\n if (klass === 'r-output' || klass === 'r-error-output') {\n return {\n type: 'element',\n tagName: 'h6',\n properties: {\n className: 'console-heading',\n },\n children: [\n {\n type: 'text',\n value: 'R Console',\n },\n ],\n };\n }\n if (klass === 'python-output' || klass === 'python-error-output') {\n return {\n type: 'element',\n tagName: 'h6',\n properties: {\n className: 'console-heading',\n },\n children: [\n {\n type: 'text',\n value: 'Python Console',\n },\n ],\n };\n }\n return null;\n}\n\nfunction parseLanguage(node: Code) {\n const lang = (node.lang || '') as string;\n\n if (lang === 'plaintext') {\n return '';\n }\n if (lang.startsWith('{')) {\n const match = lang.match(/.lang-(\\w+)/);\n if (match === null) {\n return '';\n }\n return match[1].toLowerCase();\n }\n return lang.toLowerCase();\n}\n\nfunction parseClass({ lang, meta }: Code) {\n const m = !meta || meta === 'null' ? '' : meta;\n const combined = `${lang || ''} ${m}`.trim();\n if (!combined.startsWith('{.')) {\n return '';\n }\n return combined.slice(1, -1).replace(/\\./g, '');\n}\n","import { BlockContent, Text } from 'mdast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { Node, Parent } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nexport function columns() {\n return (tree: Node) => {\n visit(tree, 'containerDirective', (node: ContainerDirective) => {\n if (node.name === 'columns') {\n node.data = {\n hProperties: {\n className: 'columns',\n },\n };\n } else if (node.name === 'column') {\n node.data = {\n hProperties: {\n className: 'column',\n },\n };\n\n if (node.attributes?.imgsrc) {\n const altText = getAltText(node);\n\n const img = {\n type: 'image',\n url: node.attributes.imgsrc,\n alt: altText,\n } as unknown as BlockContent;\n\n if (altText) {\n Object.assign(node.children[0], img);\n } else {\n node.children.unshift(img);\n }\n }\n }\n });\n };\n}\n\nfunction getAltText(column: ContainerDirective) {\n const firstChild = column.children[0] as Parent;\n if (!firstChild) {\n return false;\n }\n\n const firstChildChildren = firstChild.children as Node[];\n if (!Array.isArray(firstChildChildren)) {\n return false;\n }\n\n const firstChildFirstChild = firstChildChildren[0] as Text;\n if (!firstChildFirstChild) {\n return false;\n }\n\n return firstChildFirstChild.value;\n}\n","import { Root } from 'mdast';\nimport { unified } from 'unified';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { boxouts } from './boxouts';\nimport { moveAnswersToEnd } from './move-answers-to-end';\nimport { programSwitcher } from './program-switcher';\n\nexport async function combinedMdastPhase(\n mdast: Root,\n ctx: Context,\n file: VFile,\n targetPdf?: boolean\n) {\n const processor = unified()\n .use(programSwitcher, ctx)\n .use(boxouts, ctx.refStore);\n\n if (targetPdf) {\n processor.use(moveAnswersToEnd);\n }\n\n return processor.run(mdast, file) as Promise;\n}\n","import path from 'path';\n\nimport { Literal, Root } from 'mdast';\nimport { visit } from 'unist-util-visit';\nimport { remove } from 'unist-util-remove';\n\nimport { Context } from '../context';\nimport { LeafDirective } from 'mdast-util-directive';\n\nexport function embedAssetUrl(ctx: Context) {\n return async (tree: Root) => {\n let activeDir = '';\n\n // nodes need to be visited in the correct order\n // to derive the document directory\n visit(tree, (node, index, parent) => {\n // to ensure relative paths to assets across multiple .Rmd files\n if (node.type === 'leafDirective' && node.name === 'directory') {\n const firstChild = node.children[0] as Literal;\n activeDir = firstChild.value || '';\n }\n\n if (node.type === 'image') {\n const url = getPath(node.url, activeDir, ctx);\n node.url = url;\n }\n\n // also fix for browser template\n if (node.type === 'leafDirective' && node.name === 'browser') {\n const firstChild = node.children[0] as Literal;\n firstChild.value = getPath(firstChild.value, activeDir, ctx);\n }\n\n // also fix for raw html nodes sometimes output by knitr\n if (node.type === 'html') {\n const props = getProps(node.value);\n if (props !== null && props.src) {\n const { src, ...otherProps } = props;\n Object.assign(node, {\n type: 'image',\n url: getPath(src, activeDir, ctx),\n value: '',\n data: otherProps,\n });\n }\n }\n });\n\n // remove the directory leafDirective node from the tree\n remove(tree, (node) => {\n if (node.type === 'leafDirective') {\n const directive = node as LeafDirective;\n return directive.name === 'directory';\n }\n return false;\n });\n };\n}\n\nfunction getPath(url: string, dirname: string, ctx: Context) {\n if (ctx.options.noEmbedAssetUrl) {\n return url;\n }\n if (path.isAbsolute(url) || url.startsWith('http')) {\n return url;\n }\n // pythons matplotlib appears to assign plot images a path\n // relative to the project root, whereas all other libraries use\n // an absolute path.\n if (url.startsWith('cache')) {\n return path.join(ctx.cacheDir, url.replace('cache', ''));\n }\n return path.join(dirname, url);\n}\n\nfunction getProps(value: string) {\n const matchImg = value.match(/^$/);\n if (matchImg !== null) {\n return propsToObject(value.slice(5, -1));\n }\n const matchPdf = value.match(/^$/);\n if (matchPdf !== null) {\n return propsToObject(value.slice(7, -1));\n }\n return null;\n}\n\nfunction propsToObject(str: string) {\n return str\n .split(/(\\w+)=\"(.*?)\"/)\n .filter((s) => s.trim() !== '')\n .reduce((acc: Record, value, idx, arr) => {\n if (idx % 2 === 1) {\n const key = arr[idx - 1];\n acc[key] = value;\n }\n return acc;\n }, {});\n}\n","import { Code } from 'mdast';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nexport function gitGraph() {\n return (tree: Node) => {\n let counter = 0;\n visit(tree, 'code', (node: Code) => {\n if (node.lang === 'gitgraph') {\n createGitGraph(node, ++counter);\n }\n });\n };\n}\n\nfunction createGitGraph(node: Code, counter: number) {\n const id = `gitgraph-${counter}`;\n const options = createDefaultOptions();\n Object.assign(node, {\n type: 'gitgraph',\n data: {\n hName: 'div',\n hProperties: {\n className: 'gitgraph',\n },\n hChildren: [\n {\n type: 'text',\n value: '\\n',\n },\n {\n type: 'element',\n tagName: 'div',\n properties: { id: `gitgraph-${counter}` },\n },\n {\n type: 'text',\n value: '\\n',\n },\n // this will need to be \"singleton\" inlined\n {\n type: 'element',\n tagName: 'script',\n properties: {\n src: 'https://cdn.jsdelivr.net/npm/@gitgraph/js',\n },\n children: [],\n },\n {\n type: 'text',\n value: '\\n',\n },\n {\n type: 'element',\n tagName: 'script',\n children: [\n {\n type: 'text',\n value: [\n '',\n // The global template js (template/src/index.ts) emits a custom event\n // 'template-ready' when initialised. This is handy as the document\n // gets serveral element classes added to it which causes re-renders.\n // Here, we wait for this custom event before rendering the gitgraphs,\n // and are careful to define all variables inside the the event callback\n `document.documentElement.addEventListener('template-ready', () => {`,\n '',\n `const graphContainer = document.getElementById(\"${id}\");`,\n `const gitgraph = GitgraphJS.createGitgraph(graphContainer, ${options});`,\n `${node.value}`,\n '',\n `})`,\n '',\n ].join('\\n'),\n },\n ],\n },\n {\n type: 'text',\n value: '\\n',\n },\n ],\n },\n });\n}\n\nfunction createDefaultOptions() {\n return JSON.stringify({\n // orientation: 'vertical-reverse',\n template: {\n colors: ['#0075b0', '#00843d', '#7d2239', '#951272', '#7a6855'],\n branch: {\n color: '#ccc',\n lineWidth: 5,\n mergeStyle: 'bezier',\n spacing: 40,\n label: {\n display: true,\n bgColor: 'transparent',\n borderRadius: 10,\n },\n },\n arrow: {\n // size: 10,\n // color: '#ccc',\n // offset: -1.5\n },\n commit: {\n spacing: 40,\n hasTooltipInCompactMode: true,\n dot: {\n // size: 8,\n // strokeWidth: 0,\n size: 16,\n strokeWidth: 6,\n strokeColor: 'white',\n },\n message: {\n display: true,\n displayAuthor: false,\n displayHash: false,\n font: 'inherit',\n color: '#333',\n },\n },\n tag: {},\n },\n });\n}\n","import { Element, ElementContent, Parent } from 'hast';\nimport kebabCase from 'lodash/kebabCase.js';\nimport { Image } from 'mdast';\nimport { Literal, Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nimport { Context } from '../context';\nimport { getAssetHast } from '../utils/get-asset-hast';\n\nexport function images(ctx: Context) {\n return (tree: Node) => {\n visit(tree, 'image', (node) => {\n templateFromImage(node, ++ctx.figureCounter);\n });\n\n // knitr can output HTML for plots instead of Markdown now\n visit(tree, 'html', (node: Literal) => {\n const value = String(node.value);\n if (value.startsWith('
')) {\n const hast = getAssetHast(value);\n templateFromHTML(node, hast, ++ctx.figureCounter);\n }\n });\n };\n}\n\nfunction templateFromImage(node: Image, count: number) {\n const alt = getAltText(node.alt || '');\n const slug = kebabCase(alt ? alt : `Figure ${count}`);\n // @ts-expect-error\n createFigure(node, slug, node.url, alt, node.data?.width, count);\n}\n\nfunction templateFromHTML(node: Literal, hast: Element, count: number) {\n const children = hast.children as Element[];\n const img = children.find((o) => o.tagName === 'img');\n const properties = img?.properties || {};\n const src = String(properties.src);\n const alt = getAltText(String(properties.alt));\n const width = properties.width;\n const slug = kebabCase(alt ? alt : `Figure ${count}`);\n createFigure(node, slug, src, alt, width, count);\n}\n\nfunction createFigure(\n node: Image | Literal,\n slug: string,\n src: string,\n alt: string,\n width: unknown,\n count: number,\n) {\n Object.assign(node, {\n type: 'custom-image',\n data: {\n hName: 'figure',\n hProperties: {\n className: ['img-wrapper'],\n id: slug,\n },\n hChildren: [\n createImage(src, alt, width),\n createCaption(alt, slug, count),\n ],\n },\n });\n}\n\nfunction createImage(src: string, alt: string, width: unknown) {\n const image: Element = {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'img-bg',\n },\n children: [\n {\n type: 'element',\n tagName: 'img',\n properties: { src, alt },\n children: [],\n },\n ],\n };\n\n if (width && /^\\d+px/.test(String(width))) {\n image.properties = {\n ...image.properties,\n style: `width: ${width};`,\n };\n }\n\n return image;\n}\n\nfunction createCaption(alt: string, slug: string, count: number) {\n return {\n type: 'element',\n tagName: 'figcaption',\n children: [\n {\n type: 'element',\n tagName: 'a',\n properties: {\n href: `#${slug}`,\n },\n children: createLabel(alt, count),\n },\n ],\n };\n}\n\nfunction createLabel(alt: string, count: number) {\n const label: ElementContent[] = [\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'caption-count',\n },\n children: [\n {\n type: 'text',\n value: `Figure ${count}`,\n },\n ],\n },\n ];\n\n if (alt) {\n const elem = label[0] as Parent;\n const content = elem.children[0] as Literal;\n content.value += ':';\n\n label.push({\n type: 'text',\n value: ` ${alt}`,\n });\n }\n\n return label;\n}\n\nfunction getAltText(altText: string) {\n if (altText.includes('unnamed-chunk')) {\n return '';\n }\n return altText;\n}\n","import headings from 'rehype-autolink-headings';\nimport directive from 'remark-directive';\nimport frontmatter from 'remark-frontmatter';\nimport gfm from 'remark-gfm';\nimport markdown from 'remark-parse';\nimport slug from 'rehype-slug';\nimport { unified } from 'unified';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { aliasDirectiveToLatexSvg } from '../latex/directive-to-svg';\nimport { createSvg } from '../utils/icons';\nimport { browserWindow } from './browser-window';\nimport { codeBlocks } from './code-blocks';\nimport { columns } from './columns';\nimport { embedAssetUrl } from './embed-asset-url';\nimport { gitGraph } from './gitgraph';\nimport { images } from './images';\nimport { pagebreaks } from './pagebreaks';\nimport { removeEmptyParagraphs } from './remove-empty-paragraphs';\nimport { styledTerminal } from './styled-terminal';\nimport { textFile } from './text-file';\nimport { youtubeVideos } from './youtube-videos';\nimport { aliasDirectiveToCode } from '../code/alias-directive-to-code';\n\nexport async function mdastPhase(file: VFile, ctx: Context) {\n // https://github.com/unifiedjs/unified\n // convert markdown to syntax tree: complex transforms\n // should be more robust and straightforward\n const processor = unified()\n // third-party plugins:\n .use(markdown)\n .use(directive)\n .use(frontmatter)\n .use(gfm)\n .use(slug)\n .use(headings, {\n content: createSvg('link-icon') as any,\n properties: { className: 'link' },\n })\n // custom plugins:\n .use(() => (tree) => {})\n .use(columns)\n .use(embedAssetUrl, ctx)\n .use(youtubeVideos)\n .use(aliasDirectiveToCode, ctx)\n .use(aliasDirectiveToLatexSvg, ctx)\n .use(removeEmptyParagraphs)\n .use(gitGraph)\n .use(textFile)\n .use(browserWindow)\n .use(codeBlocks, ctx)\n .use(styledTerminal)\n .use(images, ctx)\n .use(pagebreaks);\n\n const parsed = processor.parse(file);\n // @ts-expect-error\n return processor.run(parsed, file);\n}\n","import { Node, Parent } from 'hast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { visit } from 'unist-util-visit';\n\nexport function moveAnswersToEnd() {\n return (tree: Node) => {\n visit(\n tree,\n 'containerDirective',\n (node: ContainerDirective, _index, _parent) => {\n const index = _index as number;\n const parent = _parent as Parent;\n\n // remove answer from task rehype\n if (node.name === 'task' && node.data) {\n const children = node.data.hChildren || [];\n const newChildren = children.filter((o) => {\n // @ts-expect-error\n return o.name !== 'answer';\n });\n node.data.hChildren = newChildren;\n }\n\n if (node.name === 'answer') {\n // these nodes have already been moved to the end\n if (node.attributes?.movedToEnd === 'yes') {\n return;\n }\n\n // remove answer block from task node\n const parentChildren = parent?.children || [];\n parentChildren.splice(index || 0, 1);\n\n // add to root node\n const treeParent = tree as Parent;\n const treeChildren = (treeParent.children || []) as Node[];\n\n node.attributes = {\n ...(node.attributes || {}),\n movedToEnd: 'yes',\n };\n\n treeChildren.push(node);\n }\n },\n );\n };\n}\n","import { LeafDirective } from 'mdast-util-directive';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nexport function pagebreaks() {\n return async (tree: Node) => {\n visit(tree, 'leafDirective', (node: LeafDirective) => {\n if (node.name === 'pagebreak') {\n node.data = {\n hName: 'hr',\n hProperties: {\n className: 'pagebreak',\n },\n };\n }\n });\n };\n}\n","import { Element, ElementContent } from 'hast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { toHast } from 'mdast-util-to-hast';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nimport { Context } from '../context';\n\nconst programs = ['github-desktop', 'command-line'];\nconst titleCase = ['GitHub Desktop', 'Command-line'];\n\nexport function programSwitcher(ctx: Context) {\n const programFlag = ctx.options.envProgram;\n if (programFlag !== undefined && !programs.includes(programFlag)) {\n throw new Error(\n `[environment]: envProgram ${programFlag} should be one of ${programs}`,\n );\n }\n\n return (tree: Node) => {\n visit(tree, 'containerDirective', (node: ContainerDirective) => {\n if (node.name === 'program-switcher') {\n const children = [];\n if (programFlag === undefined) {\n children.push(processMenu(node));\n }\n children.push(...processChildren(node, programFlag));\n\n node.data = {\n hProperties: {\n className: 'program-switcher',\n },\n hChildren: children,\n };\n }\n });\n };\n}\n\nfunction processMenu(parent: ContainerDirective): ElementContent {\n const children = parent.children as ContainerDirective[];\n return {\n type: 'element',\n tagName: 'ul',\n properties: {},\n children: children.map((node) => {\n const element: ElementContent = {\n type: 'element',\n tagName: 'li',\n properties: {\n 'data-program': node.name,\n },\n children: [\n {\n type: 'text',\n value: titleCase[programs.indexOf(node.name)],\n },\n ],\n };\n return element;\n }),\n };\n}\n\nfunction processChildren(\n parent: ContainerDirective,\n programFlag: string | undefined,\n): ElementContent[] {\n const children = parent.children.map((node) => {\n const parent = node as ContainerDirective;\n if (programs.includes(parent.name)) {\n node.data = {\n hProperties: {\n 'data-program': parent.name,\n className: [\n 'program',\n programFlag === parent.name ? 'show' : '',\n ],\n },\n };\n }\n return node;\n });\n\n let filtered = children;\n if (programFlag !== undefined) {\n filtered = filtered.filter((node) => {\n const parent = node as ContainerDirective;\n return programFlag === parent.name;\n });\n }\n\n const parentHast = toHast({\n type: 'root',\n children: filtered,\n }) as Element;\n\n return parentHast.children;\n}\n","import { Paragraph, Parent } from 'mdast';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nexport function removeEmptyParagraphs() {\n return async (tree: Node) => {\n visit(tree, 'paragraph', (node: Paragraph, _index, _parent) => {\n const index = _index as number;\n const parent = _parent as Parent;\n\n if (node.children.length === 0) {\n const parentChildren = parent?.children || [];\n parentChildren.splice(index || 0, 1);\n }\n });\n };\n}\n","import ansiColor from 'ansicolor';\nimport { ElementContent, Node } from 'hast';\nimport { Code, Literal } from 'mdast';\nimport { Parent } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nexport function styledTerminal() {\n return (tree: Node) => {\n visit(\n tree,\n 'custom-code',\n (node: Code, index: number, parent: Parent) => {\n if (node.lang === 'bash') {\n wrapInStyledTerminal(node, index, parent);\n }\n },\n );\n };\n}\n\nfunction wrapInStyledTerminal(code: Code, index: number, parent: Parent) {\n const codeChildren = (code.data?.hChildren || []) as ElementContent[];\n const responseChildren = [];\n\n const nextIdx = index + 1;\n const nextNode = parent.children[nextIdx];\n if (nextNode && nextNode.type === 'custom-code') {\n const response = nextNode as Code;\n if (\n response.lang === '{.knitr-output}' ||\n response.lang === '{.knitr-error-output}'\n ) {\n const children = (response.data?.hChildren ||\n []) as ElementContent[];\n const responseWithColours = ansiToHast(children);\n responseChildren.push(...responseWithColours);\n\n // remove response element\n parent.children.splice(nextIdx, 1);\n }\n }\n\n code.data = {\n hProperties: {\n className: 'terminal',\n },\n hChildren: [...codeChildren, ...responseChildren],\n };\n}\n\nfunction ansiToHast(children: ElementContent[]): ElementContent[] {\n const pre = children[1] as Parent;\n const code = pre.children[0] as Parent;\n const text = code.children[0] as Literal;\n const parsed = ansiColor.parse(text.value);\n\n const hast = parsed.spans.map((o) => {\n const text = {\n type: 'text',\n value: o.text,\n };\n if (!o.color) {\n return text;\n } else {\n return {\n type: 'element',\n tagName: 'span',\n properties: {\n className: [\n o.color.name || '',\n o.bold ? 'bold' : '',\n o.color.bright ? 'bright' : '',\n ].filter(Boolean),\n },\n children: [text],\n };\n }\n });\n\n code.children = hast;\n\n return children;\n}\n","import { Code } from 'mdast';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nexport function textFile() {\n return (tree: Node) => {\n visit(tree, 'code', (node: Code) => {\n if (node.lang === 'textfile') {\n createTextFile(node);\n }\n });\n };\n}\n\nfunction createTextFile(node: Code) {\n Object.assign(node, {\n type: 'text-file',\n data: {\n hName: 'div',\n hProperties: {\n className: 'text-file',\n },\n hChildren: [\n {\n type: 'text',\n value: '\\n',\n },\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'text-file-wrapper',\n },\n children: [\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'text-file-header',\n },\n children: [\n {\n type: 'text',\n value: node.meta?.trim() || '',\n },\n ],\n },\n {\n type: 'text',\n value: '\\n',\n },\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'text-file-content',\n },\n children: [\n {\n type: 'text',\n value: node.value,\n },\n ],\n },\n {\n type: 'text',\n value: '\\n',\n },\n ],\n },\n ],\n },\n });\n}\n","import { Literal } from 'mdast';\nimport { LeafDirective } from 'mdast-util-directive';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function youtubeVideos() {\n return async (tree: Node, file: VFile) => {\n visit(tree, 'leafDirective', (node: LeafDirective) => {\n if (node.name === 'video') {\n const attributes = node.attributes;\n const title = getTitle(node, file);\n node.data = {\n hName: 'a',\n hProperties: {\n className: ['boxout', 'video'],\n href: getYoutubeUrl(attributes?.id || ''),\n title: attributes?.title || null,\n target: '_blank',\n },\n hChildren: [\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'content',\n },\n children: [\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'type',\n },\n children: [\n {\n type: 'text',\n value: 'Video',\n },\n ],\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'title',\n },\n children: [\n {\n type: 'text',\n value: title,\n },\n ],\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'duration',\n },\n children: [\n {\n type: 'element',\n tagName: 'strong',\n properties: {},\n children: [\n {\n type: 'text',\n value: 'Duration',\n },\n ],\n },\n {\n type: 'text',\n value: formatDuration(attributes?.duration || ''),\n },\n ],\n },\n ],\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'thumbnail',\n },\n children: [\n {\n type: 'element',\n tagName: 'img',\n properties: {\n src: getYoutubeThumbnailUrl(attributes?.id || ''),\n alt: '',\n },\n children: [],\n },\n ],\n },\n ],\n };\n }\n });\n };\n}\n\nfunction getTitle(node: LeafDirective, file: VFile) {\n const children = node.children as Node[];\n const firstChild = children[0] as Literal;\n const title = firstChild?.value || '';\n if (title.trim() === '') {\n failMessage(file, 'Video has no title', node.position);\n }\n return title;\n}\n\nfunction getYoutubeUrl(id: string) {\n return `https://youtu.be/${id}`;\n}\n\nfunction getYoutubeThumbnailUrl(id: string) {\n return `http://img.youtube.com/vi/${id}/mqdefault.jpg`;\n}\n\nfunction formatDuration(duration: string = '') {\n const match = duration.match(/^(\\d+)m(\\d+)s$/);\n if (match === null) {\n return '';\n }\n return `${match[1]}:${match[2].padStart(2, '0')}`;\n}\n","import puppeteer from 'puppeteer';\n\n// const footerTemplate = `\n//
\n// Page of \n//
\n// `;\n\nexport async function convertToPdf(html: string) {\n const browser = await puppeteer.launch({\n headless: true,\n args: [\n // attempted fix for windows https://stackoverflow.com/questions/59979188#66549119\n '--disable-gpu',\n '--disable-dev-shm-usage',\n '--disable-setuid-sandbox',\n '--no-first-run',\n '--no-sandbox',\n '--no-zygote',\n ],\n });\n const page = await browser.newPage();\n page.setDefaultNavigationTimeout(0);\n await page.setContent(html);\n await page.evaluateHandle('document.fonts.ready');\n const pdf = await page.pdf({\n format: 'a4',\n printBackground: true,\n // displayHeaderFooter: true,\n // footerTemplate,\n margin: {\n top: '20px',\n left: '40px',\n right: '40px',\n bottom: '40px',\n },\n });\n await browser.close();\n return pdf;\n}\n","export function allowNoWhitespaceBeforeHeading(contents: string) {\n return contents\n .split('\\n')\n .map((line) => {\n const match = line.match(/^(#+)(\\w)(.*?)$/);\n if (match !== null) {\n return `${match[1]} ${match[2]}${match[3]}`;\n }\n return line;\n })\n .join('\\n');\n}\n","const blockList = ['\\\\newpage', '\\\\pagebreak'];\n\nexport function convertNewPageToDirective(contents: string) {\n return contents\n .split('\\n')\n .map((a) => (blockList.some((b) => a.includes(b)) ? '::pagebreak' : a))\n .join('\\n');\n}\n\nexport function convertEmptyMBoxToDirective(contents: string) {\n return contents\n .split('\\n')\n .map((line) => {\n if (\n line.includes('\\\\mbox') &&\n line.replace('{', '').replace('}', '').trim() === '\\\\mbox'\n ) {\n return '::pagebreak';\n }\n return line;\n })\n .join('\\n');\n}\n","export function convertTextBfToMd(contents: string) {\n const pattern = /\\\\textbf\\{(.*?)\\}/g;\n return contents.replace(pattern, (_, str) => `**${str}**`);\n}\n\nexport function convertUrlToMd(contents: string) {\n const pattern = /\\\\url\\{(.*?)\\}/g;\n return contents.replace(pattern, (_, str) => str);\n}\n","export function convertMacroToDirective(contents: string) {\n return contents\n .split('\\n')\n .map((line) => {\n const container = parseCustomContainer(line);\n if (container !== null) {\n return renderContainerDirective(container);\n }\n return line;\n })\n .join('\\n');\n}\n\ntype Container = {\n name: string;\n title: string;\n attributes: string;\n};\n\nfunction parseCustomContainer(line: string): Container | null {\n const match = line.match(/^#{1,6}\\s*\\[(\\D.+)](.*)/);\n if (!Array.isArray(match)) {\n return null;\n }\n const [, attributeStr = '', extra = ''] = match;\n const [name, ...attributesArr] = attributeStr\n .split(',')\n .map((s) => s.trim());\n const title = extra.trim();\n const attributes = transformAttributes(name, attributesArr);\n return { name, title, attributes };\n}\n\nfunction renderContainerDirective({ name, title, attributes }: Container) {\n const colons = getColons(name);\n if (name.startsWith('/')) {\n return colons;\n }\n const newTitle = title ? `[${title}]` : '';\n const newAttributes = attributes ? `{${attributes}}` : '';\n return colons + name + newTitle + newAttributes;\n}\n\nfunction getColons(name: string) {\n switch (name.replace('/', '')) {\n case 'task':\n case 'columns':\n return '::::';\n case 'video':\n return '::';\n default:\n return ':::';\n }\n}\n\nfunction transformAttributes(\n containerName: string,\n attributesArr: string[]\n) {\n return attributesArr\n .map((attribute) => {\n const [key, value] = attribute.split('=').map((s) => s.trim());\n if (containerName === 'video' && key === 'videoid') {\n return `id=${value}`;\n }\n return attribute;\n })\n .join(' ');\n}\n","import { VFile } from 'vfile';\n\nimport { allowNoWhitespaceBeforeHeading } from './allow-no-whitespace-before-heading';\nimport {\n convertEmptyMBoxToDirective,\n convertNewPageToDirective,\n} from './convert-block-tex';\nimport { convertTextBfToMd, convertUrlToMd } from './convert-inline-tex';\nimport { convertMacroToDirective } from './convert-macro-to-directive';\nimport { reformatPandocSimpleTables } from './reformat-pandoc-simple-tables';\n\n// Some of the original coursework syntax can't easily be parsed by\n// existing plugins for unified.js, so in a \"pre-parse\" phase\n// I transform some syntax using regex so it can be parsed.\n// A successful generic approach I found is to convert problem syntax to a\n// custom markdown directive: https://github.com/remarkjs/remark-directive\n\nexport function preParsePhase(file: VFile) {\n let result = file.value as string;\n result = removeCommentedSections(result);\n // result = escapeDollarsInCodeBlocks(result);\n result = allowNoWhitespaceBeforeHeading(result);\n result = convertMacroToDirective(result);\n result = convertTextBfToMd(result);\n result = convertUrlToMd(result);\n result = convertNewPageToDirective(result);\n result = convertEmptyMBoxToDirective(result);\n result = reformatPandocSimpleTables(result);\n file.value = result;\n return file;\n}\n\nfunction removeCommentedSections(md: string) {\n return md.replace(//g, '').replace(/\\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n\";","export default \"\\n \\n \\n\\n\";","export default \"\\n \\n\\n\";","module.exports = import(\"@double-great/remark-lint-alt-text\");;","module.exports = import(\"@mapbox/remark-lint-link-text\");;","module.exports = import(\"ansicolor\");;","module.exports = import(\"base64-arraybuffer\");;","module.exports = import(\"chalk\");;","module.exports = import(\"figures\");;","module.exports = import(\"hash-sum\");;","module.exports = import(\"image-size\");;","module.exports = import(\"js-yaml\");;","module.exports = import(\"lodash/cloneDeep.js\");;","module.exports = import(\"lodash/kebabCase.js\");;","module.exports = import(\"lodash/startCase.js\");;","module.exports = import(\"markdown-table\");;","module.exports = import(\"mathjax-full/js/adaptors/liteAdaptor.js\");;","module.exports = import(\"mathjax-full/js/core/MathItem.js\");;","module.exports = import(\"mathjax-full/js/core/MmlTree/SerializedMmlVisitor.js\");;","module.exports = import(\"mathjax-full/js/handlers/html.js\");;","module.exports = import(\"mathjax-full/js/handlers/html/HTMLDocument.js\");;","module.exports = import(\"mathjax-full/js/input/mathml.js\");;","module.exports = import(\"mathjax-full/js/input/tex.js\");;","module.exports = import(\"mathjax-full/js/input/tex/AllPackages.js\");;","module.exports = import(\"mathjax-full/js/mathjax.js\");;","module.exports = import(\"mathjax-full/js/output/svg.js\");;","module.exports = import(\"mdast-util-to-hast\");;","module.exports = import(\"mdast-util-toc\");;","module.exports = import(\"mime\");;","module.exports = import(\"node-fetch\");;","module.exports = import(\"puppeteer\");;","module.exports = import(\"refractor/lib/all.js\");;","module.exports = import(\"rehype-autolink-headings\");;","module.exports = import(\"rehype-document\");;","module.exports = import(\"rehype-format\");;","module.exports = import(\"rehype-parse\");;","module.exports = import(\"rehype-raw\");;","module.exports = import(\"rehype-slug\");;","module.exports = import(\"rehype-stringify\");;","module.exports = import(\"remark-directive\");;","module.exports = import(\"remark-frontmatter\");;","module.exports = import(\"remark-gfm\");;","module.exports = import(\"remark-parse\");;","module.exports = import(\"remark-rehype\");;","module.exports = import(\"speech-rule-engine\");;","module.exports = import(\"to-vfile\");;","module.exports = import(\"unified\");;","module.exports = import(\"unist-util-remove\");;","module.exports = import(\"unist-util-visit\");;","module.exports = import(\"vfile\");;","module.exports = import(\"yargs\");;","module.exports = import(\"yargs/helpers\");;","module.exports = import(\"yup\");;","module.exports = require(\"child_process\");","module.exports = require(\"fs\");","module.exports = require(\"os\");","module.exports = require(\"path\");","module.exports = require(\"url\");","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","var webpackQueues = typeof Symbol === \"function\" ? Symbol(\"webpack queues\") : \"__webpack_queues__\";\nvar webpackExports = typeof Symbol === \"function\" ? Symbol(\"webpack exports\") : \"__webpack_exports__\";\nvar webpackError = typeof Symbol === \"function\" ? Symbol(\"webpack error\") : \"__webpack_error__\";\nvar resolveQueue = (queue) => {\n\tif(queue && queue.d < 1) {\n\t\tqueue.d = 1;\n\t\tqueue.forEach((fn) => (fn.r--));\n\t\tqueue.forEach((fn) => (fn.r-- ? fn.r++ : fn()));\n\t}\n}\nvar wrapDeps = (deps) => (deps.map((dep) => {\n\tif(dep !== null && typeof dep === \"object\") {\n\t\tif(dep[webpackQueues]) return dep;\n\t\tif(dep.then) {\n\t\t\tvar queue = [];\n\t\t\tqueue.d = 0;\n\t\t\tdep.then((r) => {\n\t\t\t\tobj[webpackExports] = r;\n\t\t\t\tresolveQueue(queue);\n\t\t\t}, (e) => {\n\t\t\t\tobj[webpackError] = e;\n\t\t\t\tresolveQueue(queue);\n\t\t\t});\n\t\t\tvar obj = {};\n\t\t\tobj[webpackQueues] = (fn) => (fn(queue));\n\t\t\treturn obj;\n\t\t}\n\t}\n\tvar ret = {};\n\tret[webpackQueues] = x => {};\n\tret[webpackExports] = dep;\n\treturn ret;\n}));\n__webpack_require__.a = (module, body, hasAwait) => {\n\tvar queue;\n\thasAwait && ((queue = []).d = -1);\n\tvar depQueues = new Set();\n\tvar exports = module.exports;\n\tvar currentDeps;\n\tvar outerResolve;\n\tvar reject;\n\tvar promise = new Promise((resolve, rej) => {\n\t\treject = rej;\n\t\touterResolve = resolve;\n\t});\n\tpromise[webpackExports] = exports;\n\tpromise[webpackQueues] = (fn) => (queue && fn(queue), depQueues.forEach(fn), promise[\"catch\"](x => {}));\n\tmodule.exports = promise;\n\tbody((deps) => {\n\t\tcurrentDeps = wrapDeps(deps);\n\t\tvar fn;\n\t\tvar getResult = () => (currentDeps.map((d) => {\n\t\t\tif(d[webpackError]) throw d[webpackError];\n\t\t\treturn d[webpackExports];\n\t\t}))\n\t\tvar promise = new Promise((resolve) => {\n\t\t\tfn = () => (resolve(getResult));\n\t\t\tfn.r = 0;\n\t\t\tvar fnQueue = (q) => (q !== queue && !depQueues.has(q) && (depQueues.add(q), q && !q.d && (fn.r++, q.push(fn))));\n\t\t\tcurrentDeps.map((dep) => (dep[webpackQueues](fnQueue)));\n\t\t});\n\t\treturn fn.r ? promise : getResult();\n\t}, (err) => ((err ? reject(promise[webpackError] = err) : outerResolve(exports)), resolveQueue(queue)));\n\tqueue && queue.d < 0 && (queue.d = 0);\n};","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","","// startup\n// Load entry module and return exports\n// This entry module used 'module' so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(606);\n",""],"names":[],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"cli.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AACA;AAEA;AACA;;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAMA;AAEA;AACA;AAOA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAIA;AAEA;AAOA;AACA;AAMA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;;;;;;;;;;;;;;;;;;ACpHA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;ACzJA;AAOA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;ACvDA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;AC7CA;AAEA;AAgDA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;AC/DA;AAEA;AACA;AAEA;AACA;AACA;AAUA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AAKA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;AC9DA;AAEA;AACA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;AC9CA;AAEA;AACA;AAEA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;AC3BA;AACA;AACA;AAIA;AACA;AAEA;AAMA;AACA;AAAA;AAIA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1BA;AAEA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAKA;AAEA;AAEA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAMA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;ACvNA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;AC9BA;AAGA;AAEA;AACA;AACA;AACA;AAKA;AACA;AACA;AAEA;AAQA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AClEA;AACA;AACA;AAEA;AACA;AACA;AAKA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;AC3BA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;AC5BA;AAEA;AACA;AAGA;AAEA;AAKA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAIA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;AC5GA;AACA;AAEA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;;;;;;;;;;;;;;;;;AChFA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AAEA;AACA;;AC1HA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;ACpDA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;AC5CA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7EA;AACA;AACA;AACA;AAEA;AACA;AACA;AAIA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAIA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAKA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAIA;;AAEA;AACA;AACA;;AAEA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;AC/TA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;ACpCA;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAIA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;;AAEA;AAAA;AAEA;AACA;AAKA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AAEA;;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAIA;AAEA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;AC7KA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AC3BA;AAGA;AAEA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;ACpCA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACjBA;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;ACvBA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;ACzBA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AChCA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AC9BA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;ACnCA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAKA;AASA;AAAA;;AAIA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;;;;;;;;;;;;;;;;ACxEA;AAIA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;ACjFA;AACA;AAKA;AAmBA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;AC5GA;AAGA;AAEA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAKA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AAEA;AAIA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAGA;AAAA;AAGA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAIA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;ACvNA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;ACtJA;AAEA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;ACnHA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;ACzDA;AAIA;AACA;AACA;AACA;AAEA;AAMA;AAKA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;AC1BA;AAGA;AACA;AAKA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;AChGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AASA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;AC/HA;AAGA;AAGA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpJA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAOA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAgBA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;ACzDA;AAEA;AAIA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;AChGA;AAEA;AACA;AACA;AAIA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;AC7CA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;ACfA;AAEA;AAIA;AACA;AAEA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;AChGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AChBA;AAIA;AAEA;AACA;AACA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAIA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;;;;;;;;;;;;;;;;AChFA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;ACtEA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;ACnIA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACvCA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;ACXA;AAEA;AACA;AAIA;AAEA;AACA;AAGA;AAIA;AACA;AACA;AACA;AAEA;;;;;;;;;;;ACtBA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;ACRA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAEA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAIA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;AClEA;AACA;AAIA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;ACxCA;AAEA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAKA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;ACzIA;AAEA;AAGA;AAUA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;ACzDA;AAEA;AACA;AAEA;AAEA;AACA;AAIA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACtDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;ACdA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;AChBA;AAEA;AAEA;;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;AC9CA;AACA;AACA;AAQA;AACA;AAIA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;ACtEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA;AAKA;AACA;AACA;AAEA;AAKA;AACA;AACA;AAEA;AAKA;AACA;AACA;AAEA;AAMA;AACA;AACA;AACA;AACA;;;;;;;;;;ACnDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZA;AACA;AAEA;AACA;AACA;AAGA;;AAEA;AACA;AAAA;AAGA;AAIA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;AC9EA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;;ACAA;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;ACvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;AChEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;ACPA;;;;;AEAA;AACA;AACA;AACA","sources":["webpack://compiler/./src/build-unit.ts","webpack://compiler/./src/cli/cli.ts","webpack://compiler/./src/code/alias-directive-to-code.ts","webpack://compiler/./src/code/code-to-alias-directive.ts","webpack://compiler/./src/context.ts","webpack://compiler/./src/course/index.ts","webpack://compiler/./src/course/load-course.ts","webpack://compiler/./src/course/load-unit.ts","webpack://compiler/./src/hast/index.ts","webpack://compiler/./src/hast/inline-files.ts","webpack://compiler/./src/hast/responsive-tables.ts","webpack://compiler/./src/html/index.ts","webpack://compiler/./src/html/pdf.ts","webpack://compiler/./src/html/wrapper/index.ts","webpack://compiler/./src/html/wrapper/main.ts","webpack://compiler/./src/html/wrapper/sidebar.ts","webpack://compiler/./src/html/wrapper/view-options/readability.ts","webpack://compiler/./src/html/wrapper/view-options/theme.ts","webpack://compiler/./src/html/wrapper/view-options/index.ts","webpack://compiler/./src/index.ts","webpack://compiler/./src/knitr/knitr.ts","webpack://compiler/./src/latex/directive-to-svg.ts","webpack://compiler/./src/latex/mathjax-tex.ts","webpack://compiler/./src/latex/tex-to-directive.ts","webpack://compiler/./src/linter/assert-asset-exists.ts","webpack://compiler/./src/linter/assert-columns.ts","webpack://compiler/./src/linter/assert-no-h1.ts","webpack://compiler/./src/linter/assert-no-image-attributes.ts","webpack://compiler/./src/linter/assert-no-tex-tabular.ts","webpack://compiler/./src/linter/assert-program-switcher.ts","webpack://compiler/./src/linter/assert-task-answer.ts","webpack://compiler/./src/linter/assert-video-attributes.ts","webpack://compiler/./src/linter/assert-weblink-target.ts","webpack://compiler/./src/linter/index.ts","webpack://compiler/./src/linter/lint-latex.ts","webpack://compiler/./src/linter/report.ts","webpack://compiler/./src/mdast/boxouts.ts","webpack://compiler/./src/mdast/browser-window.ts","webpack://compiler/./src/mdast/code-blocks.ts","webpack://compiler/./src/mdast/columns.ts","webpack://compiler/./src/mdast/combined.ts","webpack://compiler/./src/mdast/embed-asset-url.ts","webpack://compiler/./src/mdast/gitgraph.ts","webpack://compiler/./src/mdast/images.ts","webpack://compiler/./src/mdast/index.ts","webpack://compiler/./src/mdast/language-switcher.ts","webpack://compiler/./src/mdast/move-answers-to-end.ts","webpack://compiler/./src/mdast/pagebreaks.ts","webpack://compiler/./src/mdast/program-switcher.ts","webpack://compiler/./src/mdast/remove-empty-paragraphs.ts","webpack://compiler/./src/mdast/styled-terminal.ts","webpack://compiler/./src/mdast/text-file.ts","webpack://compiler/./src/mdast/youtube-videos.ts","webpack://compiler/./src/pdf/index.ts","webpack://compiler/./src/pre-parse/allow-no-whitespace-before-heading.ts","webpack://compiler/./src/pre-parse/convert-block-tex.ts","webpack://compiler/./src/pre-parse/convert-inline-tex.ts","webpack://compiler/./src/pre-parse/convert-macro-to-directive.ts","webpack://compiler/./src/pre-parse/index.ts","webpack://compiler/./src/pre-parse/reformat-pandoc-simple-tables.ts","webpack://compiler/./src/utils/cache-to-file.ts","webpack://compiler/./src/utils/check-for-latest-version.ts","webpack://compiler/./src/utils/counter.ts","webpack://compiler/./src/utils/get-asset-hast.ts","webpack://compiler/./src/utils/get-svg-hast.ts","webpack://compiler/./src/utils/icons.ts","webpack://compiler/./src/utils/message.ts","webpack://compiler/./src/utils/timer.ts","webpack://compiler/./src/utils/utils.ts","webpack://compiler/./assets/crest.svg","webpack://compiler/./assets/dag-logo.svg","webpack://compiler/./assets/hamburger-icon.svg","webpack://compiler/./assets/hexagons.svg","webpack://compiler/./assets/link-icon.svg","webpack://compiler/./assets/uofg.svg","webpack://compiler/external module \"@double-great/remark-lint-alt-text\"","webpack://compiler/external module \"@mapbox/remark-lint-link-text\"","webpack://compiler/external module \"ansicolor\"","webpack://compiler/external module \"base64-arraybuffer\"","webpack://compiler/external module \"chalk\"","webpack://compiler/external module \"figures\"","webpack://compiler/external module \"hash-sum\"","webpack://compiler/external module \"image-size\"","webpack://compiler/external module \"js-yaml\"","webpack://compiler/external module \"lodash/cloneDeep.js\"","webpack://compiler/external module \"lodash/kebabCase.js\"","webpack://compiler/external module \"lodash/startCase.js\"","webpack://compiler/external module \"markdown-table\"","webpack://compiler/external module \"mathjax-full/js/adaptors/liteAdaptor.js\"","webpack://compiler/external module \"mathjax-full/js/core/MathItem.js\"","webpack://compiler/external module \"mathjax-full/js/core/MmlTree/SerializedMmlVisitor.js\"","webpack://compiler/external module \"mathjax-full/js/handlers/html.js\"","webpack://compiler/external module \"mathjax-full/js/handlers/html/HTMLDocument.js\"","webpack://compiler/external module \"mathjax-full/js/input/mathml.js\"","webpack://compiler/external module \"mathjax-full/js/input/tex.js\"","webpack://compiler/external module \"mathjax-full/js/input/tex/AllPackages.js\"","webpack://compiler/external module \"mathjax-full/js/mathjax.js\"","webpack://compiler/external module \"mathjax-full/js/output/svg.js\"","webpack://compiler/external module \"mdast-util-to-hast\"","webpack://compiler/external module \"mdast-util-toc\"","webpack://compiler/external module \"mime\"","webpack://compiler/external module \"node-fetch\"","webpack://compiler/external module \"puppeteer\"","webpack://compiler/external module \"refractor/lib/all.js\"","webpack://compiler/external module \"rehype-autolink-headings\"","webpack://compiler/external module \"rehype-document\"","webpack://compiler/external module \"rehype-format\"","webpack://compiler/external module \"rehype-parse\"","webpack://compiler/external module \"rehype-raw\"","webpack://compiler/external module \"rehype-slug\"","webpack://compiler/external module \"rehype-stringify\"","webpack://compiler/external module \"remark-directive\"","webpack://compiler/external module \"remark-frontmatter\"","webpack://compiler/external module \"remark-gfm\"","webpack://compiler/external module \"remark-parse\"","webpack://compiler/external module \"remark-rehype\"","webpack://compiler/external module \"speech-rule-engine\"","webpack://compiler/external module \"to-vfile\"","webpack://compiler/external module \"unified\"","webpack://compiler/external module \"unist-util-remove\"","webpack://compiler/external module \"unist-util-visit\"","webpack://compiler/external module \"vfile\"","webpack://compiler/external module \"yargs\"","webpack://compiler/external module \"yargs/helpers\"","webpack://compiler/external module \"yup\"","webpack://compiler/external node-commonjs \"child_process\"","webpack://compiler/external node-commonjs \"fs\"","webpack://compiler/external node-commonjs \"os\"","webpack://compiler/external node-commonjs \"path\"","webpack://compiler/external node-commonjs \"url\"","webpack://compiler/webpack/bootstrap","webpack://compiler/webpack/runtime/async module","webpack://compiler/webpack/runtime/compat get default export","webpack://compiler/webpack/runtime/define property getters","webpack://compiler/webpack/runtime/hasOwnProperty shorthand","webpack://compiler/webpack/before-startup","webpack://compiler/webpack/startup","webpack://compiler/webpack/after-startup"],"sourcesContent":["import { EOL } from 'os';\n\nimport { Parent as HastParent } from 'hast';\nimport { Parent as MdastParent, Root } from 'mdast';\nimport { VFile } from 'vfile';\n\nimport { Context } from './context';\nimport { Unit } from './course/types';\nimport { hastPhase } from './hast';\nimport { htmlPhase } from './html';\nimport { knitr } from './knitr/knitr';\nimport { texToAliasDirective } from './latex/tex-to-directive';\nimport { createReport, reportErrors } from './linter';\nimport { assertNoImageAttributes } from './linter/assert-no-image-attributes';\nimport { mdastPhase } from './mdast';\nimport { combinedMdastPhase } from './mdast/combined';\nimport { convertToPdf } from './pdf';\nimport { preParsePhase } from './pre-parse';\nimport { codeToAliasDirective } from './code/code-to-alias-directive';\n\nexport type BuiltUnit = {\n unit: Unit;\n md: string;\n files: VFile[];\n html?: {\n mdast: MdastParent;\n hast: HastParent;\n html: string;\n };\n pdf?: {\n mdast: MdastParent;\n hast: HastParent;\n html: string;\n pdf: Buffer;\n };\n};\n\nexport async function buildUnit(unit: Unit, ctx: Context) {\n const unifiedFile = await knitr(unit, ctx);\n\n const mdast = (await inSituTransforms(unifiedFile, ctx)) as Root;\n // console.log(mdast);\n\n await createReport(unifiedFile, mdast, ctx);\n\n const result: BuiltUnit = {\n unit,\n md: combineMdFiles(unifiedFile),\n files: [unifiedFile],\n };\n\n if (!ctx.options.noHtml) {\n result.html = await syntaxTreeTransforms(\n mdast,\n unifiedFile,\n unit,\n ctx,\n );\n }\n\n if (!ctx.options.noPdf) {\n const transformed = await syntaxTreeTransforms(\n mdast,\n unifiedFile,\n unit,\n ctx,\n true,\n );\n result.pdf = {\n ...transformed,\n pdf: await convertToPdf(transformed.html),\n };\n }\n\n if (!ctx.options.noReport) {\n reportErrors(result.files, ctx);\n }\n\n return result;\n}\n\nasync function inSituTransforms(file: VFile, ctx: Context) {\n assertNoImageAttributes(file);\n preParsePhase(file);\n await codeToAliasDirective(file, ctx);\n texToAliasDirective(file, ctx);\n return mdastPhase(file, ctx);\n}\n\nfunction combineMdFiles(file: VFile) {\n return removeDirectoryLines(file.value as string);\n}\n\nfunction removeDirectoryLines(md: string) {\n return md\n .split(EOL)\n .filter((line) => !/^::directory\\[.+\\]$/.test(line))\n .join(EOL);\n}\n\nasync function syntaxTreeTransforms(\n _mdast: Root,\n file: VFile,\n unit: Unit,\n ctx: Context,\n targetPdf?: boolean,\n) {\n const mdast = await combinedMdastPhase(_mdast, ctx, file, targetPdf);\n const hast = (await hastPhase(\n mdast,\n ctx,\n file,\n targetPdf,\n )) as HastParent;\n const html = await htmlPhase(hast, mdast, file, unit, ctx, targetPdf);\n return { mdast, hast, html };\n}\n","import chalk from 'chalk';\nimport figures from 'figures';\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\n\nimport { Options } from '../context';\nimport { reportHasFatalErrors } from '../linter/report';\nimport { rMarkdown } from '..';\n\nconst args = {\n week: {\n type: 'number',\n description: 'Build specific week (1-based index)',\n },\n watch: {\n type: 'boolean',\n description: 'Watch coursework for changes',\n },\n noDoc: {\n type: 'boolean',\n description: 'Only compile content HTML',\n },\n noHtml: {\n type: 'boolean',\n description: \"Don't create HTML file\",\n },\n noPdf: {\n type: 'boolean',\n description: \"Don't create PDF file\",\n },\n noSyntaxHighlight: {\n type: 'boolean',\n description: 'No syntax highlighting',\n },\n noReport: {\n type: 'boolean',\n description: 'Bypass linter',\n },\n noEmbedAssets: {\n type: 'boolean',\n description: \"Don't embed assets\",\n },\n noEmbedAssetUrl: {\n type: 'boolean',\n description: \"Don't complete asset Url\",\n },\n noCache: {\n type: 'boolean',\n description: 'No cache',\n },\n noTexSvg: {\n type: 'boolean',\n description: 'No Tex Svg',\n },\n noHexagons: {\n type: 'boolean',\n description: 'No cover hexagons',\n },\n spelling: {\n type: 'boolean',\n description: 'Check spelling',\n },\n pythonBin: {\n type: 'string',\n description: 'Custom path to python binary',\n },\n force: {\n type: 'boolean',\n description: 'Compile even with fatal errors',\n },\n verbose: {\n type: 'boolean',\n description: 'Show error stack',\n },\n envPlatform: {\n type: 'string',\n description: 'Specify which environment platform to display',\n },\n envProgram: {\n type: 'string',\n description: 'Specify which environment program to display',\n },\n envLanguage: {\n type: 'string',\n description: 'Specify which environment language to display',\n },\n fileName: {\n type: 'string',\n description: 'Specify name of output file',\n },\n output: {\n type: 'string',\n description: 'output to stdout',\n choices: ['md', 'html'],\n },\n} as const;\n\nconst argv = yargs(hideBin(process.argv)).options(args).parseSync();\n\nconst dirPath = String(argv._[0] || '.');\n\nconst options: Options = {\n week: argv.week,\n watch: argv.watch,\n noDoc: argv.noDoc,\n noHtml: argv.noHtml,\n noPdf: argv.noPdf,\n noSyntaxHighlight: argv.noSyntaxHighlight,\n noReport: argv.noReport,\n noEmbedAssets: argv.noEmbedAssets,\n noEmbedAssetUrl: argv.noEmbedAssetUrl,\n noCache: argv.noCache,\n noTexSvg: argv.noTexSvg,\n noHexagons: argv.noHexagons,\n spelling: argv.spelling,\n pythonBin: argv.pythonBin,\n force: argv.force,\n verbose: argv.verbose,\n envPlatform: argv.envPlatform,\n envProgram: argv.envProgram,\n envLanguage: argv.envLanguage,\n fileName: argv.fileName,\n output: argv.output as 'md' | 'html',\n};\n\nasync function run() {\n try {\n const weeks = await rMarkdown(dirPath, options);\n for (const week of weeks) {\n if (options.output === 'html') {\n console.log((week.html?.html || '').trim());\n }\n if (options.output === 'md') {\n console.log(week.md.trim());\n }\n }\n\n // correct exit code even when using --force\n for (const week of weeks) {\n if (reportHasFatalErrors(week.files)) {\n process.exit(1);\n }\n }\n } catch (err: any) {\n console.log(chalk.red(figures.cross + ' ' + err.message));\n if (options.verbose) {\n console.error(err);\n }\n process.exit(1);\n }\n process.exit(0);\n}\n\nrun();\n","import { visit } from 'unist-util-visit';\nimport { LeafDirective, TextDirective } from 'mdast-util-directive';\nimport { Literal, Node } from 'hast';\nimport { Parent } from 'mdast';\n\nimport { CodeBlock, Context } from '../context';\n\nexport function aliasDirectiveToCode(ctx: Context) {\n return (tree: Node) => {\n visit(tree, (node: Node) => {\n if (\n node.type === 'leafDirective' &&\n (node as LeafDirective).name === 'codeBlock'\n ) {\n const idx = getStoreIdx(node as Parent);\n if (ctx.codeStore === undefined) {\n return;\n }\n const stored = ctx.codeStore[idx] as CodeBlock;\n if (!stored) {\n return;\n }\n Object.assign(node, {\n type: 'code',\n name: undefined,\n lang: stored.lang,\n meta: stored.meta,\n value: stored.value,\n children: [],\n });\n }\n if (\n node.type === 'textDirective' &&\n (node as TextDirective).name === 'codeBlock'\n ) {\n const idx = getStoreIdx(node as Parent);\n if (ctx.codeStore === undefined) {\n return;\n }\n const stored = ctx.codeStore[idx] as CodeBlock;\n if (!stored) {\n return;\n }\n Object.assign(node, {\n type: 'inlineCode',\n name: undefined,\n value: stored.value,\n children: [],\n });\n }\n });\n };\n}\n\nfunction getStoreIdx(node: Parent) {\n const firstChild = node.children[0] as Literal;\n return Number(firstChild.value || 0);\n}\n","import { VFile } from 'vfile';\nimport { Context, CodeBlock } from '../context';\nimport { EOL } from 'os';\n\n// The reason for replacing all fenced code blocks with aliases\n// temporarily is because of MathJax. MathJax is designed to look\n// for TeX code inside HTML files, and in our case we need to make it\n// look inside a Markdown file. This leads to MathJax looking for TeX\n// inside code blocks, which can causes problems (especially with SAS\n// code syntax). So this function replaces code blocks with an alias,\n// allows MathJax to do it's thing, then adds it back in with\n// `aliasDirectiveToCode`.\n\nexport async function codeToAliasDirective(file: VFile, ctx: Context) {\n const store: CodeBlock[] = [];\n file.value = codeBlocksToAlias(file.value as string, store);\n file.value = inlineCodeToAlias(file.value as string, store);\n ctx.codeStore = store;\n return file;\n}\n\nfunction codeBlocksToAlias(md: string, store: CodeBlock[]) {\n const verbatimStore: string[] = [];\n return md\n .replace(/^(~~~.+?^~~~)$/gms, (_, match) => {\n verbatimStore.push(match);\n return `::verbatimStore[${verbatimStore.length - 1}]`;\n })\n .replace(/^```(.+?)^```$/gms, (_, match) => {\n const lines = match.split(EOL);\n const lang = lines[0];\n const value = lines.slice(1).join(EOL);\n store.push({ lang, value });\n return `::codeBlock[${store.length - 1}]`;\n })\n .replace(/::verbatimStore\\[(\\d+)\\]/g, (_, match) => {\n return verbatimStore[Number(match)];\n });\n}\n\nfunction inlineCodeToAlias(md: string, store: CodeBlock[]) {\n return md.replace(/`([^\\n`]+?)`/g, (_, value) => {\n store.push({ value });\n return `:codeBlock[${store.length - 1}]`;\n });\n}\n","import { collectCoursework } from './course';\nimport { Course } from './course/types';\nimport { getBuildDir, getCacheDir } from './utils/utils';\n\nexport type Options = {\n noDoc?: boolean;\n noHtml?: boolean;\n noPdf?: boolean;\n noSyntaxHighlight?: boolean;\n noReport?: boolean;\n reportOnlyErrors?: boolean;\n noEmbedAssets?: boolean;\n noEmbedAssetUrl?: boolean;\n noCache?: boolean;\n noTexSvg?: boolean;\n noHexagons?: boolean;\n week?: number;\n watch?: boolean;\n shouldFail?: boolean;\n spelling?: boolean;\n force?: boolean;\n noWrite?: boolean;\n format?: boolean;\n pythonBin?: string;\n verbose?: boolean;\n envPlatform?: string;\n envProgram?: string;\n envLanguage?: string;\n fileName?: string;\n output?: 'md' | 'html';\n};\n\nexport type CodeBlock = {\n lang?: string | null;\n meta?: string | null;\n value: string;\n};\n\nexport type Context = {\n dirPath: string;\n buildDir: string;\n cacheDir: string;\n course: Course;\n options: Options;\n mmlStore?: string[];\n codeStore?: CodeBlock[];\n refStore: Record;\n figureCounter: number;\n};\n\nexport async function createContext(\n dirPath: string,\n options: Options = {},\n): Promise {\n return {\n course: await collectCoursework(dirPath),\n dirPath,\n buildDir: getBuildDir(dirPath),\n cacheDir: getCacheDir(dirPath),\n options,\n refStore: {},\n figureCounter: 0,\n };\n}\n","import path from 'path';\n\nimport kebabCase from 'lodash/kebabCase.js';\nimport { read as readVfile } from 'to-vfile';\n\nimport { checkLocalFileExists } from '../utils/utils';\nimport { loadCourseYaml } from './load-course';\nimport { loadUnitYaml } from './load-unit';\nimport {\n Course,\n CourseYaml,\n Unit,\n UnitTitles,\n UnitTitlesInput,\n} from './types';\nimport { FileRef } from './types';\n\nexport async function collectCoursework(dirPath: string): Promise {\n const course = await loadCourseYaml(dirPath);\n const coursePath = path.join(process.cwd(), dirPath);\n const units = await Promise.all(\n course.units.map((unit) => collectUnit(unit, course, dirPath)),\n );\n return { ...course, coursePath, units };\n}\n\nasync function collectUnit(\n unit: FileRef,\n course: CourseYaml,\n dirPath: string,\n): Promise {\n const { content, ...yaml } = await loadUnitYaml(dirPath, unit.src);\n const unitPath = path.join(process.cwd(), dirPath, unit.src);\n const files = await Promise.all(\n content.map(async (c) => {\n const filePath = path.resolve(dirPath, unit.src, '..', c.src);\n if (!(await checkLocalFileExists(filePath))) {\n throw new Error(`No Rmd file exists at ${filePath}`);\n }\n return readVfile(filePath, 'utf-8');\n }),\n );\n const titles = getUnitTitles({\n courseTitle: course.title,\n unitName: yaml.name,\n unitTitle: yaml.title,\n });\n return { ...yaml, unitPath, parts: content, files, titles };\n}\n\nexport function getUnitTitles({\n courseTitle,\n unitName,\n unitTitle,\n}: UnitTitlesInput): UnitTitles {\n return {\n courseTitle,\n unitTitle: `${unitName}: ${unitTitle}`,\n unitName,\n docTitle: `${unitTitle} | ${courseTitle}`,\n fileName: kebabCase(unitName),\n };\n}\n","import path from 'path';\n\nimport yaml from 'js-yaml';\nimport * as yup from 'yup';\n\nimport { checkLocalFileExists, readFile } from '../utils/utils';\nimport { CourseYaml } from './types';\n\n// export const validCatalogValues = [\n// 'STATS5077',\n// 'STATS5078',\n// 'STATS5075',\n// 'STATS5084',\n// 'STATS5074',\n// 'STATS5081',\n// 'STATS5080',\n// 'STATS5073',\n// 'STATS5076',\n// 'STATS5079',\n// 'STATS5082',\n// 'STATS5094',\n// 'STATS5083',\n// ];\n\nconst courseSchema = yup.object().shape({\n title: yup.string().required(),\n units: yup.array().of(\n yup.object().shape({\n src: yup.string().required(),\n })\n ),\n catalog: yup.string(),\n authors: yup.string().required(),\n academic_year: yup.string().required(),\n});\n\nexport async function loadCourseYaml(dirPath: string) {\n const courseYamlPath = path.join(dirPath, 'course.yaml');\n if (!(await checkLocalFileExists(courseYamlPath))) {\n throw Error(\n `No course.yaml file exists in ${path.join(process.cwd(), dirPath)}`\n );\n }\n const fileContents = await readFile(courseYamlPath);\n const course = yaml.load(fileContents);\n return courseSchema.validateSync(course) as CourseYaml;\n}\n","import path from 'path';\n\nimport yaml from 'js-yaml';\nimport * as yup from 'yup';\n\nimport { checkLocalFileExists, readFile } from '../utils/utils';\nimport { UnitYaml } from './types';\n\nconst unitSchema = yup.object().shape({\n name: yup.string().required(),\n title: yup.string().required(),\n content: yup.array().of(\n yup.object().shape({\n src: yup.string().required(),\n })\n ),\n});\n\nexport async function loadUnitYaml(dirPath: string, src: string) {\n const contentsPath = path.join(dirPath, src);\n if (!(await checkLocalFileExists(contentsPath))) {\n throw Error(\n `No yaml file exists at ${path.join(process.cwd(), contentsPath)}`\n );\n }\n const fileContents = await readFile(contentsPath);\n const unit = yaml.load(fileContents);\n return unitSchema.validateSync(unit) as UnitYaml;\n}\n","import { Root } from 'mdast';\nimport rehypeRaw from 'rehype-raw';\nimport remark2rehype from 'remark-rehype';\nimport { unified } from 'unified';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { inlineRelativeAssets } from './inline-files';\nimport { responsiveTables } from './responsive-tables';\n\nexport async function hastPhase(\n mdast: Root,\n ctx: Context,\n file: VFile,\n targetPdf?: boolean,\n) {\n const processor = unified()\n .use(remark2rehype, { allowDangerousHtml: true })\n .use(rehypeRaw)\n .use(responsiveTables);\n\n if (!ctx.options.noEmbedAssets) {\n processor.use(inlineRelativeAssets, ctx);\n }\n\n return processor.run(mdast, file);\n}\n","import path from 'path';\n\nimport { encode as base46Encode } from 'base64-arraybuffer';\nimport { Element, Properties } from 'hast';\nimport sizeOf from 'image-size';\nimport mimes from 'mime';\nimport fetch from 'node-fetch';\nimport { toVFile } from 'to-vfile';\n// import { optimize } from 'svgo';\nimport { Parent } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\n// import { pdfToSvg } from '../pdf/pdf-to-svg';\nimport { cacheToFile } from '../utils/cache-to-file';\nimport { getSvgHast } from '../utils/get-svg-hast';\nimport { failMessage } from '../utils/message';\nimport { readFile, rehypeParser } from '../utils/utils';\n\nexport function inlineRelativeAssets(ctx: Context) {\n return async (tree: Element, file: VFile) => {\n const transformations: Promise[] = [];\n const loadedScripts: string[] = [];\n\n visit(tree, 'element', (node, index, parent) => {\n if (node.tagName === 'img') {\n transformations.push(embedFile(node, file, ctx));\n }\n if (node.tagName === 'script' && node.properties?.src) {\n transformations.push(\n embedScript(node, index, parent, loadedScripts),\n );\n }\n });\n\n await Promise.all(transformations);\n };\n}\n\nasync function embedFile(node: Element, file: VFile, ctx: Context) {\n const src = getImageSrc(node);\n const parsed = path.parse(src);\n try {\n switch (parsed.ext) {\n case '.png':\n case '.jpg':\n case '.jpeg':\n case '.gif':\n return await embedImage(node, ctx, file);\n case '.svg':\n return await embedSvg(node, ctx);\n case '.pdf':\n // return await embedPdfSvg(node);\n throw new Error(\n `Unhandled file extension: .pdf (convert to .svg)`,\n );\n case '.html':\n return await embedHtml(node);\n default:\n throw new Error(`Unhandled file extension: ${parsed.ext}`);\n }\n } catch (_err) {\n console.log(_err);\n const err = _err as Error;\n failMessage(file, err?.message || '', node.position);\n }\n}\n\nasync function embedImage(node: Element, ctx: Context, file: VFile) {\n const src = getImageSrc(node);\n const mime = mimes.getType(path.extname(src));\n try {\n const image = await getImage(src, ctx);\n const { width } = sizeOf(Buffer.from(image, 'base64'));\n node.properties = {\n ...node.properties,\n src: `data:${mime};base64,${image}`,\n style: [`max-width: ${width}px`],\n };\n } catch (err) {\n console.log(err);\n failMessage(file, `Image not found: ${src}`);\n }\n}\n\nasync function embedSvg(imgNode: Element, ctx: Context) {\n const src = getImageSrc(imgNode);\n const contents = await readFile(src);\n const idx = contents.indexOf(' String(x)).filter((s) => s !== removeClass);\n }\n return [];\n}\n\nfunction getImageSrc(node: Element) {\n const properties = (node.properties || {}) as { src: string };\n if (!properties.src) {\n throw new Error('Image has no src');\n }\n return properties.src;\n}\n\nasync function getImage(src: string, ctx: Context) {\n if (src.startsWith('http')) {\n return cacheToFile({\n ctx,\n prefix: 'youtube',\n key: src,\n execFn: getImageDataFromWeb,\n });\n }\n return readFile(src, 'base64');\n}\n\nasync function getImageDataFromWeb(src: string) {\n const response = await fetch(src);\n const buffer = await response.arrayBuffer();\n return base46Encode(buffer);\n}\n\n// async function embedPdfSvg(imgNode: Element) {\n// const src = getImageSrc(imgNode);\n// const svgNode = (await pdfToSvg(src)) as Element;\n// console.log('hey!');\n// console.log(svgNode);\n\n// const properties = {\n// ...imgNode.properties,\n// ...svgNode.properties,\n// } as Properties;\n\n// delete properties.src;\n\n// Object.assign(imgNode, svgNode, { properties });\n// }\n\nasync function embedHtml(imgNode: Element) {\n const src = getImageSrc(imgNode);\n const value = await readFile(src);\n const vfile = toVFile({ value });\n const parsed = rehypeParser().parse(vfile) as Parent;\n\n Object.assign(imgNode, {\n tagName: 'div',\n properties: {\n className: 'interactive-element',\n },\n children: parsed.children,\n });\n}\n\nasync function embedScript(\n node: Element,\n index: number | undefined,\n parent: Parent | undefined,\n loadedScripts: string[],\n) {\n if (!node.properties?.src) {\n return;\n }\n\n const src = node.properties.src as string;\n\n if (loadedScripts.includes(src)) {\n // script already inlined, remove tag\n const parentChildren = parent?.children || [];\n parentChildren.splice(index || 0, 1);\n return;\n }\n\n loadedScripts.push(src);\n\n delete node.properties.src;\n const response = await fetch(src);\n const value = await response.text();\n\n node.children = [\n {\n type: 'text',\n value: `// ${src}\\n${value}\\n`,\n },\n ];\n}\n","import { Root, Element } from 'hast';\nimport cloneDeep from 'lodash/cloneDeep.js';\nimport { visit } from 'unist-util-visit';\n\ntype ParentProps = {\n className: string[];\n};\n\nexport function responsiveTables() {\n return function (tree: Root) {\n visit(tree, 'element', (node, idx, _parent) => {\n if (node.tagName !== 'table') {\n return;\n }\n\n const parent = _parent as Element;\n const properties = (parent?.properties || {}) as ParentProps;\n const className = properties.className || [];\n\n if (!className.includes('table-wrapper')) {\n Object.assign(node, {\n tagName: 'div',\n properties: {\n className: 'table-wrapper',\n },\n children: [cloneDeep(node)],\n });\n }\n });\n };\n}\n","import path from 'path';\n\nimport { Parent as HastParent } from 'hast';\nimport startCase from 'lodash/startCase.js';\nimport { Parent as MdastParent } from 'mdast';\nimport doc, { Options } from 'rehype-document';\nimport format from 'rehype-format';\nimport stringify from 'rehype-stringify';\nimport { unified } from 'unified';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { Unit } from '../course/types';\nimport { getTemplateDir, readFile } from '../utils/utils';\nimport { pdfWrapper } from './pdf';\nimport { htmlWrapper } from './wrapper';\n\nexport async function htmlPhase(\n hast: HastParent,\n mdast: MdastParent,\n file: VFile,\n unit: Unit,\n ctx: Context,\n targetPdf?: boolean,\n) {\n const processor = unified().use(stringify, { allowDangerousHtml: true });\n\n if (ctx.options.format) {\n // hangs in some scenarios so off by default, useful in tests\n processor.use(format);\n }\n\n if (!ctx.options.noDoc) {\n const cssPath = path.join(getTemplateDir(), 'template.css');\n const docOptions: Options = {\n title: unit.titles.docTitle,\n style: `\\n${await readFile(cssPath)}\\n`,\n };\n\n if (!targetPdf) {\n const jsPath = path.join(getTemplateDir(), 'template.js2');\n docOptions.script = `\\n${await readFile(jsPath)}\\n`;\n processor.use(htmlWrapper, unit, mdast, ctx);\n } else {\n processor.use(pdfWrapper, unit, ctx);\n }\n\n processor.use(doc, docOptions);\n }\n\n const transformed = await processor.run(hast, file);\n\n const result = processor.stringify(transformed as any, file);\n\n return postTransforms(result, ctx);\n}\n\nfunction postTransforms(html: string, ctx: Context) {\n let result = '';\n result = referenceTransform(html, ctx.refStore);\n return result;\n}\n\nfunction referenceTransform(html: string, refStore: Context['refStore']) {\n return html.replace(/ref:\\/\\/(\\w+)/gms, (...match) => {\n const key = match[1];\n const link = refStore[key];\n const name = startCase(link);\n return `${name}`;\n });\n}\n","import { Node, Parent } from 'unist';\n\nimport { Context } from '../context';\nimport { Unit } from '../course/types';\n// import { UnitTitles } from '../course/types';\nimport { createDefs } from '../utils/icons';\nimport { createMain } from './wrapper/main';\n\nexport function pdfWrapper(unit: Unit, ctx: Context) {\n return async (tree: Node) => {\n const main = await createMain(\n unit.titles,\n ctx,\n (tree as Parent).children\n );\n const iconDefs = createDefs();\n return {\n type: 'root',\n children: [\n {\n type: 'element',\n tagName: 'div',\n properties: {\n id: 'root',\n className: ['hide-sidebar', 'font-default', 'pdf'],\n },\n children: [iconDefs, main],\n },\n ],\n };\n };\n}\n","import { Parent } from 'mdast';\n\nimport { Context } from '../../context';\nimport { Unit } from '../../course/types';\nimport { createDefs, createSvg } from '../../utils/icons';\nimport { createMain } from './main';\nimport { createSidebar } from './sidebar';\n\nexport function htmlWrapper(unit: Unit, mdast: Parent, ctx: Context) {\n return async (tree: Parent) => {\n const hamburgerIcon = createSvg('hamburger-icon');\n const sidebar = await createSidebar(mdast);\n const main = await createMain(unit.titles, ctx, tree.children);\n const iconDefs = createDefs();\n return {\n type: 'root',\n children: [\n {\n type: 'element',\n tagName: 'div',\n properties: {\n id: 'root',\n className: ['hide-sidebar'],\n },\n children: [iconDefs, main, hamburgerIcon, sidebar],\n },\n ],\n };\n };\n}\n","import { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nimport dagLogoSvg from '../../../assets/dag-logo.svg';\nimport coverSvg from '../../../assets/hexagons.svg';\nimport { Context } from '../../context';\nimport { Course, UnitTitles } from '../../course/types';\nimport { getAssetHast } from '../../utils/get-asset-hast';\n\nexport async function createMain(\n titles: UnitTitles,\n ctx: Context,\n content: Node[]\n) {\n const children = [];\n\n if (ctx.options.noHexagons) {\n children.push(createH1(titles));\n } else {\n children.push(createCover(titles, ctx.course));\n }\n\n children.push(...content);\n\n return {\n type: 'element',\n tagName: 'main',\n children: [\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'wrapper',\n },\n children,\n },\n ],\n };\n}\n\nfunction createCover(titles: UnitTitles, course: Course) {\n return {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'cover',\n },\n children: [\n createH1(titles),\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'logos',\n },\n children: [\n createCoverHexagons(course.catalog || ''),\n getAssetHast(dagLogoSvg),\n ],\n },\n ],\n };\n}\n\nfunction createH1(titles: UnitTitles) {\n return {\n type: 'element',\n tagName: 'h1',\n children: [\n {\n type: 'text',\n value: titles.courseTitle,\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'unit',\n },\n children: [\n {\n type: 'text',\n value: titles.unitTitle,\n },\n ],\n },\n ],\n };\n}\n\nfunction createCoverHexagons(catalog: string) {\n const hexagons = getAssetHast(coverSvg);\n\n if (catalog !== '') {\n visit(hexagons, 'element', (node) => {\n if (node.tagName === 'g') {\n const properties = node.properties || {};\n const [className] = (properties.className || []) as string[];\n if (catalog === className) {\n properties.className = ['active'];\n } else {\n properties.className = [];\n }\n node.properties = properties;\n }\n });\n }\n\n return hexagons;\n}\n","import { List, Nodes, Parent } from 'mdast';\nimport { toHast } from 'mdast-util-to-hast';\nimport { toc as getToc } from 'mdast-util-toc';\n\nimport crestSvg from '../../../assets/crest.svg';\nimport uOfGSvg from '../../../assets/uofg.svg';\nimport { getAssetHast } from '../../utils/get-asset-hast';\nimport { createSvg } from '../../utils/icons';\nimport {\n createViewOptions,\n createViewOptionsButton,\n} from './view-options';\n\nexport async function createSidebar(mdast: Parent) {\n const logo = await createLogo();\n const toc = getToc(mdast as Nodes, { maxDepth: 3 }).map;\n const tocChildren = toc === undefined ? [] : [toHast(toc)];\n\n printTableOfContents(toc);\n\n return {\n type: 'element',\n tagName: 'aside',\n children: [\n logo,\n createViewOptionsButton(),\n {\n type: 'element',\n tagName: 'nav',\n properties: {\n id: 'toc',\n },\n children: tocChildren,\n },\n {\n type: 'element',\n tagName: 'div',\n properties: {\n id: 'view-options',\n },\n children: createViewOptions(),\n },\n ],\n };\n}\n\nasync function createLogo() {\n const crest = getAssetHast(crestSvg);\n const uofg = getAssetHast(uOfGSvg);\n const hamburgerIcon = createSvg('hamburger-icon');\n return {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'logo',\n },\n children: [\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'logo-wrapper',\n },\n children: [crest, uofg],\n },\n hamburgerIcon,\n ],\n };\n}\n\nfunction printTableOfContents(toc: List | undefined) {\n // toc?.children.forEach((a) => {\n // a.children.forEach((b) => {\n // if (b.type === 'paragraph') {\n // // @ts-ignore\n // console.log(`- [ ] ${b.children[0].children[0].value}`);\n // }\n // if (b.type === 'list') {\n // b.children.forEach((c) => {\n // c.children.forEach((d) => {\n // if (d.type === 'paragraph') {\n // // @ts-ignore\n // console.log(` - [ ] ${d.children[0].children[0].value}`);\n // }\n // });\n // });\n // }\n // });\n // });\n}\n","import { Item } from './shared';\n\ntype ReadabilityItem = Item & {\n min: number;\n max: number;\n increment: number;\n};\n\nconst options: ReadabilityItem[] = [\n {\n value: 'fontSize',\n label: 'Font-size',\n min: 0.6,\n max: 2,\n increment: 0.1,\n },\n {\n value: 'lineSpacing',\n label: 'Line spacing',\n min: 0.6,\n max: 2,\n increment: 0.1,\n },\n {\n value: 'letterSpacing',\n label: 'Letter spacing',\n min: -0.1,\n max: 0.2,\n increment: 0.05,\n },\n {\n value: 'lineWidth',\n label: 'Line width',\n min: 0.6,\n max: 1.2,\n increment: 0.05,\n },\n];\n\nexport function createReadabilityList() {\n return {\n type: 'element',\n tagName: 'ul',\n properties: {\n id: 'readability',\n },\n children: options.map(createOption),\n };\n}\n\nfunction createOption(item: ReadabilityItem) {\n return {\n type: 'element',\n tagName: 'li',\n properties: {\n className: [item.value],\n 'data-min': item.min,\n 'data-max': item.max,\n 'data-increment': item.increment,\n },\n children: [\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['label'],\n },\n children: [\n {\n type: 'text',\n value: item.label,\n },\n ],\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['actions'],\n },\n children: [\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['btn', 'minus'],\n },\n children: [\n {\n type: 'text',\n value: '−',\n },\n ],\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['btn', 'plus'],\n },\n children: [\n {\n type: 'text',\n value: '+',\n },\n ],\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['btn', 'reset'],\n },\n children: [\n {\n type: 'text',\n value: 'Reset',\n },\n ],\n },\n ],\n },\n ],\n };\n}\n","import { Item } from './shared';\n\nconst themes: Item[] = [\n {\n value: 'light',\n label: 'Light',\n },\n {\n value: 'dark',\n label: 'Dark',\n },\n {\n value: 'yellow-on-black',\n label: 'Yellow on Black',\n },\n {\n value: 'black-on-yellow',\n label: 'Black on Yellow',\n },\n {\n value: 'black-on-red',\n label: 'Black on Red',\n },\n {\n value: 'black-on-blue',\n label: 'Black on Blue',\n },\n];\n\nexport function createThemeList() {\n return {\n type: 'element',\n tagName: 'ul',\n properties: {\n id: 'themes',\n },\n children: themes.map(createThemeButton),\n };\n}\n\nfunction createThemeButton(theme: Item) {\n return {\n type: 'element',\n tagName: 'li',\n properties: {\n className: [theme.value],\n },\n children: [\n {\n type: 'text',\n value: theme.label,\n },\n ],\n };\n}\n","import { Node } from 'unist';\n\n// import { createFontList } from './font';\nimport { createReadabilityList } from './readability';\nimport { createThemeList } from './theme';\n\nexport function createViewOptionsButton() {\n return {\n type: 'element',\n tagName: 'div',\n properties: {\n id: 'view-options-toggle',\n },\n children: [\n {\n type: 'text',\n value: 'View options',\n },\n ],\n };\n}\n\nexport function createViewOptions(): Node[] {\n return [\n createTitle('Theme'),\n createThemeList(),\n // createTitle('Font'),\n // createFontList(),\n createTitle('Readability'),\n createReadabilityList(),\n ];\n}\n\nfunction createTitle(value: string) {\n return {\n type: 'element',\n tagName: 'h3',\n children: [\n {\n type: 'text',\n value,\n },\n ],\n };\n}\n","import path from 'path';\n\nimport chalk from 'chalk';\n\nimport { BuiltUnit, buildUnit } from './build-unit';\nimport { Context, Options, createContext } from './context';\nimport { checkForLatestVersion } from './utils/check-for-latest-version';\nimport { Timer, createTimer } from './utils/timer';\nimport { mkdir, writeFile } from './utils/utils';\n\nexport async function rMarkdown(dirPath: string, options: Options = {}) {\n if (!options.output) {\n await checkForLatestVersion();\n }\n\n const timer = createTimer();\n const ctx = await createContext(dirPath, options);\n\n const result = [];\n\n if (ctx.options.week) {\n // write single week\n const idx = ctx.options.week - 1;\n const input = ctx.course.units[idx];\n\n if (input === undefined) {\n const courseYaml = path.join(ctx.dirPath, 'course.yaml');\n throw new Error(\n `Week ${ctx.options.week} not found in ${courseYaml}`,\n );\n }\n\n const built = await buildUnit(input, ctx);\n await writeUnit(built, ctx, timer);\n result.push(built);\n } else {\n // write full course\n for (const input of ctx.course.units) {\n const built = await buildUnit(input, ctx);\n await writeUnit(built, ctx, timer);\n result.push(built);\n }\n }\n return result;\n}\n\nasync function writeUnit(built: BuiltUnit, ctx: Context, timer: Timer) {\n if (ctx.options.noWrite) {\n return;\n }\n\n await mkdir(ctx.buildDir);\n const fileName = ctx.options.fileName\n ? ctx.options.fileName\n : built.unit.titles.fileName;\n const filePath = path.join(ctx.buildDir, fileName);\n\n if (built.html) {\n await writeFile(filePath + '.html', built.html.html);\n\n if (!ctx.options.output) {\n const status = chalk.green.bold(`Complete in ${timer.seconds()}s`);\n console.log(`✨ ${status} ${filePath}.html`);\n }\n }\n\n if (built.pdf) {\n await writeFile(filePath + '.pdf', built.pdf.pdf);\n\n // debug\n // await writeFile(filePath + '.pdf.html', built.pdf.html);\n\n if (!ctx.options.output) {\n const status = chalk.green.bold(`Complete in ${timer.seconds()}s`);\n console.log(`✨ ${status} ${filePath}.pdf`);\n }\n }\n}\n","import { exec } from 'child_process';\nimport { EOL } from 'os';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nimport chalk from 'chalk';\nimport hashSum from 'hash-sum';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { Unit } from '../course/types';\nimport { failMessage, infoMessage, warnMessage } from '../utils/message';\nimport { mkdir, rmFile, writeFile } from '../utils/utils';\n\n// bypass knitr for debugging\n// export async function knitr(unit: Unit, ctx: Context) {\n// const file = new VFile();\n// file.value = unit.files.reduce((acc, o) => {\n// return acc + EOL + EOL + o.value;\n// }, '');\n// return file;\n// }\n\nexport async function knitr(unit: Unit, ctx: Context) {\n const parentFile = await createParentFile(unit, ctx);\n // console.log(parentFile.value);\n\n const result = await execKnitr(parentFile, ctx, unit.unitPath);\n // console.log(result);\n parentFile.value = result;\n return parentFile;\n}\n\n// creating a temporary file which includes all child files allows\n// R/Python state to be shared across multiple .Rmd files\n// https://yihui.org/knitr/options/#child-documents\nasync function createParentFile(unit: Unit, ctx: Context) {\n const file = new VFile();\n\n let value = '';\n\n // pass path to custom python binary to reticulate\n // https://rstudio.github.io/reticulate/articles/r_markdown.html\n if (ctx.options.pythonBin) {\n const reticulate = `reticulate::use_python(\"${ctx.options.pythonBin}\")`;\n value += `\\`\\`\\`{r, echo=FALSE}${EOL}${reticulate}${EOL}\\`\\`\\`${EOL}${EOL}`;\n }\n\n value += unit.files.reduce((acc, o) => {\n const [filePath] = o.history;\n\n // directory directive is used to ensure external assets\n // can have relative paths to the .Rmd document.\n // used in embed-asset-url mdast transform\n const fileDir = path.parse(filePath).dir;\n const directive = `::directory[${fileDir}]`;\n\n // child document\n // convert all file paths to forward slash (windows anaconda/knitr bug)\n const formattedPath = path\n .relative(ctx.cacheDir, filePath)\n .replace(/\\\\/g, '/');\n\n const childCodeBlock = `\\`\\`\\`{r, child='${formattedPath}'}${EOL}\\`\\`\\``;\n return acc + directive + EOL + EOL + childCodeBlock + EOL + EOL;\n }, '');\n\n // console.log(value);\n\n file.value = value;\n return file;\n}\n\nasync function execKnitr(file: VFile, ctx: Context, unitPath: string) {\n const md = file.value as string;\n const uniqueId = getUniqueId(md);\n const cachedFile = path.join(ctx.cacheDir, `${uniqueId}.Rmd`);\n const cacheDir = path.join(ctx.cacheDir, uniqueId);\n await mkdir(cacheDir);\n await writeFile(cachedFile, md);\n\n return new Promise((resolve, reject) => {\n const cmd = createKnitrCommand(ctx, uniqueId, unitPath);\n\n exec(cmd, async (err, response, stdErr) => {\n if (stdErr) {\n if (!ctx.options.output) {\n console.log(chalk.grey(`[knitr] ${stdErr.trim()}`));\n }\n if (isFailingStdErr(stdErr)) {\n failMessage(file, stdErr);\n }\n }\n\n if (err) {\n console.error('ERROR', err);\n reject(err);\n } else {\n reportErrors(response, file, ctx);\n resolve(formatResponse(response));\n }\n await rmFile(cachedFile);\n });\n });\n}\n\nfunction getUniqueId(md: string) {\n const hash = hashSum(md);\n const ts = new Date().getTime().toString();\n return `knitr-${hash}-${ts}`;\n}\n\nfunction createKnitrCommand(\n ctx: Context,\n uniqueId: string,\n unitPath: string,\n) {\n const rFileDir = getKnitrFileDir();\n const rFile = path.join(rFileDir, 'knitr.R');\n const baseDir = path.parse(unitPath).dir;\n const cachedFile = path.join(ctx.cacheDir, `${uniqueId}.Rmd`);\n const cacheDir = path.join(ctx.cacheDir, uniqueId);\n\n // spawn args\n // return [rFile, cachedFile, baseDir, cacheDir];\n\n return `Rscript \"${rFile}\" \"${cachedFile}\" \"${baseDir}\" \"${cacheDir}\"`;\n}\n\nfunction getKnitrFileDir() {\n // temporary hack until this PR is merged\n // https://github.com/webpack/webpack/pull/15246\n if (process.env.NODE_ENV === 'production') {\n return __dirname;\n }\n return path.dirname(fileURLToPath(import.meta.url));\n}\n\nfunction isFailingStdErr(stdErr: string) {\n // console.log({ stdErr });\n return /status 1\\d*$/.test(stdErr.trim());\n}\n\nfunction reportErrors(response: string, file: VFile, ctx: Context) {\n const lines = response\n .split(EOL)\n .filter((s) => !s.startsWith(':directory'));\n\n const trimmed = lines.join(EOL).trim();\n\n // Warning at the start of a document\n if (trimmed.startsWith('WARNING -')) {\n const match = trimmed.match(/^WARNING - (.+?)[\\r\\n]{2,}/ms);\n\n // Check the original file doesn't start with WARNING\n const original = String(ctx.course.units[0].files[0].value)\n .split(EOL)\n .filter((s) => !s.startsWith(':directory'))\n .join(EOL)\n .trim();\n\n if (match !== null && !original.startsWith('WARNING -')) {\n warnMessage(file, match[1], {\n start: {\n line: 1,\n column: 0,\n },\n end: {\n line: 1,\n column: lines[0].length,\n },\n });\n }\n\n // Python binary path\n } else if (trimmed.startsWith('$python [1]')) {\n const match = trimmed.match(/^\\$python\\s\\[1\\]\\s(\"\\S+\")/);\n if (match !== null) {\n infoMessage(file, match[1], {\n start: {\n line: 1,\n column: 0,\n },\n end: {\n line: 1,\n column: lines[0].length,\n },\n });\n }\n }\n\n // Errors throughout document\n lines.forEach((line, idx) => {\n const trimmedLine = line.trim();\n if (trimmedLine.startsWith('## Error')) {\n warnMessage(file, trimmedLine.replace('## ', ''), {\n start: {\n line: idx + 1,\n column: 0,\n },\n end: {\n line: idx + 1,\n column: line.length,\n },\n });\n }\n });\n}\n\nasync function formatResponse(response: string) {\n let md = response;\n md = removeCustomPythonBinNotice(md);\n md = removePythonWarningMessage(md);\n md = addErrorCodeBlock(md);\n md = removeHashSigns(md);\n md = removeEmptyLog(md);\n md = addNewLineAfterKable(md);\n return md;\n}\n\nfunction removeCustomPythonBinNotice(md: string) {\n return md.replace(/^\\$python\\s\\[1\\]\\s\"\\S+\"/, '');\n}\n\nfunction removePythonWarningMessage(md: string) {\n return md.replace(/^WARNING - .+?[\\r\\n]+/m, '');\n}\n\nfunction removeHashSigns(md: string) {\n let insideCodeResponse = false;\n let openingLine = '';\n return md\n .split('\\n')\n .reduce((acc: string[], line) => {\n if (line.startsWith('```')) {\n insideCodeResponse = !insideCodeResponse;\n openingLine = insideCodeResponse ? line : '';\n }\n if (insideCodeResponse && openingLine.endsWith('-output}')) {\n acc.push(line.replace(/^##\\s+/, ''));\n } else {\n acc.push(line);\n }\n return acc;\n }, [])\n .join('\\n');\n}\n\nfunction removeEmptyLog(md: string) {\n return md.replace(/\\[1\\]\\s\"\"$/gm, '').trim();\n}\n\nfunction addErrorCodeBlock(md: string) {\n return md\n .split('\\n')\n .reduce((acc: string[], line, idx) => {\n if (idx > 0 && acc[idx - 1].startsWith('```')) {\n if (line.startsWith('## Error') || line.startsWith('## fatal')) {\n acc[acc.length - 1] = `\\`\\`\\`{.error-output}`;\n }\n }\n acc.push(line);\n return acc;\n }, [])\n .join('\\n');\n}\n\nfunction addNewLineAfterKable(md: string) {\n return md\n .split('\\n')\n .reduce((acc: string[], line, idx) => {\n if (acc[idx - 1]?.startsWith('|') && !line.startsWith('|')) {\n acc.push('', line);\n } else {\n acc.push(line);\n }\n return acc;\n }, [])\n .join('\\n');\n}\n\n// experimental streaming output\n// async function spawnKnitr(file: VFile, ctx: Context, unitPath: string) {\n// const md = file.value as string;\n// const uniqueId = getUniqueId(md);\n// const cachedFile = path.join(ctx.cacheDir, `${uniqueId}.Rmd`);\n// const cacheDir = path.join(ctx.cacheDir, uniqueId);\n// await mkdir(cacheDir);\n// await writeFile(cachedFile, md);\n\n// return new Promise((resolve, reject) => {\n// const args = createKnitrCommand(ctx, uniqueId, unitPath);\n// const knitr = spawn('Rscript', args);\n// const result: string[] = [];\n\n// knitr.stdout.on('data', (data) => {\n// const str = data.toString();\n// console.log(str);\n// result.push(str);\n// });\n\n// knitr.stdout.on('end', () => {\n// console.log('STDOUT END');\n// const end = result.join('');\n// console.log('END', end);\n// reportErrors(end, file);\n// resolve(formatResponse(end));\n// });\n\n// knitr.stdout.on('error', (err) => {\n// console.log('STDOUT ERROR', err, err.toString());\n// reject();\n// });\n\n// knitr.stderr.on('data', (data) => {\n// const str = data.toString();\n// console.log('STDERR ERROR', str);\n// });\n// }).then(async (result) => {\n// await rmFile(cachedFile);\n// return result;\n// });\n// }\n","import { Element, Literal } from 'hast';\nimport { Parent, Root } from 'mdast';\nimport { TextDirective } from 'mdast-util-directive';\nimport { visit } from 'unist-util-visit';\n\nimport { Context } from '../context';\nimport { rehypeParser } from '../utils/utils';\nimport { mmlToSpeech, mmlToSvg } from './mathjax-tex';\n\nexport function aliasDirectiveToLatexSvg(ctx: Context) {\n return (tree: Root) => {\n visit(tree, 'textDirective', (node: TextDirective) => {\n if (!ctx.mmlStore || ctx.options.noTexSvg) {\n return;\n }\n switch (node.name) {\n case 'inlineMath':\n case 'blockMath': {\n const idx = getTexIdx(node as TextDirective);\n const mml = ctx.mmlStore[idx];\n const svg = renderSvg(mml);\n const properties = {\n ...svg.properties,\n className:\n node.name === 'inlineMath' ? 'inline-math' : 'block-math',\n id: getRefId(mml),\n };\n node.data = {\n hName: svg.tagName,\n hProperties: properties,\n hChildren: svg.children,\n };\n }\n }\n });\n };\n}\n\nfunction getTexIdx(node: Parent) {\n const firstChild = node.children[0] as Literal;\n return Number(firstChild.value || 0);\n}\n\nfunction getRefId(mml: string) {\n const match = mml.match(/;\n\n const newProperties: Record = {\n width: properties.width,\n height: properties.height,\n viewBox: properties.viewBox,\n role: 'img',\n };\n\n if (label !== '') {\n const uniqueId = `math-${Math.random().toString(16).slice(2)}`;\n newProperties['aria-labelledby'] = uniqueId;\n svg.children.unshift({\n type: 'element',\n tagName: 'title',\n properties: {\n id: uniqueId,\n },\n children: [\n {\n type: 'text',\n value: label,\n },\n ],\n });\n }\n\n svg.properties = newProperties;\n return svg;\n}\n","import { liteAdaptor } from 'mathjax-full/js/adaptors/liteAdaptor.js';\nimport { STATE } from 'mathjax-full/js/core/MathItem.js';\nimport { SerializedMmlVisitor } from 'mathjax-full/js/core/MmlTree/SerializedMmlVisitor.js';\nimport { RegisterHTMLHandler } from 'mathjax-full/js/handlers/html.js';\nimport { HTMLDocument } from 'mathjax-full/js/handlers/html/HTMLDocument.js';\nimport { MathML } from 'mathjax-full/js/input/mathml.js';\nimport { TeX } from 'mathjax-full/js/input/tex.js';\nimport { AllPackages } from 'mathjax-full/js/input/tex/AllPackages.js';\nimport { mathjax } from 'mathjax-full/js/mathjax.js';\nimport { SVG } from 'mathjax-full/js/output/svg.js';\n// @ts-expect-error\nimport SRE from 'speech-rule-engine';\n\nexport function texToMml(tex: string = '') {\n const adaptor = liteAdaptor();\n // Busproofs requires an output jax, which we aren't using\n const packages = AllPackages.filter((name) => name !== 'bussproofs');\n const input = new TeX({ packages });\n const doc = new HTMLDocument('', adaptor, { InputJax: input });\n const node = doc.convert(tex, { end: STATE.CONVERT });\n const visitor = new SerializedMmlVisitor();\n return visitor.visitTree(node);\n}\n\nexport function mmlToSvg(mml: string) {\n const adaptor = liteAdaptor();\n RegisterHTMLHandler(adaptor);\n const input = new MathML();\n const output = new SVG({ fontCache: 'local' });\n const doc = mathjax.document('', { InputJax: input, OutputJax: output });\n const node = doc.convert(mml, { em: 25 });\n return adaptor.outerHTML(node);\n}\n\nexport function mmlToSpeech(mml: string) {\n return SRE.toSpeech(mml);\n}\n","import { liteAdaptor } from 'mathjax-full/js/adaptors/liteAdaptor.js';\nimport { MathDocument } from 'mathjax-full/js/core/MathDocument.js';\nimport * as MathItem from 'mathjax-full/js/core/MathItem.js';\nimport { SerializedMmlVisitor } from 'mathjax-full/js/core/MmlTree/SerializedMmlVisitor.js';\nimport { RegisterHTMLHandler } from 'mathjax-full/js/handlers/html.js';\nimport { TeX } from 'mathjax-full/js/input/tex.js';\nimport { AllPackages } from 'mathjax-full/js/input/tex/AllPackages.js';\nimport { mathjax } from 'mathjax-full/js/mathjax.js';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { assertNoTexTabular } from '../linter/assert-no-tex-tabular';\nimport { failMessage } from '../utils/message';\n\n// This custom MathJax implementation has had to diverge from the provided demos found\n// here: https://github.com/mathjax/MathJax-demos-node, because they are all focused on\n// either converting LaTeX on its own or (referencing \"page\" demos) LaTeX embedded in\n// HTML, whereas at this stage in the processor we're dealing with LaTeX embedded in\n// Markdown. Due to TeX/LaTeX making heavy use of the backslash (\\) character, we need\n// to deal with it early as it conflicts with other libraries used later.\n\n// I use the MathJax \"page\" process as it will pick up LaTeX even without delimiters\n// and stores context required for numbered references (based on direct/tex2mml-page).\n// However this has a naive HTML handler which will munge HTML (and Python) in some\n// cases so I am careful to only mutate TeX and leave the rest of the Markdown alone.\n\n// I replace the TeX with a placeholder formatted as a Markdown directive, for example\n// :inlineMath[21] or :blockMath[42].\n\n// I convert the TeX to MathML and store it memory for use later (in directive-to-svg.ts).\n\nexport function texToAliasDirective(file: VFile, ctx: Context) {\n // simple regex tests\n assertNoTexTabular(file);\n\n const md = file.value as string;\n const store: string[] = [];\n const adaptor = liteAdaptor();\n const visitor = new SerializedMmlVisitor();\n RegisterHTMLHandler(adaptor);\n\n const doc = mathjax.document(md, {\n InputJax: new TeX({\n // Bussproofs requires an output jax\n packages: AllPackages.filter((name) => name !== 'bussproofs'),\n // Allow numbered references\n tags: 'ams',\n // Allow single $ delimiters\n inlineMath: [\n ['$', '$'],\n ['\\\\(', '\\\\)'],\n ],\n displayMath: [\n ['$$', '$$'],\n [`\\\\[`, `\\\\]`],\n ],\n }),\n // wrap verbatim latex with
\n ignoreHtmlClass: 'mathjax-ignore',\n renderActions: {\n typeset: [\n MathItem.STATE.TYPESET,\n ({ math }: MathDocument) => {\n for (const item of Array.from(math)) {\n let newMarkdown = '';\n\n // convert to MathML\n const mml = visitor.visitTree(item.root);\n assertNoMmlError(mml, file);\n\n // escaped dollar sign...\n if (item.math === '$') {\n newMarkdown = '$';\n }\n\n // double backslash...\n else if (item.math === '\\\\') {\n newMarkdown = '\\\\\\\\';\n }\n\n // reference link...\n else if (isReferenceLink(item.math)) {\n const refNum = extractRefNumFromMml(mml, item.math, file);\n const anchor = extractAnchorLinkFromMml(\n mml,\n item.math,\n file,\n );\n newMarkdown = `[${refNum}](${anchor})`;\n }\n\n // normal use case (math notation)...\n else {\n store.push(mml);\n const type = item.display ? 'blockMath' : 'inlineMath';\n newMarkdown = `:${type}[${store.length - 1}]`;\n }\n\n const tree = adaptor.parse(newMarkdown, 'text/html');\n item.typesetRoot = adaptor.firstChild(adaptor.body(tree));\n }\n },\n ],\n },\n });\n\n // add store to ctx\n ctx.mmlStore = store;\n\n doc.render();\n\n // replace md in VFile\n const result = adaptor.innerHTML(adaptor.body(doc.document));\n file.value = postParse(result);\n\n return file;\n}\n\nfunction assertNoMmlError(mml: string, file: VFile) {\n const match = mml.match(/(.+)<\\/mtext>/);\n if (match === null) {\n failMessage(file, `Invalid reference: ${tex}`);\n return;\n }\n if (match[1] === '???') {\n failMessage(\n file,\n `Invalid reference: ${tex}. You may only reference numbered sections.`,\n );\n }\n return match[1] as string;\n}\n\nfunction extractAnchorLinkFromMml(mml: string, tex: string, file: VFile) {\n const match = mml.match(//);\n if (match === null) {\n failMessage(file, `Reference has no anchor link: ${tex}`);\n return;\n }\n return decodeURIComponent(match[1] || '') as string;\n}\n\nfunction postParse(html: string) {\n let result = html.trim();\n result = unprotectHtml(result);\n result = removeUnresolvedLabels(result);\n result = removeHTMLClosingTags(result);\n return result;\n}\n\n// https://github.com/mathjax/MathJax-src/blob/41565a97529c8de57cb170e6a67baf311e61de13/ts/adaptors/lite/Parser.ts#L399-L403\nfunction unprotectHtml(html: string) {\n return html\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n\nfunction removeUnresolvedLabels(html: string) {\n return html.replace(/\\\\label{def:.*?}/gm, '');\n}\n\nfunction removeHTMLClosingTags(html: string) {\n return html.replace(/(<\\/\\S+>)+$/, '');\n}\n","import { Image } from 'mdast';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\nimport { checkLocalFileExists } from '../utils/utils';\n\nexport function assertAssetExists() {\n async function getAssetUrl(node: Image, file: VFile) {\n const url = (node.url || '') as string;\n if (!file.dirname) {\n throw new Error('VFile dirname undefined');\n }\n if (!url.startsWith('http')) {\n const exists = await checkLocalFileExists(url);\n if (!exists) {\n failMessage(file, `No asset found at ${url}`, node.position);\n }\n }\n }\n\n return async (tree: Node, file: VFile) => {\n const transformations: Promise[] = [];\n visit(tree, 'image', (node) => {\n transformations.push(getAssetUrl(node, file));\n });\n await Promise.all(transformations);\n };\n}\n","import { Root } from 'mdast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function assertColumnStructure() {\n return (tree: Root, file: VFile) => {\n visit(\n tree,\n 'containerDirective',\n (node: ContainerDirective, index, _parent) => {\n if (node.name === 'columns') {\n const children = node.children as ContainerDirective[];\n const columns = children.filter((o) => o.name === 'column');\n if (columns.length < 2) {\n failMessage(\n file,\n 'Columns must contain at least 2 columns',\n node.position,\n );\n }\n }\n if (node.name === 'column') {\n const parent = _parent as ContainerDirective;\n if (!parent || parent.name !== 'columns') {\n failMessage(\n file,\n 'Column must be nested inside columns',\n node.position,\n );\n }\n }\n },\n );\n };\n}\n","import { Root } from 'mdast';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function assertNoH1() {\n return (tree: Root, file: VFile) => {\n visit(tree, 'heading', (node) => {\n if (node.depth === 1) {\n failMessage(\n file,\n 'Level 1 heading found. Only one Level 1 heading can be used in the document and it is automatically generated from .yaml file and should not be found in .Rmd file. Please use Level 2 (## Example) and below.',\n node.position,\n );\n return;\n }\n });\n };\n}\n","import { VFile } from 'vfile';\n\nimport { warnMessage } from '../utils/message';\n\nexport function assertNoImageAttributes(file: VFile) {\n const md = file.value as string;\n md.split('\\n').forEach((line, idx) => {\n const match = line.match(/!\\[.*\\]\\(.*\\)({.+})/);\n if (match !== null) {\n warnMessage(\n file,\n `image attributes are not supported: ${match[1]}`,\n {\n start: {\n line: idx + 1,\n column: 0,\n },\n end: {\n line: idx + 1,\n column: line.length,\n },\n }\n );\n }\n });\n}\n","import { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\n// TODO: could possibly try converting to array here\n// https://stackoverflow.com/questions/51803244\n\nexport function assertNoTexTabular(file: VFile) {\n const md = file.value as string;\n md.split('\\n').forEach((line, idx) => {\n if (line.includes('\\\\begin{tabular}')) {\n failMessage(\n file,\n 'LaTeX tables are not allowed, please use Markdown syntax',\n {\n start: {\n line: idx + 1,\n column: 0,\n },\n end: {\n line: idx + 1,\n column: line.length,\n },\n }\n );\n }\n });\n}\n","import { Root } from 'mdast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function assertProgramSwitcherStructure() {\n return (tree: Root, file: VFile) => {\n let count = 0;\n visit(tree, 'containerDirective', (node, index, _parent) => {\n if (node.name === 'task') {\n count++;\n const children = node.children as ContainerDirective[];\n const answers = children.filter((o) => o.name === 'answer');\n if (answers.length < 1) {\n failMessage(file, `Task ${count} has no answer`, node.position);\n }\n if (answers.length > 1) {\n failMessage(file, 'Task has multiple answers', node.position);\n }\n }\n if (node.name === 'answer') {\n const parent = _parent as ContainerDirective;\n if (!parent || parent.name !== 'task') {\n failMessage(\n file,\n 'Answer must be nested inside task',\n node.position,\n );\n }\n }\n });\n };\n}\n","import { Root } from 'mdast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function assertTaskAnswerStructure() {\n return (tree: Root, file: VFile) => {\n let count = 0;\n visit(tree, 'containerDirective', (node, index, _parent) => {\n if (node.name === 'task') {\n count++;\n const children = node.children as ContainerDirective[];\n const answers = children.filter((o) => o.name === 'answer');\n if (answers.length < 1) {\n failMessage(file, `Task ${count} has no answer`, node.position);\n }\n if (answers.length > 1) {\n failMessage(file, 'Task has multiple answers', node.position);\n }\n }\n if (node.name === 'answer') {\n const parent = _parent as ContainerDirective;\n if (!parent || parent.name !== 'task') {\n failMessage(\n file,\n 'Answer must be nested inside task',\n node.position,\n );\n }\n }\n });\n };\n}\n","import { Literal, Parent } from 'mdast';\nimport { Root } from 'mdast';\nimport { LeafDirective } from 'mdast-util-directive';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function assertVideoAttributes() {\n return async (tree: Root, file: VFile) => {\n visit(tree, 'leafDirective', (node: LeafDirective) => {\n if (node.name === 'video') {\n if (!node.attributes?.id) {\n failMessage(file, 'id attribute is required', node.position);\n }\n if (!node.attributes?.duration) {\n failMessage(\n file,\n 'duration attribute is required',\n node.position,\n );\n }\n\n const title = getTitle(node);\n if (!title) {\n failMessage(file, 'title is required', node.position);\n }\n }\n });\n };\n}\n\nfunction getTitle(node: Parent) {\n const children = node.children as Node[];\n const firstChild = children[0] as Literal;\n return (firstChild?.value || '') as string;\n}\n","import { Root } from 'mdast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function assertWeblinkTarget() {\n return (tree: Root, file: VFile) => {\n visit(tree, 'containerDirective', (node: ContainerDirective) => {\n if (node.name === 'weblink') {\n if (node.attributes?.target === undefined) {\n failMessage(\n file,\n 'Weblink has no target attribute',\n node.position,\n );\n }\n }\n });\n };\n}\n","import lintAltText from '@double-great/remark-lint-alt-text';\n// @ts-expect-error\nimport lintLinkText from '@mapbox/remark-lint-link-text';\n// import dictionary from 'dictionary-en-gb';\n// import remark2retext from 'remark-retext';\n// import english from 'retext-english';\n// import spell from 'retext-spell';\nimport { unified } from 'unified';\nimport { Node } from 'unist';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { assertAssetExists } from './assert-asset-exists';\nimport { assertColumnStructure } from './assert-columns';\nimport { assertNoH1 } from './assert-no-h1';\nimport { assertProgramSwitcherStructure } from './assert-program-switcher';\nimport { assertTaskAnswerStructure } from './assert-task-answer';\nimport { assertVideoAttributes } from './assert-video-attributes';\nimport { assertWeblinkTarget } from './assert-weblink-target';\nimport { lintLatex } from './lint-latex';\nimport { printReport, reportHasFatalErrors } from './report';\nimport { Root } from 'mdast';\n\nexport function reportErrors(files: VFile[], ctx: Context) {\n if (!ctx.options.noReport) {\n printReport(files, ctx);\n }\n if (reportHasFatalErrors(files)) {\n if (ctx.options.noReport) {\n printReport(files, {\n ...ctx,\n options: {\n ...ctx.options,\n reportOnlyErrors: true,\n },\n });\n }\n console.log('Report has fatal errors');\n if (ctx.options.force) {\n console.log('Compiling using force option...');\n } else {\n process.exit(1);\n }\n }\n}\n\nexport async function createReport(\n file: VFile,\n mdast: Node,\n ctx: Context,\n) {\n const processor = unified()\n .use(assertAssetExists)\n .use(assertVideoAttributes)\n .use(assertTaskAnswerStructure)\n .use(assertProgramSwitcherStructure)\n .use(assertColumnStructure)\n .use(assertWeblinkTarget)\n .use(assertNoH1)\n .use(lintLatex)\n // @ts-expect-error\n .use(lintAltText)\n .use(lintLinkText);\n\n // if (ctx.options.spelling) {\n // const retextProcessor = unified()\n // .use(english)\n // .use(spell, { dictionary, max: 1 });\n // processor.use(remark2retext, retextProcessor);\n // }\n\n processor.run(mdast as Root, file);\n}\n","import { exec } from 'child_process';\n\nimport { Literal, Root } from 'mdast';\nimport { Position } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nexport function lintLatex() {\n return async (tree: Root, file: VFile) => {\n const transformations: Promise[] = [];\n\n visit(tree, 'math', (node: Literal) => {\n transformations.push(chktex(node, file));\n });\n\n await Promise.all(transformations);\n return tree;\n };\n}\n\nasync function chktex(node: Literal, file: VFile) {\n return new Promise((resolve, reject) => {\n exec(`chktex -q <<< \"${node.value}\"`, (err, response) => {\n if (err) {\n reject(err);\n } else {\n const messages = formatResponse(response);\n const position = node.position as Position;\n messages.forEach(({ line, column, message }) => {\n file.message(message, {\n line: position.start.line + line,\n column: position.start.column + column,\n });\n });\n resolve();\n }\n });\n });\n}\n\ntype Message = {\n line: number;\n column: number;\n message: string;\n};\n\nfunction formatResponse(response: string) {\n if (response.trim() === '') {\n return [];\n }\n\n function formatMessage(message: string) {\n return message.replace(/'/g, '').replace(/`/g, '');\n }\n\n return response\n .split(/Warning \\d+ in stdin line /)\n .filter(Boolean)\n .reduce((acc: Message[], s) => {\n const [key, value] = s.split(':');\n const line = Number(key);\n const trimmed = value.trim();\n\n const match = trimmed.match(/(.*)\\n(.*)\\n(\\s*)\\^/m);\n if (Array.isArray(match)) {\n const message = formatMessage(match[1]);\n acc.push({\n line,\n column: match[3].length,\n message: `${message}\\n\\n${match[2]}\\n${match[3]}^`,\n });\n } else {\n acc.push({\n line,\n column: 0,\n message: formatMessage(trimmed),\n });\n }\n\n return acc;\n }, []);\n}\n","import chalk from 'chalk';\nimport figures from 'figures';\nimport { VFile } from 'vfile';\nimport { VFileMessage } from 'vfile-message';\n\nimport { Context } from '../context';\nimport { MessageStatus } from '../utils/message';\n\nexport type Report = {\n failed: boolean;\n files: ReportFile[];\n};\n\nexport type ReportFile = Omit & {\n messages: ReportMessage[];\n};\n\nexport type ReportMessage = {\n status: MessageStatus;\n position: string;\n reason: string;\n line: number;\n column: number;\n};\n\nexport function printReport(files: VFile[], ctx: Context) {\n const { reportOnlyErrors, shouldFail } = ctx.options;\n\n if (reportOnlyErrors && shouldFail) {\n return;\n }\n\n for (const file of files) {\n // console.log(file.messages);\n const messages = reportOnlyErrors\n ? failingMessages(file.messages as any)\n : file.messages;\n\n if (messages.length !== 0) {\n // if (file.path !== undefined) {\n // console.log(`\\n${getFilePath(file.path)}`);\n // }\n messages.forEach((message) => {\n printMessage(message as any);\n });\n }\n }\n}\n\nexport function reportHasFatalErrors(files: VFile[]) {\n return files.some((file) => {\n const messages = file.messages as unknown as ReportMessage[];\n return messages.some(\n (message) => message.status === MessageStatus.fail,\n );\n });\n}\n\nexport function reportHasWarnings(files: VFile[]) {\n return files.some((file) => {\n const messages = file.messages as unknown as ReportMessage[];\n return messages.some(\n (message) => message.status === MessageStatus.warning,\n );\n });\n}\n\nfunction failingMessages(_messages: VFileMessage[]) {\n const messages = _messages as unknown as ReportMessage[];\n return messages.filter(\n (o) => o.status === MessageStatus.fail,\n ) as unknown as VFileMessage[];\n}\n\nfunction printMessage(_message: VFileMessage) {\n const message = _message as unknown as ReportMessage;\n // console.log(message);\n const status = message.status;\n const position = chalk.grey(`${message.line}:${message.column}`);\n const reason = formatReason(message.reason, status);\n console.log(`${formatStatus(status)} ${position} ${reason}`);\n}\n\n// function getFilePath(filePath: string) {\n// return path.isAbsolute(filePath)\n// ? filePath\n// : path.join(process.cwd(), filePath);\n// }\n\nfunction formatStatus(status: MessageStatus) {\n const statusColour = getStatusColour(status);\n switch (status) {\n case MessageStatus.fail:\n return statusColour(figures.cross);\n default:\n return statusColour(figures.warning);\n // TODO: fail on unsupported status?\n }\n}\n\nfunction formatReason(reason: string, status: MessageStatus) {\n const statusColour = getStatusColour(status);\n const [first, ...rest] = reason.split('\\n');\n const formattedFirst = statusColour(first);\n const formattedRest = rest.map((line) => chalk.grey(line));\n return [formattedFirst, ...formattedRest].join('\\n');\n}\n\nfunction getStatusColour(status: MessageStatus) {\n switch (status) {\n case MessageStatus.fail:\n return chalk.red;\n default:\n return chalk.yellow;\n }\n}\n","import {\n Element,\n ElementContent,\n Parent as HastParent,\n Text,\n Node,\n} from 'hast';\nimport startCase from 'lodash/startCase.js';\nimport { Root } from 'mdast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { toHast } from 'mdast-util-to-hast';\nimport { Parent } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nimport { Context } from '../context';\nimport { createCounter } from '../utils/counter';\n\nexport function boxouts(refStore: Context['refStore']) {\n const counter = createCounter();\n return async (tree: Node) => {\n visit(tree, 'containerDirective', (node: ContainerDirective) => {\n switch (node.name) {\n case 'example':\n case 'error':\n case 'supplement':\n case 'background':\n case 'definition':\n case 'weblink':\n case 'theorem':\n case 'task':\n case 'proposition':\n case 'answer': {\n const name = node.name as string;\n const count = counter.increment(name);\n node.data = {\n hProperties: createAttributes(node, count, refStore),\n hChildren: createBoxout(node, count) as any,\n };\n }\n }\n });\n };\n}\n\nfunction createAttributes(\n node: ContainerDirective,\n count: number,\n refStore: Context['refStore'],\n) {\n const name = node.name as string;\n const id = `${name}-${count}`;\n\n const attributes = node.attributes as Record;\n const className = ['boxout', name];\n if (attributes.icon) {\n className.push(`${attributes.icon}-icon`);\n }\n\n if (\n node.attributes?.label !== undefined &&\n node.attributes?.label !== null\n ) {\n refStore[node.attributes.label] = id;\n }\n\n return { className, id };\n}\n\nexport function createBoxout(\n node: ContainerDirective,\n count: number,\n): Node[] {\n const typeTitle = createBoxoutType(node, count);\n const titles = [typeTitle];\n\n const titleValue = getTitleValue(node);\n if (titleValue.length > 0) {\n const title = createTitle(node);\n titles.push(title);\n }\n\n const children = node.children as ContainerDirective[];\n\n const content = children\n // @ts-expect-error\n .filter((o) => !o.data?.directiveLabel)\n .filter((o) => o.type !== 'containerDirective' && o.name !== 'answer')\n .map((o) => toHast(o, { allowDangerousHtml: true }))\n .filter(Boolean) as HastParent[];\n\n if (node.name === 'task') {\n const answer = children.find(\n (o) => o.type === 'containerDirective' && o.name === 'answer',\n );\n if (answer) {\n const answerHast = createAnswer(answer, count);\n content.push(answerHast as HastParent);\n }\n }\n\n return [...titles, ...content];\n}\n\nfunction createAnswer(node: ContainerDirective, count: number) {\n const { children } = toHast(node) as HastParent;\n return {\n type: 'element',\n tagName: 'div',\n properties: {\n className: ['answer'],\n },\n children: [\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['answer-trigger'],\n 'data-answer-id': count,\n },\n children: [\n {\n type: 'text',\n value: 'Show answer',\n },\n ],\n },\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: ['answer-reveal'],\n id: `answer-${count}`,\n },\n children,\n },\n ],\n };\n}\n\nfunction createBoxoutType(\n node: ContainerDirective,\n count: number,\n): Element {\n const name = node.name as string;\n const label = startCase(name);\n let value = `${label} ${count}`;\n\n if (node.attributes?.optional !== undefined) {\n value += ` (Optional)`;\n }\n\n return {\n type: 'element',\n tagName: 'span',\n properties: {\n className: ['type'],\n },\n children: [\n {\n type: 'text',\n value,\n },\n ],\n };\n}\n\nfunction createTitle(node: ContainerDirective): Element {\n return {\n type: 'element',\n tagName: 'h3',\n children: createTitleValue(node) as ElementContent[],\n properties: {},\n };\n}\n\nfunction createTitleValue(node: ContainerDirective) {\n const name = node.name as string;\n const newRoot = {\n type: 'root',\n children: getTitleValue(node),\n };\n const { children = [] } = toHast(newRoot as Root) as Parent;\n if (name !== 'weblink') {\n return children;\n }\n const { target } = node.attributes as Record;\n return [\n {\n type: 'element',\n tagName: 'a',\n properties: {\n href: target,\n target: '_blank',\n className: ['target'],\n },\n children,\n },\n ];\n}\n\nfunction getTitleValue(node: ContainerDirective): Node[] {\n const children = (node.children || []) as Node[];\n const parent = (children[0] || {}) as Parent;\n\n // @ts-expect-error\n if (!parent.data?.directiveLabel) {\n if (node.name === 'weblink') {\n const attributes = node.attributes as Record;\n return [\n {\n type: 'text',\n value: attributes.target,\n } as Text,\n ];\n }\n return [];\n }\n\n return parent.children || [];\n}\n","import { Element } from 'hast';\nimport { Literal } from 'mdast';\nimport { LeafDirective } from 'mdast-util-directive';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function browserWindow() {\n return (tree: Node, file: VFile) => {\n visit(tree, 'leafDirective', (node: LeafDirective) => {\n if (node.name === 'browser') {\n template(node, file);\n }\n });\n };\n}\n\nfunction template(node: LeafDirective, file: VFile) {\n const url = node.attributes?.url || '';\n const alt = node.attributes?.alt || '';\n const imagePath = getImagePath(node, file);\n\n const browser = createBrowserWindow(imagePath, url, alt);\n const caption = createCaption(alt);\n\n Object.assign(node, {\n type: 'browser-window',\n data: {\n hName: 'figure',\n hProperties: {\n className: ['browser'],\n },\n hChildren: [browser, caption],\n },\n });\n}\n\nfunction createBrowserWindow(\n imagePath: string,\n url: string,\n alt: string,\n): Element {\n return {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'browser-window',\n },\n children: [\n {\n type: 'text',\n value: '\\n',\n },\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'browser-window-wrapper',\n },\n children: [\n createBrowserHeader(url),\n {\n type: 'text',\n value: '\\n',\n },\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'browser-window-content',\n },\n children: [\n {\n type: 'element',\n tagName: 'img',\n properties: {\n src: imagePath,\n alt,\n },\n children: [],\n },\n ],\n },\n {\n type: 'text',\n value: '\\n',\n },\n ],\n },\n ],\n };\n}\n\nfunction createBrowserHeader(url: string): Element {\n return {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'browser-window-header',\n },\n children: [\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'browser-window-address-bar',\n },\n children: [\n {\n type: 'text',\n value: url?.trim() || '',\n },\n ],\n },\n ],\n };\n}\n\nfunction createCaption(alt: string): Element | null {\n if (alt.trim() === '') {\n return null;\n }\n return {\n type: 'element',\n tagName: 'figcaption',\n properties: {},\n children: [\n {\n type: 'element',\n tagName: 'a',\n properties: {},\n children: [\n {\n type: 'text',\n value: ` ${alt}`,\n },\n ],\n },\n ],\n };\n}\n\nfunction getImagePath(node: LeafDirective, file: VFile) {\n const children = node.children as Node[];\n const firstChild = children[0] as Literal;\n const title = firstChild?.value || '';\n if (title.trim() === '') {\n failMessage(file, 'Video has no title', node.position);\n }\n return title;\n}\n","import { Properties, Text } from 'hast';\nimport { Code } from 'mdast';\nimport { RefractorElement, refractor } from 'refractor/lib/all.js';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\n\nexport function codeBlocks(ctx: Context) {\n return async (tree: Node, file: VFile) => {\n visit(tree, 'code', (node: Code) => {\n customCode(node, ctx, file);\n });\n };\n}\n\nfunction customCode(node: Code, ctx: Context, file: VFile) {\n const language = parseLanguage(node);\n const klass = parseClass(node);\n\n const codeProps: Properties = {};\n const children: (RefractorElement | Text)[] = [];\n const trimmed = node.value.trim();\n\n if (ctx.options.noSyntaxHighlight || language === '') {\n children.push({\n type: 'text',\n value: trimmed,\n });\n } else {\n const highlighted = refractor.highlight(trimmed, language);\n children.push(...highlighted.children);\n }\n\n Object.assign(node, {\n type: 'custom-code',\n data: {\n hName: 'div',\n hProperties: {\n className: ['code-wrapper', klass],\n },\n hChildren: [\n addConsoleHeading(klass),\n {\n type: 'element',\n tagName: 'pre',\n children: [\n {\n type: 'element',\n tagName: 'code',\n properties: codeProps,\n children,\n },\n ],\n },\n ],\n },\n });\n}\n\nfunction addConsoleHeading(klass: string) {\n if (klass === 'r-output' || klass === 'r-error-output') {\n return {\n type: 'element',\n tagName: 'h6',\n properties: {\n className: 'console-heading',\n },\n children: [\n {\n type: 'text',\n value: 'R Console',\n },\n ],\n };\n }\n if (klass === 'python-output' || klass === 'python-error-output') {\n return {\n type: 'element',\n tagName: 'h6',\n properties: {\n className: 'console-heading',\n },\n children: [\n {\n type: 'text',\n value: 'Python Console',\n },\n ],\n };\n }\n return null;\n}\n\nfunction parseLanguage(node: Code) {\n const lang = (node.lang || '') as string;\n\n if (lang === 'plaintext') {\n return '';\n }\n if (lang.startsWith('{')) {\n const match = lang.match(/.lang-(\\w+)/);\n if (match === null) {\n return '';\n }\n return match[1].toLowerCase();\n }\n return lang.toLowerCase();\n}\n\nfunction parseClass({ lang, meta }: Code) {\n const m = !meta || meta === 'null' ? '' : meta;\n const combined = `${lang || ''} ${m}`.trim();\n if (!combined.startsWith('{.')) {\n return '';\n }\n return combined.slice(1, -1).replace(/\\./g, '');\n}\n","import { BlockContent, Text } from 'mdast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { Node, Parent } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nexport function columns() {\n return (tree: Node) => {\n visit(tree, 'containerDirective', (node: ContainerDirective) => {\n if (node.name === 'columns') {\n node.data = {\n hProperties: {\n className: 'columns',\n },\n };\n } else if (node.name === 'column') {\n node.data = {\n hProperties: {\n className: 'column',\n },\n };\n\n if (node.attributes?.imgsrc) {\n const altText = getAltText(node);\n\n const img = {\n type: 'image',\n url: node.attributes.imgsrc,\n alt: altText,\n } as unknown as BlockContent;\n\n if (altText) {\n Object.assign(node.children[0], img);\n } else {\n node.children.unshift(img);\n }\n }\n }\n });\n };\n}\n\nfunction getAltText(column: ContainerDirective) {\n const firstChild = column.children[0] as Parent;\n if (!firstChild) {\n return false;\n }\n\n const firstChildChildren = firstChild.children as Node[];\n if (!Array.isArray(firstChildChildren)) {\n return false;\n }\n\n const firstChildFirstChild = firstChildChildren[0] as Text;\n if (!firstChildFirstChild) {\n return false;\n }\n\n return firstChildFirstChild.value;\n}\n","import { Root } from 'mdast';\nimport { unified } from 'unified';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { boxouts } from './boxouts';\nimport { moveAnswersToEnd } from './move-answers-to-end';\nimport { programSwitcher } from './program-switcher';\nimport { languageSwitcher } from './language-switcher';\n\nexport async function combinedMdastPhase(\n mdast: Root,\n ctx: Context,\n file: VFile,\n targetPdf?: boolean,\n) {\n const processor = unified()\n .use(programSwitcher, ctx)\n .use(languageSwitcher, ctx)\n .use(boxouts, ctx.refStore);\n\n if (targetPdf) {\n processor.use(moveAnswersToEnd);\n }\n\n return processor.run(mdast, file) as Promise;\n}\n","import path from 'path';\n\nimport { Literal, Root } from 'mdast';\nimport { visit } from 'unist-util-visit';\nimport { remove } from 'unist-util-remove';\n\nimport { Context } from '../context';\nimport { LeafDirective } from 'mdast-util-directive';\n\nexport function embedAssetUrl(ctx: Context) {\n return async (tree: Root) => {\n let activeDir = '';\n\n // nodes need to be visited in the correct order\n // to derive the document directory\n visit(tree, (node, index, parent) => {\n // to ensure relative paths to assets across multiple .Rmd files\n if (node.type === 'leafDirective' && node.name === 'directory') {\n const firstChild = node.children[0] as Literal;\n activeDir = firstChild.value || '';\n }\n\n if (node.type === 'image') {\n const url = getPath(node.url, activeDir, ctx);\n node.url = url;\n }\n\n // also fix for browser template\n if (node.type === 'leafDirective' && node.name === 'browser') {\n const firstChild = node.children[0] as Literal;\n firstChild.value = getPath(firstChild.value, activeDir, ctx);\n }\n\n // also fix for raw html nodes sometimes output by knitr\n if (node.type === 'html') {\n const props = getProps(node.value);\n if (props !== null && props.src) {\n const { src, ...otherProps } = props;\n Object.assign(node, {\n type: 'image',\n url: getPath(src, activeDir, ctx),\n value: '',\n data: otherProps,\n });\n }\n }\n });\n\n // remove the directory leafDirective node from the tree\n remove(tree, (node) => {\n if (node.type === 'leafDirective') {\n const directive = node as LeafDirective;\n return directive.name === 'directory';\n }\n return false;\n });\n };\n}\n\nfunction getPath(url: string, dirname: string, ctx: Context) {\n if (ctx.options.noEmbedAssetUrl) {\n return url;\n }\n if (path.isAbsolute(url) || url.startsWith('http')) {\n return url;\n }\n // pythons matplotlib appears to assign plot images a path\n // relative to the project root, whereas all other libraries use\n // an absolute path.\n if (url.startsWith('cache')) {\n return path.join(ctx.cacheDir, url.replace('cache', ''));\n }\n return path.join(dirname, url);\n}\n\nfunction getProps(value: string) {\n const matchImg = value.match(/^$/);\n if (matchImg !== null) {\n return propsToObject(value.slice(5, -1));\n }\n const matchPdf = value.match(/^$/);\n if (matchPdf !== null) {\n return propsToObject(value.slice(7, -1));\n }\n return null;\n}\n\nfunction propsToObject(str: string) {\n return str\n .split(/(\\w+)=\"(.*?)\"/)\n .filter((s) => s.trim() !== '')\n .reduce((acc: Record, value, idx, arr) => {\n if (idx % 2 === 1) {\n const key = arr[idx - 1];\n acc[key] = value;\n }\n return acc;\n }, {});\n}\n","import { Code } from 'mdast';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nexport function gitGraph() {\n return (tree: Node) => {\n let counter = 0;\n visit(tree, 'code', (node: Code) => {\n if (node.lang === 'gitgraph') {\n createGitGraph(node, ++counter);\n }\n });\n };\n}\n\nfunction createGitGraph(node: Code, counter: number) {\n const id = `gitgraph-${counter}`;\n const options = createDefaultOptions();\n Object.assign(node, {\n type: 'gitgraph',\n data: {\n hName: 'div',\n hProperties: {\n className: 'gitgraph',\n },\n hChildren: [\n {\n type: 'text',\n value: '\\n',\n },\n {\n type: 'element',\n tagName: 'div',\n properties: { id: `gitgraph-${counter}` },\n },\n {\n type: 'text',\n value: '\\n',\n },\n // this will need to be \"singleton\" inlined\n {\n type: 'element',\n tagName: 'script',\n properties: {\n src: 'https://cdn.jsdelivr.net/npm/@gitgraph/js',\n },\n children: [],\n },\n {\n type: 'text',\n value: '\\n',\n },\n {\n type: 'element',\n tagName: 'script',\n children: [\n {\n type: 'text',\n value: [\n '',\n // The global template js (template/src/index.ts) emits a custom event\n // 'template-ready' when initialised. This is handy as the document\n // gets serveral element classes added to it which causes re-renders.\n // Here, we wait for this custom event before rendering the gitgraphs,\n // and are careful to define all variables inside the the event callback\n `document.documentElement.addEventListener('template-ready', () => {`,\n '',\n `const graphContainer = document.getElementById(\"${id}\");`,\n `const gitgraph = GitgraphJS.createGitgraph(graphContainer, ${options});`,\n `${node.value}`,\n '',\n `})`,\n '',\n ].join('\\n'),\n },\n ],\n },\n {\n type: 'text',\n value: '\\n',\n },\n ],\n },\n });\n}\n\nfunction createDefaultOptions() {\n return JSON.stringify({\n // orientation: 'vertical-reverse',\n template: {\n colors: ['#0075b0', '#00843d', '#7d2239', '#951272', '#7a6855'],\n branch: {\n color: '#ccc',\n lineWidth: 5,\n mergeStyle: 'bezier',\n spacing: 40,\n label: {\n display: true,\n bgColor: 'transparent',\n borderRadius: 10,\n },\n },\n arrow: {\n // size: 10,\n // color: '#ccc',\n // offset: -1.5\n },\n commit: {\n spacing: 40,\n hasTooltipInCompactMode: true,\n dot: {\n // size: 8,\n // strokeWidth: 0,\n size: 16,\n strokeWidth: 6,\n strokeColor: 'white',\n },\n message: {\n display: true,\n displayAuthor: false,\n displayHash: false,\n font: 'inherit',\n color: '#333',\n },\n },\n tag: {},\n },\n });\n}\n","import { Element, ElementContent, Parent } from 'hast';\nimport kebabCase from 'lodash/kebabCase.js';\nimport { Image } from 'mdast';\nimport { Literal, Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nimport { Context } from '../context';\nimport { getAssetHast } from '../utils/get-asset-hast';\n\nexport function images(ctx: Context) {\n return (tree: Node) => {\n visit(tree, 'image', (node) => {\n templateFromImage(node, ++ctx.figureCounter);\n });\n\n // knitr can output HTML for plots instead of Markdown now\n visit(tree, 'html', (node: Literal) => {\n const value = String(node.value);\n if (value.startsWith('
')) {\n const hast = getAssetHast(value);\n templateFromHTML(node, hast, ++ctx.figureCounter);\n }\n });\n };\n}\n\nfunction templateFromImage(node: Image, count: number) {\n const alt = getAltText(node.alt || '');\n const slug = kebabCase(alt ? alt : `Figure ${count}`);\n // @ts-expect-error\n createFigure(node, slug, node.url, alt, node.data?.width, count);\n}\n\nfunction templateFromHTML(node: Literal, hast: Element, count: number) {\n const children = hast.children as Element[];\n const img = children.find((o) => o.tagName === 'img');\n const properties = img?.properties || {};\n const src = String(properties.src);\n const alt = getAltText(String(properties.alt));\n const width = properties.width;\n const slug = kebabCase(alt ? alt : `Figure ${count}`);\n createFigure(node, slug, src, alt, width, count);\n}\n\nfunction createFigure(\n node: Image | Literal,\n slug: string,\n src: string,\n alt: string,\n width: unknown,\n count: number,\n) {\n Object.assign(node, {\n type: 'custom-image',\n data: {\n hName: 'figure',\n hProperties: {\n className: ['img-wrapper'],\n id: slug,\n },\n hChildren: [\n createImage(src, alt, width),\n createCaption(alt, slug, count),\n ],\n },\n });\n}\n\nfunction createImage(src: string, alt: string, width: unknown) {\n const image: Element = {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'img-bg',\n },\n children: [\n {\n type: 'element',\n tagName: 'img',\n properties: { src, alt },\n children: [],\n },\n ],\n };\n\n if (width && /^\\d+px/.test(String(width))) {\n image.properties = {\n ...image.properties,\n style: `width: ${width};`,\n };\n }\n\n return image;\n}\n\nfunction createCaption(alt: string, slug: string, count: number) {\n return {\n type: 'element',\n tagName: 'figcaption',\n children: [\n {\n type: 'element',\n tagName: 'a',\n properties: {\n href: `#${slug}`,\n },\n children: createLabel(alt, count),\n },\n ],\n };\n}\n\nfunction createLabel(alt: string, count: number) {\n const label: ElementContent[] = [\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'caption-count',\n },\n children: [\n {\n type: 'text',\n value: `Figure ${count}`,\n },\n ],\n },\n ];\n\n if (alt) {\n const elem = label[0] as Parent;\n const content = elem.children[0] as Literal;\n content.value += ':';\n\n label.push({\n type: 'text',\n value: ` ${alt}`,\n });\n }\n\n return label;\n}\n\nfunction getAltText(altText: string) {\n if (altText.includes('unnamed-chunk')) {\n return '';\n }\n return altText;\n}\n","import headings from 'rehype-autolink-headings';\nimport directive from 'remark-directive';\nimport frontmatter from 'remark-frontmatter';\nimport gfm from 'remark-gfm';\nimport markdown from 'remark-parse';\nimport slug from 'rehype-slug';\nimport { unified } from 'unified';\nimport { VFile } from 'vfile';\n\nimport { Context } from '../context';\nimport { aliasDirectiveToLatexSvg } from '../latex/directive-to-svg';\nimport { createSvg } from '../utils/icons';\nimport { browserWindow } from './browser-window';\nimport { codeBlocks } from './code-blocks';\nimport { columns } from './columns';\nimport { embedAssetUrl } from './embed-asset-url';\nimport { gitGraph } from './gitgraph';\nimport { images } from './images';\nimport { pagebreaks } from './pagebreaks';\nimport { removeEmptyParagraphs } from './remove-empty-paragraphs';\nimport { styledTerminal } from './styled-terminal';\nimport { textFile } from './text-file';\nimport { youtubeVideos } from './youtube-videos';\nimport { aliasDirectiveToCode } from '../code/alias-directive-to-code';\n\nexport async function mdastPhase(file: VFile, ctx: Context) {\n // https://github.com/unifiedjs/unified\n // convert markdown to syntax tree: complex transforms\n // should be more robust and straightforward\n const processor = unified()\n // third-party plugins:\n .use(markdown)\n .use(directive)\n .use(frontmatter)\n .use(gfm)\n .use(slug)\n .use(headings, {\n content: createSvg('link-icon') as any,\n properties: { className: 'link' },\n })\n // custom plugins:\n .use(() => (tree) => {})\n .use(columns)\n .use(embedAssetUrl, ctx)\n .use(youtubeVideos)\n .use(aliasDirectiveToCode, ctx)\n .use(aliasDirectiveToLatexSvg, ctx)\n .use(removeEmptyParagraphs)\n .use(gitGraph)\n .use(textFile)\n .use(browserWindow)\n .use(codeBlocks, ctx)\n .use(styledTerminal)\n .use(images, ctx)\n .use(pagebreaks);\n\n const parsed = processor.parse(file);\n // @ts-expect-error\n return processor.run(parsed, file);\n}\n","import { Element, ElementContent } from 'hast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { toHast } from 'mdast-util-to-hast';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nimport { Context } from '../context';\n\nconst languages = ['r', 'python'];\nconst titleCase = ['R', 'Python'];\n\nexport function languageSwitcher(ctx: Context) {\n const languageFlag = ctx.options.envLanguage;\n if (languageFlag !== undefined && !languages.includes(languageFlag)) {\n throw new Error(\n `[environment]: envLanguage ${languageFlag} should be one of ${languages}`,\n );\n }\n\n return (tree: Node) => {\n visit(tree, 'containerDirective', (node: ContainerDirective) => {\n if (node.name === 'language-switcher') {\n const children = [];\n if (languageFlag === undefined) {\n children.push(processMenu(node));\n }\n children.push(...processChildren(node, languageFlag));\n\n node.data = {\n hProperties: {\n className: 'language-switcher',\n },\n hChildren: children,\n };\n }\n });\n };\n}\n\nfunction processMenu(parent: ContainerDirective): ElementContent {\n const children = parent.children as ContainerDirective[];\n return {\n type: 'element',\n tagName: 'ul',\n properties: {},\n children: children.map((node) => {\n const element: ElementContent = {\n type: 'element',\n tagName: 'li',\n properties: {\n 'data-language': node.name,\n },\n children: [\n {\n type: 'text',\n value: titleCase[languages.indexOf(node.name)],\n },\n ],\n };\n return element;\n }),\n };\n}\n\nfunction processChildren(\n parent: ContainerDirective,\n languageFlag: string | undefined,\n): ElementContent[] {\n const children = parent.children.map((node) => {\n const parent = node as ContainerDirective;\n if (languages.includes(parent.name)) {\n node.data = {\n hProperties: {\n 'data-language': parent.name,\n className: [\n 'language',\n languageFlag === parent.name ? 'show' : '',\n ],\n },\n };\n }\n return node;\n });\n\n let filtered = children;\n if (languageFlag !== undefined) {\n filtered = filtered.filter((node) => {\n const parent = node as ContainerDirective;\n return languageFlag === parent.name;\n });\n }\n\n const parentHast = toHast({\n type: 'root',\n children: filtered,\n }) as Element;\n\n return parentHast.children;\n}\n","import { Node, Parent } from 'hast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { visit } from 'unist-util-visit';\n\nexport function moveAnswersToEnd() {\n return (tree: Node) => {\n visit(\n tree,\n 'containerDirective',\n (node: ContainerDirective, _index, _parent) => {\n const index = _index as number;\n const parent = _parent as Parent;\n\n // remove answer from task rehype\n if (node.name === 'task' && node.data) {\n const children = node.data.hChildren || [];\n const newChildren = children.filter((o) => {\n // @ts-expect-error\n return o.name !== 'answer';\n });\n node.data.hChildren = newChildren;\n }\n\n if (node.name === 'answer') {\n // these nodes have already been moved to the end\n if (node.attributes?.movedToEnd === 'yes') {\n return;\n }\n\n // remove answer block from task node\n const parentChildren = parent?.children || [];\n parentChildren.splice(index || 0, 1);\n\n // add to root node\n const treeParent = tree as Parent;\n const treeChildren = (treeParent.children || []) as Node[];\n\n node.attributes = {\n ...(node.attributes || {}),\n movedToEnd: 'yes',\n };\n\n treeChildren.push(node);\n }\n },\n );\n };\n}\n","import { LeafDirective } from 'mdast-util-directive';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nexport function pagebreaks() {\n return async (tree: Node) => {\n visit(tree, 'leafDirective', (node: LeafDirective) => {\n if (node.name === 'pagebreak') {\n node.data = {\n hName: 'hr',\n hProperties: {\n className: 'pagebreak',\n },\n };\n }\n });\n };\n}\n","import { Element, ElementContent } from 'hast';\nimport { ContainerDirective } from 'mdast-util-directive';\nimport { toHast } from 'mdast-util-to-hast';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nimport { Context } from '../context';\n\nconst programs = ['github-desktop', 'command-line'];\nconst titleCase = ['GitHub Desktop', 'Command-line'];\n\nexport function programSwitcher(ctx: Context) {\n const programFlag = ctx.options.envProgram;\n if (programFlag !== undefined && !programs.includes(programFlag)) {\n throw new Error(\n `[environment]: envProgram ${programFlag} should be one of ${programs}`,\n );\n }\n\n return (tree: Node) => {\n visit(tree, 'containerDirective', (node: ContainerDirective) => {\n if (node.name === 'program-switcher') {\n const children = [];\n if (programFlag === undefined) {\n children.push(processMenu(node));\n }\n children.push(...processChildren(node, programFlag));\n\n node.data = {\n hProperties: {\n className: 'program-switcher',\n },\n hChildren: children,\n };\n }\n });\n };\n}\n\nfunction processMenu(parent: ContainerDirective): ElementContent {\n const children = parent.children as ContainerDirective[];\n return {\n type: 'element',\n tagName: 'ul',\n properties: {},\n children: children.map((node) => {\n const element: ElementContent = {\n type: 'element',\n tagName: 'li',\n properties: {\n 'data-program': node.name,\n },\n children: [\n {\n type: 'text',\n value: titleCase[programs.indexOf(node.name)],\n },\n ],\n };\n return element;\n }),\n };\n}\n\nfunction processChildren(\n parent: ContainerDirective,\n programFlag: string | undefined,\n): ElementContent[] {\n const children = parent.children.map((node) => {\n const parent = node as ContainerDirective;\n if (programs.includes(parent.name)) {\n node.data = {\n hProperties: {\n 'data-program': parent.name,\n className: [\n 'program',\n programFlag === parent.name ? 'show' : '',\n ],\n },\n };\n }\n return node;\n });\n\n let filtered = children;\n if (programFlag !== undefined) {\n filtered = filtered.filter((node) => {\n const parent = node as ContainerDirective;\n return programFlag === parent.name;\n });\n }\n\n const parentHast = toHast({\n type: 'root',\n children: filtered,\n }) as Element;\n\n return parentHast.children;\n}\n","import { Paragraph, Parent } from 'mdast';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nexport function removeEmptyParagraphs() {\n return async (tree: Node) => {\n visit(tree, 'paragraph', (node: Paragraph, _index, _parent) => {\n const index = _index as number;\n const parent = _parent as Parent;\n\n if (node.children.length === 0) {\n const parentChildren = parent?.children || [];\n parentChildren.splice(index || 0, 1);\n }\n });\n };\n}\n","import ansiColor from 'ansicolor';\nimport { ElementContent, Node } from 'hast';\nimport { Code, Literal } from 'mdast';\nimport { Parent } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nexport function styledTerminal() {\n return (tree: Node) => {\n visit(\n tree,\n 'custom-code',\n (node: Code, index: number, parent: Parent) => {\n if (node.lang === 'bash') {\n wrapInStyledTerminal(node, index, parent);\n }\n },\n );\n };\n}\n\nfunction wrapInStyledTerminal(code: Code, index: number, parent: Parent) {\n const codeChildren = (code.data?.hChildren || []) as ElementContent[];\n const responseChildren = [];\n\n const nextIdx = index + 1;\n const nextNode = parent.children[nextIdx];\n if (nextNode && nextNode.type === 'custom-code') {\n const response = nextNode as Code;\n if (\n response.lang === '{.knitr-output}' ||\n response.lang === '{.knitr-error-output}'\n ) {\n const children = (response.data?.hChildren ||\n []) as ElementContent[];\n const responseWithColours = ansiToHast(children);\n responseChildren.push(...responseWithColours);\n\n // remove response element\n parent.children.splice(nextIdx, 1);\n }\n }\n\n code.data = {\n hProperties: {\n className: 'terminal',\n },\n hChildren: [...codeChildren, ...responseChildren],\n };\n}\n\nfunction ansiToHast(children: ElementContent[]): ElementContent[] {\n const pre = children[1] as Parent;\n const code = pre.children[0] as Parent;\n const text = code.children[0] as Literal;\n const parsed = ansiColor.parse(text.value);\n\n const hast = parsed.spans.map((o) => {\n const text = {\n type: 'text',\n value: o.text,\n };\n if (!o.color) {\n return text;\n } else {\n return {\n type: 'element',\n tagName: 'span',\n properties: {\n className: [\n o.color.name || '',\n o.bold ? 'bold' : '',\n o.color.bright ? 'bright' : '',\n ].filter(Boolean),\n },\n children: [text],\n };\n }\n });\n\n code.children = hast;\n\n return children;\n}\n","import { Code } from 'mdast';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\n\nexport function textFile() {\n return (tree: Node) => {\n visit(tree, 'code', (node: Code) => {\n if (node.lang === 'textfile') {\n createTextFile(node);\n }\n });\n };\n}\n\nfunction createTextFile(node: Code) {\n Object.assign(node, {\n type: 'text-file',\n data: {\n hName: 'div',\n hProperties: {\n className: 'text-file',\n },\n hChildren: [\n {\n type: 'text',\n value: '\\n',\n },\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'text-file-wrapper',\n },\n children: [\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'text-file-header',\n },\n children: [\n {\n type: 'text',\n value: node.meta?.trim() || '',\n },\n ],\n },\n {\n type: 'text',\n value: '\\n',\n },\n {\n type: 'element',\n tagName: 'div',\n properties: {\n className: 'text-file-content',\n },\n children: [\n {\n type: 'text',\n value: node.value,\n },\n ],\n },\n {\n type: 'text',\n value: '\\n',\n },\n ],\n },\n ],\n },\n });\n}\n","import { Literal } from 'mdast';\nimport { LeafDirective } from 'mdast-util-directive';\nimport { Node } from 'unist';\nimport { visit } from 'unist-util-visit';\nimport { VFile } from 'vfile';\n\nimport { failMessage } from '../utils/message';\n\nexport function youtubeVideos() {\n return async (tree: Node, file: VFile) => {\n visit(tree, 'leafDirective', (node: LeafDirective) => {\n if (node.name === 'video') {\n const attributes = node.attributes;\n const title = getTitle(node, file);\n node.data = {\n hName: 'a',\n hProperties: {\n className: ['boxout', 'video'],\n href: getYoutubeUrl(attributes?.id || ''),\n title: attributes?.title || null,\n target: '_blank',\n },\n hChildren: [\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'content',\n },\n children: [\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'type',\n },\n children: [\n {\n type: 'text',\n value: 'Video',\n },\n ],\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'title',\n },\n children: [\n {\n type: 'text',\n value: title,\n },\n ],\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'duration',\n },\n children: [\n {\n type: 'element',\n tagName: 'strong',\n properties: {},\n children: [\n {\n type: 'text',\n value: 'Duration',\n },\n ],\n },\n {\n type: 'text',\n value: formatDuration(attributes?.duration || ''),\n },\n ],\n },\n ],\n },\n {\n type: 'element',\n tagName: 'span',\n properties: {\n className: 'thumbnail',\n },\n children: [\n {\n type: 'element',\n tagName: 'img',\n properties: {\n src: getYoutubeThumbnailUrl(attributes?.id || ''),\n alt: '',\n },\n children: [],\n },\n ],\n },\n ],\n };\n }\n });\n };\n}\n\nfunction getTitle(node: LeafDirective, file: VFile) {\n const children = node.children as Node[];\n const firstChild = children[0] as Literal;\n const title = firstChild?.value || '';\n if (title.trim() === '') {\n failMessage(file, 'Video has no title', node.position);\n }\n return title;\n}\n\nfunction getYoutubeUrl(id: string) {\n return `https://youtu.be/${id}`;\n}\n\nfunction getYoutubeThumbnailUrl(id: string) {\n return `http://img.youtube.com/vi/${id}/mqdefault.jpg`;\n}\n\nfunction formatDuration(duration: string = '') {\n const match = duration.match(/^(\\d+)m(\\d+)s$/);\n if (match === null) {\n return '';\n }\n return `${match[1]}:${match[2].padStart(2, '0')}`;\n}\n","import puppeteer from 'puppeteer';\n\n// const footerTemplate = `\n//
\n// Page of \n//
\n// `;\n\nexport async function convertToPdf(html: string) {\n const browser = await puppeteer.launch({\n headless: true,\n args: [\n // attempted fix for windows https://stackoverflow.com/questions/59979188#66549119\n '--disable-gpu',\n '--disable-dev-shm-usage',\n '--disable-setuid-sandbox',\n '--no-first-run',\n '--no-sandbox',\n '--no-zygote',\n ],\n });\n const page = await browser.newPage();\n page.setDefaultNavigationTimeout(0);\n await page.setContent(html);\n await page.evaluateHandle('document.fonts.ready');\n const pdf = await page.pdf({\n format: 'a4',\n printBackground: true,\n // displayHeaderFooter: true,\n // footerTemplate,\n margin: {\n top: '20px',\n left: '40px',\n right: '40px',\n bottom: '40px',\n },\n });\n await browser.close();\n return pdf;\n}\n","export function allowNoWhitespaceBeforeHeading(contents: string) {\n return contents\n .split('\\n')\n .map((line) => {\n const match = line.match(/^(#+)(\\w)(.*?)$/);\n if (match !== null) {\n return `${match[1]} ${match[2]}${match[3]}`;\n }\n return line;\n })\n .join('\\n');\n}\n","const blockList = ['\\\\newpage', '\\\\pagebreak'];\n\nexport function convertNewPageToDirective(contents: string) {\n return contents\n .split('\\n')\n .map((a) => (blockList.some((b) => a.includes(b)) ? '::pagebreak' : a))\n .join('\\n');\n}\n\nexport function convertEmptyMBoxToDirective(contents: string) {\n return contents\n .split('\\n')\n .map((line) => {\n if (\n line.includes('\\\\mbox') &&\n line.replace('{', '').replace('}', '').trim() === '\\\\mbox'\n ) {\n return '::pagebreak';\n }\n return line;\n })\n .join('\\n');\n}\n","export function convertTextBfToMd(contents: string) {\n const pattern = /\\\\textbf\\{(.*?)\\}/g;\n return contents.replace(pattern, (_, str) => `**${str}**`);\n}\n\nexport function convertUrlToMd(contents: string) {\n const pattern = /\\\\url\\{(.*?)\\}/g;\n return contents.replace(pattern, (_, str) => str);\n}\n","export function convertMacroToDirective(contents: string) {\n return contents\n .split('\\n')\n .map((line) => {\n const container = parseCustomContainer(line);\n if (container !== null) {\n return renderContainerDirective(container);\n }\n return line;\n })\n .join('\\n');\n}\n\ntype Container = {\n name: string;\n title: string;\n attributes: string;\n};\n\nfunction parseCustomContainer(line: string): Container | null {\n const match = line.match(/^#{1,6}\\s*\\[(\\D.+)](.*)/);\n if (!Array.isArray(match)) {\n return null;\n }\n const [, attributeStr = '', extra = ''] = match;\n const [name, ...attributesArr] = attributeStr\n .split(',')\n .map((s) => s.trim());\n const title = extra.trim();\n const attributes = transformAttributes(name, attributesArr);\n return { name, title, attributes };\n}\n\nfunction renderContainerDirective({ name, title, attributes }: Container) {\n const colons = getColons(name);\n if (name.startsWith('/')) {\n return colons;\n }\n const newTitle = title ? `[${title}]` : '';\n const newAttributes = attributes ? `{${attributes}}` : '';\n return colons + name + newTitle + newAttributes;\n}\n\nfunction getColons(name: string) {\n switch (name.replace('/', '')) {\n case 'task':\n case 'columns':\n return '::::';\n case 'video':\n return '::';\n default:\n return ':::';\n }\n}\n\nfunction transformAttributes(\n containerName: string,\n attributesArr: string[]\n) {\n return attributesArr\n .map((attribute) => {\n const [key, value] = attribute.split('=').map((s) => s.trim());\n if (containerName === 'video' && key === 'videoid') {\n return `id=${value}`;\n }\n return attribute;\n })\n .join(' ');\n}\n","import { VFile } from 'vfile';\n\nimport { allowNoWhitespaceBeforeHeading } from './allow-no-whitespace-before-heading';\nimport {\n convertEmptyMBoxToDirective,\n convertNewPageToDirective,\n} from './convert-block-tex';\nimport { convertTextBfToMd, convertUrlToMd } from './convert-inline-tex';\nimport { convertMacroToDirective } from './convert-macro-to-directive';\nimport { reformatPandocSimpleTables } from './reformat-pandoc-simple-tables';\n\n// Some of the original coursework syntax can't easily be parsed by\n// existing plugins for unified.js, so in a \"pre-parse\" phase\n// I transform some syntax using regex so it can be parsed.\n// A successful generic approach I found is to convert problem syntax to a\n// custom markdown directive: https://github.com/remarkjs/remark-directive\n\nexport function preParsePhase(file: VFile) {\n let result = file.value as string;\n result = removeCommentedSections(result);\n // result = escapeDollarsInCodeBlocks(result);\n result = allowNoWhitespaceBeforeHeading(result);\n result = convertMacroToDirective(result);\n result = convertTextBfToMd(result);\n result = convertUrlToMd(result);\n result = convertNewPageToDirective(result);\n result = convertEmptyMBoxToDirective(result);\n result = reformatPandocSimpleTables(result);\n file.value = result;\n return file;\n}\n\nfunction removeCommentedSections(md: string) {\n return md.replace(//g, '').replace(/\\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n\";","export default \"\\n \\n \\n\\n\";","export default \"\\n \\n\\n\";","module.exports = import(\"@double-great/remark-lint-alt-text\");;","module.exports = import(\"@mapbox/remark-lint-link-text\");;","module.exports = import(\"ansicolor\");;","module.exports = import(\"base64-arraybuffer\");;","module.exports = import(\"chalk\");;","module.exports = import(\"figures\");;","module.exports = import(\"hash-sum\");;","module.exports = import(\"image-size\");;","module.exports = import(\"js-yaml\");;","module.exports = import(\"lodash/cloneDeep.js\");;","module.exports = import(\"lodash/kebabCase.js\");;","module.exports = import(\"lodash/startCase.js\");;","module.exports = import(\"markdown-table\");;","module.exports = import(\"mathjax-full/js/adaptors/liteAdaptor.js\");;","module.exports = import(\"mathjax-full/js/core/MathItem.js\");;","module.exports = import(\"mathjax-full/js/core/MmlTree/SerializedMmlVisitor.js\");;","module.exports = import(\"mathjax-full/js/handlers/html.js\");;","module.exports = import(\"mathjax-full/js/handlers/html/HTMLDocument.js\");;","module.exports = import(\"mathjax-full/js/input/mathml.js\");;","module.exports = import(\"mathjax-full/js/input/tex.js\");;","module.exports = import(\"mathjax-full/js/input/tex/AllPackages.js\");;","module.exports = import(\"mathjax-full/js/mathjax.js\");;","module.exports = import(\"mathjax-full/js/output/svg.js\");;","module.exports = import(\"mdast-util-to-hast\");;","module.exports = import(\"mdast-util-toc\");;","module.exports = import(\"mime\");;","module.exports = import(\"node-fetch\");;","module.exports = import(\"puppeteer\");;","module.exports = import(\"refractor/lib/all.js\");;","module.exports = import(\"rehype-autolink-headings\");;","module.exports = import(\"rehype-document\");;","module.exports = import(\"rehype-format\");;","module.exports = import(\"rehype-parse\");;","module.exports = import(\"rehype-raw\");;","module.exports = import(\"rehype-slug\");;","module.exports = import(\"rehype-stringify\");;","module.exports = import(\"remark-directive\");;","module.exports = import(\"remark-frontmatter\");;","module.exports = import(\"remark-gfm\");;","module.exports = import(\"remark-parse\");;","module.exports = import(\"remark-rehype\");;","module.exports = import(\"speech-rule-engine\");;","module.exports = import(\"to-vfile\");;","module.exports = import(\"unified\");;","module.exports = import(\"unist-util-remove\");;","module.exports = import(\"unist-util-visit\");;","module.exports = import(\"vfile\");;","module.exports = import(\"yargs\");;","module.exports = import(\"yargs/helpers\");;","module.exports = import(\"yup\");;","module.exports = require(\"child_process\");","module.exports = require(\"fs\");","module.exports = require(\"os\");","module.exports = require(\"path\");","module.exports = require(\"url\");","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","var webpackQueues = typeof Symbol === \"function\" ? Symbol(\"webpack queues\") : \"__webpack_queues__\";\nvar webpackExports = typeof Symbol === \"function\" ? Symbol(\"webpack exports\") : \"__webpack_exports__\";\nvar webpackError = typeof Symbol === \"function\" ? Symbol(\"webpack error\") : \"__webpack_error__\";\nvar resolveQueue = (queue) => {\n\tif(queue && queue.d < 1) {\n\t\tqueue.d = 1;\n\t\tqueue.forEach((fn) => (fn.r--));\n\t\tqueue.forEach((fn) => (fn.r-- ? fn.r++ : fn()));\n\t}\n}\nvar wrapDeps = (deps) => (deps.map((dep) => {\n\tif(dep !== null && typeof dep === \"object\") {\n\t\tif(dep[webpackQueues]) return dep;\n\t\tif(dep.then) {\n\t\t\tvar queue = [];\n\t\t\tqueue.d = 0;\n\t\t\tdep.then((r) => {\n\t\t\t\tobj[webpackExports] = r;\n\t\t\t\tresolveQueue(queue);\n\t\t\t}, (e) => {\n\t\t\t\tobj[webpackError] = e;\n\t\t\t\tresolveQueue(queue);\n\t\t\t});\n\t\t\tvar obj = {};\n\t\t\tobj[webpackQueues] = (fn) => (fn(queue));\n\t\t\treturn obj;\n\t\t}\n\t}\n\tvar ret = {};\n\tret[webpackQueues] = x => {};\n\tret[webpackExports] = dep;\n\treturn ret;\n}));\n__webpack_require__.a = (module, body, hasAwait) => {\n\tvar queue;\n\thasAwait && ((queue = []).d = -1);\n\tvar depQueues = new Set();\n\tvar exports = module.exports;\n\tvar currentDeps;\n\tvar outerResolve;\n\tvar reject;\n\tvar promise = new Promise((resolve, rej) => {\n\t\treject = rej;\n\t\touterResolve = resolve;\n\t});\n\tpromise[webpackExports] = exports;\n\tpromise[webpackQueues] = (fn) => (queue && fn(queue), depQueues.forEach(fn), promise[\"catch\"](x => {}));\n\tmodule.exports = promise;\n\tbody((deps) => {\n\t\tcurrentDeps = wrapDeps(deps);\n\t\tvar fn;\n\t\tvar getResult = () => (currentDeps.map((d) => {\n\t\t\tif(d[webpackError]) throw d[webpackError];\n\t\t\treturn d[webpackExports];\n\t\t}))\n\t\tvar promise = new Promise((resolve) => {\n\t\t\tfn = () => (resolve(getResult));\n\t\t\tfn.r = 0;\n\t\t\tvar fnQueue = (q) => (q !== queue && !depQueues.has(q) && (depQueues.add(q), q && !q.d && (fn.r++, q.push(fn))));\n\t\t\tcurrentDeps.map((dep) => (dep[webpackQueues](fnQueue)));\n\t\t});\n\t\treturn fn.r ? promise : getResult();\n\t}, (err) => ((err ? reject(promise[webpackError] = err) : outerResolve(exports)), resolveQueue(queue)));\n\tqueue && queue.d < 0 && (queue.d = 0);\n};","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","","// startup\n// Load entry module and return exports\n// This entry module used 'module' so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(606);\n",""],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/release/package.json b/release/package.json index ed60ea4..c590df6 100644 --- a/release/package.json +++ b/release/package.json @@ -47,4 +47,4 @@ "yargs": "17.7.2", "yup": "1.3.2" } -} +} \ No newline at end of file