ipynb2web
Version:
Prepare and convert Jupyter Notebooks into HTML templating content.
1,046 lines (984 loc) โข 81.2 kB
JavaScript
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ 3:
/***/ ((module) => {
module.exports = require("path");
/***/ }),
/***/ 50:
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Wl: () => (/* binding */ replaceAndLog),
/* harmony export */ e4: () => (/* binding */ replaceEmojis),
/* harmony export */ nm: () => (/* binding */ makeDetails),
/* harmony export */ zX: () => (/* binding */ convertNotes)
/* harmony export */ });
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
/**
* @fileOverview Utility functions used by the [convert](module-convert.html).
* @module convert_util
* @exports {Object} - An object containing utility functions.
* @author Charles Karpati
*/
/**
* Creates an HTML details element with the given content. Called by [processOutput](module-convert.html#.processOutput) and [processSource](module-convert.html#.processSource).
*
* @param {string} content - The HTML content to be placed inside the details tag.
* @param {boolean} open - Determines if the details should be open by default.
* @returns {string} An HTML string representing a details element.
* @memberof module:convert_util
*/
function makeDetails(content, open) {
return "<details " + (open ? "open" : "") + "> <summary>Click to toggle</summary> " + content + "</details>";
}
/**
* Replaces specified emoji characters in the text with their corresponding HTML entities. Convert emojis to html entities
*
* @param {string} text - The text containing emojis to be replaced.
* @returns {string} The text with emojis replaced by HTML entities.
* @memberof module:convert_util
*/
function replaceEmojis(text) {
// Dec => Code => https://apps.timwhitlock.info/unicode/inspect/hex/1F633
text = text.replaceAll("๐", "F642");
text = text.replaceAll("๐ณ", "😳");
text = text.replaceAll("\u2003", " ");
text = text.replaceAll("๐ท", "👷");
text = text.replaceAll("๐งก", "🧡");
text = text.replaceAll("๐", "💖");
return text;
}
/**
* Converts special note syntax in a string to HTML elements for displaying notes.
*
* @param {string} str - The string containing note syntax to be converted.
* @returns {string} The string with note syntax converted to HTML elements.
* @memberof module:convert_util
*/
function convertNotes(str) {
// console.log("Converting notes", str);
str = createElement(str);
str = createInlineFootnotes(str);
str = createSpans(str);
return str;
}
//
// Markdown content will be prefaced with :::{#id .class}
// Removes 'pre' and 'code' blocks while processing and then reinserts at end.
// check six layers deep. do this by first by creating an array of substrings that are wrapped by an opening and closing
// ':::' * 6, then within the resulting arrays, create sub arrays for ':::' * 5, and so on and so on, then handle each
// one at ':::' * 1 and merge all the results back to the final form.
function createElement(str) {
// 1. Shield existing <pre>/<code> blocks
var codeBlocks = [];
str = str.replace(/<pre[\s\S]*?<\/pre>|<code[\s\S]*?<\/code>/g, function (m) {
return "__CODE_".concat(codeBlocks.push(m) - 1, "__");
});
// helper to build the element
var buildElement = function buildElement(attrs, content) {
return "<div".concat(buildAttrs(attrs), ">").concat(content.trim(), "</div>");
};
// helper to build id/class string
var buildAttrs = function buildAttrs(attrs) {
var idMatch = attrs.match(/#([A-Za-z0-9_-]+)/);
var classMatches = _toConsumableArray(attrs.matchAll(/\.([A-Za-z0-9_-]+)/g)).map(function (m) {
return m[1];
});
return "".concat(idMatch ? " id=\"".concat(idMatch[1], "\"") : '').concat(classMatches.length ? " class=\"".concat(classMatches.join(' '), "\"") : '');
};
// 2. process :::...::: blocks from 6 colons down to 1
for (var level = 6; level > 0; level--) {
var colons = ':'.repeat(level);
var regex = new RegExp("".concat(colons, "\\s*{\\s*([^}]*)}\\s*([\\s\\S]*?)\\s*").concat(colons), 'g');
str = str.replace(regex, function (_, attrs, content) {
return buildElement(attrs, content.trim());
});
}
// 3. restore code blocks
return str.replace(/__CODE_(\d+)__/g, function (_, i) {
return codeBlocks[i];
});
}
// test string:
// "Here is an inline note.^[Inlines notes are easier to write, since you don't have to pick an identifier and move down to type the note.]"
function createInlineFootnotes(str) {
var count = 0;
return str.replace(/\^\[([\s\S]+?)\]/g, function (_, text) {
console.log("Inline note:", text);
count++;
var label = "<label tabindex=\"0\" for=\"note".concat(count, "\" class=\"notelbl\">[").concat(count, "]</label>");
return "<span class=\"note\">\n <input type=\"checkbox\" id=\"note".concat(count, "\" class=\"notebox\">\n ").concat(label, "\n <aside class=\"inline-note\"> \n ").concat(label, "\n ").concat(text, "\n </aside>\n </span>");
});
}
// Example: [This text is smallcaps]{.smallcaps #id}
function createSpans(str) {
// 1. Shield existing <pre>/<code> blocks
var codeBlocks = [];
str = str.replace(/<pre[\s\S]*?<\/pre>|<code[\s\S]*?<\/code>/g, function (m) {
return "__CODE_".concat(codeBlocks.push(m) - 1, "__");
});
// helper to build id/class string
var buildAttrs = function buildAttrs(attrs) {
var idMatch = attrs.match(/#([A-Za-z0-9_-]+)/);
var classMatches = _toConsumableArray(attrs.matchAll(/\.([A-Za-z0-9_-]+)/g)).map(function (m) {
return m[1];
});
return "".concat(idMatch ? " id=\"".concat(idMatch[1], "\"") : '').concat(classMatches.length ? " class=\"".concat(classMatches.join(' '), "\"") : '');
};
// 2. replace [text]{attrs} with <span ...>text</span>
str = str.replace(/\[([^\]]*?)\]\s*\{\s*([^}]*)\}/g, function (_, text, attrs) {
return "<span".concat(buildAttrs(attrs), ">").concat(text, "</span>");
});
// 3. restore code blocks
return str.replace(/__CODE_(\d+)__/g, function (_, i) {
return codeBlocks[i];
});
}
/**
* Replaces occurrences of a pattern in a string and optionally logs the replacement.
*
* @param {string} text - The text in which replacements are to be made.
* @param {RegExp|string} input - The pattern to search for in the text.
* @param {Function|string} output - The replacement text or a function that returns the replacement text.
* @returns {string} The text after performing the replacements.
* @memberof module:convert_util
*/
function replaceAndLog(text, input, output) {
return text.replace(input, function (match, capture) {
var _output$replace;
return ((_output$replace = output.replace) === null || _output$replace === void 0 ? void 0 : _output$replace.call(output, '$1', capture)) || output(match, capture);
});
}
;
/***/ }),
/***/ 233:
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ createSpeech: () => (/* binding */ createSpeech),
/* harmony export */ getTextFromJson: () => (/* binding */ getTextFromJson),
/* harmony export */ saveSpeech: () => (/* binding */ saveSpeech),
/* harmony export */ speechFromDir: () => (/* binding */ speechFromDir)
/* harmony export */ });
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(383);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); }
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
/**
* @fileOverview Provides functionalities for generating audio content from text and JSON data using OpenAI's APIs.
*
* This module contains functions for creating speech from text input, saving audio files, extracting text from JSON for speech synthesis, and converting JSON data to audio files in a specified directory. It leverages OpenAI's text-to-speech and GPT-4 models to process and convert textual content into spoken audio, supporting various customization options like voice model and speech speed.
*
* Functions exposed from [cli](module-Ipynb2web_cli.html) and [node](module-Ipynb2web_node.html).
* @module create_audio
* @exports {Object} - Exports functions like createSpeech, saveSpeech, getTextFromJson, and speechFromDir for audio processing and generation.
* @author Charles Karpati
*/
/**
* Creates an audio speech from text using the OpenAI API.
*
* @async
* @public
* @param {string} input - The text to be converted into speech.
* @param {string} [apikey] - The OpenAI API key. If not provided, it will use the environment variable 'OPENAI_API_KEY'.
* @param {string} [voice='echo'] - The voice model to use.
* @param {number} [speed=1.0] - The speed of the speech (0.25 to 4.0).
* @param {string} [model='tts-1'] - The speech model to use.
* @param {boolean} [verbose=false] - If set to true, enables verbose logging for detailed information.
* @returns {Buffer|null} The audio data as a Buffer, or null if an error occurs or no API key is provided.
* @throws {Error} Logs an error to the console if fetching the speech fails and verbose is true.
* @memberof module:create_audio
*/
function createSpeech(_x, _x2) {
return _createSpeech.apply(this, arguments);
}
/**
* Saves the given audio buffer to a file.
*
* @async
* @param {string} mp3SaveFilePath - The file path where the MP3 should be saved.
* @param {Buffer} buffer - The audio data to be saved.
* @param {boolean} [verbose=false] - If set to true, enables verbose logging for detailed information.
* @returns {void} Does not return a value; saves the audio buffer to a file.
* @throws {Error} Logs an error to the console if there is a failure in saving the audio file and verbose is true.
* @memberof module:create_audio
*/
function _createSpeech() {
_createSpeech = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(input, apikey) {
var voice,
speed,
model,
verbose,
openai,
mp3Response,
buffer,
_args = arguments,
_t;
return _regenerator().w(function (_context) {
while (1) switch (_context.p = _context.n) {
case 0:
voice = _args.length > 2 && _args[2] !== undefined ? _args[2] : 'echo';
speed = _args.length > 3 && _args[3] !== undefined ? _args[3] : 1.0;
model = _args.length > 4 && _args[4] !== undefined ? _args[4] : 'tts-1';
verbose = _args.length > 5 && _args[5] !== undefined ? _args[5] : false;
if (!apikey) {
apikey = process.env.OPENAI_API_KEY;
}
if (apikey) {
_context.n = 1;
break;
}
verbose && console.log('No API Key provided and \"env.OPENAI_API_KEY\" not found.');
return _context.a(2);
case 1:
_context.p = 1;
openai = new OpenAI(apikey); // Speed [ `0.25` - `4.0`]. default = `1.0`.
// The maximum length is 4096 characters.
_context.n = 2;
return fetch('https://api.openai.com/v1/audio/speech', {
method: 'POST',
headers: {
'Authorization': "Bearer ".concat(apikey),
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: model,
input: input,
voice: voice,
speed: speed,
response_format: 'mp3'
})
});
case 2:
mp3Response = _context.v;
_context.n = 3;
return mp3Response.buffer();
case 3:
buffer = _context.v;
_context.n = 5;
break;
case 4:
_context.p = 4;
_t = _context.v;
verbose && console.log('createSpeech error', _t);
return _context.a(2);
case 5:
return _context.a(2, buffer);
}
}, _callee, null, [[1, 4]]);
}));
return _createSpeech.apply(this, arguments);
}
function saveSpeech(_x3, _x4) {
return _saveSpeech.apply(this, arguments);
}
/**
* Pass json to chatGPT and ask it to extract the text for speech using gpt4.
*
* @async
* @param {Object} json - The JSON object containing the data to extract text from.
* @param {string} [apikey] - The OpenAI API key. If not provided, it will use the environment variable 'OPENAI_API_KEY'.
* @param {string} [model='gpt-4o-mini'] - The text model to use.
* @param {boolean} [verbose=false] - If set to true, enables verbose logging for detailed information.
* @returns {string|null} The extracted text from the JSON object, or null if an error occurs or no API key is provided.
* @throws {Error} Logs an error to the console if there is an error in fetching or processing the request and verbose is true.
* @memberof module:create_audio
*/
function _saveSpeech() {
_saveSpeech = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(mp3SaveFilePath, buffer) {
var verbose,
_args2 = arguments,
_t2;
return _regenerator().w(function (_context2) {
while (1) switch (_context2.p = _context2.n) {
case 0:
verbose = _args2.length > 2 && _args2[2] !== undefined ? _args2[2] : false;
_context2.p = 1;
_context2.n = 2;
return fs__WEBPACK_IMPORTED_MODULE_0__.promises.writeFile(mp3SaveFilePath, buffer);
case 2:
verbose && console.log("Audio saved to ".concat(mp3SaveFilePath));
_context2.n = 4;
break;
case 3:
_context2.p = 3;
_t2 = _context2.v;
verbose && console.log('saveSpeech error', _t2);
case 4:
return _context2.a(2);
}
}, _callee2, null, [[1, 3]]);
}));
return _saveSpeech.apply(this, arguments);
}
function getTextFromJson(_x5, _x6) {
return _getTextFromJson.apply(this, arguments);
}
/**
* Converts all JSON files in a directory to speech files.
* Recursively processes directories and skips non-JSON files.
*
* @async
* @param {string} fromFolder - The directory containing JSON files.
* @param {string} toFolder - The directory where the resulting MP3 files will be saved.
* @param {string} [apikey] - The OpenAI API key. If not provided, it will use the environment variable 'OPENAI_API_KEY'.
* @param {boolean} [verbose=false] - If set to true, enables verbose logging for detailed information.
* @returns {void} Does not return a value; processes files in place.
* @throws {Error} Logs an error to the console if there is a failure in reading the directory or processing files and verbose is true.
* @memberof module:create_audio
*/
function _getTextFromJson() {
_getTextFromJson = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(json, apikey) {
var model,
verbose,
text,
requestBody,
response,
_data,
responseData,
_args3 = arguments,
_t3;
return _regenerator().w(function (_context3) {
while (1) switch (_context3.p = _context3.n) {
case 0:
model = _args3.length > 2 && _args3[2] !== undefined ? _args3[2] : 'gpt-4o-mini';
verbose = _args3.length > 3 && _args3[3] !== undefined ? _args3[3] : false;
if (!apikey) {
apikey = process.env.OPENAI_API_KEY;
}
if (apikey) {
_context3.n = 1;
break;
}
verbose && console.log('No API Key provided and \"env.OPENAI_API_KEY\" not found.');
return _context3.a(2);
case 1:
_context3.p = 1;
text = !json.title ? '' : "Title: ".concat(json.title, " \n ");
text += !json.summary ? '' : "Summary: ".concat(json.summary, " \n ");
text += "Content: ".concat(JSON.stringify(json.content));
requestBody = {
model: model,
messages: [{
"role": "system",
"content": "\nYou are an assistant to a webpage to audio service. \nYou will be given a webpage you must convert it to a form of text ready for reading aloud.\nStart every conversion with a statement \"You are listening to the audio version of this webpage\" followed by the title and summary.\nUnder no circumstances should code be read and should be paraphrased or skipped. \n"
}, {
"role": "user",
"content": text
}]
};
_context3.n = 2;
return fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': "Bearer ".concat(apikey),
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
case 2:
response = _context3.v;
_context3.n = 3;
return response.json();
case 3:
responseData = _context3.v;
_data = responseData.choices[0].message.content;
_context3.n = 5;
break;
case 4:
_context3.p = 4;
_t3 = _context3.v;
verbose && console.log('getTextFromJson error', _t3);
return _context3.a(2);
case 5:
return _context3.a(2, data);
}
}, _callee3, null, [[1, 4]]);
}));
return _getTextFromJson.apply(this, arguments);
}
function speechFromDir(_x7, _x8, _x9) {
return _speechFromDir.apply(this, arguments);
}
function _speechFromDir() {
_speechFromDir = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(fromFolder, toFolder, apikey) {
var verbose,
files,
i,
filename,
stat,
_json$meta,
file,
json,
text,
buffer,
_file,
savePath,
_args4 = arguments,
_t4;
return _regenerator().w(function (_context4) {
while (1) switch (_context4.p = _context4.n) {
case 0:
verbose = _args4.length > 3 && _args4[3] !== undefined ? _args4[3] : false;
if (!apikey) {
apikey = process.env.OPENAI_API_KEY;
}
if (apikey) {
_context4.n = 1;
break;
}
verbose && console.log('No API Key provided and \"env.OPENAI_API_KEY\" not found.');
return _context4.a(2);
case 1:
_context4.p = 1;
files = fs__WEBPACK_IMPORTED_MODULE_0__.readdirSync(fromFolder);
i = 0;
case 2:
if (!(i < files.length)) {
_context4.n = 7;
break;
}
filename = path__WEBPACK_IMPORTED_MODULE_1__.join(fromFolder, files[i]);
stat = fs__WEBPACK_IMPORTED_MODULE_0__.lstatSync(filename);
if (!stat.isDirectory()) {
_context4.n = 3;
break;
}
speechFromDir(filename, toFolder); //recurse
_context4.n = 6;
break;
case 3:
if (!(filename.indexOf('.json') >= 0)) {
_context4.n = 6;
break;
}
file = fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(filename, 'utf8');
json = JSON.parse(file);
if (!(json !== null && json !== void 0 && (_json$meta = json.meta) !== null && _json$meta !== void 0 && _json$meta.audio)) {
_context4.n = 6;
break;
}
_context4.n = 4;
return getTextFromJson(json);
case 4:
text = _context4.v;
_context4.n = 5;
return createSpeech(text, apikey);
case 5:
buffer = _context4.v;
_file = files[i].substring(0, files[i].length - 5); // console.log('file', file)
savePath = path__WEBPACK_IMPORTED_MODULE_1__.join(toFolder, _file) + '.mp3'; // console.log('savePath', savePath)
saveSpeech(savePath, buffer);
case 6:
i++;
_context4.n = 2;
break;
case 7:
_context4.n = 9;
break;
case 8:
_context4.p = 8;
_t4 = _context4.v;
verbose && console.log('speechFromDir error', _t4);
return _context4.a(2);
case 9:
return _context4.a(2);
}
}, _callee4, null, [[1, 8]]);
}));
return _speechFromDir.apply(this, arguments);
}
/***/ }),
/***/ 383:
/***/ ((module) => {
module.exports = require("fs");
/***/ }),
/***/ 799:
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
convertNb: () => (/* binding */ convertNb),
get_metadata: () => (/* binding */ get_metadata),
nb2json: () => (/* binding */ nb2json)
});
;// external "marked"
const external_marked_namespaceObject = require("marked");
// EXTERNAL MODULE: ./src/convert_util.mjs
var convert_util = __webpack_require__(50);
;// ./src/convert.mjs
function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
/**
* @fileOverview Houses the core [nb2json](module-convert.html#.nb2json) function and accompanying utils.
* Functions exposed from [browser](module-Ipynb2web_browser.html) and [node](module-Ipynb2web_node.html).
*
* Where processing happens
* - -1 - Calling nb2json - yaml filename returned gets formatted
* - 0 - nb2json - meta.filename is fixed up right before returning too
* - 0 - nb2json - meta.prettify inserts script
* - 0 - nb2json - replaceEmojies
* - 0 - nb2json - convertNotes
* - 1 - get_metadata - yaml is parsed, title, summary, keyValues set
*
* @module convert
* @exports {Object} - An object containing utility functions.
* @author Charles Karpati
*/
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// fname = ./src/ipynb/route/filename (wihout the .ipynb extension, when server calling it)
// fname = /route/filename when from client
// meta.filename = fname UNDERCASED WITH SPACES REPLACED WITH UNDERSCORES.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var prettify = false;
var pyCode = [];
/**
* Converts a Jupyter Notebook (.ipynb) file to a JSON object containing metadata and content as two distinct entries.
*
* @async
* @param {string} ipynbPath - The path to the Jupyter Notebook file.
* @param {boolean} [verbose=false] - If set to true, enables verbose logging for detailed information.
* @returns {Object} An object with metadata and processed content of the notebook.
* @memberof module:convert
*/
function nb2json(_x) {
return _nb2json.apply(this, arguments);
}
/**
* Extracts metadata from the first cell of a Jupyter Notebook, interpreting it as YAML.
* Get markdown and check EACH LINE for yaml. Special characters must have a space after them.
*
* The Lines:
* ```
* # Title
* > summary
* - key1: value1"
* ```
* Will return:
* ```
* { title: "Title", summary: "summary", key1: "value1" }
* ```
*
* @param {Object[]} data - An array of cells from a Jupyter Notebook.
* @returns {Object} An object containing extracted metadata like title, summary, and key-values.
*/
function _nb2json() {
_nb2json = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(ipynbPath) {
var verbose,
url,
ipynb,
nb,
meta,
content,
resp,
_args = arguments;
return _regenerator().w(function (_context) {
while (1) switch (_context.n) {
case 0:
verbose = _args.length > 1 && _args[1] !== undefined ? _args[1] : false;
pyCode = [];
prettify = false;
url = ipynbPath;
if (typeof process !== "undefined" && !ipynbPath.startsWith("http")) {
url = "http://localhost:8085/".concat(ipynbPath, ".ipynb");
}
_context.n = 1;
return fetch(url, {
headers: {
"Content-Type": "application/json; charset=utf-8"
}
});
case 1:
ipynb = _context.v;
_context.n = 2;
return ipynb.json();
case 2:
nb = _context.v;
// console.log('nb', nb);
meta = get_metadata(nb.cells[0]);
meta.filename = ipynbPath.split("/")[ipynbPath.split("/").length - 1].toLowerCase().replaceAll(" ", "_");
verbose && console.log('- get_metadata', meta, '\n');
// Convert file
content = convertNb(nb.cells.slice(1), meta, verbose).flat().join(" ");
verbose && pyCode.length && console.log({
pyCode: pyCode
});
meta.pyCode = pyCode;
(meta.prettify || prettify) && (content += "\n <script src=\"https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js\"></script>\n <link rel=\"stylesheet\" href=\"https://cdn.rawgit.com/google/code-prettify/master/styles/desert.css\"/>\n ");
// verbose && console.log('- - content Ran ~~~~~~~~~~~', content, '~~~~~~~~~~~\n');
resp = (0,convert_util/* replaceEmojis */.e4)(content);
verbose && console.log('- - replaceEmojis Ran', '\n');
return _context.a(2, {
meta: meta,
content: resp
});
}
}, _callee);
}));
return _nb2json.apply(this, arguments);
}
function get_metadata(data) {
var returnThis = {};
var _iterator = _createForOfIteratorHelper(data.source),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var line = _step.value;
if (line.startsWith("#")) {
returnThis.title = line.replaceAll("\n", "").replaceAll("# ", "", 2);
} else if (line.startsWith(">")) {
returnThis.summary = line.replaceAll("\n", "").replaceAll("> ", "", 1);
} else if (line.startsWith("-")) {
var key = line.slice(line.indexOf("- ") + 2, line.indexOf(": "));
var val = line.slice(line.indexOf(": ") + 2).replaceAll("\n", "").trim();
returnThis[key] = val;
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return returnThis;
}
/**
* Processes each cell of a Jupyter Notebook and returns an array of converted content.
*
* @param {Object[]} cells - An array of cells from a Jupyter Notebook.
* @param {Object} meta - Metadata associated with the notebook.
* @param {boolean} [verbose=false] - If set to true, enables verbose logging for detailed information.
* @returns {string[]} An array of strings representing the processed content of each cell.
*/
function convertNb(cells, meta) {
var verbose = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
verbose && console.group('- convertNb Running');
var returnThis = cells.map(function (c) {
return cleanCell(c, meta, verbose);
});
verbose && console.groupEnd();
return returnThis;
}
/**
* Processes an individual cell from a Jupyter Notebook, handling either markdown or code cells.
* Returns text or passes cell to 'code cell' processor
*
* @param {Object} cell - A cell from a Jupyter Notebook.
* @param {Object} meta - Metadata associated with the notebook.
* @param {boolean} [verbose=false] - If set to true, enables verbose logging for detailed information.
* @returns {string} The processed content of the cell.
*/
function cleanCell(cell, meta) {
var verbose = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
var x;
if (cell["cell_type"] == "markdown") {
x = processMarkdown(cell["source"].join(" "));
// verbose && console.log('- - - Parsing Markdown', x);
} else {
// verbose && console.log('- - Parsing Code');//, cell ,'\n');
x = processCode(cell, meta, verbose);
}
return x;
}
/**
* Processes markdown content, converting it to HTML, handling special syntax, and applying transformations.
*
* @param {string} x - The markdown content to be processed.
* @returns {string} The processed HTML content.
*/
function processMarkdown(txt) {
// Does not process markdown wrapped in html
var x = (0,external_marked_namespaceObject.marked)(txt);
// Two spaces at lines end transform into line breaks
x = x.replace(/\s{2,}<\/p>/g, "</p><br>");
// Remove newline chars even though they dont get rendered.
// x = x.replace(/\n/g, '');
// replace code blocks with pre.prettyprint
x = (0,convert_util/* replaceAndLog */.Wl)(x, /<pre><code>([\s\S]*?)<\/code><\/pre>/g, function (match, content) {
prettify = true;
return "<pre class='prettyprint'>".concat(content, "</pre>");
});
// Single line code blocks do NOT get prettified
// x = replaceAndLog(x, /<code>([\s\S]*?)<\/code>/g, (match, content) => { prettify = true; return `<pre class='prettyprint' style='display:inline'>${content}</pre>`; });
// Open links in new tab
x = (0,convert_util/* replaceAndLog */.Wl)(x, /<a\s+(?:[^>]*?\s+)?href="(.*?)"/g, function (match, href) {
if (!href.startsWith("./")) {
match += ' target="_blank" rel="nosopener noreferrer nofollow"';
}
return match;
});
// x = createSpans(createInlineFootnotes(createElement(str))
x = (0,convert_util/* convertNotes */.zX)(x);
return x;
}
/**
* Processes a code cell from a Jupyter Notebook, applying various transformations based on flags and output type.
*
* Calls [getFlags](module-convert.html#.getFlags), [processSource](module-convert.html#.processSource), [processOutput](module-convert.html#.processOutput)
*
* @param {Object} cell - A code cell from a Jupyter Notebook.
* @param {Object} meta - Metadata associated with the notebook.
* @param {boolean} [verbose=false] - If set to true, enables verbose logging for detailed information.
* @returns {string[]} An array of strings representing the processed content of the code cell.
*/
function processCode(cell, meta) {
var verbose = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
// verbose && console.log('- - - processCode Running');
var x = [];
var flags = [];
// source
// verbose && console.group('ProcessCode');
if (cell["source"].length) {
var source = cell["source"];
flags = getFlags(source[0]);
// verbose && console.log('Input: ', {'Raw': cell['source'], 'Flags': flags } )
if (flags.length > 0) {
source = source.slice(1);
}
source = processSource(source.join(" "), flags, meta);
x.push(source);
}
// output
if (cell["outputs"].length) {
// verbose && console.log(flags, cell['outputs'])
var _iterator2 = _createForOfIteratorHelper(cell["outputs"]),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var o = _step2.value;
x.push(processOutput(o, flags));
}
// clear_output();
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
// verbose && console.groupEnd();
return x;
}
/**
* Detects special flags in the source code of a notebook cell and handles them accordingly.
*
* @memberof module:convert
* @param {string} source - The source code of a notebook cell.
* @returns {string[]} An array of detected flags in the cell's source code.
*/
function getFlags(source) {
var input_aug = ["#collapse_input_open", "#collapse_input", "#collapse_output_open", "#collapse_output", "#hide_input", "#hide_output", "#hide", "%%capture", "%%javascript", "%%html", "#export"];
var sourceFlags = source.split(/\s+/); // Split by whitespace
return input_aug.filter(function (x) {
return sourceFlags.includes(x);
});
}
/**
* Processes the source of a code cell, applying transformations based on flags and metadata.
* Strip Flags from text, make details, hide all. Append to pyCode
*
* @memberof module:convert
* @param {string} source - The source code of a notebook cell.
* @param {string[]} flags - An array of flags affecting the processing.
* @param {Object} meta - Metadata associated with the notebook.
* @param {boolean} [verbose=false] - If set to true, enables verbose logging for detailed information.
* @returns {string} The processed source code.
*/
function processSource(source, flags, meta) {
var verbose = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
if ('#export' == flags[flags.length - 1]) {
pyCode.push(source);
}
var _iterator3 = _createForOfIteratorHelper(flags),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var _lbl = _step3.value;
var skipList = ["#hide", "#hide_input", "%%javascript", "%%html", "%%capture"];
if (skipList.includes(_lbl)) {
return "";
}
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
if (meta.prettify) {
source = "<pre class='prettyprint'>".concat(source, "</pre>");
}
var flagg = flags && !!flags.includes('#collapse_input_open');
if (flagg) {
verbose && console.log(flags);
var _iterator4 = _createForOfIteratorHelper(flags),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var lbl = _step4.value;
source = source.replaceAll(lbl + "\r\n", "");
source = source.replaceAll(lbl + "\n", ""); // Strip the Flag
if (lbl == "#collapse_input_open") source = (0,convert_util/* makeDetails */.nm)(source, true);else if (lbl == "#collapse_input") source = (0,convert_util/* makeDetails */.nm)(source, false);
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
return source;
}
}
/**
* Processes the output of a code cell, applying transformations based on flags and output type.
* Strip Flags from output, make details, hide all.
*
* @function processOutput
* @memberof module:convert
* @param {Object} source - The output of a code cell.
* @param {string[]} flags - An array of flags affecting the processing.
* @param {boolean} [verbose=false] - If set to true, enables verbose logging for detailed information.
* @returns {string} The processed output content.
*/
function processOutput(source, flags) {
var verbose = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
if (source["output_type"] == "error") {
return "";
}
if (source["output_type"] == "stream") {
if (source["name"] == "stderr") {
return "";
}
source["data"] = {
"text/html": source["text"]
};
}
var keys = Object.keys(source["data"]);
if (keys.includes("text/html")) {
source = source["data"]["text/html"];
source = source.join("");
} else if (keys.includes("application/javascript")) {
source = "<script>" + source["data"]["application/javascript"] + "</script>";
} else if (keys.includes("image/png")) {
source = '<img src="data:image/png;base64,' + source["data"]["image/png"] + "\" alt='Image Alt Text'>";
} else if (keys.includes("text/plain")) {
source = !/<Figure/.test(source["data"]["text/plain"]) ? source["data"]["text/plain"] : "";
}
var _iterator5 = _createForOfIteratorHelper(flags),
_step5;
try {
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var lbl = _step5.value;
try {
source = source.replaceAll(lbl + "\r\n", "");
source = source.replaceAll(lbl + "\n", "");
} catch (_unused) {
verbose && console.log("ERROR: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!processOutput... ", _typeof(source), source);
}
if (lbl == "#collapse_output_open") {
source = (0,convert_util/* makeDetails */.nm)(source, true);
}
if (lbl == "#collapse_output") {
source = (0,convert_util/* makeDetails */.nm)(source, false);
}
if (lbl == "#hide_output") {
source = "";
}
if (lbl == "#hide") {
source = "";
}
}
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
return source;
//output_type == 'stream' ==> text
//output_type == 'display_data' ==> data{'application/javascript' or 'text/html' or 'execute_result'}
}
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
"default": () => (/* binding */ node),
ipynb2web: () => (/* binding */ ipynb2web)
});
// EXTERNAL MODULE: external "fs"
var external_fs_ = __webpack_require__(383);
// EXTERNAL MODULE: external "path"
var external_path_ = __webpack_require__(3);
;// external "http-server"
const external_http_server_namespaceObject = require("http-server");
;// ./src/prerender.mjs
var _excluded = ["csp", "sitemap", "breadcrumbs", "badges", "keywords", "comments", "hide", "image", "toc", "title"],
_excluded2 = ["csp", "sitemap", "breadcrumbs", "badges", "keywords", "comments", "hide", "image", "toc", "title"];
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0;