diff --git a/.eslintignore b/.eslintignore index 069b17363..71a1c0380 100644 --- a/.eslintignore +++ b/.eslintignore @@ -50,3 +50,4 @@ ElectronClient/app/packageInfo.js # Ignore files generated from TypeScript files ElectronClient/app/gui/ShareNoteDialog.js ReactNativeClient/lib/JoplinServerApi.js +ReactNativeClient/pluginAssetsLoader.js diff --git a/.gitignore b/.gitignore index f930ed530..300905eb6 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ Tools/commit_hook.txt # Ignore files generated from TypeScript files ElectronClient/app/gui/ShareNoteDialog.js ReactNativeClient/lib/JoplinServerApi.js +ReactNativeClient/pluginAssetsLoader.js diff --git a/CliClient/package-lock.json b/CliClient/package-lock.json index 32f0f9802..760c425d8 100644 --- a/CliClient/package-lock.json +++ b/CliClient/package-lock.json @@ -806,6 +806,11 @@ "debug": "^2.6.9" } }, + "font-awesome-filetypes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/font-awesome-filetypes/-/font-awesome-filetypes-2.1.0.tgz", + "integrity": "sha512-U6hi14GRjfZFIWsTNyVmCBuHyPhiizWEKVbaQqHipKQv3rA1l1PNvmKulzpqxonFnQMToty5ZhfWbc/0IjLDGA==" + }, "for-each-property": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/for-each-property/-/for-each-property-0.0.4.tgz", @@ -959,6 +964,24 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, + "handlebars": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", + "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -1533,6 +1556,75 @@ "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", "dev": true }, + "joplin-renderer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/joplin-renderer/-/joplin-renderer-1.0.4.tgz", + "integrity": "sha512-Q7GoEYA6hYtv8ZQgxccn/gSw25V8kQPyWdolK0PJhG7m2BJa0zunyagtaOhMkYuWl8beDYHwTsvsVx2ayKqMcQ==", + "requires": { + "base-64": "^0.1.0", + "font-awesome-filetypes": "^2.1.0", + "fs-extra": "^8.1.0", + "highlight.js": "^9.17.1", + "html-entities": "^1.2.1", + "katex": "^0.11.1", + "markdown-it": "^10.0.0", + "markdown-it-abbr": "^1.0.4", + "markdown-it-anchor": "^5.2.5", + "markdown-it-deflist": "^2.0.3", + "markdown-it-emoji": "^1.4.0", + "markdown-it-footnote": "^3.0.2", + "markdown-it-ins": "^3.0.0", + "markdown-it-mark": "^3.0.0", + "markdown-it-multimd-table": "^4.0.0", + "markdown-it-sub": "^1.0.0", + "markdown-it-sup": "^1.0.0", + "markdown-it-toc-done-right": "^4.1.0", + "md5": "^2.2.1", + "uslug": "^1.0.4" + }, + "dependencies": { + "entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + }, + "highlight.js": { + "version": "9.17.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.17.1.tgz", + "integrity": "sha512-TA2/doAur5Ol8+iM3Ov7qy3jYcr/QiJ2eDTdRF4dfbjG7AaaB99J5G+zSl11ljbl6cIcahgPY6SKb3sC3EJ0fw==", + "requires": { + "handlebars": "^4.5.3" + } + }, + "markdown-it": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "requires": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + } + } + }, "joplin-turndown": { "version": "4.0.19", "resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.19.tgz", @@ -1636,6 +1728,21 @@ "resolved": "https://registry.npmjs.org/jssha/-/jssha-2.3.1.tgz", "integrity": "sha1-FHshJTaQNcpLL30hDcU58Amz3po=" }, + "katex": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.11.1.tgz", + "integrity": "sha512-5oANDICCTX0NqYIyAiFCCwjQ7ERu3DQG2JFHLbYOf+fXaMoH8eg/zOq5WSYJsKMi/QebW+Eh3gSM+oss1H/bww==", + "requires": { + "commander": "^2.19.0" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + } + } + }, "klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", @@ -1755,6 +1862,64 @@ "uc.micro": "^1.0.5" } }, + "markdown-it-abbr": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/markdown-it-abbr/-/markdown-it-abbr-1.0.4.tgz", + "integrity": "sha1-1mtTZFIcuz3Yqlna37ovtoZcj9g=" + }, + "markdown-it-anchor": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.2.5.tgz", + "integrity": "sha512-xLIjLQmtym3QpoY9llBgApknl7pxAcN3WDRc2d3rwpl+/YvDZHPmKscGs+L6E05xf2KrCXPBvosWt7MZukwSpQ==" + }, + "markdown-it-deflist": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/markdown-it-deflist/-/markdown-it-deflist-2.0.3.tgz", + "integrity": "sha512-/BNZ8ksW42bflm1qQLnRI09oqU2847Z7MVavrR0MORyKLtiUYOMpwtlAfMSZAQU9UCvaUZMpgVAqoS3vpToJxw==" + }, + "markdown-it-emoji": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", + "integrity": "sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=" + }, + "markdown-it-footnote": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-3.0.2.tgz", + "integrity": "sha512-JVW6fCmZWjvMdDQSbOT3nnOQtd9iAXmw7hTSh26+v42BnvXeVyGMDBm5b/EZocMed2MbCAHiTX632vY0FyGB8A==" + }, + "markdown-it-ins": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-3.0.0.tgz", + "integrity": "sha512-+vyAdBuMGwmT2yMlAFJSx2VR/0QZ1onQ/Mkkmr4l9tDFOh5sVoAgRbkgbuSsk+sxJ9vaMH/IQ323ydfvQrPO/Q==" + }, + "markdown-it-mark": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-3.0.0.tgz", + "integrity": "sha512-HqMWeKfMMOu4zBO0emmxsoMWmbf2cPKZY1wP6FsTbKmicFfp5y4L3KXAsNeO1rM6NTJVOrNlLKMPjWzriBGspw==" + }, + "markdown-it-multimd-table": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-4.0.0.tgz", + "integrity": "sha512-kdM3fH+/sRMfHQgD2CM1BcIpLNODUCuoiFr6TwS7mDJBYntVXDJxZbFwGDRflIc9ZzAfsUbr0lnHc6RbYafIsw==", + "requires": { + "markdown-it": "^8.4.2" + } + }, + "markdown-it-sub": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz", + "integrity": "sha1-N1/WAm6ufdywEkl/ZBEZXqHjr+g=" + }, + "markdown-it-sup": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz", + "integrity": "sha1-y5yf+RpSVawI8/09YyhuFd8KH8M=" + }, + "markdown-it-toc-done-right": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/markdown-it-toc-done-right/-/markdown-it-toc-done-right-4.1.0.tgz", + "integrity": "sha512-UhD2Oj6cZV3ycYPoelt4hTkwKIK3zbPP1wjjdpCq7UGtWQOFalDFDv1s2zBYV6aR2gMs/X8kpJcOYsQmUbiXDw==" + }, "md5": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", @@ -1911,6 +2076,11 @@ } } }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + }, "nextgen-events": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/nextgen-events/-/nextgen-events-1.3.0.tgz", @@ -2089,6 +2259,15 @@ "wrappy": "1" } }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, "optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -3205,6 +3384,11 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" }, + "unorm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", + "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==" + }, "unpack-string": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/unpack-string/-/unpack-string-0.0.2.tgz", @@ -3244,6 +3428,14 @@ "requires-port": "^1.0.0" } }, + "uslug": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/uslug/-/uslug-1.0.4.tgz", + "integrity": "sha1-uaIvCRTgqGFAYz2swwLl9PpFBnc=", + "requires": { + "unorm": ">= 1.0.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -3333,6 +3525,11 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, "wordwrapjs": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-3.0.0.tgz", diff --git a/CliClient/package.json b/CliClient/package.json index bce8af198..3013a0bc8 100644 --- a/CliClient/package.json +++ b/CliClient/package.json @@ -44,6 +44,7 @@ "html-minifier": "^3.5.15", "image-data-uri": "^2.0.0", "image-type": "^3.0.0", + "joplin-renderer": "^1.0.4", "joplin-turndown": "^4.0.19", "joplin-turndown-plugin-gfm": "^1.0.11", "jssha": "^2.3.0", diff --git a/ElectronClient/app/app.js b/ElectronClient/app/app.js index dd26548ce..e245fdb92 100644 --- a/ElectronClient/app/app.js +++ b/ElectronClient/app/app.js @@ -6,6 +6,7 @@ const Setting = require('lib/models/Setting.js'); const { shim } = require('lib/shim.js'); const MasterKey = require('lib/models/MasterKey'); const Note = require('lib/models/Note'); +const { MarkupToHtml } = require('joplin-renderer'); const { _, setLocale } = require('lib/locale.js'); const { Logger } = require('lib/logger.js'); const fs = require('fs-extra'); @@ -1132,7 +1133,7 @@ class Application extends BaseApplication { for (const itemId of ['copy', 'paste', 'cut', 'selectAll', 'bold', 'italic', 'link', 'code', 'insertDateTime', 'commandStartExternalEditing', 'setTags', 'showLocalSearch']) { const menuItem = Menu.getApplicationMenu().getMenuItemById(`edit:${itemId}`); if (!menuItem) continue; - menuItem.enabled = !!note && note.markup_language === Note.MARKUP_LANGUAGE_MARKDOWN; + menuItem.enabled = !!note && note.markup_language === MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN; } const menuItem = Menu.getApplicationMenu().getMenuItemById('help:toggleDevTools'); diff --git a/ElectronClient/app/gui/NoteRevisionViewer.jsx b/ElectronClient/app/gui/NoteRevisionViewer.jsx index 6fc3eafa1..61e787475 100644 --- a/ElectronClient/app/gui/NoteRevisionViewer.jsx +++ b/ElectronClient/app/gui/NoteRevisionViewer.jsx @@ -6,16 +6,16 @@ const NoteTextViewer = require('./NoteTextViewer.min'); const HelpButton = require('./HelpButton.min'); const BaseModel = require('lib/BaseModel'); const Revision = require('lib/models/Revision'); -const Note = require('lib/models/Note'); const urlUtils = require('lib/urlUtils'); const Setting = require('lib/models/Setting'); const RevisionService = require('lib/services/RevisionService'); const shared = require('lib/components/shared/note-screen-shared.js'); -const MarkupToHtml = require('lib/renderers/MarkupToHtml'); +const { MarkupToHtml } = require('joplin-renderer'); const { time } = require('lib/time-utils.js'); const ReactTooltip = require('react-tooltip'); const { urlDecode, substrWithEllipsis } = require('lib/string-utils'); const { bridge } = require('electron').remote.require('./bridge'); +const markupLanguageUtils = require('lib/markupLanguageUtils'); class NoteRevisionViewerComponent extends React.PureComponent { constructor() { @@ -101,7 +101,7 @@ class NoteRevisionViewerComponent extends React.PureComponent { async reloadNote() { let noteBody = ''; - let markupLanguage = Note.MARKUP_LANGUAGE_MARKDOWN; + let markupLanguage = MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN; if (!this.state.revisions.length || !this.state.currentRevId) { noteBody = _('This note has no history'); this.setState({ note: null }); @@ -116,18 +116,18 @@ class NoteRevisionViewerComponent extends React.PureComponent { const theme = themeStyle(this.props.theme); - const markupToHtml = new MarkupToHtml({ + const markupToHtml = markupLanguageUtils.newMarkupToHtml({ resourceBaseUrl: `file://${Setting.value('resourceDir')}/`, }); - const result = markupToHtml.render(markupLanguage, noteBody, theme, { + const result = await markupToHtml.render(markupLanguage, noteBody, theme, { codeTheme: theme.codeThemeCss, userCss: this.props.customCss ? this.props.customCss : '', resources: await shared.attachedResources(noteBody), postMessageSyntax: 'ipcProxySendToHost', }); - this.viewerRef_.current.wrappedInstance.send('setHtml', result.html, { cssFiles: result.cssFiles }); + this.viewerRef_.current.wrappedInstance.send('setHtml', result.html, { cssFiles: result.cssFiles, pluginAssets: result.pluginAssets }); } async webview_ipcMessage(event) { diff --git a/ElectronClient/app/gui/NoteText.jsx b/ElectronClient/app/gui/NoteText.jsx index 12e99ebf1..00cba4dce 100644 --- a/ElectronClient/app/gui/NoteText.jsx +++ b/ElectronClient/app/gui/NoteText.jsx @@ -15,7 +15,7 @@ const TagList = require('./TagList.min.js'); const { connect } = require('react-redux'); const { _ } = require('lib/locale.js'); const { reg } = require('lib/registry.js'); -const MarkupToHtml = require('lib/renderers/MarkupToHtml'); +const { MarkupToHtml } = require('joplin-renderer'); const shared = require('lib/components/shared/note-screen-shared.js'); const { bridge } = require('electron').remote.require('./bridge'); const { themeStyle } = require('../theme.js'); @@ -41,6 +41,7 @@ const SearchEngine = require('lib/services/SearchEngine'); const NoteTextViewer = require('./NoteTextViewer.min'); const NoteRevisionViewer = require('./NoteRevisionViewer.min'); const TemplateUtils = require('lib/TemplateUtils'); +const markupLanguageUtils = require('lib/markupLanguageUtils'); require('brace/mode/markdown'); // https://ace.c9.io/build/kitchen-sink.html @@ -111,6 +112,7 @@ class NoteTextComponent extends React.Component { newAndNoTitleChangeNoteId: null, bodyHtml: '', lastRenderCssFiles: [], + lastRenderPluginAssets: [], lastKeys: [], showLocalSearch: false, localSearch: Object.assign({}, this.localSearchDefaultState), @@ -401,9 +403,11 @@ class NoteTextComponent extends React.Component { markupToHtml() { if (this.markupToHtml_) return this.markupToHtml_; - this.markupToHtml_ = new MarkupToHtml({ + + this.markupToHtml_ = markupLanguageUtils.newMarkupToHtml({ resourceBaseUrl: `file://${Setting.value('resourceDir')}/`, }); + return this.markupToHtml_; } @@ -1048,10 +1052,10 @@ class NoteTextComponent extends React.Component { if (bodyToRender === null) { bodyToRender = this.state.note && this.state.note.body ? this.state.note.body : ''; - markupLanguage = this.state.note ? this.state.note.markup_language : Note.MARKUP_LANGUAGE_MARKDOWN; + markupLanguage = this.state.note ? this.state.note.markup_language : MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN; } - if (!markupLanguage) markupLanguage = Note.MARKUP_LANGUAGE_MARKDOWN; + if (!markupLanguage) markupLanguage = MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN; const resources = await shared.attachedResources(bodyToRender); @@ -1072,11 +1076,11 @@ class NoteTextComponent extends React.Component { bodyToRender = `${_('This note has no content. Click on "%s" to toggle the editor and edit the note.', _('Layout'))}`; } - const result = this.markupToHtml().render(markupLanguage, bodyToRender, theme, mdOptions); + const result = await this.markupToHtml().render(markupLanguage, bodyToRender, theme, mdOptions); this.setState({ bodyHtml: result.html, - lastRenderCssFiles: result.cssFiles, + lastRenderPluginAssets: result.pluginAssets, }); } @@ -1630,7 +1634,7 @@ class NoteTextComponent extends React.Component { }); } - if (note.markup_language === Note.MARKUP_LANGUAGE_MARKDOWN && editorIsVisible) { + if (note.markup_language === MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN && editorIsVisible) { toolbarItems.push({ tooltip: _('Bold'), iconName: 'fa-bold', @@ -1858,7 +1862,7 @@ class NoteTextComponent extends React.Component { const style = this.props.style; const note = this.state.note; const body = note && note.body ? note.body : ''; - const markupLanguage = note ? note.markup_language : Note.MARKUP_LANGUAGE_MARKDOWN; + const markupLanguage = note ? note.markup_language : MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN; const theme = themeStyle(this.props.theme); const visiblePanes = this.props.visiblePanes || ['editor', 'viewer']; const isTodo = note && !!note.is_todo; @@ -1999,7 +2003,7 @@ class NoteTextComponent extends React.Component { const htmlHasChanged = this.lastSetHtml_ !== html; if (htmlHasChanged) { let options = { - cssFiles: this.state.lastRenderCssFiles, + pluginAssets: this.state.lastRenderPluginAssets, downloadResources: Setting.value('sync.resourceDownloadMode'), }; this.webviewRef_.current.wrappedInstance.send('setHtml', html, options); diff --git a/ElectronClient/app/gui/note-viewer/index.html b/ElectronClient/app/gui/note-viewer/index.html index 5aaa9bcf7..d641ad21b 100644 --- a/ElectronClient/app/gui/note-viewer/index.html +++ b/ElectronClient/app/gui/note-viewer/index.html @@ -66,15 +66,21 @@ } })); - const loadedCssFiles_ = {}; - function loadCssFiles(cssFiles) { - for (let i = 0; i < cssFiles.length; i++) { - const f = cssFiles[i]; - if (loadedCssFiles_[f]) continue; - const link = document.createElement('link'); - link.rel = 'stylesheet'; - link.href = f; - document.getElementById('joplin-container-styleContainer').appendChild(link); + const loadedPluginAssets_ = {} + function loadPluginAssets(assets) { + if (!assets) return; + + for (let i = 0; i < assets.length; i++) { + const asset = assets[i]; + if (loadedPluginAssets_[asset.name]) continue; + loadedPluginAssets_[asset.name] = true; + + if (asset.mime === 'text/css') { + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = 'pluginAssets/' + asset.name; + document.getElementById('joplin-container-styleContainer').appendChild(link); + } } } @@ -154,7 +160,9 @@ }, 1); } - loadCssFiles(event.options.cssFiles); + // loadCssFiles(event.options.cssFiles); + + loadPluginAssets(event.options.pluginAssets); if (event.options.downloadResources === 'manual') { webviewLib.setupResourceManualDownload(); diff --git a/ElectronClient/app/gui/note-viewer/pluginAssets/highlight.js/atom-one-dark-reasonable.css b/ElectronClient/app/gui/note-viewer/pluginAssets/highlight.js/atom-one-dark-reasonable.css new file mode 100644 index 000000000..0a43fe26b --- /dev/null +++ b/ElectronClient/app/gui/note-viewer/pluginAssets/highlight.js/atom-one-dark-reasonable.css @@ -0,0 +1,75 @@ +/* + +Atom One Dark With support for ReasonML by Gidi Morris, based off work by Daniel Gamage + +Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax + +*/ +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #abb2bf; + background: #282c34; +} +.hljs-keyword, .hljs-operator { + color: #F92672; +} +.hljs-pattern-match { + color: #F92672; +} +.hljs-pattern-match .hljs-constructor { + color: #61aeee; +} +.hljs-function { + color: #61aeee; +} +.hljs-function .hljs-params { + color: #A6E22E; +} +.hljs-function .hljs-params .hljs-typing { + color: #FD971F; +} +.hljs-module-access .hljs-module { + color: #7e57c2; +} +.hljs-constructor { + color: #e2b93d; +} +.hljs-constructor .hljs-string { + color: #9CCC65; +} +.hljs-comment, .hljs-quote { + color: #b18eb1; + font-style: italic; +} +.hljs-doctag, .hljs-formula { + color: #c678dd; +} +.hljs-section, .hljs-name, .hljs-selector-tag, .hljs-deletion, .hljs-subst { + color: #e06c75; +} +.hljs-literal { + color: #56b6c2; +} +.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute, .hljs-meta-string { + color: #98c379; +} +.hljs-built_in, .hljs-class .hljs-title { + color: #e6c07b; +} +.hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-type, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-number { + color: #d19a66; +} +.hljs-symbol, .hljs-bullet, .hljs-link, .hljs-meta, .hljs-selector-id, .hljs-title { + color: #61aeee; +} +.hljs-emphasis { + font-style: italic; +} +.hljs-strong { + font-weight: bold; +} +.hljs-link { + text-decoration: underline; +} diff --git a/ElectronClient/app/gui/note-viewer/pluginAssets/highlight.js/atom-one-light.css b/ElectronClient/app/gui/note-viewer/pluginAssets/highlight.js/atom-one-light.css new file mode 100644 index 000000000..d5bd1d2a9 --- /dev/null +++ b/ElectronClient/app/gui/note-viewer/pluginAssets/highlight.js/atom-one-light.css @@ -0,0 +1,96 @@ +/* + +Atom One Light by Daniel Gamage +Original One Light Syntax theme from https://github.com/atom/one-light-syntax + +base: #fafafa +mono-1: #383a42 +mono-2: #686b77 +mono-3: #a0a1a7 +hue-1: #0184bb +hue-2: #4078f2 +hue-3: #a626a4 +hue-4: #50a14f +hue-5: #e45649 +hue-5-2: #c91243 +hue-6: #986801 +hue-6-2: #c18401 + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #383a42; + background: #fafafa; +} + +.hljs-comment, +.hljs-quote { + color: #a0a1a7; + font-style: italic; +} + +.hljs-doctag, +.hljs-keyword, +.hljs-formula { + color: #a626a4; +} + +.hljs-section, +.hljs-name, +.hljs-selector-tag, +.hljs-deletion, +.hljs-subst { + color: #e45649; +} + +.hljs-literal { + color: #0184bb; +} + +.hljs-string, +.hljs-regexp, +.hljs-addition, +.hljs-attribute, +.hljs-meta-string { + color: #50a14f; +} + +.hljs-built_in, +.hljs-class .hljs-title { + color: #c18401; +} + +.hljs-attr, +.hljs-variable, +.hljs-template-variable, +.hljs-type, +.hljs-selector-class, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-number { + color: #986801; +} + +.hljs-symbol, +.hljs-bullet, +.hljs-link, +.hljs-meta, +.hljs-selector-id, +.hljs-title { + color: #4078f2; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-link { + text-decoration: underline; +} diff --git a/ElectronClient/app/gui/note-viewer/pluginAssets/katex/fonts/KaTeX_Main-Regular.woff2 b/ElectronClient/app/gui/note-viewer/pluginAssets/katex/fonts/KaTeX_Main-Regular.woff2 new file mode 100644 index 000000000..e3f71eb7e Binary files /dev/null and b/ElectronClient/app/gui/note-viewer/pluginAssets/katex/fonts/KaTeX_Main-Regular.woff2 differ diff --git a/ElectronClient/app/gui/note-viewer/pluginAssets/katex/fonts/KaTeX_Math-Italic.woff2 b/ElectronClient/app/gui/note-viewer/pluginAssets/katex/fonts/KaTeX_Math-Italic.woff2 new file mode 100644 index 000000000..e3ea522a6 Binary files /dev/null and b/ElectronClient/app/gui/note-viewer/pluginAssets/katex/fonts/KaTeX_Math-Italic.woff2 differ diff --git a/ElectronClient/app/gui/note-viewer/pluginAssets/katex/fonts/KaTeX_Size1-Regular.woff2 b/ElectronClient/app/gui/note-viewer/pluginAssets/katex/fonts/KaTeX_Size1-Regular.woff2 new file mode 100644 index 000000000..483e7b66e Binary files /dev/null and b/ElectronClient/app/gui/note-viewer/pluginAssets/katex/fonts/KaTeX_Size1-Regular.woff2 differ diff --git a/ElectronClient/app/gui/note-viewer/pluginAssets/katex/fonts/KaTeX_Size2-Regular.woff2 b/ElectronClient/app/gui/note-viewer/pluginAssets/katex/fonts/KaTeX_Size2-Regular.woff2 new file mode 100644 index 000000000..5ff706067 Binary files /dev/null and b/ElectronClient/app/gui/note-viewer/pluginAssets/katex/fonts/KaTeX_Size2-Regular.woff2 differ diff --git a/ElectronClient/app/gui/note-viewer/pluginAssets/katex/katex.css b/ElectronClient/app/gui/note-viewer/pluginAssets/katex/katex.css new file mode 100644 index 000000000..c0cd1451a --- /dev/null +++ b/ElectronClient/app/gui/note-viewer/pluginAssets/katex/katex.css @@ -0,0 +1 @@ +@font-face{font-family:KaTeX_AMS;src:url(fonts/KaTeX_AMS-Regular.woff2) format("woff2"),url(fonts/KaTeX_AMS-Regular.woff) format("woff"),url(fonts/KaTeX_AMS-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Caligraphic;src:url(fonts/KaTeX_Caligraphic-Bold.woff2) format("woff2"),url(fonts/KaTeX_Caligraphic-Bold.woff) format("woff"),url(fonts/KaTeX_Caligraphic-Bold.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Caligraphic;src:url(fonts/KaTeX_Caligraphic-Regular.woff2) format("woff2"),url(fonts/KaTeX_Caligraphic-Regular.woff) format("woff"),url(fonts/KaTeX_Caligraphic-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Fraktur;src:url(fonts/KaTeX_Fraktur-Bold.woff2) format("woff2"),url(fonts/KaTeX_Fraktur-Bold.woff) format("woff"),url(fonts/KaTeX_Fraktur-Bold.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Fraktur;src:url(fonts/KaTeX_Fraktur-Regular.woff2) format("woff2"),url(fonts/KaTeX_Fraktur-Regular.woff) format("woff"),url(fonts/KaTeX_Fraktur-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Bold.woff2) format("woff2"),url(fonts/KaTeX_Main-Bold.woff) format("woff"),url(fonts/KaTeX_Main-Bold.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-BoldItalic.woff2) format("woff2"),url(fonts/KaTeX_Main-BoldItalic.woff) format("woff"),url(fonts/KaTeX_Main-BoldItalic.ttf) format("truetype");font-weight:700;font-style:italic}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Italic.woff2) format("woff2"),url(fonts/KaTeX_Main-Italic.woff) format("woff"),url(fonts/KaTeX_Main-Italic.ttf) format("truetype");font-weight:400;font-style:italic}@font-face{font-family:KaTeX_Main;src:url(fonts/KaTeX_Main-Regular.woff2) format("woff2"),url(fonts/KaTeX_Main-Regular.woff) format("woff"),url(fonts/KaTeX_Main-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Math;src:url(fonts/KaTeX_Math-BoldItalic.woff2) format("woff2"),url(fonts/KaTeX_Math-BoldItalic.woff) format("woff"),url(fonts/KaTeX_Math-BoldItalic.ttf) format("truetype");font-weight:700;font-style:italic}@font-face{font-family:KaTeX_Math;src:url(fonts/KaTeX_Math-Italic.woff2) format("woff2"),url(fonts/KaTeX_Math-Italic.woff) format("woff"),url(fonts/KaTeX_Math-Italic.ttf) format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"KaTeX_SansSerif";src:url(fonts/KaTeX_SansSerif-Bold.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Bold.woff) format("woff"),url(fonts/KaTeX_SansSerif-Bold.ttf) format("truetype");font-weight:700;font-style:normal}@font-face{font-family:"KaTeX_SansSerif";src:url(fonts/KaTeX_SansSerif-Italic.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Italic.woff) format("woff"),url(fonts/KaTeX_SansSerif-Italic.ttf) format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"KaTeX_SansSerif";src:url(fonts/KaTeX_SansSerif-Regular.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Regular.woff) format("woff"),url(fonts/KaTeX_SansSerif-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Script;src:url(fonts/KaTeX_Script-Regular.woff2) format("woff2"),url(fonts/KaTeX_Script-Regular.woff) format("woff"),url(fonts/KaTeX_Script-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size1;src:url(fonts/KaTeX_Size1-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size1-Regular.woff) format("woff"),url(fonts/KaTeX_Size1-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size2;src:url(fonts/KaTeX_Size2-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size2-Regular.woff) format("woff"),url(fonts/KaTeX_Size2-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size3;src:url(fonts/KaTeX_Size3-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size3-Regular.woff) format("woff"),url(fonts/KaTeX_Size3-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Size4;src:url(fonts/KaTeX_Size4-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size4-Regular.woff) format("woff"),url(fonts/KaTeX_Size4-Regular.ttf) format("truetype");font-weight:400;font-style:normal}@font-face{font-family:KaTeX_Typewriter;src:url(fonts/KaTeX_Typewriter-Regular.woff2) format("woff2"),url(fonts/KaTeX_Typewriter-Regular.woff) format("woff"),url(fonts/KaTeX_Typewriter-Regular.ttf) format("truetype");font-weight:400;font-style:normal}.katex{font:normal 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;text-indent:0;text-rendering:auto}.katex *{-ms-high-contrast-adjust:none!important}.katex .katex-version:after{content:"0.11.1"}.katex .katex-mathml{position:absolute;clip:rect(1px,1px,1px,1px);padding:0;border:0;height:1px;width:1px;overflow:hidden}.katex .katex-html>.newline{display:block}.katex .base{position:relative;white-space:nowrap;width:min-content}.katex .base,.katex .strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathdefault{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-weight:700;font-style:italic}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{display:inline-table;table-layout:fixed}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;vertical-align:bottom;position:relative}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;vertical-align:bottom;font-size:1px;width:2px;min-width:2px}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{display:inline-block;width:100%;border-bottom-style:solid}.katex .hdashline,.katex .hline,.katex .mfrac .frac-line,.katex .overline .overline-line,.katex .rule,.katex .underline .underline-line{min-height:1px}.katex .mspace{display:inline-block}.katex .clap,.katex .llap,.katex .rlap{width:0;position:relative}.katex .clap>.inner,.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .clap>.fix,.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .clap>.inner,.katex .rlap>.inner{left:0}.katex .clap>.inner>span{margin-left:-50%;margin-right:50%}.katex .rule{display:inline-block;border:0 solid;position:relative}.katex .hline,.katex .overline .overline-line,.katex .underline .underline-line{display:inline-block;width:100%;border-bottom-style:solid}.katex .hdashline{display:inline-block;width:100%;border-bottom-style:dashed}.katex .sqrt>.root{margin-left:.27777778em;margin-right:-.55555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.83333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.16666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.66666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.45666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .sizing.reset-size2.size11{font-size:4.14666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.71428571em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.85714286em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.14285714em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.28571429em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.42857143em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.71428571em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.05714286em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.46857143em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:2.96285714em}.katex .fontsize-ensurer.reset-size3.size11,.katex .sizing.reset-size3.size11{font-size:3.55428571em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.55555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.66666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.77777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.88888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.11111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.33333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.30444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .sizing.reset-size5.size11{font-size:2.76444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.41666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.58333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.66666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.83333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.72833333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .sizing.reset-size7.size11{font-size:2.07333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.34722222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.41666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.48611111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.55555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.69444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.83333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.44027778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .sizing.reset-size8.size11{font-size:1.72777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.28935185em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.34722222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.40509259em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.46296296em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.52083333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.5787037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.69444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.83333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.20023148em}.katex .fontsize-ensurer.reset-size9.size11,.katex .sizing.reset-size9.size11{font-size:1.43981481em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.24108004em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.28929605em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.33751205em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.38572806em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.43394407em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.48216008em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.57859209em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.69431051em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.83317261em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .sizing.reset-size10.size11{font-size:1.19961427em}.katex .fontsize-ensurer.reset-size11.size1,.katex .sizing.reset-size11.size1{font-size:.20096463em}.katex .fontsize-ensurer.reset-size11.size2,.katex .sizing.reset-size11.size2{font-size:.24115756em}.katex .fontsize-ensurer.reset-size11.size3,.katex .sizing.reset-size11.size3{font-size:.28135048em}.katex .fontsize-ensurer.reset-size11.size4,.katex .sizing.reset-size11.size4{font-size:.32154341em}.katex .fontsize-ensurer.reset-size11.size5,.katex .sizing.reset-size11.size5{font-size:.36173633em}.katex .fontsize-ensurer.reset-size11.size6,.katex .sizing.reset-size11.size6{font-size:.40192926em}.katex .fontsize-ensurer.reset-size11.size7,.katex .sizing.reset-size11.size7{font-size:.48231511em}.katex .fontsize-ensurer.reset-size11.size8,.katex .sizing.reset-size11.size8{font-size:.57877814em}.katex .fontsize-ensurer.reset-size11.size9,.katex .sizing.reset-size11.size9{font-size:.69453376em}.katex .fontsize-ensurer.reset-size11.size10,.katex .sizing.reset-size11.size10{font-size:.83360129em}.katex .fontsize-ensurer.reset-size11.size11,.katex .sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .op-limits>.vlist-t{text-align:center}.katex .accent>.vlist-t{text-align:center}.katex .accent .accent-body{position:relative}.katex .accent .accent-body:not(.accent-full){width:0}.katex .overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{display:block;position:absolute;width:100%;height:inherit;fill:currentColor;stroke:currentColor;fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1}.katex svg path{stroke:none}.katex img{border-style:none;min-width:0;min-height:0;max-width:none;max-height:none}.katex .stretchy{width:100%;display:block;position:relative;overflow:hidden}.katex .stretchy:after,.katex .stretchy:before{content:""}.katex .hide-tail{width:100%;position:relative;overflow:hidden}.katex .halfarrow-left{position:absolute;left:0;width:50.2%;overflow:hidden}.katex .halfarrow-right{position:absolute;right:0;width:50.2%;overflow:hidden}.katex .brace-left{position:absolute;left:0;width:25.1%;overflow:hidden}.katex .brace-center{position:absolute;left:25%;width:50%;overflow:hidden}.katex .brace-right{position:absolute;right:0;width:25.1%;overflow:hidden}.katex .x-arrow-pad{padding:0 .5em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{box-sizing:border-box;border:.04em solid}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .sout{border-bottom-style:solid;border-bottom-width:.08em}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.tag{left:0;right:auto}.katex-display.fleqn>.katex{text-align:left} diff --git a/ElectronClient/app/package-lock.json b/ElectronClient/app/package-lock.json index 0a38941a1..ac4aa67db 100644 --- a/ElectronClient/app/package-lock.json +++ b/ElectronClient/app/package-lock.json @@ -706,8 +706,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -728,14 +727,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -750,20 +747,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -880,8 +874,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -893,7 +886,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -908,7 +900,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -916,14 +907,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -942,7 +931,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -1023,8 +1011,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -1036,7 +1023,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -1122,8 +1108,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -1159,7 +1144,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1179,7 +1163,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1223,14 +1206,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -1248,15 +1229,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true, - "optional": true + "dev": true }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, - "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -1658,8 +1637,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.0.tgz", "integrity": "sha512-OElxJ1lUSinuoUnkpOgLmxp0DC4ytEhODEL6QJU0NpxE/mI4rUSh8h1P1Wkvfi3xQEBcxXR2gBIPNYNuaFcAbQ==", - "dev": true, - "optional": true + "dev": true }, "boxen": { "version": "3.2.0", @@ -3588,15 +3566,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true, - "optional": true + "dev": true }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, - "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -3721,6 +3697,24 @@ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" }, + "handlebars": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", + "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -3785,9 +3779,12 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, "highlight.js": { - "version": "9.15.6", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.6.tgz", - "integrity": "sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ==" + "version": "9.17.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.17.1.tgz", + "integrity": "sha512-TA2/doAur5Ol8+iM3Ov7qy3jYcr/QiJ2eDTdRF4dfbjG7AaaB99J5G+zSl11ljbl6cIcahgPY6SKb3sC3EJ0fw==", + "requires": { + "handlebars": "^4.5.3" + } }, "hoist-non-react-statics": { "version": "2.5.0", @@ -4181,6 +4178,67 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, + "joplin-renderer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/joplin-renderer/-/joplin-renderer-1.0.4.tgz", + "integrity": "sha512-Q7GoEYA6hYtv8ZQgxccn/gSw25V8kQPyWdolK0PJhG7m2BJa0zunyagtaOhMkYuWl8beDYHwTsvsVx2ayKqMcQ==", + "requires": { + "base-64": "^0.1.0", + "font-awesome-filetypes": "^2.1.0", + "fs-extra": "^8.1.0", + "highlight.js": "^9.17.1", + "html-entities": "^1.2.1", + "katex": "^0.11.1", + "markdown-it": "^10.0.0", + "markdown-it-abbr": "^1.0.4", + "markdown-it-anchor": "^5.2.5", + "markdown-it-deflist": "^2.0.3", + "markdown-it-emoji": "^1.4.0", + "markdown-it-footnote": "^3.0.2", + "markdown-it-ins": "^3.0.0", + "markdown-it-mark": "^3.0.0", + "markdown-it-multimd-table": "^4.0.0", + "markdown-it-sub": "^1.0.0", + "markdown-it-sup": "^1.0.0", + "markdown-it-toc-done-right": "^4.1.0", + "md5": "^2.2.1", + "uslug": "^1.0.4" + }, + "dependencies": { + "entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + }, + "markdown-it": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "requires": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + } + } + }, "joplin-turndown": { "version": "4.0.19", "resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.19.tgz", @@ -4547,37 +4605,19 @@ "integrity": "sha512-JVW6fCmZWjvMdDQSbOT3nnOQtd9iAXmw7hTSh26+v42BnvXeVyGMDBm5b/EZocMed2MbCAHiTX632vY0FyGB8A==" }, "markdown-it-ins": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-2.0.0.tgz", - "integrity": "sha1-papqMPHi9x6Ul1Z8/f9A8f3mdIM=" - }, - "markdown-it-katex": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/markdown-it-katex/-/markdown-it-katex-2.0.3.tgz", - "integrity": "sha1-17hqGuoLnWSW+rTnkZoY/e9YnDk=", - "requires": { - "katex": "^0.6.0" - }, - "dependencies": { - "katex": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.6.0.tgz", - "integrity": "sha1-EkGOCRIcBckgQbazuftrqyE8tvM=", - "requires": { - "match-at": "^0.1.0" - } - } - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-3.0.0.tgz", + "integrity": "sha512-+vyAdBuMGwmT2yMlAFJSx2VR/0QZ1onQ/Mkkmr4l9tDFOh5sVoAgRbkgbuSsk+sxJ9vaMH/IQ323ydfvQrPO/Q==" }, "markdown-it-mark": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-2.0.0.tgz", - "integrity": "sha1-RqGqlHEFrtgYiXjgoBYXnkBPQsc=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-3.0.0.tgz", + "integrity": "sha512-HqMWeKfMMOu4zBO0emmxsoMWmbf2cPKZY1wP6FsTbKmicFfp5y4L3KXAsNeO1rM6NTJVOrNlLKMPjWzriBGspw==" }, "markdown-it-multimd-table": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-3.2.0.tgz", - "integrity": "sha512-dBtYHVtyAnoWslzYLYDh0d9jX2/qroyMIsJ1BjFdIcLgZjzqBIBGwZ1j3AaaWh+IIfe3KVm5Irqn5Uzadm5kQA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-4.0.0.tgz", + "integrity": "sha512-kdM3fH+/sRMfHQgD2CM1BcIpLNODUCuoiFr6TwS7mDJBYntVXDJxZbFwGDRflIc9ZzAfsUbr0lnHc6RbYafIsw==", "requires": { "markdown-it": "^8.4.2" }, @@ -4611,11 +4651,6 @@ "resolved": "https://registry.npmjs.org/markdown-it-toc-done-right/-/markdown-it-toc-done-right-4.1.0.tgz", "integrity": "sha512-UhD2Oj6cZV3ycYPoelt4hTkwKIK3zbPP1wjjdpCq7UGtWQOFalDFDv1s2zBYV6aR2gMs/X8kpJcOYsQmUbiXDw==" }, - "match-at": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/match-at/-/match-at-0.1.1.tgz", - "integrity": "sha512-h4Yd392z9mST+dzc+yjuybOGFNOZjmXIPKWjxBd1Bb23r4SmDOsk2NYCU2BMUBGbSpZqwVsZYNq26QS3xfaT3Q==" - }, "matcher": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-2.1.0.tgz", @@ -4826,6 +4861,11 @@ } } }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + }, "no-case": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", @@ -5112,7 +5152,6 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, - "optional": true, "requires": { "remove-trailing-separator": "^1.0.1" } @@ -5231,6 +5270,15 @@ "mimic-fn": "^1.0.0" } }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, "optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -5422,8 +5470,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true, - "optional": true + "dev": true }, "is-glob": { "version": "2.0.1", @@ -5993,15 +6040,13 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true, - "optional": true + "dev": true }, "repeat-element": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true, - "optional": true + "dev": true }, "repeat-string": { "version": "1.6.1", @@ -7149,6 +7194,11 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", diff --git a/ElectronClient/app/package.json b/ElectronClient/app/package.json index 0ee0daf03..78742dbe5 100644 --- a/ElectronClient/app/package.json +++ b/ElectronClient/app/package.json @@ -99,34 +99,20 @@ "es6-promise-pool": "^2.5.0", "file-uri-to-path": "^1.0.0", "follow-redirects": "^1.5.0", - "font-awesome-filetypes": "^2.1.0", "form-data": "^2.3.2", "formatcoords": "^1.1.3", "fs-extra": "^5.0.0", - "highlight.js": "^9.15.6", "html-entities": "^1.2.1", "html-minifier": "^4.0.0", "image-type": "^3.0.0", + "joplin-renderer": "^1.0.4", "joplin-turndown": "^4.0.19", "joplin-turndown-plugin-gfm": "^1.0.11", "jssha": "^2.3.1", - "katex": "^0.11.1", "levenshtein": "^1.0.5", "lodash": "^4.17.15", "mark.js": "^8.11.1", "markdown-it": "^8.4.1", - "markdown-it-abbr": "^1.0.4", - "markdown-it-anchor": "^5.2.5", - "markdown-it-deflist": "^2.0.3", - "markdown-it-emoji": "^1.4.0", - "markdown-it-footnote": "^3.0.2", - "markdown-it-ins": "^2.0.0", - "markdown-it-katex": "^2.0.3", - "markdown-it-mark": "^2.0.0", - "markdown-it-multimd-table": "^3.2.0", - "markdown-it-sub": "^1.0.0", - "markdown-it-sup": "^1.0.0", - "markdown-it-toc-done-right": "^4.1.0", "md5": "^2.2.1", "moment": "^2.22.2", "multiparty": "^4.2.1", @@ -157,7 +143,6 @@ "tcp-port-used": "^0.1.2", "uglifycss": "0.0.29", "url-parse": "^1.4.3", - "uslug": "^1.0.4", "uuid": "^3.2.1", "valid-url": "^1.0.9", "xml2js": "^0.4.19" diff --git a/ElectronClient/run.bat b/ElectronClient/run.bat index c7ad48273..4640da608 100644 --- a/ElectronClient/run.bat +++ b/ElectronClient/run.bat @@ -5,5 +5,7 @@ set script_dir=%mypath:~0,-1% call build.bat if %errorlevel% neq 0 exit /b %errorlevel% +rem xcopy /C /I /H /R /Y /S /Q D:\Docs\PROGS\Node\joplin-renderer %script_dir%\app\node_modules\joplin-renderer + cd %script_dir%\app call .\node_modules\.bin\electron.cmd . --env dev --log-level debug --no-welcome --open-dev-tools "$@" diff --git a/ReactNativeClient/PluginAssetsLoader.ts b/ReactNativeClient/PluginAssetsLoader.ts new file mode 100644 index 000000000..0124baf84 --- /dev/null +++ b/ReactNativeClient/PluginAssetsLoader.ts @@ -0,0 +1,55 @@ +const { dirname } = require('lib/path-utils.js'); +const { shim } = require('lib/shim'); +const Setting = require('lib/models/Setting'); +const pluginAssets = require('./pluginAssets/index'); +const KvStore = require('lib/services/KvStore.js'); + +export default class PluginAssetsLoader { + + static instance_:PluginAssetsLoader = null; + logger_:any = null; + + static instance() { + if (PluginAssetsLoader.instance_) return PluginAssetsLoader.instance_; + PluginAssetsLoader.instance_ = new PluginAssetsLoader(); + return PluginAssetsLoader.instance_; + } + + setLogger(logger:any) { + this.logger_ = logger; + } + + logger() { + return this.logger_; + } + + async importAssets() { + const destDir = `${Setting.value('resourceDir')}/pluginAssets`; + await shim.fsDriver().mkdir(destDir); + + const hash = pluginAssets.hash; + if (hash === await KvStore.instance().value('PluginAssetsLoader.lastHash')) { + this.logger().info(`PluginAssetsLoader: Assets are up to date. Hash: ${hash}`); + return; + } + + this.logger().info(`PluginAssetsLoader: Importing assets to ${destDir}`); + + try { + for (let name in pluginAssets.files) { + const dataBase64 = pluginAssets.files[name].data; + const destPath = `${destDir}/${name}`; + await shim.fsDriver().mkdir(dirname(destPath)); + await shim.fsDriver().unlink(destPath); + + this.logger().info(`PluginAssetsLoader: Copying: ${name} => ${destPath}`); + await shim.fsDriver().writeFile(destPath, dataBase64); + } + } catch (error) { + this.logger().error(error); + } + + KvStore.instance().setValue('PluginAssetsLoader.lastHash', hash); + } + +} diff --git a/ReactNativeClient/encodeAssets.js b/ReactNativeClient/encodeAssets.js new file mode 100644 index 000000000..86d986b0c --- /dev/null +++ b/ReactNativeClient/encodeAssets.js @@ -0,0 +1,74 @@ +require('app-module-path').addPath(`${__dirname}`); + +const fs = require('fs-extra'); +const { dirname, fileExtension } = require('lib/path-utils'); +const md5 = require('md5'); + +const rootDir = __dirname; +const outputDir = `${rootDir}/pluginAssets`; + +var walk = function(dir) { + var results = []; + var list = fs.readdirSync(dir); + list.forEach(function(file) { + file = `${dir}/${file}`; + var stat = fs.statSync(file); + if (stat && stat.isDirectory()) { + results = results.concat(walk(file)); + } else { + results.push(file); + } + }); + return results; +}; + +async function encodeFile(sourcePath, destPath) { + const buffer = await fs.readFile(sourcePath); + const hash = md5(buffer.toString('base64')); + const js = `module.exports = \`${buffer.toString('base64')}\`;`; + const outputPath = `${outputDir}/${destPath}.base64.js`; + await fs.mkdirp(dirname(outputPath)); + await fs.writeFile(outputPath, js); + + const ext = fileExtension(sourcePath).toLowerCase(); + let mime = 'application/octet-stream'; + if (ext === 'js') mime = 'application/javascript'; + if (ext === 'css') mime = 'text/css'; + + return { + encoding: 'base64', + name: destPath, + encodedName: `${destPath}.base64.js`, + mime: mime, + hash: hash, + }; +} + +async function main() { + await fs.mkdirp(outputDir); + + const encodedFiles = []; + const sourceAssetDir = `${rootDir}/node_modules/joplin-renderer/assets`; + const files = walk(sourceAssetDir); + + for (const file of files) { + const destFile = file.substr(sourceAssetDir.length + 1); + encodedFiles.push(await encodeFile(file, destFile)); + } + + const hashes = []; + const indexJs = []; + for (const file of encodedFiles) { + indexJs.push(`'${file.name}': { data: require('./${file.encodedName}'), mime: '${file.mime}', encoding: '${file.encoding}' },`); + hashes.push(file.hash); + } + + const hash = md5(hashes.join('')); + + await fs.writeFile(`${outputDir}/index.js`, `module.exports = {\nhash:"${hash}", files: {\n${indexJs.join('\n')}\n}\n};`); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/ReactNativeClient/lib/components/global-style.js b/ReactNativeClient/lib/components/global-style.js index 163fb17a9..86902e2ea 100644 --- a/ReactNativeClient/lib/components/global-style.js +++ b/ReactNativeClient/lib/components/global-style.js @@ -38,7 +38,7 @@ const globalStyle = { htmlCodeBorderColor: 'rgb(220, 220, 220)', htmlCodeColor: 'rgb(0,0,0)', - codeThemeCss: 'hljs-atom-one-light.css', + codeThemeCss: 'atom-one-light.css', }; globalStyle.marginRight = globalStyle.margin; diff --git a/ReactNativeClient/lib/components/note-body-viewer.js b/ReactNativeClient/lib/components/note-body-viewer.js index 40a72b9fc..f83e30b1e 100644 --- a/ReactNativeClient/lib/components/note-body-viewer.js +++ b/ReactNativeClient/lib/components/note-body-viewer.js @@ -1,13 +1,15 @@ const React = require('react'); const Component = React.Component; -const { Platform, View } = require('react-native'); +const { Platform, View, Text } = require('react-native'); const { WebView } = require('react-native-webview'); const { themeStyle } = require('lib/components/global-style.js'); const Setting = require('lib/models/Setting.js'); const { reg } = require('lib/registry.js'); const { shim } = require('lib/shim'); -const MdToHtml = require('lib/renderers/MdToHtml.js'); const shared = require('lib/components/shared/note-screen-shared.js'); +const markupLanguageUtils = require('lib/markupLanguageUtils'); + +import Async from 'react-async'; class NoteBodyViewer extends Component { constructor() { @@ -15,21 +17,134 @@ class NoteBodyViewer extends Component { this.state = { resources: {}, webViewLoaded: false, + bodyHtml: '', }; this.isMounted_ = false; + + this.markupToHtml_ = markupLanguageUtils.newMarkupToHtml(); + + this.reloadNote = this.reloadNote.bind(this); } - UNSAFE_componentWillMount() { - this.mdToHtml_ = new MdToHtml(); + componentDidMount() { this.isMounted_ = true; } componentWillUnmount() { - this.mdToHtml_ = null; + this.markupToHtml_ = null; this.isMounted_ = false; } + async reloadNote() { + const note = this.props.note; + const theme = themeStyle(this.props.theme); + + const bodyToRender = note ? note.body : ''; + + const mdOptions = { + onResourceLoaded: () => { + if (this.resourceLoadedTimeoutId_) { + clearTimeout(this.resourceLoadedTimeoutId_); + this.resourceLoadedTimeoutId_ = null; + } + + this.resourceLoadedTimeoutId_ = setTimeout(() => { + this.resourceLoadedTimeoutId_ = null; + this.forceUpdate(); + }, 100); + }, + paddingBottom: '3.8em', // Extra bottom padding to make it possible to scroll past the action button (so that it doesn't overlap the text) + highlightedKeywords: this.props.highlightedKeywords, + resources: this.props.noteResources, // await shared.attachedResources(bodyToRender), + codeTheme: theme.codeThemeCss, + postMessageSyntax: 'window.ReactNativeWebView.postMessage', + }; + + let result = await this.markupToHtml_.render(note.markup_language, bodyToRender, this.props.webViewStyle, mdOptions); + let html = result.html; + + const resourceDownloadMode = Setting.value('sync.resourceDownloadMode'); + + const injectedJs = []; + injectedJs.push(shim.injectedJs('webviewLib')); + injectedJs.push('webviewLib.initialize({ postMessage: msg => { return window.ReactNativeWebView.postMessage(msg); } });'); + injectedJs.push(` + const readyStateCheckInterval = setInterval(function() { + if (document.readyState === "complete") { + clearInterval(readyStateCheckInterval); + if ("${resourceDownloadMode}" === "manual") webviewLib.setupResourceManualDownload(); + + const hash = "${this.props.noteHash}"; + // Gives it a bit of time before scrolling to the anchor + // so that images are loaded. + if (hash) { + setTimeout(() => { + const e = document.getElementById(hash); + if (!e) { + console.warn('Cannot find hash', hash); + return; + } + e.scrollIntoView(); + }, 500); + } + } + }, 10); + `); + + const headers = []; + for (let i = 0; i < result.pluginAssets.length; i++) { + const asset = result.pluginAssets[i]; + if (asset.mime === 'text/css') { + headers.push(``); + } else if (asset.mime === 'application/javascript') { + // NOT TESTED!! + headers.push(``); + } + } + + html = + ` + + + + + ${headers.join('\n')} + + + ${html} + + + `; + + // On iOS scalesPageToFit work like this: + // + // Find the widest image, resize it *and everything else* by x% so that + // the image fits within the viewport. The problem is that it means if there's + // a large image, everything is going to be scaled to a very small size, making + // the text unreadable. + // + // On Android: + // + // Find the widest elements and scale them (and them only) to fit within the viewport + // It means it's going to scale large images, but the text will remain at the normal + // size. + // + // That means we can use scalesPageToFix on Android but not on iOS. + // The weird thing is that on iOS, scalesPageToFix=false along with a CSS + // rule "img { max-width: 100% }", works like scalesPageToFix=true on Android. + // So we use scalesPageToFix=false on iOS along with that CSS rule. + + // `baseUrl` is where the images will be loaded from. So images must use a path relative to resourceDir. + return { + source: { + html: html, + baseUrl: `file://${Setting.value('resourceDir')}/`, + }, + injectedJs: injectedJs, + }; + } + onLoadEnd() { setTimeout(() => { if (this.props.onLoadEnd) this.props.onLoadEnd(); @@ -70,80 +185,18 @@ class NoteBodyViewer extends Component { } rebuildMd() { - // this.mdToHtml_.clearCache(); this.forceUpdate(); } render() { - const note = this.props.note; - const style = this.props.style; + // Note: useWebKit={false} is needed to go around this bug: + // https://github.com/react-native-community/react-native-webview/issues/376 + // However, if we add the tag as described there, it is no longer necessary and WebKit can be used! + // https://github.com/react-native-community/react-native-webview/issues/312#issuecomment-501991406 + // + // However, on iOS, due to the bug below, we cannot use WebKit: + // https://github.com/react-native-community/react-native-webview/issues/312#issuecomment-503754654 - const theme = themeStyle(this.props.theme); - - const bodyToRender = note ? note.body : ''; - - const mdOptions = { - onResourceLoaded: () => { - if (this.resourceLoadedTimeoutId_) { - clearTimeout(this.resourceLoadedTimeoutId_); - this.resourceLoadedTimeoutId_ = null; - } - - this.resourceLoadedTimeoutId_ = setTimeout(() => { - this.resourceLoadedTimeoutId_ = null; - this.forceUpdate(); - }, 100); - }, - paddingBottom: '3.8em', // Extra bottom padding to make it possible to scroll past the action button (so that it doesn't overlap the text) - highlightedKeywords: this.props.highlightedKeywords, - resources: this.props.noteResources, // await shared.attachedResources(bodyToRender), - codeTheme: theme.codeThemeCss, - postMessageSyntax: 'window.ReactNativeWebView.postMessage', - }; - - let result = this.mdToHtml_.render(bodyToRender, this.props.webViewStyle, mdOptions); - let html = result.html; - - const resourceDownloadMode = Setting.value('sync.resourceDownloadMode'); - - const injectedJs = [this.mdToHtml_.injectedJavaScript()]; - injectedJs.push(shim.injectedJs('webviewLib')); - injectedJs.push('webviewLib.initialize({ postMessage: msg => { return window.ReactNativeWebView.postMessage(msg); } });'); - injectedJs.push(` - const readyStateCheckInterval = setInterval(function() { - if (document.readyState === "complete") { - clearInterval(readyStateCheckInterval); - if ("${resourceDownloadMode}" === "manual") webviewLib.setupResourceManualDownload(); - - const hash = "${this.props.noteHash}"; - // Gives it a bit of time before scrolling to the anchor - // so that images are loaded. - if (hash) { - setTimeout(() => { - const e = document.getElementById(hash); - if (!e) { - console.warn('Cannot find hash', hash); - return; - } - e.scrollIntoView(); - }, 500); - } - } - }, 10); - `); - - html = - ` - - - - - - - ${html} - - - `; let webViewStyle = { backgroundColor: this.props.webViewStyle.backgroundColor }; // On iOS, the onLoadEnd() event is never fired so always @@ -153,68 +206,49 @@ class NoteBodyViewer extends Component { webViewStyle.opacity = this.state.webViewLoaded ? 1 : 0.01; } - // On iOS scalesPageToFit work like this: - // - // Find the widest image, resize it *and everything else* by x% so that - // the image fits within the viewport. The problem is that it means if there's - // a large image, everything is going to be scaled to a very small size, making - // the text unreadable. - // - // On Android: - // - // Find the widest elements and scale them (and them only) to fit within the viewport - // It means it's going to scale large images, but the text will remain at the normal - // size. - // - // That means we can use scalesPageToFix on Android but not on iOS. - // The weird thing is that on iOS, scalesPageToFix=false along with a CSS - // rule "img { max-width: 100% }", works like scalesPageToFix=true on Android. - // So we use scalesPageToFix=false on iOS along with that CSS rule. - - // `baseUrl` is where the images will be loaded from. So images must use a path relative to resourceDir. - const source = { - html: html, - baseUrl: `file://${Setting.value('resourceDir')}/`, - }; - - // Note: useWebKit={false} is needed to go around this bug: - // https://github.com/react-native-community/react-native-webview/issues/376 - // However, if we add the tag as described there, it is no longer necessary and WebKit can be used! - // https://github.com/react-native-community/react-native-webview/issues/312#issuecomment-501991406 - // - // However, on iOS, due to the bug below, we cannot use WebKit: - // https://github.com/react-native-community/react-native-webview/issues/312#issuecomment-503754654 - return ( - - this.onLoadEnd()} - onError={() => reg.logger().error('WebView error')} - onMessage={event => { - // Since RN 58 (or 59) messages are now escaped twice??? - let msg = unescape(unescape(event.nativeEvent.data)); - - console.info('Got IPC message: ', msg); - - if (msg.indexOf('checkboxclick:') === 0) { - const newBody = shared.toggleCheckbox(msg, this.props.note.body); - if (this.props.onCheckboxChange) this.props.onCheckboxChange(newBody); - } else if (msg.indexOf('markForDownload:') === 0) { - msg = msg.split(':'); - const resourceId = msg[1]; - if (this.props.onMarkForDownload) this.props.onMarkForDownload({ resourceId: resourceId }); - } else { - this.props.onJoplinLinkClick(msg); + + + {({ data, error, isPending }) => { + if (error) { + console.error(error); + return {error.message}; } + + if (isPending) return null; + + return ( + this.onLoadEnd()} + onError={() => reg.logger().error('WebView error')} + onMessage={event => { + // Since RN 58 (or 59) messages are now escaped twice??? + let msg = unescape(unescape(event.nativeEvent.data)); + + console.info('Got IPC message: ', msg); + + if (msg.indexOf('checkboxclick:') === 0) { + const newBody = shared.toggleCheckbox(msg, this.props.note.body); + if (this.props.onCheckboxChange) this.props.onCheckboxChange(newBody); + } else if (msg.indexOf('markForDownload:') === 0) { + msg = msg.split(':'); + const resourceId = msg[1]; + if (this.props.onMarkForDownload) this.props.onMarkForDownload({ resourceId: resourceId }); + } else { + this.props.onJoplinLinkClick(msg); + } + }} + /> + ); }} - /> + ); } diff --git a/ReactNativeClient/lib/fs-driver-rn.js b/ReactNativeClient/lib/fs-driver-rn.js index f87f60ea5..6363219a2 100644 --- a/ReactNativeClient/lib/fs-driver-rn.js +++ b/ReactNativeClient/lib/fs-driver-rn.js @@ -38,7 +38,13 @@ class FsDriverRN extends FsDriverBase { if (!options) options = {}; if (!('recursive' in options)) options.recursive = false; - let items = await RNFS.readDir(path); + let items = []; + try { + items = await RNFS.readDir(path); + } catch (error) { + throw new Error(`Could not read directory: ${path}: ${error.message}`); + } + let output = []; for (let i = 0; i < items.length; i++) { const item = items[i]; diff --git a/ReactNativeClient/lib/import-enex.js b/ReactNativeClient/lib/import-enex.js index 09a575821..a25155fc1 100644 --- a/ReactNativeClient/lib/import-enex.js +++ b/ReactNativeClient/lib/import-enex.js @@ -4,6 +4,7 @@ const BaseModel = require('lib/BaseModel.js'); const Note = require('lib/models/Note.js'); const Tag = require('lib/models/Tag.js'); const Resource = require('lib/models/Resource.js'); +const { MarkupToHtml } = require('joplin-renderer'); const { enexXmlToMd } = require('./import-enex-md-gen.js'); const { enexXmlToHtml } = require('./import-enex-html-gen.js'); const { time } = require('lib/time-utils.js'); @@ -224,8 +225,8 @@ function importEnex(parentFolderId, filePath, importOptions = null) { delete note.bodyXml; note.markup_language = importOptions.outputFormat === 'html' ? - Note.MARKUP_LANGUAGE_HTML : - Note.MARKUP_LANGUAGE_MARKDOWN; + MarkupToHtml.MARKUP_LANGUAGE_HTML : + MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN; // console.info('*************************************************************************'); // console.info(body); diff --git a/ReactNativeClient/lib/joplin-database.js b/ReactNativeClient/lib/joplin-database.js index c685dbd63..8b3ec7669 100644 --- a/ReactNativeClient/lib/joplin-database.js +++ b/ReactNativeClient/lib/joplin-database.js @@ -287,6 +287,11 @@ class JoplinDatabase extends Database { }); } + addMigrationFile(num) { + const timestamp = Date.now(); + return { sql: 'INSERT INTO migrations (number, created_time, updated_time) VALUES (?, ?, ?)', params: [num, timestamp, timestamp] }; + } + async upgradeDatabase(fromVersion) { // INSTRUCTIONS TO UPGRADE THE DATABASE: // @@ -302,7 +307,7 @@ class JoplinDatabase extends Database { // must be set in the synchronizer too. // Note: v16 and v17 don't do anything. They were used to debug an issue. - const existingDatabaseVersions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]; + const existingDatabaseVersions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27]; let currentVersionIndex = existingDatabaseVersions.indexOf(fromVersion); @@ -596,9 +601,8 @@ class JoplinDatabase extends Database { `; queries.push(this.sqlStringToLines(newTableSql)[0]); - const timestamp = Date.now(); queries.push('ALTER TABLE resources ADD COLUMN `size` INT NOT NULL DEFAULT -1'); - queries.push({ sql: 'INSERT INTO migrations (number, created_time, updated_time) VALUES (20, ?, ?)', params: [timestamp, timestamp] }); + queries.push(this.addMigrationFile(20)); } if (targetVersion == 21) { @@ -657,6 +661,10 @@ class JoplinDatabase extends Database { } } + if (targetVersion == 27) { + queries.push(this.addMigrationFile(27)); + } + queries.push({ sql: 'UPDATE version SET version = ?', params: [targetVersion] }); try { diff --git a/ReactNativeClient/lib/markdownUtils.js b/ReactNativeClient/lib/markdownUtils.js index 51e155ce4..c619b54db 100644 --- a/ReactNativeClient/lib/markdownUtils.js +++ b/ReactNativeClient/lib/markdownUtils.js @@ -1,7 +1,7 @@ const stringPadding = require('string-padding'); const urlUtils = require('lib/urlUtils'); const MarkdownIt = require('markdown-it'); -const setupLinkify = require('lib/renderers/MdToHtml/setupLinkify'); +const { setupLinkify } = require('joplin-renderer'); const markdownUtils = { // Not really escaping because that's not supported by marked.js diff --git a/ReactNativeClient/lib/markupLanguageUtils.js b/ReactNativeClient/lib/markupLanguageUtils.js index 5e0de8b78..50b863597 100644 --- a/ReactNativeClient/lib/markupLanguageUtils.js +++ b/ReactNativeClient/lib/markupLanguageUtils.js @@ -1,17 +1,36 @@ const markdownUtils = require('lib/markdownUtils'); const htmlUtils = require('lib/htmlUtils'); -const Note = require('lib/models/Note'); +const Setting = require('lib/models/Setting'); +const Resource = require('lib/models/Resource'); +const { MarkupToHtml } = require('joplin-renderer'); class MarkupLanguageUtils { lib_(language) { - if (language === Note.MARKUP_LANGUAGE_HTML) return htmlUtils; - if (language === Note.MARKUP_LANGUAGE_MARKDOWN) return markdownUtils; + if (language === MarkupToHtml.MARKUP_LANGUAGE_HTML) return htmlUtils; + if (language === MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN) return markdownUtils; throw new Error(`Unsupported markup language: ${language}`); } extractImageUrls(language, text) { return this.lib_(language).extractImageUrls(text); } + + // Create a new MarkupToHtml instance while injecting options specific to Joplin + // desktop and mobile applications. + newMarkupToHtml(options = null) { + const subValues = Setting.subValues('markdown.plugin', Setting.toPlainObject()); + const pluginOptions = {}; + for (const n in subValues) { + pluginOptions[n] = { enabled: subValues[n] }; + } + + options = Object.assign({ + ResourceModel: Resource, + pluginOptions: pluginOptions, + }, options); + + return new MarkupToHtml(options); + } } const markupLanguageUtils = new MarkupLanguageUtils(); diff --git a/ReactNativeClient/lib/migrations/27.js b/ReactNativeClient/lib/migrations/27.js new file mode 100644 index 000000000..c861c06bd --- /dev/null +++ b/ReactNativeClient/lib/migrations/27.js @@ -0,0 +1,10 @@ +const Setting = require('lib/models/Setting'); + +const script = {}; + +script.exec = async function() { + Setting.setValue('markdown.plugin.softbreaks', Setting.value('markdown.softbreaks')); + Setting.setValue('markdown.plugin.typographer', Setting.value('markdown.typographer')); +}; + +module.exports = script; diff --git a/ReactNativeClient/lib/models/Migration.js b/ReactNativeClient/lib/models/Migration.js index 08c2b072e..8e7964c45 100644 --- a/ReactNativeClient/lib/models/Migration.js +++ b/ReactNativeClient/lib/models/Migration.js @@ -2,6 +2,7 @@ const BaseModel = require('lib/BaseModel.js'); const migrationScripts = { 20: require('lib/migrations/20.js'), + 27: require('lib/migrations/27.js'), }; class Migration extends BaseModel { @@ -18,6 +19,7 @@ class Migration extends BaseModel { } static script(number) { + if (!migrationScripts[number]) throw new Error('Migration script has not been added to "migrationScripts" array'); return migrationScripts[number]; } } diff --git a/ReactNativeClient/lib/models/Note.js b/ReactNativeClient/lib/models/Note.js index 8239da439..93c65b205 100644 --- a/ReactNativeClient/lib/models/Note.js +++ b/ReactNativeClient/lib/models/Note.js @@ -11,6 +11,7 @@ const { _ } = require('lib/locale.js'); const ArrayUtils = require('lib/ArrayUtils.js'); const lodash = require('lodash'); const urlUtils = require('lib/urlUtils.js'); +const { MarkupToHtml } = require('joplin-renderer'); class Note extends BaseItem { static tableName() { @@ -624,8 +625,8 @@ class Note extends BaseItem { } static markupLanguageToLabel(markupLanguageId) { - if (markupLanguageId === Note.MARKUP_LANGUAGE_MARKDOWN) return 'Markdown'; - if (markupLanguageId === Note.MARKUP_LANGUAGE_HTML) return 'HTML'; + if (markupLanguageId === MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN) return 'Markdown'; + if (markupLanguageId === MarkupToHtml.MARKUP_LANGUAGE_HTML) return 'HTML'; throw new Error(`Invalid markup language ID: ${markupLanguageId}`); } } @@ -633,7 +634,4 @@ class Note extends BaseItem { Note.updateGeolocationEnabled_ = true; Note.geolocationUpdating_ = false; -Note.MARKUP_LANGUAGE_MARKDOWN = 1; -Note.MARKUP_LANGUAGE_HTML = 2; - module.exports = Note; diff --git a/ReactNativeClient/lib/models/Setting.js b/ReactNativeClient/lib/models/Setting.js index d2a8efd2d..ec1fea757 100644 --- a/ReactNativeClient/lib/models/Setting.js +++ b/ReactNativeClient/lib/models/Setting.js @@ -334,8 +334,14 @@ class Setting extends BaseModel { }; }, }, - 'markdown.softbreaks': { value: false, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable soft breaks') }, - 'markdown.typographer': { value: false, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable typographer support') }, + + // Deprecated - use markdown.plugin.* + 'markdown.softbreaks': { value: false, type: Setting.TYPE_BOOL, public: false, appTypes: ['mobile', 'desktop']}, + 'markdown.typographer': { value: false, type: Setting.TYPE_BOOL, public: false, appTypes: ['mobile', 'desktop']}, + // Deprecated + + 'markdown.plugin.softbreaks': { value: false, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable soft breaks') }, + 'markdown.plugin.typographer': { value: false, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable typographer support') }, 'markdown.plugin.katex': { value: true, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable math expressions') }, 'markdown.plugin.mark': { value: true, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable ==mark== syntax') }, 'markdown.plugin.footnote': { value: true, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable footnotes') }, @@ -848,12 +854,14 @@ class Setting extends BaseModel { // { sync.5.path: 'http://example', sync.5.username: 'testing' } // and baseKey is 'sync.5', the function will return // { path: 'http://example', username: 'testing' } - static subValues(baseKey, settings) { + static subValues(baseKey, settings, options = null) { + const includeBaseKeyInName = !!options && !!options.includeBaseKeyInName; + let output = {}; for (let key in settings) { if (!settings.hasOwnProperty(key)) continue; if (key.indexOf(baseKey) === 0) { - const subKey = key.substr(baseKey.length + 1); + const subKey = includeBaseKeyInName ? key : key.substr(baseKey.length + 1); output[subKey] = settings[key]; } } diff --git a/ReactNativeClient/lib/renderers/HtmlToHtml.js b/ReactNativeClient/lib/renderers/HtmlToHtml.js deleted file mode 100644 index ab719ea26..000000000 --- a/ReactNativeClient/lib/renderers/HtmlToHtml.js +++ /dev/null @@ -1,41 +0,0 @@ -const htmlUtils = require('lib/htmlUtils'); -const utils = require('./utils'); -const noteStyle = require('./noteStyle'); - -class HtmlToHtml { - constructor(options) { - if (!options) options = {}; - this.resourceBaseUrl_ = 'resourceBaseUrl' in options ? options.resourceBaseUrl : null; - } - - render(markup, theme, options) { - const html = htmlUtils.processImageTags(markup, data => { - if (!data.src) return null; - - const r = utils.imageReplacement(data.src, options.resources, this.resourceBaseUrl_); - if (!r) return null; - - if (typeof r === 'string') { - return { - type: 'replaceElement', - html: r, - }; - } else { - return { - type: 'setAttributes', - attrs: r, - }; - } - }); - - const cssStrings = noteStyle(theme, options); - const styleHtml = ``; - - return { - html: styleHtml + html, - cssFiles: [], - }; - } -} - -module.exports = HtmlToHtml; diff --git a/ReactNativeClient/lib/renderers/MarkupToHtml.js b/ReactNativeClient/lib/renderers/MarkupToHtml.js deleted file mode 100644 index 57478e213..000000000 --- a/ReactNativeClient/lib/renderers/MarkupToHtml.js +++ /dev/null @@ -1,37 +0,0 @@ -const MdToHtml = require('./MdToHtml'); -const HtmlToHtml = require('./HtmlToHtml'); -const Note = require('lib/models/Note'); - -class MarkupToHtml { - constructor(options) { - this.options_ = options; - this.renderers_ = {}; - } - - renderer(markupLanguage) { - if (this.renderers_[markupLanguage]) return this.renderers_[markupLanguage]; - - let RendererClass = null; - - if (markupLanguage === Note.MARKUP_LANGUAGE_MARKDOWN) { - RendererClass = MdToHtml; - } else if (markupLanguage === Note.MARKUP_LANGUAGE_HTML) { - RendererClass = HtmlToHtml; - } else { - throw new Error(`Invalid markup language: ${markupLanguage}`); - } - - this.renderers_[markupLanguage] = new RendererClass(this.options_); - return this.renderers_[markupLanguage]; - } - - injectedJavaScript() { - return ''; - } - - render(markupLanguage, markup, theme, options) { - return this.renderer(markupLanguage).render(markup, theme, options); - } -} - -module.exports = MarkupToHtml; diff --git a/ReactNativeClient/lib/renderers/MdToHtml.js b/ReactNativeClient/lib/renderers/MdToHtml.js deleted file mode 100644 index 659e02dfb..000000000 --- a/ReactNativeClient/lib/renderers/MdToHtml.js +++ /dev/null @@ -1,199 +0,0 @@ -const MarkdownIt = require('markdown-it'); -const { shim } = require('lib/shim.js'); -const md5 = require('md5'); -const noteStyle = require('./noteStyle'); -const Setting = require('lib/models/Setting.js'); -const rules = { - image: require('./MdToHtml/rules/image'), - checkbox: require('./MdToHtml/rules/checkbox'), - katex: require('./MdToHtml/rules/katex'), - link_open: require('./MdToHtml/rules/link_open'), - html_image: require('./MdToHtml/rules/html_image'), - highlight_keywords: require('./MdToHtml/rules/highlight_keywords'), - code_inline: require('./MdToHtml/rules/code_inline'), - fountain: require('./MdToHtml/rules/fountain'), -}; -const setupLinkify = require('./MdToHtml/setupLinkify'); -const hljs = require('highlight.js'); -const uslug = require('uslug'); -const markdownItAnchor = require('markdown-it-anchor'); -// The keys must match the corresponding entry in Setting.js -const plugins = { - mark: { module: require('markdown-it-mark') }, - footnote: { module: require('markdown-it-footnote') }, - sub: { module: require('markdown-it-sub') }, - sup: { module: require('markdown-it-sup') }, - deflist: { module: require('markdown-it-deflist') }, - abbr: { module: require('markdown-it-abbr') }, - emoji: { module: require('markdown-it-emoji') }, - insert: { module: require('markdown-it-ins') }, - multitable: { module: require('markdown-it-multimd-table'), options: { enableMultilineRows: true, enableRowspan: true } }, - toc: { module: require('markdown-it-toc-done-right'), options: { listType: 'ul', slugify: uslugify } }, -}; - -function uslugify(s) { - return uslug(s); -} - -class MdToHtml { - constructor(options = null) { - if (!options) options = {}; - - // Must include last "/" - this.resourceBaseUrl_ = 'resourceBaseUrl' in options ? options.resourceBaseUrl : null; - - this.cachedOutputs_ = {}; - - this.lastCodeHighlightCacheKey_ = null; - this.cachedHighlightedCode_ = {}; - } - - render(body, style, options = null) { - if (!options) options = {}; - if (!options.postMessageSyntax) options.postMessageSyntax = 'postMessage'; - if (!options.paddingBottom) options.paddingBottom = '0'; - if (!options.highlightedKeywords) options.highlightedKeywords = []; - - // The "codeHighlightCacheKey" option indicates what set of cached object should be - // associated with this particular Markdown body. It is only used to allow us to - // clear the cache whenever switching to a different note. - // If "codeHighlightCacheKey" is not specified, code highlighting won't be cached. - if (options.codeHighlightCacheKey !== this.lastCodeHighlightCacheKey_ || !options.codeHighlightCacheKey) { - this.cachedHighlightedCode_ = {}; - this.lastCodeHighlightCacheKey_ = options.codeHighlightCacheKey; - } - - const breaks_ = Setting.value('markdown.softbreaks') ? false : true; - const typographer_ = Setting.value('markdown.typographer') ? true : false; - - const cacheKey = md5(escape(body + JSON.stringify(options) + JSON.stringify(style))); - const cachedOutput = this.cachedOutputs_[cacheKey]; - if (cachedOutput) return cachedOutput; - - const context = { - css: {}, - cssFiles: {}, - assetLoaders: {}, - }; - - const ruleOptions = Object.assign({}, options, { resourceBaseUrl: this.resourceBaseUrl_ }); - - const markdownIt = new MarkdownIt({ - breaks: breaks_, - typographer: typographer_, - linkify: true, - html: true, - highlight: (str, lang) => { - try { - let hlCode = ''; - - const cacheKey = md5(`${str}_${lang}`); - - if (options.codeHighlightCacheKey && this.cachedHighlightedCode_[cacheKey]) { - hlCode = this.cachedHighlightedCode_[cacheKey]; - } else { - if (lang && hljs.getLanguage(lang)) { - hlCode = hljs.highlight(lang, str, true).value; - } else { - hlCode = hljs.highlightAuto(str).value; - } - this.cachedHighlightedCode_[cacheKey] = hlCode; - } - - if (shim.isReactNative()) { - context.css['hljs'] = shim.loadCssFromJs(options.codeTheme); - } else { - context.cssFiles['hljs'] = `highlight/styles/${options.codeTheme}`; - } - - return `
${hlCode}
`; - } catch (error) { - return `
${markdownIt.utils.escapeHtml(str)}
`; - } - }, - }); - - // To add a plugin, there are three options: - // - // 1. If the plugin does not need any application specific data, use the standard way: - // - // const someMarkdownPlugin = require('someMarkdownPlugin'); - // markdownIt.use(someMarkdownPlugin); - // - // 2. If the plugin does not need any application specific data, and you want the user - // to be able to toggle the plugin: - // - // Add the plugin to the plugins object - // const plugins = { - // plugin: require('someMarkdownPlugin'), - // } - // - // And add a corresponding entry into Setting.js - // 'markdown.plugin.mark': {value: true, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable ==mark== syntax')}, - // - // 3. If the plugin needs application data (in ruleOptions) or needs to pass data (CSS, files to load, etc.) back - // to the application (using the context object), use the application-specific way: - // - // const imagePlugin = require('./MdToHtml/rules/image'); - // markdownIt.use(imagePlugin(context, ruleOptions)); - // - // Using the `context` object, a plugin can send back either CSS strings (in .css) or CSS files that need - // to be loaded (in .cssFiles). In general, the desktop app will load the CSS files and the mobile app - // will load the CSS strings. - - markdownIt.use(rules.image(context, ruleOptions)); - markdownIt.use(rules.checkbox(context, ruleOptions)); - markdownIt.use(rules.link_open(context, ruleOptions)); - markdownIt.use(rules.html_image(context, ruleOptions)); - if (Setting.value('markdown.plugin.katex')) markdownIt.use(rules.katex(context, ruleOptions)); - if (Setting.value('markdown.plugin.fountain')) markdownIt.use(rules.fountain(context, ruleOptions)); - markdownIt.use(rules.highlight_keywords(context, ruleOptions)); - markdownIt.use(rules.code_inline(context, ruleOptions)); - markdownIt.use(markdownItAnchor, { slugify: uslugify }); - - for (let key in plugins) { - if (Setting.value(`markdown.plugin.${key}`)) markdownIt.use(plugins[key].module, plugins[key].options); - } - - setupLinkify(markdownIt); - - const renderedBody = markdownIt.render(body); - - const cssStrings = noteStyle(style, options); - - for (let k in context.css) { - if (!context.css.hasOwnProperty(k)) continue; - cssStrings.push(context.css[k]); - } - - for (let k in context.assetLoaders) { - if (!context.assetLoaders.hasOwnProperty(k)) continue; - context.assetLoaders[k]().catch(error => { - console.warn(`MdToHtml: Error loading assets for ${k}: `, error.message); - }); - } - - if (options.userCss) cssStrings.push(options.userCss); - - const styleHtml = ``; - - const html = `${styleHtml}
${renderedBody}
`; - - const output = { - html: html, - cssFiles: Object.keys(context.cssFiles).map(k => context.cssFiles[k]), - }; - - // Fow now, we keep only the last entry in the cache - this.cachedOutputs_ = {}; - this.cachedOutputs_[cacheKey] = output; - - return output; - } - - injectedJavaScript() { - return ''; - } -} - -module.exports = MdToHtml; diff --git a/ReactNativeClient/lib/renderers/MdToHtml/rules/checkbox.js b/ReactNativeClient/lib/renderers/MdToHtml/rules/checkbox.js deleted file mode 100644 index ed74e6ef2..000000000 --- a/ReactNativeClient/lib/renderers/MdToHtml/rules/checkbox.js +++ /dev/null @@ -1,126 +0,0 @@ -let checkboxIndex_ = -1; - -const checkboxStyle = ` - /* Remove the indentation from the checkboxes at the root of the document - (otherwise they are too far right), but keep it for their children to allow - nested lists. Make sure this value matches the UL margin. */ - - #rendered-md > ul > li.md-checkbox { - margin-left: -1.7em; - } - - li.md-checkbox { - list-style-type: none; - } - - li.md-checkbox input[type=checkbox] { - margin-right: 1em; - } -`; - -function createPrefixTokens(Token, id, checked, label, postMessageSyntax, sourceToken) { - let token = null; - const tokens = []; - - // A bit hard to handle errors here and it's unlikely that the token won't have a valid - // map parameter, but if it does set it to a very high value, which will be more easy to notice - // in calling code. - const lineIndex = sourceToken.map && sourceToken.map.length ? sourceToken.map[0] : 99999999; - const checkedString = checked ? 'checked' : 'unchecked'; - - const labelId = `cb-label-${id}`; - - const js = ` - ${postMessageSyntax}('checkboxclick:${checkedString}:${lineIndex}'); - const label = document.getElementById("${labelId}"); - label.classList.remove(this.checked ? 'checkbox-label-unchecked' : 'checkbox-label-checked'); - label.classList.add(this.checked ? 'checkbox-label-checked' : 'checkbox-label-unchecked'); - return true; - `; - - token = new Token('checkbox_input', 'input', 0); - token.attrs = [['type', 'checkbox'], ['id', id], ['onclick', js]]; - if (checked) token.attrs.push(['checked', 'true']); - tokens.push(token); - - token = new Token('label_open', 'label', 1); - token.attrs = [['id', labelId], ['for', id], ['class', `checkbox-label-${checkedString}`]]; - tokens.push(token); - - if (label) { - token = new Token('text', '', 0); - token.content = label; - tokens.push(token); - } - - return tokens; -} - -function createSuffixTokens(Token) { - return [new Token('label_close', 'label', -1)]; -} - -function installRule(markdownIt, mdOptions, ruleOptions, context) { - markdownIt.core.ruler.push('checkbox', state => { - const tokens = state.tokens; - const Token = state.Token; - - const checkboxPattern = /^\[([x|X| ])\] (.*)$/; - let currentListItem = null; - let processedFirstInline = false; - for (let i = 0; i < tokens.length; i++) { - const token = tokens[i]; - - if (token.type === 'list_item_open') { - currentListItem = token; - processedFirstInline = false; - continue; - } - - if (token.type === 'list_item_close') { - currentListItem = null; - processedFirstInline = false; - continue; - } - - // Note that we only support list items that start with "-" (not with "*") - if (currentListItem && currentListItem.markup === '-' && !processedFirstInline && token.type === 'inline') { - processedFirstInline = true; - const firstChild = token.children && token.children.length ? token.children[0] : null; - if (!firstChild) continue; - - const matches = checkboxPattern.exec(firstChild.content); - if (!matches || matches.length < 2) continue; - - checkboxIndex_++; - const checked = matches[1] !== ' '; - const id = `md-checkbox-${checkboxIndex_}`; - const label = matches.length >= 3 ? matches[2] : ''; - - // Prepend the text content with the checkbox markup and the opening tag at the end of the text content. - - const prefix = createPrefixTokens(Token, id, checked, label, ruleOptions.postMessageSyntax, token); - const suffix = createSuffixTokens(Token); - - token.children = markdownIt.utils.arrayReplaceAt(token.children, 0, prefix); - token.children = token.children.concat(suffix); - - // Add a class to the
  • container so that it can be targetted with CSS. - - let itemClass = currentListItem.attrGet('class'); - if (!itemClass) itemClass = ''; - itemClass += ' md-checkbox'; - currentListItem.attrSet('class', itemClass.trim()); - - context.css['checkbox'] = checkboxStyle; - } - } - }); -} - -module.exports = function(context, ruleOptions) { - return function(md, mdOptions) { - installRule(md, mdOptions, ruleOptions, context); - }; -}; diff --git a/ReactNativeClient/lib/renderers/MdToHtml/rules/code_inline.js b/ReactNativeClient/lib/renderers/MdToHtml/rules/code_inline.js deleted file mode 100644 index c0711d2d2..000000000 --- a/ReactNativeClient/lib/renderers/MdToHtml/rules/code_inline.js +++ /dev/null @@ -1,22 +0,0 @@ -function installRule(markdownIt) { - const defaultRender = - markdownIt.renderer.rules.code_inline || - function(tokens, idx, options, env, self) { - return self.renderToken(tokens, idx, options); - }; - - markdownIt.renderer.rules.code_inline = (tokens, idx, options, env, self) => { - const token = tokens[idx]; - let tokenClass = token.attrGet('class'); - if (!tokenClass) tokenClass = ''; - tokenClass += ' inline-code'; - token.attrSet('class', tokenClass.trim()); - return defaultRender(tokens, idx, options, env, self); - }; -} - -module.exports = function(context, ruleOptions) { - return function(md, mdOptions) { - installRule(md, mdOptions, ruleOptions); - }; -}; diff --git a/ReactNativeClient/lib/renderers/MdToHtml/rules/fountain.js b/ReactNativeClient/lib/renderers/MdToHtml/rules/fountain.js deleted file mode 100644 index fefc8e6b4..000000000 --- a/ReactNativeClient/lib/renderers/MdToHtml/rules/fountain.js +++ /dev/null @@ -1,134 +0,0 @@ -const fountain = require('lib/vendor/fountain.min.js'); - -const fountainCss = ` -.fountain { - font-family: monospace; - line-height: 107%; - max-width: 1000px; - margin-left: auto; - margin-right: auto; -} - -.fountain .title-page, -.fountain .page { - box-shadow: 0 0 5px rgba(0,0,0,0.1); - border: 1px solid #d2d2d2; - padding: 10%; - margin-bottom: 2em; -} - -.fountain h1, -.fountain h2, -.fountain h3, -.fountain h4, -.fountain p { - font-weight: normal; - line-height: 107%; - margin: 1em 0; - border: none; - font-size: 1em; -} - -.fountain .bold { - font-weight: bold; -} - -.fountain .underline { - text-decoration: underline; -} - -.fountain .centered { - text-align: center; -} - -.fountain h2 { - text-align: right; -} - -.fountain .dialogue p.parenthetical { - margin-left: 11%; -} - -.fountain .title-page .credit, -.fountain .title-page .authors, -.fountain .title-page .source { - text-align: center; -} - -.fountain .title-page h1 { - margin-bottom: 1.5em; - text-align: center; -} - -.fountain .title-page .source { - margin-top: 1.5em; -} - -.fountain .title-page .notes { - text-align: right; - margin: 3em 0; -} - -.fountain .title-page h1 { - margin-bottom: 1.5em; - text-align: center; -} - -.fountain .dialogue { - margin-left: 3em; - margin-right: 3em; -} - -.fountain .dialogue p, -.fountain .dialogue h1, -.fountain .dialogue h2, -.fountain .dialogue h3, -.fountain .dialogue h4 { - margin: 0; -} - -.fountain .dialogue h1, -.fountain .dialogue h2, -.fountain .dialogue h3, -.fountain .dialogue h4 { - text-align: center; -} -`; - -function renderFountainScript(content) { - const result = fountain.parse(content); - return ` -
    -
    - ${result.html.title_page} -
    -
    - ${result.html.script} -
    -
    - `; -} - -function addContextAssets(context) { - if ('fountain' in context.css) return; - context.css['fountain'] = fountainCss; -} - -function installRule(markdownIt, mdOptions, ruleOptions, context) { - const defaultRender = markdownIt.renderer.rules.fence || function(tokens, idx, options, env, self) { - return self.renderToken(tokens, idx, options); - }; - - markdownIt.renderer.rules.fence = function(tokens, idx, options, env, self) { - const token = tokens[idx]; - if (token.info !== 'fountain') return defaultRender(tokens, idx, options, env, self); - addContextAssets(context); - return renderFountainScript(token.content); - }; -} - -module.exports = function(context, ruleOptions) { - return function(md, mdOptions) { - installRule(md, mdOptions, ruleOptions, context); - }; -}; diff --git a/ReactNativeClient/lib/renderers/MdToHtml/rules/highlight_keywords.js b/ReactNativeClient/lib/renderers/MdToHtml/rules/highlight_keywords.js deleted file mode 100644 index 252cb711c..000000000 --- a/ReactNativeClient/lib/renderers/MdToHtml/rules/highlight_keywords.js +++ /dev/null @@ -1,67 +0,0 @@ -const StringUtils = require('lib/string-utils.js'); -const md5 = require('md5'); - -function createHighlightedTokens(Token, splitted) { - let token; - const output = []; - - for (let i = 0; i < splitted.length; i++) { - const text = splitted[i]; - if (!text) continue; - - if (i % 2 === 0) { - token = new Token('text', '', 0); - token.content = text; - output.push(token); - } else { - token = new Token('highlighted_keyword_open', 'span', 1); - token.attrs = [['class', 'highlighted-keyword']]; - output.push(token); - - token = new Token('text', '', 0); - token.content = text; - output.push(token); - - token = new Token('highlighted_keyword_close', 'span', -1); - output.push(token); - } - } - - return output; -} - -function installRule(markdownIt, mdOptions, ruleOptions) { - const divider = md5(Date.now().toString() + Math.random().toString()); - - markdownIt.core.ruler.push('highlight_keywords', state => { - const keywords = ruleOptions.highlightedKeywords; - if (!keywords || !keywords.length) return; - - const tokens = state.tokens; - const Token = state.Token; - - for (let i = 0; i < tokens.length; i++) { - const token = tokens[i]; - - if (token.type !== 'inline') continue; - - for (let j = 0; j < token.children.length; j++) { - const child = token.children[j]; - if (child.type !== 'text') continue; - - const splitted = StringUtils.surroundKeywords(keywords, child.content, divider, divider).split(divider); - const splittedTokens = createHighlightedTokens(Token, splitted); - if (splittedTokens.length <= 1) continue; - - token.children = markdownIt.utils.arrayReplaceAt(token.children, j, splittedTokens); - j += splittedTokens.length - 1; - } - } - }); -} - -module.exports = function(context, ruleOptions) { - return function(md, mdOptions) { - installRule(md, mdOptions, ruleOptions); - }; -}; diff --git a/ReactNativeClient/lib/renderers/MdToHtml/rules/html_image.js b/ReactNativeClient/lib/renderers/MdToHtml/rules/html_image.js deleted file mode 100644 index ea6ddc63b..000000000 --- a/ReactNativeClient/lib/renderers/MdToHtml/rules/html_image.js +++ /dev/null @@ -1,51 +0,0 @@ -const Resource = require('lib/models/Resource.js'); -const htmlUtils = require('lib/htmlUtils.js'); -const utils = require('../../utils'); - -function renderImageHtml(before, src, after, ruleOptions) { - const r = utils.imageReplacement(src, ruleOptions.resources, ruleOptions.resourceBaseUrl); - if (typeof r === 'string') return r; - if (r) return ``; - return `[Image: ${src}]`; -} - -function installRule(markdownIt, mdOptions, ruleOptions) { - const htmlBlockDefaultRender = - markdownIt.renderer.rules.html_block || - function(tokens, idx, options, env, self) { - return self.renderToken(tokens, idx, options); - }; - - const htmlInlineDefaultRender = - markdownIt.renderer.rules.html_inline || - function(tokens, idx, options, env, self) { - return self.renderToken(tokens, idx, options); - }; - - const imageRegex = //gi; - - const handleImageTags = function(defaultRender) { - return function(tokens, idx, options, env, self) { - const token = tokens[idx]; - const content = token.content; - - if (!content.match(imageRegex)) return defaultRender(tokens, idx, options, env, self); - - return content.replace(imageRegex, (v, before, src, after) => { - if (!Resource.isResourceUrl(src)) return defaultRender(tokens, idx, options, env, self); - return renderImageHtml(before, src, after, ruleOptions); - }); - }; - }; - - // It seems images sometimes are inline, sometimes a block - // to make sure they both render correctly. - markdownIt.renderer.rules.html_block = handleImageTags(htmlBlockDefaultRender); - markdownIt.renderer.rules.html_inline = handleImageTags(htmlInlineDefaultRender); -} - -module.exports = function(context, ruleOptions) { - return function(md, mdOptions) { - installRule(md, mdOptions, ruleOptions); - }; -}; diff --git a/ReactNativeClient/lib/renderers/MdToHtml/rules/image.js b/ReactNativeClient/lib/renderers/MdToHtml/rules/image.js deleted file mode 100644 index 6f9c09b84..000000000 --- a/ReactNativeClient/lib/renderers/MdToHtml/rules/image.js +++ /dev/null @@ -1,27 +0,0 @@ -const Resource = require('lib/models/Resource.js'); -const utils = require('../../utils'); -const htmlUtils = require('lib/htmlUtils.js'); - -function installRule(markdownIt, mdOptions, ruleOptions) { - const defaultRender = markdownIt.renderer.rules.image; - - markdownIt.renderer.rules.image = (tokens, idx, options, env, self) => { - const token = tokens[idx]; - const src = utils.getAttr(token.attrs, 'src'); - const title = utils.getAttr(token.attrs, 'title'); - - if (!Resource.isResourceUrl(src) || ruleOptions.plainResourceRendering) return defaultRender(tokens, idx, options, env, self); - - const r = utils.imageReplacement(src, ruleOptions.resources, ruleOptions.resourceBaseUrl); - if (typeof r === 'string') return r; - if (r) return ``; - - return defaultRender(tokens, idx, options, env, self); - }; -} - -module.exports = function(context, ruleOptions) { - return function(md, mdOptions) { - installRule(md, mdOptions, ruleOptions); - }; -}; diff --git a/ReactNativeClient/lib/renderers/MdToHtml/rules/katex.js b/ReactNativeClient/lib/renderers/MdToHtml/rules/katex.js deleted file mode 100644 index 894ec3d25..000000000 --- a/ReactNativeClient/lib/renderers/MdToHtml/rules/katex.js +++ /dev/null @@ -1,295 +0,0 @@ -// Based on https://github.com/waylonflinn/markdown-it-katex - -'use strict'; - -const { shim } = require('lib/shim'); -const Setting = require('lib/models/Setting'); -var katex = require('katex'); -const katexCss = require('lib/csstojs/katex.css.js'); -const md5 = require('md5'); -const mhchemModule = require('./katex_mhchem.js'); - -katex = mhchemModule(katex); - -// const style = ` -// /* -// This is to fix https://github.com/laurent22/joplin/issues/764 -// Without this, the tag attached to an equation float at an absolute position of the page, -// instead of a position relative to the container. -// 2018-03-13: No longer needed?? -// */ - -// /* -// .katex-display>.katex>.katex-html { -// position: relative; -// } -// */ -// ` - -// Test if potential opening or closing delimieter -// Assumes that there is a "$" at state.src[pos] -function isValidDelim(state, pos) { - var prevChar, - nextChar, - max = state.posMax, - can_open = true, - can_close = true; - - prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1; - nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1; - - // Check non-whitespace conditions for opening and closing, and - // check that closing delimeter isn't followed by a number - if (prevChar === 0x20 /* " " */ || prevChar === 0x09 /* \t */ || (nextChar >= 0x30 /* "0" */ && nextChar <= 0x39) /* "9" */) { - can_close = false; - } - if (nextChar === 0x20 /* " " */ || nextChar === 0x09 /* \t */) { - can_open = false; - } - - return { - can_open: can_open, - can_close: can_close, - }; -} - -function math_inline(state, silent) { - var start, match, token, res, pos; - - if (state.src[state.pos] !== '$') { - return false; - } - - res = isValidDelim(state, state.pos); - if (!res.can_open) { - if (!silent) { - state.pending += '$'; - } - state.pos += 1; - return true; - } - - // First check for and bypass all properly escaped delimieters - // This loop will assume that the first leading backtick can not - // be the first character in state.src, which is known since - // we have found an opening delimieter already. - start = state.pos + 1; - match = start; - while ((match = state.src.indexOf('$', match)) !== -1) { - // Found potential $, look for escapes, pos will point to - // first non escape when complete - pos = match - 1; - while (state.src[pos] === '\\') { - pos -= 1; - } - - // Even number of escapes, potential closing delimiter found - if ((match - pos) % 2 == 1) { - break; - } - match += 1; - } - - // No closing delimter found. Consume $ and continue. - if (match === -1) { - if (!silent) { - state.pending += '$'; - } - state.pos = start; - return true; - } - - // Check if we have empty content, ie: $$. Do not parse. - if (match - start === 0) { - if (!silent) { - state.pending += '$$'; - } - state.pos = start + 1; - return true; - } - - // Check for valid closing delimiter - res = isValidDelim(state, match); - if (!res.can_close) { - if (!silent) { - state.pending += '$'; - } - state.pos = start; - return true; - } - - if (!silent) { - token = state.push('math_inline', 'math', 0); - token.markup = '$'; - token.content = state.src.slice(start, match); - } - - state.pos = match + 1; - return true; -} - -function math_block(state, start, end, silent) { - var firstLine, - lastLine, - next, - lastPos, - found = false, - token, - pos = state.bMarks[start] + state.tShift[start], - max = state.eMarks[start]; - - if (pos + 2 > max) { - return false; - } - if (state.src.slice(pos, pos + 2) !== '$$') { - return false; - } - - pos += 2; - firstLine = state.src.slice(pos, max); - - if (silent) { - return true; - } - if (firstLine.trim().slice(-2) === '$$') { - // Single line expression - firstLine = firstLine.trim().slice(0, -2); - found = true; - } - - for (next = start; !found;) { - next++; - - if (next >= end) { - break; - } - - pos = state.bMarks[next] + state.tShift[next]; - max = state.eMarks[next]; - - if (pos < max && state.tShift[next] < state.blkIndent) { - // non-empty line with negative indent should stop the list: - break; - } - - if ( - state.src - .slice(pos, max) - .trim() - .slice(-2) === '$$' - ) { - lastPos = state.src.slice(0, max).lastIndexOf('$$'); - lastLine = state.src.slice(pos, lastPos); - found = true; - } - } - - state.line = next + 1; - - token = state.push('math_block', 'math', 0); - token.block = true; - token.content = (firstLine && firstLine.trim() ? `${firstLine}\n` : '') + state.getLines(start + 1, next, state.tShift[start], true) + (lastLine && lastLine.trim() ? lastLine : ''); - token.map = [start, state.line]; - token.markup = '$$'; - return true; -} - -let assetsLoaded_ = false; -let cache_ = {}; - -module.exports = function(context) { - // Keep macros that persist across Katex blocks to allow defining a macro - // in one block and re-using it later in other blocks. - // https://github.com/laurent22/joplin/issues/1105 - context.__katex = { macros: {} }; - - const addContextAssets = () => { - context.css['katex'] = katexCss; - context.assetLoaders['katex'] = async () => { - if (assetsLoaded_) return; - - // In node, the fonts are simply copied using copycss to where Katex expects to find them, which is under app/gui/note-viewer/fonts - - // In React Native, it's more complicated and we need to download and copy them to the right directory. Ideally, we should embed - // them as an asset and copy them from there (or load them from there by modifying Katex CSS), but for now that will do. - - if (shim.isReactNative()) { - // Fonts must go under the resourceDir directory because this is the baseUrl of NoteBodyViewer - const baseDir = Setting.value('resourceDir'); - await shim.fsDriver().mkdir(`${baseDir}/fonts`); - - await shim.fetchBlob('https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0-beta1/fonts/KaTeX_Main-Regular.woff2', { overwrite: false, path: `${baseDir}/fonts/KaTeX_Main-Regular.woff2` }); - await shim.fetchBlob('https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0-beta1/fonts/KaTeX_Math-Italic.woff2', { overwrite: false, path: `${baseDir}/fonts/KaTeX_Math-Italic.woff2` }); - await shim.fetchBlob('https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0-beta1/fonts/KaTeX_Size1-Regular.woff2', { overwrite: false, path: `${baseDir}/fonts/KaTeX_Size1-Regular.woff2` }); - } - - // eslint-disable-next-line require-atomic-updates - assetsLoaded_ = true; - }; - }; - - function renderToStringWithCache(latex, options) { - const cacheKey = md5(escape(latex) + escape(JSON.stringify(options))); - if (cacheKey in cache_) { - return cache_[cacheKey]; - } else { - const beforeMacros = JSON.stringify(options.macros); - const output = katex.renderToString(latex, options); - const afterMacros = JSON.stringify(options.macros); - - // Don't cache the formulas that add macros, otherwise - // they won't be added on second run. - if (beforeMacros === afterMacros) cache_[cacheKey] = output; - return output; - } - } - - return function(md, options) { - // Default options - - options = options || {}; - options.macros = context.__katex.macros; - - // set KaTeX as the renderer for markdown-it-simplemath - var katexInline = function(latex) { - options.displayMode = false; - try { - return renderToStringWithCache(latex, options); - } catch (error) { - if (options.throwOnError) { - console.log(error); - } - return latex; - } - }; - - var inlineRenderer = function(tokens, idx) { - addContextAssets(); - return katexInline(tokens[idx].content); - }; - - var katexBlock = function(latex) { - options.displayMode = true; - try { - return `

    ${renderToStringWithCache(latex, options)}

    `; - } catch (error) { - if (options.throwOnError) { - console.log(error); - } - return latex; - } - }; - - var blockRenderer = function(tokens, idx) { - addContextAssets(); - return `${katexBlock(tokens[idx].content)}\n`; - }; - - md.inline.ruler.after('escape', 'math_inline', math_inline); - md.block.ruler.after('blockquote', 'math_block', math_block, { - alt: ['paragraph', 'reference', 'blockquote', 'list'], - }); - md.renderer.rules.math_inline = inlineRenderer; - md.renderer.rules.math_block = blockRenderer; - }; -}; diff --git a/ReactNativeClient/lib/renderers/MdToHtml/rules/katex_mhchem.js b/ReactNativeClient/lib/renderers/MdToHtml/rules/katex_mhchem.js deleted file mode 100644 index 97887e4f8..000000000 --- a/ReactNativeClient/lib/renderers/MdToHtml/rules/katex_mhchem.js +++ /dev/null @@ -1,1732 +0,0 @@ -/* eslint-disable */ - - - - - -// 2018-10-13: -// This file is generated from mhchem.js by wrapping it in a function -// so that it can be imported in the various Joplin apps. -// To update it, paste the content of mhchem.js file inside the markers below. -// The file is at https://github.com/KaTeX/KaTeX/blob/master/contrib/mhchem/mhchem.js - - - - - - - -/************************************************************* - * - * KaTeX mhchem.js - * - * This file implements a KaTeX version of mhchem version 3.3.0. - * It is adapted from MathJax/extensions/TeX/mhchem.js - * It differs from the MathJax version as follows: - * 1. The interface is changed so that it can be called from KaTeX, not MathJax. - * 2. \rlap and \llap are replaced with \mathrlap and \mathllap. - * 3. Four lines of code are edited in order to use \raisebox instead of \raise. - * 4. The reaction arrow code is simplified. All reaction arrows are rendered - * using KaTeX extensible arrows instead of building non-extensible arrows. - * 5. \tripledash vertical alignment is slightly adjusted. - * - * This code, as other KaTeX code, is released under the MIT license. - * - * /************************************************************* - * - * MathJax/extensions/TeX/mhchem.js - * - * Implements the \ce command for handling chemical formulas - * from the mhchem LaTeX package. - * - * --------------------------------------------------------------------- - * - * Copyright (c) 2011-2015 The MathJax Consortium - * Copyright (c) 2015-2018 Martin Hensel - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Coding Style -// - use '' for identifiers that can by minified/uglified -// - use "" for strings that need to stay untouched - -// version: "3.3.0" for MathJax and KaTeX - - -// Add \ce, \pu, and \tripledash to the KaTeX macros. - -var mhchemModule = function(katex) { - - // ************************************************************************* - // ************************************************************************* - // Paste https://github.com/KaTeX/KaTeX/blob/master/contrib/mhchem/mhchem.js - // ************************************************************************* - // ************************************************************************* - - katex.__defineMacro("\\ce", function(context) { - return chemParse(context.consumeArgs(1)[0], "ce") - }); - - katex.__defineMacro("\\pu", function(context) { - return chemParse(context.consumeArgs(1)[0], "pu"); - }); - - // Needed for \bond for the ~ forms - // Raise by 2.56mu, not 2mu. We're raising a hyphen-minus, U+002D, not - // a mathematical minus, U+2212. So we need that extra 0.56. - katex.__defineMacro("\\tripledash", "{\\vphantom{-}\\raisebox{2.56mu}{$\\mkern2mu" - + "\\tiny\\text{-}\\mkern1mu\\text{-}\\mkern1mu\\text{-}\\mkern2mu$}}"); - - // - // This is the main function for handing the \ce and \pu commands. - // It takes the argument to \ce or \pu and returns the corresponding TeX string. - // - - var chemParse = function (tokens, stateMachine) { - // Recreate the argument string from KaTeX's array of tokens. - var str = ""; - var expectedLoc = tokens[tokens.length - 1].loc.start - for (var i = tokens.length - 1; i >= 0; i--) { - if(tokens[i].loc.start > expectedLoc) { - // context.consumeArgs has eaten a space. - str += " "; - expectedLoc = tokens[i].loc.start; - } - str += tokens[i].text; - expectedLoc += tokens[i].text.length; - } - var tex = texify.go(mhchemParser.go(str, stateMachine)); - return tex; - }; - - // - // Core parser for mhchem syntax (recursive) - // - /** @type {MhchemParser} */ - var mhchemParser = { - // - // Parses mchem \ce syntax - // - // Call like - // go("H2O"); - // - go: function (input, stateMachine) { - if (!input) { return []; } - if (stateMachine === undefined) { stateMachine = 'ce'; } - var state = '0'; - - // - // String buffers for parsing: - // - // buffer.a == amount - // buffer.o == element - // buffer.b == left-side superscript - // buffer.p == left-side subscript - // buffer.q == right-side subscript - // buffer.d == right-side superscript - // - // buffer.r == arrow - // buffer.rdt == arrow, script above, type - // buffer.rd == arrow, script above, content - // buffer.rqt == arrow, script below, type - // buffer.rq == arrow, script below, content - // - // buffer.text_ - // buffer.rm - // etc. - // - // buffer.parenthesisLevel == int, starting at 0 - // buffer.sb == bool, space before - // buffer.beginsWithBond == bool - // - // These letters are also used as state names. - // - // Other states: - // 0 == begin of main part (arrow/operator unlikely) - // 1 == next entity - // 2 == next entity (arrow/operator unlikely) - // 3 == next atom - // c == macro - // - /** @type {Buffer} */ - var buffer = {}; - buffer['parenthesisLevel'] = 0; - - input = input.replace(/\n/g, " "); - input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-"); - input = input.replace(/[\u2026]/g, "..."); - - // - // Looks through mhchemParser.transitions, to execute a matching action - // (recursive) - // - var lastInput; - var watchdog = 10; - /** @type {ParserOutput[]} */ - var output = []; - while (true) { - if (lastInput !== input) { - watchdog = 10; - lastInput = input; - } else { - watchdog--; - } - // - // Find actions in transition table - // - var machine = mhchemParser.stateMachines[stateMachine]; - var t = machine.transitions[state] || machine.transitions['*']; - iterateTransitions: - for (var i=0; i 0) { - if (!task.revisit) { - input = matches.remainder; - } - if (!task.toContinue) { - break iterateTransitions; - } - } else { - return output; - } - } - } - // - // Prevent infinite loop - // - if (watchdog <= 0) { - throw ["MhchemBugU", "mhchem bug U. Please report."]; // Unexpected character - } - } - }, - concatArray: function (a, b) { - if (b) { - if (Array.isArray(b)) { - for (var iB=0; iB': /^[=<>]/, - '#': /^[#\u2261]/, - '+': /^\+/, - '-$': /^-(?=[\s_},;\]/]|$|\([a-z]+\))/, // -space -, -; -] -/ -$ -state-of-aggregation - '-9': /^-(?=[0-9])/, - '- orbital overlap': /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/, - '-': /^-/, - 'pm-operator': /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/, - 'operator': /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/, - 'arrowUpDown': /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/, - '\\bond{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\bond{", "", "", "}"); }, - '->': /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/, - 'CMT': /^[CMT](?=\[)/, - '[(...)]': function (input) { return mhchemParser.patterns.findObserveGroups(input, "[", "", "", "]"); }, - '1st-level escape': /^(&|\\\\|\\hline)\s*/, - '\\,': /^(?:\\[,\ ;:])/, // \\x - but output no space before - '\\x{}{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); }, - '\\x{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", ""); }, - '\\ca': /^\\ca(?:\s+|(?![a-zA-Z]))/, - '\\x': /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/, - 'orbital': /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/, // only those with numbers in front, because the others will be formatted correctly anyway - 'others': /^[\/~|]/, - '\\frac{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\frac{", "", "", "}", "{", "", "", "}"); }, - '\\overset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\overset{", "", "", "}", "{", "", "", "}"); }, - '\\underset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underset{", "", "", "}", "{", "", "", "}"); }, - '\\underbrace{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underbrace{", "", "", "}_", "{", "", "", "}"); }, - '\\color{(...)}0': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}"); }, - '\\color{(...)}{(...)}1': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}", "{", "", "", "}"); }, - '\\color(...){(...)}2': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color", "\\", "", /^(?=\{)/, "{", "", "", "}"); }, - '\\ce{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\ce{", "", "", "}"); }, - 'oxidation$': /^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, - 'd-oxidation$': /^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, // 0 could be oxidation or charge - 'roman numeral': /^[IVX]+/, - '1/2$': /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/, - 'amount': function (input) { - var match; - // e.g. 2, 0.5, 1/2, -2, n/2, +; $a$ could be added later in parsing - match = input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - var a = mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); - if (a) { // e.g. $2n-1$, $-$ - match = a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - } - return null; - }, - 'amount2': function (input) { return this['amount'](input); }, - '(KV letters),': /^(?:[A-Z][a-z]{0,2}|i)(?=,)/, - 'formula$': function (input) { - if (input.match(/^\([a-z]+\)$/)) { return null; } // state of aggregation = no formula - var match = input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - return null; - }, - 'uprightEntities': /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/, - '/': /^\s*(\/)\s*/, - '//': /^\s*(\/\/)\s*/, - '*': /^\s*[*.]\s*/ - }, - findObserveGroups: function (input, begExcl, begIncl, endIncl, endExcl, beg2Excl, beg2Incl, end2Incl, end2Excl, combine) { - /** @type {{(input: string, pattern: string | RegExp): string | string[] | null;}} */ - var _match = function (input, pattern) { - if (typeof pattern === "string") { - if (input.indexOf(pattern) !== 0) { return null; } - return pattern; - } else { - var match = input.match(pattern); - if (!match) { return null; } - return match[0]; - } - }; - /** @type {{(input: string, i: number, endChars: string | RegExp): {endMatchBegin: number, endMatchEnd: number} | null;}} */ - var _findObserveGroups = function (input, i, endChars) { - var braces = 0; - while (i < input.length) { - var a = input.charAt(i); - var match = _match(input.substr(i), endChars); - if (match !== null && braces === 0) { - return { endMatchBegin: i, endMatchEnd: i + match.length }; - } else if (a === "{") { - braces++; - } else if (a === "}") { - if (braces === 0) { - throw ["ExtraCloseMissingOpen", "Extra close brace or missing open brace"]; - } else { - braces--; - } - } - i++; - } - if (braces > 0) { - return null; - } - return null; - }; - var match = _match(input, begExcl); - if (match === null) { return null; } - input = input.substr(match.length); - match = _match(input, begIncl); - if (match === null) { return null; } - var e = _findObserveGroups(input, match.length, endIncl || endExcl); - if (e === null) { return null; } - var match1 = input.substring(0, (endIncl ? e.endMatchEnd : e.endMatchBegin)); - if (!(beg2Excl || beg2Incl)) { - return { - match_: match1, - remainder: input.substr(e.endMatchEnd) - }; - } else { - var group2 = this.findObserveGroups(input.substr(e.endMatchEnd), beg2Excl, beg2Incl, end2Incl, end2Excl); - if (group2 === null) { return null; } - /** @type {string[]} */ - var matchRet = [match1, group2.match_]; - return { - match_: (combine ? matchRet.join("") : matchRet), - remainder: group2.remainder - }; - } - }, - - // - // Matching function - // e.g. match("a", input) will look for the regexp called "a" and see if it matches - // returns null or {match_:"a", remainder:"bc"} - // - match_: function (m, input) { - var pattern = mhchemParser.patterns.patterns[m]; - if (pattern === undefined) { - throw ["MhchemBugP", "mhchem bug P. Please report. (" + m + ")"]; // Trying to use non-existing pattern - } else if (typeof pattern === "function") { - return mhchemParser.patterns.patterns[m](input); // cannot use cached var pattern here, because some pattern functions need this===mhchemParser - } else { // RegExp - var match = input.match(pattern); - if (match) { - var mm; - if (match[2]) { - mm = [ match[1], match[2] ]; - } else if (match[1]) { - mm = match[1]; - } else { - mm = match[0]; - } - return { match_: mm, remainder: input.substr(match[0].length) }; - } - return null; - } - } - }, - - // - // Generic state machine actions - // - actions: { - 'a=': function (buffer, m) { buffer.a = (buffer.a || "") + m; }, - 'b=': function (buffer, m) { buffer.b = (buffer.b || "") + m; }, - 'p=': function (buffer, m) { buffer.p = (buffer.p || "") + m; }, - 'o=': function (buffer, m) { buffer.o = (buffer.o || "") + m; }, - 'q=': function (buffer, m) { buffer.q = (buffer.q || "") + m; }, - 'd=': function (buffer, m) { buffer.d = (buffer.d || "") + m; }, - 'rm=': function (buffer, m) { buffer.rm = (buffer.rm || "") + m; }, - 'text=': function (buffer, m) { buffer.text_ = (buffer.text_ || "") + m; }, - 'insert': function (buffer, m, a) { return { type_: a }; }, - 'insert+p1': function (buffer, m, a) { return { type_: a, p1: m }; }, - 'insert+p1+p2': function (buffer, m, a) { return { type_: a, p1: m[0], p2: m[1] }; }, - 'copy': function (buffer, m) { return m; }, - 'rm': function (buffer, m) { return { type_: 'rm', p1: m || ""}; }, - 'text': function (buffer, m) { return mhchemParser.go(m, 'text'); }, - '{text}': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'text')); - ret.push("}"); - return ret; - }, - 'tex-math': function (buffer, m) { return mhchemParser.go(m, 'tex-math'); }, - 'tex-math tight': function (buffer, m) { return mhchemParser.go(m, 'tex-math tight'); }, - 'bond': function (buffer, m, k) { return { type_: 'bond', kind_: k || m }; }, - 'color0-output': function (buffer, m) { return { type_: 'color0', color: m[0] }; }, - 'ce': function (buffer, m) { return mhchemParser.go(m); }, - '1/2': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m.match(/^[+\-]/)) { - ret.push(m.substr(0, 1)); - m = m.substr(1); - } - var n = m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/); - n[1] = n[1].replace(/\$/g, ""); - ret.push({ type_: 'frac', p1: n[1], p2: n[2] }); - if (n[3]) { - n[3] = n[3].replace(/\$/g, ""); - ret.push({ type_: 'tex-math', p1: n[3] }); - } - return ret; - }, - '9,9': function (buffer, m) { return mhchemParser.go(m, '9,9'); } - }, - // - // createTransitions - // convert { 'letter': { 'state': { action_: 'output' } } } to { 'state' => [ { pattern: 'letter', task: { action_: [{type_: 'output'}] } } ] } - // with expansion of 'a|b' to 'a' and 'b' (at 2 places) - // - createTransitions: function (o) { - var pattern, state; - /** @type {string[]} */ - var stateArray; - var i; - // - // 1. Collect all states - // - /** @type {Transitions} */ - var transitions = {}; - for (pattern in o) { - for (state in o[pattern]) { - stateArray = state.split("|"); - o[pattern][state].stateArray = stateArray; - for (i=0; i': { - '0|1|2|3': { action_: 'r=', nextState: 'r' }, - 'a|as': { action_: [ 'output', 'r=' ], nextState: 'r' }, - '*': { action_: [ 'output', 'r=' ], nextState: 'r' } }, - '+': { - 'o': { action_: 'd= kv', nextState: 'd' }, - 'd|D': { action_: 'd=', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd|qD': { action_: 'd=', nextState: 'qd' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' }, - '3': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - 'amount': { - '0|2': { action_: 'a=', nextState: 'a' } }, - 'pm-operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', { type_: 'operator', option: '\\pm' } ], nextState: '0' } }, - 'operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - '-$': { - 'o|q': { action_: [ 'charge or bond', 'output' ], nextState: 'qd' }, - 'd': { action_: 'd=', nextState: 'd' }, - 'D': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd': { action_: 'd=', nextState: 'qd' }, - 'qD|dq': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - '-9': { - '3|o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '3' } }, - '- orbital overlap': { - 'o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'd': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' } }, - '-': { - '0|1|2': { action_: [ { type_: 'output', option: 1 }, 'beginsWithBond=true', { type_: 'bond', option: "-" } ], nextState: '3' }, - '3': { action_: { type_: 'bond', option: "-" } }, - 'a': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'as': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "-" } ], nextState: '3' }, - 'b': { action_: 'b=' }, - 'o': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'q': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'd|qd|dq': { action_: { type_: '- after o/d', option: true }, nextState: '2' }, - 'D|qD|p': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - 'amount2': { - '1|3': { action_: 'a=', nextState: 'a' } }, - 'letters': { - '0|1|2|3|a|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, - 'q|dq': { action_: ['output', 'o='], nextState: 'o' }, - 'd|D|qd|qD': { action_: 'o after d', nextState: 'o' } }, - 'digits': { - 'o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q': { action_: [ 'output', 'o=' ], nextState: 'o' }, - 'a': { action_: 'o=', nextState: 'o' } }, - 'space A': { - 'b|p|bp': {} }, - 'space': { - 'a': { nextState: 'as' }, - '0': { action_: 'sb=false' }, - '1|2': { action_: 'sb=true' }, - 'r|rt|rd|rdt|rdq': { action_: 'output', nextState: '0' }, - '*': { action_: [ 'output', 'sb=true' ], nextState: '1'} }, - '1st-level escape': { - '1|2': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ] }, - '*': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ], nextState: '0' } }, - '[(...)]': { - 'r|rt': { action_: 'rd=', nextState: 'rd' }, - 'rd|rdt': { action_: 'rq=', nextState: 'rdq' } }, - '...': { - 'o|d|D|dq|qd|qD': { action_: [ 'output', { type_: 'bond', option: "..." } ], nextState: '3' }, - '*': { action_: [ { type_: 'output', option: 1 }, { type_: 'insert', option: 'ellipsis' } ], nextState: '1' } }, - '. |* ': { - '*': { action_: [ 'output', { type_: 'insert', option: 'addition compound' } ], nextState: '1' } }, - 'state of aggregation $': { - '*': { action_: [ 'output', 'state of aggregation' ], nextState: '1' } }, - '{[(': { - 'a|as|o': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '0|1|2|3': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '*': { action_: [ 'output', 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' } }, - ')]}': { - '0|1|2|3|b|p|bp|o': { action_: [ 'o=', 'parenthesisLevel--' ], nextState: 'o' }, - 'a|as|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=', 'parenthesisLevel--' ], nextState: 'o' } }, - ', ': { - '*': { action_: [ 'output', 'comma' ], nextState: '0' } }, - '^_': { // ^ and _ without a sensible argument - '*': { } }, - '^{(...)}|^($...$)': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'D' }, - 'q': { action_: 'd=', nextState: 'qD' }, - 'd|D|qd|qD|dq': { action_: [ 'output', 'd=' ], nextState: 'D' } }, - '^a|^\\x{}{}|^\\x{}|^\\x|\'': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'd|qd|D|qD': { action_: 'd=' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' } }, - '_{(state of aggregation)}$': { - 'd|D|q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x': { - '0|1|2|as': { action_: 'p=', nextState: 'p' }, - 'b': { action_: 'p=', nextState: 'bp' }, - '3|o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '=<>': { - '0|1|2|3|a|as|o|q|d|D|qd|qD|dq': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: '3' } }, - '#': { - '0|1|2|3|a|as|o': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "#" } ], nextState: '3' } }, - '{}': { - '*': { action_: { type_: 'output', option: 1 }, nextState: '1' } }, - '{...}': { - '0|1|2|3|a|as|b|p|bp': { action_: 'o=', nextState: 'o' }, - 'o|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '$...$': { - 'a': { action_: 'a=' }, // 2$n$ - '0|1|2|3|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, // not 'amount' - 'as|o': { action_: 'o=' }, - 'q|d|D|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '\\bond{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: "3" } }, - '\\frac{(...)}': { - '*': { action_: [ { type_: 'output', option: 1 }, 'frac-output' ], nextState: '3' } }, - '\\overset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'overset-output' ], nextState: '3' } }, - '\\underset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underset-output' ], nextState: '3' } }, - '\\underbrace{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underbrace-output' ], nextState: '3' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color-output' ], nextState: '3' } }, - '\\color{(...)}0': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color0-output' ] } }, - '\\ce{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'ce' ], nextState: '3' } }, - '\\,': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '1' } }, - '\\x{}{}|\\x{}|\\x': { - '0|1|2|3|a|as|b|p|bp|o|c0': { action_: [ 'o=', 'output' ], nextState: '3' }, - '*': { action_: ['output', 'o=', 'output' ], nextState: '3' } }, - 'others': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '3' } }, - 'else2': { - 'a': { action_: 'a to o', nextState: 'o', revisit: true }, - 'as': { action_: [ 'output', 'sb=true' ], nextState: '1', revisit: true }, - 'r|rt|rd|rdt|rdq': { action_: [ 'output' ], nextState: '0', revisit: true }, - '*': { action_: [ 'output', 'copy' ], nextState: '3' } } - }), - actions: { - 'o after d': function (buffer, m) { - var ret; - if ((buffer.d || "").match(/^[0-9]+$/)) { - var tmp = buffer.d; - buffer.d = undefined; - ret = this['output'](buffer); - buffer.b = tmp; - } else { - ret = this['output'](buffer); - } - mhchemParser.actions['o='](buffer, m); - return ret; - }, - 'd= kv': function (buffer, m) { - buffer.d = m; - buffer.dType = 'kv'; - }, - 'charge or bond': function (buffer, m) { - if (buffer['beginsWithBond']) { - /** @type {ParserOutput[]} */ - var ret = []; - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - return ret; - } else { - buffer.d = m; - } - }, - '- after o/d': function (buffer, m, isAfterD) { - var c1 = mhchemParser.patterns.match_('orbital', buffer.o || ""); - var c2 = mhchemParser.patterns.match_('one lowercase greek letter $', buffer.o || ""); - var c3 = mhchemParser.patterns.match_('one lowercase latin letter $', buffer.o || ""); - var c4 = mhchemParser.patterns.match_('$one lowercase latin letter$ $', buffer.o || ""); - var hyphenFollows = m==="-" && ( c1 && c1.remainder==="" || c2 || c3 || c4 ); - if (hyphenFollows && !buffer.a && !buffer.b && !buffer.p && !buffer.d && !buffer.q && !c1 && c3) { - buffer.o = '$' + buffer.o + '$'; - } - /** @type {ParserOutput[]} */ - var ret = []; - if (hyphenFollows) { - mhchemParser.concatArray(ret, this['output'](buffer)); - ret.push({ type_: 'hyphen' }); - } else { - c1 = mhchemParser.patterns.match_('digits', buffer.d || ""); - if (isAfterD && c1 && c1.remainder==='') { - mhchemParser.concatArray(ret, mhchemParser.actions['d='](buffer, m)); - mhchemParser.concatArray(ret, this['output'](buffer)); - } else { - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - } - } - return ret; - }, - 'a to o': function (buffer) { - buffer.o = buffer.a; - buffer.a = undefined; - }, - 'sb=true': function (buffer) { buffer.sb = true; }, - 'sb=false': function (buffer) { buffer.sb = false; }, - 'beginsWithBond=true': function (buffer) { buffer['beginsWithBond'] = true; }, - 'beginsWithBond=false': function (buffer) { buffer['beginsWithBond'] = false; }, - 'parenthesisLevel++': function (buffer) { buffer['parenthesisLevel']++; }, - 'parenthesisLevel--': function (buffer) { buffer['parenthesisLevel']--; }, - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation', p1: mhchemParser.go(m, 'o') }; - }, - 'comma': function (buffer, m) { - var a = m.replace(/\s*$/, ''); - var withSpace = (a !== m); - if (withSpace && buffer['parenthesisLevel'] === 0) { - return { type_: 'comma enumeration L', p1: a }; - } else { - return { type_: 'comma enumeration M', p1: a }; - } - }, - 'output': function (buffer, m, entityFollows) { - // entityFollows: - // undefined = if we have nothing else to output, also ignore the just read space (buffer.sb) - // 1 = an entity follows, never omit the space if there was one just read before (can only apply to state 1) - // 2 = 1 + the entity can have an amount, so output a\, instead of converting it to o (can only apply to states a|as) - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - if (!buffer.r) { - ret = []; - if (!buffer.a && !buffer.b && !buffer.p && !buffer.o && !buffer.q && !buffer.d && !entityFollows) { - //ret = []; - } else { - if (buffer.sb) { - ret.push({ type_: 'entitySkip' }); - } - if (!buffer.o && !buffer.q && !buffer.d && !buffer.b && !buffer.p && entityFollows!==2) { - buffer.o = buffer.a; - buffer.a = undefined; - } else if (!buffer.o && !buffer.q && !buffer.d && (buffer.b || buffer.p)) { - buffer.o = buffer.a; - buffer.d = buffer.b; - buffer.q = buffer.p; - buffer.a = buffer.b = buffer.p = undefined; - } else { - if (buffer.o && buffer.dType==='kv' && mhchemParser.patterns.match_('d-oxidation$', buffer.d || "")) { - buffer.dType = 'oxidation'; - } else if (buffer.o && buffer.dType==='kv' && !buffer.q) { - buffer.dType = undefined; - } - } - ret.push({ - type_: 'chemfive', - a: mhchemParser.go(buffer.a, 'a'), - b: mhchemParser.go(buffer.b, 'bd'), - p: mhchemParser.go(buffer.p, 'pq'), - o: mhchemParser.go(buffer.o, 'o'), - q: mhchemParser.go(buffer.q, 'pq'), - d: mhchemParser.go(buffer.d, (buffer.dType === 'oxidation' ? 'oxidation' : 'bd')), - dType: buffer.dType - }); - } - } else { // r - /** @type {ParserOutput[]} */ - var rd; - if (buffer.rdt === 'M') { - rd = mhchemParser.go(buffer.rd, 'tex-math'); - } else if (buffer.rdt === 'T') { - rd = [ { type_: 'text', p1: buffer.rd || "" } ]; - } else { - rd = mhchemParser.go(buffer.rd); - } - /** @type {ParserOutput[]} */ - var rq; - if (buffer.rqt === 'M') { - rq = mhchemParser.go(buffer.rq, 'tex-math'); - } else if (buffer.rqt === 'T') { - rq = [ { type_: 'text', p1: buffer.rq || ""} ]; - } else { - rq = mhchemParser.go(buffer.rq); - } - ret = { - type_: 'arrow', - r: buffer.r, - rd: rd, - rq: rq - }; - } - for (var p in buffer) { - if (p !== 'parenthesisLevel' && p !== 'beginsWithBond') { - delete buffer[p]; - } - } - return ret; - }, - 'oxidation-output': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'oxidation')); - ret.push("}"); - return ret; - }, - 'frac-output': function (buffer, m) { - return { type_: 'frac-ce', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'overset-output': function (buffer, m) { - return { type_: 'overset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underset-output': function (buffer, m) { - return { type_: 'underset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underbrace-output': function (buffer, m) { - return { type_: 'underbrace', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1]) }; - }, - 'r=': function (buffer, m) { buffer.r = m; }, - 'rdt=': function (buffer, m) { buffer.rdt = m; }, - 'rd=': function (buffer, m) { buffer.rd = m; }, - 'rqt=': function (buffer, m) { buffer.rqt = m; }, - 'rq=': function (buffer, m) { buffer.rq = m; }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; } - } - }, - 'a': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - '$(...)$': { - '*': { action_: 'tex-math tight', nextState: '1' } }, - ',': { - '*': { action_: { type_: 'insert', option: 'commaDecimal' } } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'o': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - 'letters': { - '*': { action_: 'rm' } }, - '\\ca': { - '*': { action_: { type_: 'insert', option: 'circa' } } }, - '\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: '{text}' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'text': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '{...}': { - '*': { action_: 'text=' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '\\greek': { - '*': { action_: [ 'output', 'rm' ] } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: [ 'output', 'copy' ] } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.text_) { - /** @type {ParserOutput} */ - var ret = { type_: 'text', p1: buffer.text_ }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'pq': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'state of aggregation $': { - '*': { action_: 'state of aggregation' } }, - 'i$': { - '0': { nextState: '!f', revisit: true } }, - '(KV letters),': { - '0': { action_: 'rm', nextState: '0' } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'letters': { - '*': { action_: 'rm' } }, - '-9.,9': { - '*': { action_: '9,9' } }, - ',': { - '*': { action_: { type_: 'insert+p1', option: 'comma enumeration S' } } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation subscript', p1: mhchemParser.go(m, 'o') }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'pq') }; - } - } - }, - 'bd': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'x$': { - '0': { nextState: '!f', revisit: true } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '-9.,9 no missing 0': { - '*': { action_: '9,9' } }, - '.': { - '*': { action_: { type_: 'insert', option: 'electron dot' } } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'x': { - '*': { action_: { type_: 'insert', option: 'KV x' } } }, - 'letters': { - '*': { action_: 'rm' } }, - '\'': { - '*': { action_: { type_: 'insert', option: 'prime' } } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'bd') }; - } - } - }, - 'oxidation': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'roman numeral': { - '*': { action_: 'roman-numeral' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'roman-numeral': function (buffer, m) { return { type_: 'roman numeral', p1: m || "" }; } - } - }, - 'tex-math': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'tex-math tight': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - '-|+': { - '*': { action_: 'tight operator' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'tight operator': function (buffer, m) { buffer.o = (buffer.o || "") + "{"+m+"}"; }, - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - '9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - ',': { - '*': { action_: 'comma' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; } - } - }, - //#endregion - // - // \pu state machines - // - //#region pu - 'pu': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - 'space$': { - '*': { action_: [ 'output', 'space' ] } }, - '{[(|)]}': { - '0|a': { action_: 'copy' } }, - '(-)(9)^(-9)': { - '0': { action_: 'number^', nextState: 'a' } }, - '(-)(9.,9)(e)(99)': { - '0': { action_: 'enumber', nextState: 'a' } }, - 'space': { - '0|a': {} }, - 'pm-operator': { - '0|a': { action_: { type_: 'operator', option: '\\pm' }, nextState: '0' } }, - 'operator': { - '0|a': { action_: 'copy', nextState: '0' } }, - '//': { - 'd': { action_: 'o=', nextState: '/' } }, - '/': { - 'd': { action_: 'o=', nextState: '/' } }, - '{...}|else': { - '0|d': { action_: 'd=', nextState: 'd' }, - 'a': { action_: [ 'space', 'd=' ], nextState: 'd' }, - '/|q': { action_: 'q=', nextState: 'q' } } - }), - actions: { - 'enumber': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - if (m[1]) { - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - if (m[2]) { - if (m[2].match(/[,.]/)) { - mhchemParser.concatArray(ret, mhchemParser.go(m[2], 'pu-9,9')); - } else { - ret.push(m[2]); - } - } - m[3] = m[4] || m[3]; - if (m[3]) { - m[3] = m[3].trim(); - if (m[3] === "e" || m[3].substr(0, 1) === "*") { - ret.push({ type_: 'cdot' }); - } else { - ret.push({ type_: 'times' }); - } - } - } - if (m[3]) { - ret.push("10^{"+m[5]+"}"); - } - return ret; - }, - 'number^': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - ret.push("^{"+m[2]+"}"); - return ret; - }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; }, - 'space': function () { return { type_: 'pu-space-1' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - var md = mhchemParser.patterns.match_('{(...)}', buffer.d || ""); - if (md && md.remainder === '') { buffer.d = md.match_; } - var mq = mhchemParser.patterns.match_('{(...)}', buffer.q || ""); - if (mq && mq.remainder === '') { buffer.q = mq.match_; } - if (buffer.d) { - buffer.d = buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.d = buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - } - if (buffer.q) { // fraction - buffer.q = buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.q = buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - var b5 = { - d: mhchemParser.go(buffer.d, 'pu'), - q: mhchemParser.go(buffer.q, 'pu') - }; - if (buffer.o === '//') { - ret = { type_: 'pu-frac', p1: b5.d, p2: b5.q }; - } else { - ret = b5.d; - if (b5.d.length > 1 || b5.q.length > 1) { - ret.push({ type_: ' / ' }); - } else { - ret.push({ type_: '/' }); - } - mhchemParser.concatArray(ret, b5.q); - } - } else { // no fraction - ret = mhchemParser.go(buffer.d, 'pu-2'); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-2': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '*': { - '*': { action_: [ 'output', 'cdot' ], nextState: '0' } }, - '\\x': { - '*': { action_: 'rm=' } }, - 'space': { - '*': { action_: [ 'output', 'space' ], nextState: '0' } }, - '^{(...)}|^(-1)': { - '1': { action_: '^(-1)' } }, - '-9.,9': { - '0': { action_: 'rm=', nextState: '0' }, - '1': { action_: '^(-1)', nextState: '0' } }, - '{...}|else': { - '*': { action_: 'rm=', nextState: '1' } } - }), - actions: { - 'cdot': function () { return { type_: 'tight cdot' }; }, - '^(-1)': function (buffer, m) { buffer.rm += "^{"+m+"}"; }, - 'space': function () { return { type_: 'pu-space-2' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret = []; - if (buffer.rm) { - var mrm = mhchemParser.patterns.match_('{(...)}', buffer.rm || ""); - if (mrm && mrm.remainder === '') { - ret = mhchemParser.go(mrm.match_, 'pu'); - } else { - ret = { type_: 'rm', p1: buffer.rm }; - } - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '0': { action_: 'output-0' }, - 'o': { action_: 'output-o' } }, - ',': { - '0': { action_: [ 'output-0', 'comma' ], nextState: 'o' } }, - '.': { - '0': { action_: [ 'output-0', 'copy' ], nextState: 'o' } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; }, - 'output-0': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length % 3; - if (a === 0) { a = 3; } - for (var i=buffer.text_.length-3; i>0; i-=3) { - ret.push(buffer.text_.substr(i, 3)); - ret.push({ type_: '1000 separator' }); - } - ret.push(buffer.text_.substr(0, a)); - ret.reverse(); - } else { - ret.push(buffer.text_); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - }, - 'output-o': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length - 3; - for (var i=0; i": return "rightarrow"; - case "\u2192": return "rightarrow"; - case "\u27F6": return "rightarrow"; - case "<-": return "leftarrow"; - case "<->": return "leftrightarrow"; - case "<-->": return "rightleftarrows"; - case "<=>": return "rightleftharpoons"; - case "\u21CC": return "rightleftharpoons"; - case "<=>>": return "rightequilibrium"; - case "<<=>": return "leftequilibrium"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getBond: function (a) { - switch (a) { - case "-": return "{-}"; - case "1": return "{-}"; - case "=": return "{=}"; - case "2": return "{=}"; - case "#": return "{\\equiv}"; - case "3": return "{\\equiv}"; - case "~": return "{\\tripledash}"; - case "~-": return "{\\mathrlap{\\raisebox{-.1em}{$-$}}\\raisebox{.1em}{$\\tripledash$}}"; - case "~=": return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}"; - case "~--": return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}"; - case "-~-": return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$-$}}\\tripledash}"; - case "...": return "{{\\cdot}{\\cdot}{\\cdot}}"; - case "....": return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}"; - case "->": return "{\\rightarrow}"; - case "<-": return "{\\leftarrow}"; - case "<": return "{<}"; - case ">": return "{>}"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getOperator: function (a) { - switch (a) { - case "+": return " {}+{} "; - case "-": return " {}-{} "; - case "=": return " {}={} "; - case "<": return " {}<{} "; - case ">": return " {}>{} "; - case "<<": return " {}\\ll{} "; - case ">>": return " {}\\gg{} "; - case "\\pm": return " {}\\pm{} "; - case "\\approx": return " {}\\approx{} "; - case "$\\approx$": return " {}\\approx{} "; - case "v": return " \\downarrow{} "; - case "(v)": return " \\downarrow{} "; - case "^": return " \\uparrow{} "; - case "(^)": return " \\uparrow{} "; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - } - }; - - // - // Helpers for code anaylsis - // Will show type error at calling position - // - /** @param {number} a */ - function assertNever(a) {} - /** @param {string} a */ - function assertString(a) {} - - // ******************************************************************************** - // ******************************************************************************** - // End of paste https://github.com/KaTeX/KaTeX/blob/master/contrib/mhchem/mhchem.js - // ******************************************************************************** - // ******************************************************************************** - - return katex; -} - -if (this.katex) { - // We're running in a browser and the global Katex variable is defined - this.katex = mhchemModule(this.katex); -} else if (typeof module !== 'undefined' && module.exports) { - // We're running in Node.js - module.exports = mhchemModule; -} diff --git a/ReactNativeClient/lib/renderers/MdToHtml/rules/link_open.js b/ReactNativeClient/lib/renderers/MdToHtml/rules/link_open.js deleted file mode 100644 index 2fbcf4ea9..000000000 --- a/ReactNativeClient/lib/renderers/MdToHtml/rules/link_open.js +++ /dev/null @@ -1,74 +0,0 @@ -const Entities = require('html-entities').AllHtmlEntities; -const htmlentities = new Entities().encode; -const utils = require('../../utils'); -const urlUtils = require('lib/urlUtils.js'); -const { getClassNameForMimeType } = require('font-awesome-filetypes'); - -function installRule(markdownIt, mdOptions, ruleOptions) { - markdownIt.renderer.rules.link_open = function(tokens, idx) { - const token = tokens[idx]; - let href = utils.getAttr(token.attrs, 'href'); - const resourceHrefInfo = urlUtils.parseResourceUrl(href); - const isResourceUrl = !!resourceHrefInfo; - let title = utils.getAttr(token.attrs, 'title', isResourceUrl ? '' : href); - - let resourceIdAttr = ''; - let icon = ''; - let hrefAttr = '#'; - let mime = ''; - if (isResourceUrl) { - const resourceId = resourceHrefInfo.itemId; - - const result = ruleOptions.resources[resourceId]; - const resourceStatus = utils.resourceStatus(result); - - if (result && result.item) { - title = utils.getAttr(token.attrs, 'title', result.item.title); - mime = result.item.mime; - } - - if (result && resourceStatus !== 'ready' && !ruleOptions.plainResourceRendering) { - const icon = utils.resourceStatusFile(resourceStatus); - return `` + ``; - } else { - href = `joplin://${resourceId}`; - if (resourceHrefInfo.hash) href += `#${resourceHrefInfo.hash}`; - resourceIdAttr = `data-resource-id='${resourceId}'`; - - let iconType = getClassNameForMimeType(mime); - if (!mime) { - iconType = 'fa-joplin'; - } - // Icons are defined in lib/renderers/noteStyle.js using inline svg - // The icons are taken from fork-awesome but use the font-awesome naming scheme in order - // to be more compatible with the getClass library - icon = ``; - } - } else { - // If the link is a plain URL (as opposed to a resource link), set the href to the actual - // link. This allows the link to be exported too when exporting to PDF. - hrefAttr = href; - } - - // A single quote is valid in a URL but we don't want any because the - // href is already enclosed in single quotes. - // https://github.com/laurent22/joplin/issues/2030 - href = href.replace(/'/g, '%27'); - - let js = `${ruleOptions.postMessageSyntax}(${JSON.stringify(href)}); return false;`; - if (hrefAttr.indexOf('#') === 0 && href.indexOf('#') === 0) js = ''; // If it's an internal anchor, don't add any JS since the webview is going to handle navigating to the right place - - if (ruleOptions.plainResourceRendering) { - return ``; - } else { - return `${icon}`; - } - }; -} - -module.exports = function(context, ruleOptions) { - - return function(md, mdOptions) { - installRule(md, mdOptions, ruleOptions); - }; -}; diff --git a/ReactNativeClient/lib/renderers/MdToHtml/setupLinkify.js b/ReactNativeClient/lib/renderers/MdToHtml/setupLinkify.js deleted file mode 100644 index 5552f8f45..000000000 --- a/ReactNativeClient/lib/renderers/MdToHtml/setupLinkify.js +++ /dev/null @@ -1,29 +0,0 @@ -module.exports = function(markdownIt) { - // Add `file:` protocol in linkify to allow text in the format of "file://..." to translate into - // file-URL links in html view - markdownIt.linkify.add('file:', { - validate: function(text, pos, self) { - var tail = text.slice(pos); - if (!self.re.file) { - // matches all local file URI on Win/Unix/MacOS systems including reserved characters in some OS (i.e. no OS specific sanity check) - self.re.file = new RegExp('^[\\/]{2,3}[\\S]+'); - } - if (self.re.file.test(tail)) { - return tail.match(self.re.file)[0].length; - } - return 0; - }, - }); - - // enable file link URLs in MarkdownIt. Keeps other URL restrictions of MarkdownIt untouched. - // Format [link name](file://...) - markdownIt.validateLink = function(url) { - var BAD_PROTO_RE = /^(vbscript|javascript|data):/; - var GOOD_DATA_RE = /^data:image\/(gif|png|jpeg|webp);/; - - // url should be normalized at this point, and existing entities are decoded - var str = url.trim().toLowerCase(); - - return BAD_PROTO_RE.test(str) ? (GOOD_DATA_RE.test(str) ? true : false) : true; - }; -}; diff --git a/ReactNativeClient/lib/renderers/noteStyle.js b/ReactNativeClient/lib/renderers/noteStyle.js deleted file mode 100644 index 64d4d5764..000000000 --- a/ReactNativeClient/lib/renderers/noteStyle.js +++ /dev/null @@ -1,291 +0,0 @@ -module.exports = function(style, options) { - // https://necolas.github.io/normalize.css/ - const normalizeCss = ` - html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0} - article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible} - pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects} - b,strong{font-weight:bolder}small{font-size:80%}img{border-style:none} - `; - - const fontFamily = '\'Avenir\', \'Arial\', sans-serif'; - - const css = - ` - body { - font-size: ${style.htmlFontSize}; - color: ${style.htmlColor}; - line-height: ${style.htmlLineHeight}; - background-color: ${style.htmlBackgroundColor}; - font-family: ${fontFamily}; - padding-bottom: ${options.paddingBottom}; - } - strong { - color: ${style.colorBright}; - } - kbd { - border: 1px solid ${style.htmlCodeBorderColor}; - box-shadow: inset 0 -1px 0 ${style.htmlCodeBorderColor}; - padding: 2px 4px; - border-radius: 3px; - background-color: ${style.htmlCodeBackgroundColor}; - } - ::-webkit-scrollbar { - width: 7px; - height: 7px; - } - ::-webkit-scrollbar-corner { - background: none; - } - ::-webkit-scrollbar-track { - border: none; - } - ::-webkit-scrollbar-thumb { - background: rgba(100, 100, 100, 0.3); - border-radius: 5px; - } - ::-webkit-scrollbar-track:hover { - background: rgba(0, 0, 0, 0.1); - } - ::-webkit-scrollbar-thumb:hover { - background: rgba(100, 100, 100, 0.7); - } - - /* Remove top padding and margin from first child so that top of rendered text is aligned to top of text editor text */ - #rendered-md h1:first-child, - #rendered-md h2:first-child, - #rendered-md h3:first-child, - #rendered-md h4:first-child, - #rendered-md ul:first-child, - #rendered-md ol:first-child, - #rendered-md table:first-child, - #rendered-md blockquote:first-child, - #rendered-md img:first-child, - #rendered-md p:first-child { - margin-top: 0; - padding-top: 0; - } - - p, h1, h2, h3, h4, h5, h6, ul, table { - margin-top: .6em; - margin-bottom: .65em; - } - h1, h2, h3, h4, h5, h6 { - line-height: 1.5em; - } - h1 { - font-size: 1.5em; - font-weight: bold; - border-bottom: 1px solid ${style.htmlDividerColor}; - padding-bottom: .3em; - } - h2 { - font-size: 1.3em; - font-weight: bold; - padding-bottom: .1em; */ - } - h3 { - font-size: 1.1em; - } - h4, h5, h6 { - font-size: 1em; - font-weight: bold; - } - a { - color: ${style.htmlLinkColor}; - } - ul, ol { - padding-left: 0; - margin-left: 1.7em; - } - li { - margin-bottom: .4em; - } - li p { - margin-top: 0.2em; - margin-bottom: 0; - } - .resource-icon { - display: inline-block; - position: relative; - top: .5em; - text-decoration: none; - width: 1.2em; - height: 1.4em; - margin-right: 0.4em; - background-color: ${style.htmlLinkColor}; - } - /* These icons are obtained from the wonderful ForkAwesome project by copying the src svgs - * into the css classes below. - * svgs are obtained from https://github.com/ForkAwesome/Fork-Awesome/tree/master/src/icons/svg - * instead of the svg width, height property you must use a viewbox here, 0 0 1536 1792 is typically the actual size of the icon - * each line begins with the pre-amble -webkit-mask: url("data:image/svg+xml;utf8, - * and of course finishes with "); - * to precvent artifacts it is also necessary to include -webkit-mask-repeat: no-repeat; - * on the following line - * */ - .fa-joplin { - /* Awesome Font file */ - -webkit-mask: url("data:image/svg+xml;utf8,"); - } - .fa-file-image { - -webkit-mask: url("data:image/svg+xml;utf8,"); - -webkit-mask-repeat: no-repeat; - } - .fa-file-pdf { - -webkit-mask: url("data:image/svg+xml;utf8,"); - -webkit-mask-repeat: no-repeat; - } - .fa-file-word { - -webkit-mask: url("data:image/svg+xml;utf8,"); - -webkit-mask-repeat: no-repeat; - } - .fa-file-powerpoint { - -webkit-mask: url("data:image/svg+xml;utf8,"); - -webkit-mask-repeat: no-repeat; - } - .fa-file-excel { - -webkit-mask: url("data:image/svg+xml;utf8,"); - -webkit-mask-repeat: no-repeat; - } - .fa-file-audio { - -webkit-mask: url("data:image/svg+xml;utf8,"); - -webkit-mask-repeat: no-repeat; - } - .fa-file-video { - -webkit-mask: url("data:image/svg+xml;utf8,"); - -webkit-mask-repeat: no-repeat; - } - .fa-file-archive { - -webkit-mask: url("data:image/svg+xml;utf8,"); - -webkit-mask-repeat: no-repeat; - } - .fa-file-code { - -webkit-mask: url("data:image/svg+xml;utf8,"); - -webkit-mask-repeat: no-repeat; - } - .fa-file-alt, .fa-file-csv { - /* fork-awesome doesn't have csv so we use the text icon */ - -webkit-mask: url("data:image/svg+xml;utf8,"); - -webkit-mask-repeat: no-repeat; - } - .fa-file { - -webkit-mask: url("data:image/svg+xml;utf8,"); - -webkit-mask-repeat: no-repeat; - } - blockquote { - border-left: 4px solid ${style.htmlCodeBorderColor}; - padding-left: 1.2em; - margin-left: 0; - opacity: .7; - } - table { - text-align: left-align; - border-collapse: collapse; - border: 1px solid ${style.htmlCodeBorderColor}; - background-color: ${style.htmlBackgroundColor}; - } - td, th { - padding: .5em 1em .5em 1em; - font-size: ${style.htmlFontSize}; - color: ${style.htmlColor}; - font-family: ${fontFamily}; - } - td { - border: 1px solid ${style.htmlCodeBorderColor}; - } - th { - border: 1px solid ${style.htmlCodeBorderColor}; - border-bottom: 2px solid ${style.htmlCodeBorderColor}; - background-color: ${style.htmlTableBackgroundColor}; - } - tr:nth-child(even) { - background-color: ${style.htmlTableBackgroundColor}; - } - tr:hover { - background-color: ${style.raisedBackgroundColor}; - } - hr { - border: none; - border-bottom: 2px solid ${style.htmlDividerColor}; - } - img { - max-width: 100%; - height: auto; - } - .inline-code { - border: 1px solid ${style.htmlCodeBorderColor}; - background-color: ${style.htmlCodeBackgroundColor}; - padding-right: .2em; - padding-left: .2em; - border-radius: .25em; - color: ${style.htmlCodeColor}; - font-size: ${style.htmlCodeFontSize}; - } - - .highlighted-keyword { - background-color: #F3B717; - color: black; - } - - .not-loaded-resource img { - width: 1.15em; - height: 1.15em; - background: white; - padding: 2px !important; - border-radius: 2px; - box-shadow: 0 1px 3px #000000aa; - } - - a.not-loaded-resource img { - margin-right: .2em; - } - - a.not-loaded-resource { - display: flex; - flex-direction: row; - align-items: center; - } - - .md-checkbox input[type=checkbox]:checked { - opacity: 0.7; - } - - .md-checkbox .checkbox-label-checked { - opacity: 0.5; - } - - .exported-note-title { - font-size: 2.2em; - font-weight: bold; - margin-bottom: 1em; - } - - .exported-note { - padding: 1em; - } - - @media print { - body { - height: auto !important; - } - - pre { - white-space: pre-wrap; - } - - .code, .inline-code { - border: 1px solid #CBCBCB; - } - - #joplin-container-content { - /* The height of the content is set dynamically by JavaScript (in updateBodyHeight) to go - around various issues related to scrolling. However when printing we don't want this - fixed size as that would crop the content. So we set it to auto here. "important" is - needed to override the style set by JavaScript at the element-level. */ - height: auto !important; - } - } - `; - - return [normalizeCss, css]; -}; diff --git a/ReactNativeClient/lib/renderers/utils.js b/ReactNativeClient/lib/renderers/utils.js deleted file mode 100644 index 10ff06b0f..000000000 --- a/ReactNativeClient/lib/renderers/utils.js +++ /dev/null @@ -1,122 +0,0 @@ -const Resource = require('lib/models/Resource.js'); -const Entities = require('html-entities').AllHtmlEntities; -const htmlentities = new Entities().encode; - -const utils = {}; - -utils.getAttr = function(attrs, name, defaultValue = null) { - for (let i = 0; i < attrs.length; i++) { - if (attrs[i][0] === name) return attrs[i].length > 1 ? attrs[i][1] : null; - } - return defaultValue; -}; - -utils.notDownloadedResource = function() { - return ` - - - - `; -}; - -utils.notDownloadedImage = function() { - // https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/file-image-o.svg - // Height changed to 1795 - return ` - - - - `; -}; - -utils.notDownloadedFile = function() { - // https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/file-o.svg - return ` - - - - `; -}; - -utils.errorImage = function() { - // https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/times-circle.svg - return ` - - - - `; -}; - -utils.loaderImage = function() { - // https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/hourglass-half.svg - return ` - - - - `; -}; - -utils.resourceStatusImage = function(state) { - if (state === 'notDownloaded') return utils.notDownloadedResource(); - return utils.resourceStatusFile(state); -}; - -utils.resourceStatusFile = function(state) { - if (state === 'notDownloaded') return utils.notDownloadedResource(); - if (state === 'downloading') return utils.loaderImage(); - if (state === 'encrypted') return utils.loaderImage(); - if (state === 'error') return utils.errorImage(); - - throw new Error(`Unknown state: ${state}`); -}; - -utils.resourceStatus = function(resourceInfo) { - let resourceStatus = 'ready'; - - if (resourceInfo) { - const resource = resourceInfo.item; - const localState = resourceInfo.localState; - - if (localState.fetch_status === Resource.FETCH_STATUS_IDLE) { - resourceStatus = 'notDownloaded'; - } else if (localState.fetch_status === Resource.FETCH_STATUS_STARTED) { - resourceStatus = 'downloading'; - } else if (localState.fetch_status === Resource.FETCH_STATUS_DONE) { - if (resource.encryption_blob_encrypted || resource.encryption_applied) { - resourceStatus = 'encrypted'; - } - } - } else { - resourceStatus = 'notDownloaded'; - } - - return resourceStatus; -}; - -utils.imageReplacement = function(src, resources, resourceBaseUrl) { - if (!Resource.isResourceUrl(src)) return null; - - const resourceId = Resource.urlToId(src); - const result = resources[resourceId]; - const resource = result ? result.item : null; - const resourceStatus = utils.resourceStatus(result); - - if (resourceStatus !== 'ready') { - const icon = utils.resourceStatusImage(resourceStatus); - return `
    ` + `` + '
    '; - } - - const mime = resource.mime ? resource.mime.toLowerCase() : ''; - if (Resource.isSupportedImageMimeType(mime)) { - let newSrc = `./${Resource.filename(resource)}`; - if (resourceBaseUrl) newSrc = resourceBaseUrl + newSrc; - return { - 'data-resource-id': resource.id, - src: newSrc, - }; - } - - return null; -}; - -module.exports = utils; diff --git a/ReactNativeClient/lib/services/InteropService_Exporter_Html.js b/ReactNativeClient/lib/services/InteropService_Exporter_Html.js index 6fdb78ca4..3f8db2a02 100644 --- a/ReactNativeClient/lib/services/InteropService_Exporter_Html.js +++ b/ReactNativeClient/lib/services/InteropService_Exporter_Html.js @@ -6,11 +6,11 @@ const Note = require('lib/models/Note'); const Setting = require('lib/models/Setting'); const Resource = require('lib/models/Resource'); const { shim } = require('lib/shim'); -const MarkupToHtml = require('lib/renderers/MarkupToHtml.js'); const dataurl = require('dataurl'); const { themeStyle } = require('../../theme.js'); const { dirname } = require('lib/path-utils.js'); const { escapeHtml } = require('lib/string-utils.js'); +const markupLanguageUtils = require('lib/markupLanguageUtils'); class InteropService_Exporter_Html extends InteropService_Exporter_Base { @@ -27,7 +27,7 @@ class InteropService_Exporter_Html extends InteropService_Exporter_Base { this.resourceDir_ = this.destDir_ ? `${this.destDir_}/_resources` : null; await shim.fsDriver().mkdir(this.destDir_); - this.markupToHtml_ = new MarkupToHtml(); + this.markupToHtml_ = markupLanguageUtils.newMarkupToHtml(); this.resources_ = []; this.style_ = themeStyle(Setting.THEME_LIGHT); } @@ -103,7 +103,7 @@ class InteropService_Exporter_Html extends InteropService_Exporter_Base { } const bodyMd = await this.processNoteResources_(item); - const result = this.markupToHtml_.render(item.markup_language, bodyMd, this.style_, { resources: this.resources_, plainResourceRendering: true }); + const result = await this.markupToHtml_.render(item.markup_language, bodyMd, this.style_, { resources: this.resources_, plainResourceRendering: true }); const noteContent = []; if (item.title) noteContent.push(`
    ${escapeHtml(item.title)}
    `); if (result.html) noteContent.push(result.html); diff --git a/ReactNativeClient/lib/services/rest/Api.js b/ReactNativeClient/lib/services/rest/Api.js index 10c883c97..c2dd92d49 100644 --- a/ReactNativeClient/lib/services/rest/Api.js +++ b/ReactNativeClient/lib/services/rest/Api.js @@ -22,6 +22,7 @@ const ApiResponse = require('lib/services/rest/ApiResponse'); const SearchEngineUtils = require('lib/services/SearchEngineUtils'); const { FoldersScreenUtils } = require('lib/folders-screen-utils.js'); const uri2path = require('file-uri-to-path'); +const { MarkupToHtml } = require('joplin-renderer'); class ApiError extends Error { constructor(message, httpCode = 400) { @@ -491,7 +492,7 @@ class Api { } output.body = styleTag + minifiedHtml; output.body = htmlUtils.prependBaseUrl(output.body, baseUrl); - output.markup_language = Note.MARKUP_LANGUAGE_HTML; + output.markup_language = MarkupToHtml.MARKUP_LANGUAGE_HTML; } else { // Convert to Markdown // Parsing will not work if the HTML is not wrapped in a top level tag, which is not guaranteed @@ -501,7 +502,7 @@ class Api { baseUrl: baseUrl, anchorNames: requestNote.anchor_names ? requestNote.anchor_names : [], }); - output.markup_language = Note.MARKUP_LANGUAGE_MARKDOWN; + output.markup_language = MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN; } } @@ -520,7 +521,7 @@ class Api { if ('is_todo' in requestNote) output.is_todo = Database.formatValue(Database.TYPE_INT, requestNote.is_todo); if ('markup_language' in requestNote) output.markup_language = Database.formatValue(Database.TYPE_INT, requestNote.markup_language); - if (!output.markup_language) output.markup_language = Note.MARKUP_LANGUAGE_MARKDOWN; + if (!output.markup_language) output.markup_language = MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN; return output; } @@ -664,7 +665,7 @@ class Api { replaceImageUrlsByResources_(markupLanguage, md, urls, imageSizes) { const imageSizesIndexes = {}; - if (markupLanguage === Note.MARKUP_LANGUAGE_HTML) { + if (markupLanguage === MarkupToHtml.MARKUP_LANGUAGE_HTML) { return htmlUtils.replaceImageUrls(md, imageUrl => { const urlInfo = urls[imageUrl]; if (!urlInfo || !urlInfo.resource) return imageUrl; diff --git a/ReactNativeClient/lib/shim-init-react.js b/ReactNativeClient/lib/shim-init-react.js index 3dd56c1ff..f701560b7 100644 --- a/ReactNativeClient/lib/shim-init-react.js +++ b/ReactNativeClient/lib/shim-init-react.js @@ -16,11 +16,6 @@ const injectedJs = { webviewLib: require('lib/rnInjectedJs/webviewLib'), }; -const cssToJs = { - 'hljs-atom-one-dark-reasonable.css': require('lib/csstojs/hljs-atom-one-dark-reasonable.css.js'), - 'hljs-atom-one-light.css': require('lib/csstojs/hljs-atom-one-light.css.js'), -}; - function shimInit() { shim.Geolocation = GeolocationReact; shim.setInterval = PoorManIntervals.setInterval; @@ -187,11 +182,6 @@ function shimInit() { if (!(name in injectedJs)) throw new Error(`Cannot find injectedJs file (add it to "injectedJs" object): ${name}`); return injectedJs[name]; }; - - shim.loadCssFromJs = function(name) { - if (!(name in cssToJs)) throw new Error(`Cannot find csstojs file (add it to "cssToJs" object): ${name}`); - return cssToJs[name]; - }; } module.exports = { shimInit }; diff --git a/ReactNativeClient/lib/shim.js b/ReactNativeClient/lib/shim.js index e26aae053..fa230c601 100644 --- a/ReactNativeClient/lib/shim.js +++ b/ReactNativeClient/lib/shim.js @@ -199,10 +199,6 @@ shim.waitForFrame = () => { shim.injectedJs = name => ''; -shim.loadCssFromJs = name => { - throw new Error('Not implemented'); -}; - let isTestingEnv_ = false; shim.isTestingEnv = () => { diff --git a/ReactNativeClient/package-lock.json b/ReactNativeClient/package-lock.json index 2a0485857..c57a04012 100644 --- a/ReactNativeClient/package-lock.json +++ b/ReactNativeClient/package-lock.json @@ -1466,6 +1466,12 @@ } } }, + "app-module-path": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/app-module-path/-/app-module-path-2.2.0.tgz", + "integrity": "sha1-ZBqlXft9am8KgUHEucCqULbCTdU=", + "dev": true + }, "are-we-there-yet": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", @@ -2727,22 +2733,19 @@ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, "fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "dependencies": { - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "requires": { - "graceful-fs": "^4.1.6" - } + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" } } }, @@ -2768,8 +2771,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -2787,13 +2789,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2806,18 +2806,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -2920,8 +2917,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -2931,7 +2927,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2944,20 +2939,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.3.5", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -2974,7 +2966,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -3047,8 +3038,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -3058,7 +3048,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3134,8 +3123,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -3165,7 +3153,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3183,7 +3170,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3222,13 +3208,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.0.3", - "bundled": true, - "optional": true + "bundled": true } } }, @@ -3313,6 +3297,40 @@ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" }, + "handlebars": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", + "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "optional": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "uglify-js": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.3.tgz", + "integrity": "sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg==", + "optional": true, + "requires": { + "commander": "~2.20.3", + "source-map": "~0.6.1" + } + } + } + }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -3386,9 +3404,12 @@ } }, "highlight.js": { - "version": "9.15.6", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.6.tgz", - "integrity": "sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ==" + "version": "9.17.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.17.1.tgz", + "integrity": "sha512-TA2/doAur5Ol8+iM3Ov7qy3jYcr/QiJ2eDTdRF4dfbjG7AaaB99J5G+zSl11ljbl6cIcahgPY6SKb3sC3EJ0fw==", + "requires": { + "handlebars": "^4.5.3" + } }, "hoist-non-react-statics": { "version": "2.5.0", @@ -3774,6 +3795,57 @@ "integrity": "sha512-+f/4OLeqY8RAmXnonI1ffeY1DR8kMNJPhv5WMFehchf7U71cjMQVKkOz1n6asz6kfVoAqKNWJz1A/18i18AcXA==", "dev": true }, + "joplin-renderer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/joplin-renderer/-/joplin-renderer-1.0.4.tgz", + "integrity": "sha512-Q7GoEYA6hYtv8ZQgxccn/gSw25V8kQPyWdolK0PJhG7m2BJa0zunyagtaOhMkYuWl8beDYHwTsvsVx2ayKqMcQ==", + "requires": { + "base-64": "^0.1.0", + "font-awesome-filetypes": "^2.1.0", + "fs-extra": "^8.1.0", + "highlight.js": "^9.17.1", + "html-entities": "^1.2.1", + "katex": "^0.11.1", + "markdown-it": "^10.0.0", + "markdown-it-abbr": "^1.0.4", + "markdown-it-anchor": "^5.2.5", + "markdown-it-deflist": "^2.0.3", + "markdown-it-emoji": "^1.4.0", + "markdown-it-footnote": "^3.0.2", + "markdown-it-ins": "^3.0.0", + "markdown-it-mark": "^3.0.0", + "markdown-it-multimd-table": "^4.0.0", + "markdown-it-sub": "^1.0.0", + "markdown-it-sup": "^1.0.0", + "markdown-it-toc-done-right": "^4.1.0", + "md5": "^2.2.1", + "uslug": "^1.0.4" + }, + "dependencies": { + "entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" + }, + "markdown-it": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "requires": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + } + } + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -4028,37 +4100,19 @@ "integrity": "sha512-JVW6fCmZWjvMdDQSbOT3nnOQtd9iAXmw7hTSh26+v42BnvXeVyGMDBm5b/EZocMed2MbCAHiTX632vY0FyGB8A==" }, "markdown-it-ins": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-2.0.0.tgz", - "integrity": "sha1-papqMPHi9x6Ul1Z8/f9A8f3mdIM=" - }, - "markdown-it-katex": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/markdown-it-katex/-/markdown-it-katex-2.0.3.tgz", - "integrity": "sha1-17hqGuoLnWSW+rTnkZoY/e9YnDk=", - "requires": { - "katex": "^0.6.0" - }, - "dependencies": { - "katex": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.6.0.tgz", - "integrity": "sha1-EkGOCRIcBckgQbazuftrqyE8tvM=", - "requires": { - "match-at": "^0.1.0" - } - } - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-3.0.0.tgz", + "integrity": "sha512-+vyAdBuMGwmT2yMlAFJSx2VR/0QZ1onQ/Mkkmr4l9tDFOh5sVoAgRbkgbuSsk+sxJ9vaMH/IQ323ydfvQrPO/Q==" }, "markdown-it-mark": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-2.0.0.tgz", - "integrity": "sha1-RqGqlHEFrtgYiXjgoBYXnkBPQsc=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-3.0.0.tgz", + "integrity": "sha512-HqMWeKfMMOu4zBO0emmxsoMWmbf2cPKZY1wP6FsTbKmicFfp5y4L3KXAsNeO1rM6NTJVOrNlLKMPjWzriBGspw==" }, "markdown-it-multimd-table": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-3.2.0.tgz", - "integrity": "sha512-dBtYHVtyAnoWslzYLYDh0d9jX2/qroyMIsJ1BjFdIcLgZjzqBIBGwZ1j3AaaWh+IIfe3KVm5Irqn5Uzadm5kQA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-4.0.0.tgz", + "integrity": "sha512-kdM3fH+/sRMfHQgD2CM1BcIpLNODUCuoiFr6TwS7mDJBYntVXDJxZbFwGDRflIc9ZzAfsUbr0lnHc6RbYafIsw==", "requires": { "markdown-it": "^8.4.2" }, @@ -4097,11 +4151,6 @@ "resolved": "https://registry.npmjs.org/markdown-it-toc-done-right/-/markdown-it-toc-done-right-4.1.0.tgz", "integrity": "sha512-UhD2Oj6cZV3ycYPoelt4hTkwKIK3zbPP1wjjdpCq7UGtWQOFalDFDv1s2zBYV6aR2gMs/X8kpJcOYsQmUbiXDw==" }, - "match-at": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/match-at/-/match-at-0.1.1.tgz", - "integrity": "sha512-h4Yd392z9mST+dzc+yjuybOGFNOZjmXIPKWjxBd1Bb23r4SmDOsk2NYCU2BMUBGbSpZqwVsZYNq26QS3xfaT3Q==" - }, "math-random": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", @@ -4239,6 +4288,16 @@ "ua-parser-js": "^0.7.18" } }, + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" + } + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -4247,6 +4306,14 @@ "loose-envify": "^1.0.0" } }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, "metro-react-native-babel-preset": { "version": "0.51.1", "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.51.1.tgz", @@ -4731,6 +4798,11 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -5352,6 +5424,11 @@ } } }, + "react-async": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/react-async/-/react-async-10.0.0.tgz", + "integrity": "sha512-Uk7yG49ftaJ1ShMfgTqsZUcEIRxdWHV2ABojw+dzFifCSMeqydCFhzj9x7okACClCzMDgkGqC5/bOtY95yQG1A==" + }, "react-clone-referenced-element": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/react-clone-referenced-element/-/react-clone-referenced-element-1.1.0.tgz", @@ -5488,6 +5565,16 @@ "ua-parser-js": "^0.7.18" } }, + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" + } + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -5496,6 +5583,14 @@ "loose-envify": "^1.0.0" } }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, "node-fetch": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", diff --git a/ReactNativeClient/package.json b/ReactNativeClient/package.json index 20c984523..e1a575a6a 100644 --- a/ReactNativeClient/package.json +++ b/ReactNativeClient/package.json @@ -6,7 +6,8 @@ "private": true, "scripts": { "start": "node node_modules/react-native/local-cli/cli.js start", - "postinstall": "node ../Tools/copycss.js && node ../Tools/buildReactNativeInjectedJs.js && npx jetify" + "postinstall": "node ../Tools/buildReactNativeInjectedJs.js && npx jetify && npm run encodeAssets", + "encodeAssets": "node encodeAssets.js" }, "dependencies": { "@react-native-community/slider": "^1.1.3", @@ -16,31 +17,18 @@ "diacritics": "^1.3.0", "diff-match-patch": "^1.0.4", "events": "^1.1.1", - "font-awesome-filetypes": "^2.1.0", "form-data": "^2.1.4", - "highlight.js": "^9.15.6", "html-entities": "^1.2.1", + "joplin-renderer": "^1.0.4", "jsc-android": "241213.1.0", - "katex": "^0.11.1", "markdown-it": "^8.4.0", - "markdown-it-abbr": "^1.0.4", - "markdown-it-anchor": "^5.2.5", - "markdown-it-deflist": "^2.0.3", - "markdown-it-emoji": "^1.4.0", - "markdown-it-footnote": "^3.0.2", - "markdown-it-ins": "^2.0.0", - "markdown-it-katex": "^2.0.3", - "markdown-it-mark": "^2.0.0", - "markdown-it-multimd-table": "^3.2.0", - "markdown-it-sub": "^1.0.0", - "markdown-it-sup": "^1.0.0", - "markdown-it-toc-done-right": "^4.1.0", "md5": "^2.2.1", "moment": "^2.24.0", "prop-types": "^15.6.0", "punycode": "^2.1.1", "query-string": "4.3.4", "react": "^16.8.3", + "react-async": "^10.0.0", "react-native": "0.59.10", "react-native-action-button": "^2.6.9", "react-native-camera": "^2.10.2", @@ -74,7 +62,6 @@ "timers": "^0.1.1", "url": "^0.11.0", "url-parse": "^1.4.7", - "uslug": "^1.0.4", "uuid": "^3.0.1", "valid-url": "^1.0.9", "word-wrap": "^1.2.3", @@ -83,6 +70,8 @@ "devDependencies": { "@babel/core": "^7.4.5", "@babel/runtime": "^7.4.5", + "app-module-path": "^2.2.0", + "fs-extra": "^8.1.0", "jetifier": "^1.6.4", "metro-react-native-babel-preset": "^0.54.1", "react-test-renderer": "^16.8.3" diff --git a/ReactNativeClient/pluginAssets/highlight.js/atom-one-dark-reasonable.css.base64.js b/ReactNativeClient/pluginAssets/highlight.js/atom-one-dark-reasonable.css.base64.js new file mode 100644 index 000000000..e7a0b3f63 --- /dev/null +++ b/ReactNativeClient/pluginAssets/highlight.js/atom-one-dark-reasonable.css.base64.js @@ -0,0 +1 @@ +module.exports = `LyoKCkF0b20gT25lIERhcmsgV2l0aCBzdXBwb3J0IGZvciBSZWFzb25NTCBieSBHaWRpIE1vcnJpcywgYmFzZWQgb2ZmIHdvcmsgYnkgRGFuaWVsIEdhbWFnZQoKT3JpZ2luYWwgT25lIERhcmsgU3ludGF4IHRoZW1lIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL2F0b20vb25lLWRhcmstc3ludGF4CgoqLwouaGxqcyB7CiAgZGlzcGxheTogYmxvY2s7CiAgb3ZlcmZsb3cteDogYXV0bzsKICBwYWRkaW5nOiAwLjVlbTsKICBjb2xvcjogI2FiYjJiZjsKICBiYWNrZ3JvdW5kOiAjMjgyYzM0Owp9Ci5obGpzLWtleXdvcmQsIC5obGpzLW9wZXJhdG9yIHsKICBjb2xvcjogI0Y5MjY3MjsKfQouaGxqcy1wYXR0ZXJuLW1hdGNoIHsKICBjb2xvcjogI0Y5MjY3MjsKfQouaGxqcy1wYXR0ZXJuLW1hdGNoIC5obGpzLWNvbnN0cnVjdG9yIHsKICBjb2xvcjogIzYxYWVlZTsKfQouaGxqcy1mdW5jdGlvbiB7CiAgY29sb3I6ICM2MWFlZWU7Cn0KLmhsanMtZnVuY3Rpb24gLmhsanMtcGFyYW1zIHsKICBjb2xvcjogI0E2RTIyRTsKfQouaGxqcy1mdW5jdGlvbiAuaGxqcy1wYXJhbXMgLmhsanMtdHlwaW5nIHsKICBjb2xvcjogI0ZEOTcxRjsKfQouaGxqcy1tb2R1bGUtYWNjZXNzIC5obGpzLW1vZHVsZSB7CiAgY29sb3I6ICM3ZTU3YzI7Cn0KLmhsanMtY29uc3RydWN0b3IgewogIGNvbG9yOiAjZTJiOTNkOwp9Ci5obGpzLWNvbnN0cnVjdG9yIC5obGpzLXN0cmluZyB7CiAgY29sb3I6ICM5Q0NDNjU7Cn0KLmhsanMtY29tbWVudCwgLmhsanMtcXVvdGUgewogIGNvbG9yOiAjYjE4ZWIxOwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKfQouaGxqcy1kb2N0YWcsIC5obGpzLWZvcm11bGEgewogIGNvbG9yOiAjYzY3OGRkOwp9Ci5obGpzLXNlY3Rpb24sIC5obGpzLW5hbWUsIC5obGpzLXNlbGVjdG9yLXRhZywgLmhsanMtZGVsZXRpb24sIC5obGpzLXN1YnN0IHsKICBjb2xvcjogI2UwNmM3NTsKfQouaGxqcy1saXRlcmFsIHsKICBjb2xvcjogIzU2YjZjMjsKfQouaGxqcy1zdHJpbmcsIC5obGpzLXJlZ2V4cCwgLmhsanMtYWRkaXRpb24sIC5obGpzLWF0dHJpYnV0ZSwgLmhsanMtbWV0YS1zdHJpbmcgewogIGNvbG9yOiAjOThjMzc5Owp9Ci5obGpzLWJ1aWx0X2luLCAuaGxqcy1jbGFzcyAuaGxqcy10aXRsZSB7CiAgY29sb3I6ICNlNmMwN2I7Cn0KLmhsanMtYXR0ciwgLmhsanMtdmFyaWFibGUsIC5obGpzLXRlbXBsYXRlLXZhcmlhYmxlLCAuaGxqcy10eXBlLCAuaGxqcy1zZWxlY3Rvci1jbGFzcywgLmhsanMtc2VsZWN0b3ItYXR0ciwgLmhsanMtc2VsZWN0b3ItcHNldWRvLCAuaGxqcy1udW1iZXIgewogIGNvbG9yOiAjZDE5YTY2Owp9Ci5obGpzLXN5bWJvbCwgLmhsanMtYnVsbGV0LCAuaGxqcy1saW5rLCAuaGxqcy1tZXRhLCAuaGxqcy1zZWxlY3Rvci1pZCwgLmhsanMtdGl0bGUgewogIGNvbG9yOiAjNjFhZWVlOwp9Ci5obGpzLWVtcGhhc2lzIHsKICBmb250LXN0eWxlOiBpdGFsaWM7Cn0KLmhsanMtc3Ryb25nIHsKICBmb250LXdlaWdodDogYm9sZDsKfQouaGxqcy1saW5rIHsKICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsKfQo=`; \ No newline at end of file diff --git a/ReactNativeClient/pluginAssets/highlight.js/atom-one-light.css.base64.js b/ReactNativeClient/pluginAssets/highlight.js/atom-one-light.css.base64.js new file mode 100644 index 000000000..0223dfcb0 --- /dev/null +++ b/ReactNativeClient/pluginAssets/highlight.js/atom-one-light.css.base64.js @@ -0,0 +1 @@ +module.exports = `LyoKCkF0b20gT25lIExpZ2h0IGJ5IERhbmllbCBHYW1hZ2UKT3JpZ2luYWwgT25lIExpZ2h0IFN5bnRheCB0aGVtZSBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9hdG9tL29uZS1saWdodC1zeW50YXgKCmJhc2U6ICAgICNmYWZhZmEKbW9uby0xOiAgIzM4M2E0Mgptb25vLTI6ICAjNjg2Yjc3Cm1vbm8tMzogICNhMGExYTcKaHVlLTE6ICAgIzAxODRiYgpodWUtMjogICAjNDA3OGYyCmh1ZS0zOiAgICNhNjI2YTQKaHVlLTQ6ICAgIzUwYTE0ZgpodWUtNTogICAjZTQ1NjQ5Cmh1ZS01LTI6ICNjOTEyNDMKaHVlLTY6ICAgIzk4NjgwMQpodWUtNi0yOiAjYzE4NDAxCgoqLwoKLmhsanMgewogIGRpc3BsYXk6IGJsb2NrOwogIG92ZXJmbG93LXg6IGF1dG87CiAgcGFkZGluZzogMC41ZW07CiAgY29sb3I6ICMzODNhNDI7CiAgYmFja2dyb3VuZDogI2ZhZmFmYTsKfQoKLmhsanMtY29tbWVudCwKLmhsanMtcXVvdGUgewogIGNvbG9yOiAjYTBhMWE3OwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKfQoKLmhsanMtZG9jdGFnLAouaGxqcy1rZXl3b3JkLAouaGxqcy1mb3JtdWxhIHsKICBjb2xvcjogI2E2MjZhNDsKfQoKLmhsanMtc2VjdGlvbiwKLmhsanMtbmFtZSwKLmhsanMtc2VsZWN0b3ItdGFnLAouaGxqcy1kZWxldGlvbiwKLmhsanMtc3Vic3QgewogIGNvbG9yOiAjZTQ1NjQ5Owp9CgouaGxqcy1saXRlcmFsIHsKICBjb2xvcjogIzAxODRiYjsKfQoKLmhsanMtc3RyaW5nLAouaGxqcy1yZWdleHAsCi5obGpzLWFkZGl0aW9uLAouaGxqcy1hdHRyaWJ1dGUsCi5obGpzLW1ldGEtc3RyaW5nIHsKICBjb2xvcjogIzUwYTE0ZjsKfQoKLmhsanMtYnVpbHRfaW4sCi5obGpzLWNsYXNzIC5obGpzLXRpdGxlIHsKICBjb2xvcjogI2MxODQwMTsKfQoKLmhsanMtYXR0ciwKLmhsanMtdmFyaWFibGUsCi5obGpzLXRlbXBsYXRlLXZhcmlhYmxlLAouaGxqcy10eXBlLAouaGxqcy1zZWxlY3Rvci1jbGFzcywKLmhsanMtc2VsZWN0b3ItYXR0ciwKLmhsanMtc2VsZWN0b3ItcHNldWRvLAouaGxqcy1udW1iZXIgewogIGNvbG9yOiAjOTg2ODAxOwp9CgouaGxqcy1zeW1ib2wsCi5obGpzLWJ1bGxldCwKLmhsanMtbGluaywKLmhsanMtbWV0YSwKLmhsanMtc2VsZWN0b3ItaWQsCi5obGpzLXRpdGxlIHsKICBjb2xvcjogIzQwNzhmMjsKfQoKLmhsanMtZW1waGFzaXMgewogIGZvbnQtc3R5bGU6IGl0YWxpYzsKfQoKLmhsanMtc3Ryb25nIHsKICBmb250LXdlaWdodDogYm9sZDsKfQoKLmhsanMtbGluayB7CiAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7Cn0K`; \ No newline at end of file diff --git a/ReactNativeClient/pluginAssets/index.js b/ReactNativeClient/pluginAssets/index.js new file mode 100644 index 000000000..1c750586e --- /dev/null +++ b/ReactNativeClient/pluginAssets/index.js @@ -0,0 +1,11 @@ +module.exports = { + hash: '964177e31d959b03bc63f11216c61e3e', files: { + 'highlight.js/atom-one-dark-reasonable.css': { data: require('./highlight.js/atom-one-dark-reasonable.css.base64.js'), mime: 'text/css', encoding: 'base64' }, + 'highlight.js/atom-one-light.css': { data: require('./highlight.js/atom-one-light.css.base64.js'), mime: 'text/css', encoding: 'base64' }, + 'katex/fonts/KaTeX_Main-Regular.woff2': { data: require('./katex/fonts/KaTeX_Main-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' }, + 'katex/fonts/KaTeX_Math-Italic.woff2': { data: require('./katex/fonts/KaTeX_Math-Italic.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' }, + 'katex/fonts/KaTeX_Size1-Regular.woff2': { data: require('./katex/fonts/KaTeX_Size1-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' }, + 'katex/fonts/KaTeX_Size2-Regular.woff2': { data: require('./katex/fonts/KaTeX_Size2-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' }, + 'katex/katex.css': { data: require('./katex/katex.css.base64.js'), mime: 'text/css', encoding: 'base64' }, + }, +}; diff --git a/ReactNativeClient/pluginAssets/katex/fonts/KaTeX_Main-Regular.woff2.base64.js b/ReactNativeClient/pluginAssets/katex/fonts/KaTeX_Main-Regular.woff2.base64.js new file mode 100644 index 000000000..5ef84cccc --- /dev/null +++ b/ReactNativeClient/pluginAssets/katex/fonts/KaTeX_Main-Regular.woff2.base64.js @@ -0,0 +1 @@ +module.exports = `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`; \ No newline at end of file diff --git a/ReactNativeClient/pluginAssets/katex/fonts/KaTeX_Math-Italic.woff2.base64.js b/ReactNativeClient/pluginAssets/katex/fonts/KaTeX_Math-Italic.woff2.base64.js new file mode 100644 index 000000000..cf6447e3d --- /dev/null +++ b/ReactNativeClient/pluginAssets/katex/fonts/KaTeX_Math-Italic.woff2.base64.js @@ -0,0 +1 @@ +module.exports = `d09GMgABAAAAAE6AAA4AAAAAoHwAAE4nAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmAAg0oIaAmXFxEICoKKOIHjfgE2AiQDgxQLgUwABCAFjVIHg1sMgRUbfosF3BinYeMAWBj5EkYhsHEAQNL3Y/4/H7dGCF5gVtZvgQzlnFRrl1ch+bgvjK4yvZz6SCKhklJqGL3vFcQ3NovFEjUSHrwCQ+HSMH+OEgpSJAVfCz/+x6YtCIo1/vFh8c7N81Rko/j65aVXqEmmHQhNE8IZ2DbyJzl5B/i1+a+u3tXLi3wXHHFw3B1VF01dkkqlAQgC1gBFeypG9aLcpq6+c6mrchUu8tfGvDo/ZUyiAJpIFpkozmcXiKa+bF0P1q7dOs1Hf5az/r2rtHOTWm0aL54hNAY84ITz5KhG3mGr2JBde9r9IeMr/v/W3TikCbApJYHsfPyp7sMT/UF7u3uXNDcTWCBJEmKRh9BMeGSBHUgz33++n2rnXHrvf8lmxU0UIMtyFQfQboDAUeSgktQdcH8JVp3NilYzK6bd7IBxi/+ralqreJdKkelt246SnT5mWYEVWD/wIYEKHYtNppq7mkNd7aDg8vZkbVDCWmaSA1ZfxpRQ6C2gETVCvK6Ftv9ZUYKnmWURyyH25bCcoZJFkye/qCnqdNXkcAjb9ncWjXnbSaokN0VAkdo91FmNZNlxEJZDDgAqzAvkxQPkrnqury3e9937S/6E8tgzJxXJNRU6bDVX+4HjQTuCv/r/efC7zfAQDsrsC2x1g7AXUYBnX3sdZ9+BS7oSWBzCpFhakQi1dpe4K9QiTNr4Jswvf2+q1r6/YICoC9JFOUs3Q4fIizXEy93NtVde0Vy5eH//YvfvkgR2SQhYkCNoIdES4ECCioADAIJjJjlQcgqZXMi0ScoaGXBOR1+OoWiuKK+rUyjaMpbZxtJaDSWmqRsVhu8VG6ZanOEMp3E3JwmdADuv6hDT1q25961xMAYhSE1yE3zCa4l38uMvBwDlK9lCAUDffRIANr6fNPinNxDWR54A+Anzwz13TvizcQEg5hHG/5OGvmKDAWy+0wcA8LfnAICRWnDSVL9OBoDnNHCejDh9c5owEGyMBksc1u3bvX07uMM7tpM7sxf3fOv9s/ljA8xjOLUCPbdNO7HTu+KqVPwlit9/9lNn9//JY0cOHdy/b++2jesW/r9gnQBomgk+AU1p6Q0SAAmc/9qKXCMlWDnVyv900QU+ndO8hhGKMaGMJ2mWF2VVN23XD+cRrO6YHu6pMn+nF7WOwXiJvQ6ge8bnj7y0AYYJ57uKhQ9Izk3+yeOuR7h7E3lC6F5GVR8FQFjEwYCn/0B1/ZTc7afIxDY9z+kAZfFErPk/TzydL3XhRAh7hJr2MyCqpeCJQGs98MTACvz9iiR/mj2cYlgObz5HUXFl94Djqyikzw7M/LhV5tlQUbPyih4b+1UECBEegcLvNjhA+ZXnIFOTiVuVXPajkIKUP1kbZ0fkZkoYx7WZJwMMING8Atl4FclKICfBiRhR9SRQUcGqspMAldQ6fgsR1zKLjIkjFCj9sv2x6TUyVJL8OqZXLr+xqOYO09u4c9cr1rRI22VBSVyaAXMDnCLJUQVB52biyQGrXyVE1oolAaxsL4/lP0JnGO9t0Wpipv5wcTxmyQzVhnBR2AZpNvu6rJowcnWkkmjCUBxtJChVBmzQuS2t26QEzUdGNfdt9EdePkBnGIFOj6DAHq3uLE/9kyhOxS6KpxIV9054AZvlqULxA2zEk/LemYi3jMpfyZQoxTuhBqjhZDH8I3ReHC1waiSUU0WFAB1Mg6fvYiXfvZ2OmfSjPxStafbr+PTtNeCkuPQb1qGCOt4r6iGFqAWq3XoUxxqq4kaUixGtKcjoxSt7fhJbpPxCu2ETjZN/0R0AsPdFl7ZGRUxUJq85x1jlM4JjVoBD2hMFoTQj5vvzgB4bFT55F6mWgIFyCZQJcQ1IRO23ZmGTVFQN5fRfN3I+dXfKPA2ooL/kaURFP4BJwGAWGLAIBNYEFtYFDjYECWwKPGwJ0rZeoCF6Z5cPfl1++DtDb2ODNzeS7JBtYsUJbAIGu8CAQyDgFFgQBA5cggTcAg8eQaoEErRQIdg+UVPR6Zp344HxwwMO5w/BHXUG7ZoaBjDlMRS25h3NY/lDQk7sbIiMT2G0xrBVlleHeNV6qEWpyU8fiwG3DFbjwGXkpBWLyFvvXGGD6Res7zj9Pd2pMV696JkAWkwGhwg1FffzKYnmWOuZwvqJXF784mlUTKYzaMQiOFzb8XH5NcmkGXHh8qJoHXlOMa8evuiZAcFEol+KGZzSuLQuIQHakvF7ZBvRVGKTSIBZ4GnAj0qv4098sH3gfuK8vWUhCSb4QHHA/ToeA5KIJZ4SkZTtB8GRVkom8kq9q0B2xFMSylkolBU6Esk65h2n5GMk1pE2s8yEo67pTiEPkh9mNb9yoiyS3CVNrXBrktJcRmOKPZBzg0nkJjaTENJ2x+7K1yAvAcCIreFw8YKC9oBRuiTMY4NWxZnkK4cxMucBTpc9Hm9+pZHq1IXZ0HDxY158It3ywtP2OWcf5bGMl6BoaBt0fBPRWlNDvHLJXlme7lUvFN456NgrYMZrTa2CWS/Wg9ZbllUyUzuSaBjCNtRcDLLPB6OKFlq3U98Zu47KDzT44i/E5H5oPyaYo7a642TAm8SM5A02ZAKEZpPoiXXE12fS0o3RacwQiMohhzthj0l7bgcV0CrAJCldkJoeoTccmAZFg7E4GlFGH/4YYG/eboAZoBcyFBCMqhCRscB8AiKDMEWBWRUiMheYL4Q8FJYosKpCRHYF5ntCOmEfBQ6qEJFDgfmRkFE4RoGTKkTkVGAuCgnCGQqcVyEiFwJveQnmeOZXvwVY2l1EDrKDG+hCEkSDwOEsE7jKRCsTSXA36DvUMoVWptDLFJ5Kg7fMYJQZfGW20MSDGyJ7T4rrWnjt/NX4MbZRccgAQOCJrbWqE7/1enEKgOa92fABZFsMkHl7fbRhCAwEdXbXIHXfkIJ9k3/MUnZeXQsAgI2Vwz3gJfuPPsn8wmZWTaYJvzLCI4gHLZSQ5XbFQP/IcW/epvjSmEzuleeo8PnS2pa5oZVTzWX50gxFYYjMwEM5VEhQLCjpzhuLSMi4sogsrfLUurq6uuv8Er5MneFLSzN3+uY2i9H75hWoDKaiPNyVcCnFwvSalKCtT0K6GLxEjVuChWRFW6ReXCAiC/QFRBayfuXzWXykhg87FZlP0wvCd+o8/l9gnfoI5zkXVEEAGPiEbcJEPYUChe9sRat+sGIABrl+6N/ohvWdkkGTT9Ew+Ws1VQgrVpSi9TLRCa8mTkFuoI+5rRaQRrLoNRHzeHkNocDde+mHKVlirxMLDDRzJE5MfjxJPy1KQka0DEjD48KaJ2ib8JSpZjDgnVKNPTQKFS2aZbQ81DalDkJZs/KQovz2hGhxqizW+8nVvh+SsUs9tLnsaJVvJI3k0QYCrqy8dsL62SJeIVZ78xRqs7ZAQy2rSrtSbyJeLB6TgvVAAY/Iie9i6OA6mSoI8KCOUrOkoxGplNiDhl4N9ZV71yhdn+EC6j7dwXarCQRJRYv94lWMgtF+SzFtddeAK0LU6/iMGE2/tG1xGThbcSKKOJHplhnqwViUWTZvYKpceNQg4gSoz+9lbUJ1HBuRQIV6Ki8lmzwaRNOqeQ4KZ2bSqefg6j0XA+bCqg2zSfCxS5fzRYv6bKr/woMqU6zOml8jK0Z3Mo2DTgxsqzghQJTudSeyNhG2i7haebar9YFOykwbgIsmC0q1ylxCfZsqW4yekXOR1FZIt6Gq3YKnr6jIucSEiQ6O7oQqy4nV2sKEA8M+rcnAvqYpipetYJEncgoDadhEE/6H+oyqk7yfgCrvw/YthpvO6+NXUUp7cJFb/N8CESmGWDA67mIAAEZxLs5O+u12q7PiwiQ53LHAIohSKwgoRcNoxOd2vU7jfntrqq+o3nrKj9D7Fl+VRkffI43jLntsYfphYhaJ+mWv/8wI2p7cwuO/49Gs8x6uUqU2REpXg4tt8JJZLeddzFGUQPcsMKfp1HbfOWlzEwu5FZP+nX3YusdWDgPLGm2pyBNdog3azarFnUE7UQ2LIDqJhRFr5H7y426/1GfU/4a5xRHPfmAmlNapVhVZey9tn8hwb/tb5/LcSoPW6YTqolWW06HrtOS3W3sFYNuXsibDNP+BwawqFF01kd8qQmthDxYqupfeRNc4NKVOmSjS0J8BCQLefYbqJwfNfmLLymPCT6/xTzp9axQiSvNIB1AuA1McjMfHvJ1cjddDiZ8HPoE9sKvDp1Cff0rmyaArBHM/BOp5XGXMEckDQNgnI4Y9fxdEDzEqmydiusO9u23CW8sMrAGBG9cG8QdA8kZHX0iKFndMPga2stNP/IqXzv1pTIXbFFOwWzlntDgizsi2ddxGmLGnj6fr8DVep6pqiYigK65ZNxC1heRmAmleUTYGQMlMHKZzqQKYh7CZGtPiqiAaBGXpTilhu2iLOj3EfPhmM8VuuWnkOA8A6I3AZYr8QmXUpZ8lgTS20ekOpOWgccuuAJqiQ0yoBBSOqHP9U/npyYys801r0IIU7y2QOAgmgTSEx9nfzP3Mw0Lp2sVgEJuK3vW34pxNV5WABS/VB8uWLGJTRZLdp3CyDiuqL7z00md5W0e8C6v4g52aDe7IcWBbZywzpG1gZyAn+uN/+ulOaQ5TjlxbYa+isS7OniegVNJ+zClzK+/azWxRt2SKWSwVab/AjCeZXS/OQV60SKu1DfsAbKxwEJmbIUstppnPQZM8oB/5bZSTlIVCQssg1TvJVfHuXzwlC6rNdUk2i86btQcBgnTwceG5j7JfK1JOJ6mgt4XFSMHCzds0WH98U7+2gCCNq+hg/8+YU4dmwNE2ELOZfj+Pi5k0JCIrCS4GbBllRRwZIUTPHHxKdVhTNUDk2FkUSrfQEXlB7TH8SORvf2RUk3XUSOJXbqNUZajtt4hYDOEMv40YzoSpNcKhahObJB+hjW8FvIsS+mR1CJhLNFOgW1CNFUbZ+/kzIP0MVOKlESJ/d6ZK3gfvEz6LeA5sDSuF/3npXMswFvqqgNlT+NZT69v1lq8t/k9eawwrqyIcegRmI6glU0xE0an1qbcm16visNgW5a/otWFDOJpmbrhiIps/dNhwKHlLMkbYNvgEn4qlHcLhewW13aty736XRS+hykdlK2oWoBkUATdW0tkPiyuIGPNTwqiSATE6txO9uG8oai5Nax/yj97M4aYiFtAILskfOToW4XJB0Tain2DRMoFizyg9COyXofbDnflnDd48zQ18MF355l72I8IBbFE4I7Q7MkwRNqcrtmBxiTJ+8VJ5K7tYcgIUj/+GyoFfbrHGlxXd9Gc2iN+takJQgxnv5qYHXcRvjrUasTQt7MWCCmgjIAPjGGJBziU/jEz01ESuDi61CsU/54KNqn+I6XIdXAzxOv1NJi9ABIaFeiAmdqEmQaXs2IeRgbqGiuLDfM/Vsy/dBdUH/lPKR64vCcfj8Xz8KDnrbINVVaBATIzaZjjnkX9FrCCsTvGY2IdeZGCEZi+bTsy9gbb4FcNshodMtjTjhpy5j5+L6srQXMrqGR8AjzUpo2T4Gbk00DxE7CDL8Z42oAZfyGuI8mz2VsuAZl0js+uKvcX30Ih4yeXg2qzgI3hic1PcrZyKsiD8tp5jT2LGyTgi2ZUvjQ87MW4VjE40EmYYdjIGZrtWHbiW/9BSGsqL27bXL4dQzPFUTJhKMx5oUAIpM12fSRVyaSnVn8piR82zDdb9FEEWm121DTQf8qSf8uO6e9k/R+cS6ylUVlA2xbVQIRY6GUxqg2flNhnroxL51G55bVaou98RiovKdDF+EpzswxwsGokr7yzuaQYk+FzwhKpfI4qyKJs+08aaIw7ePP2eYNfz3EU32NW+ZzVLHPHZXtFBcsL7AhktqS1U4gXHVmgaG0CqxTIEY4jXS0jqznC3zil7pyidnsZ/jEh0pkgil7wBx7Dof0zHd5YE+Kl3owN7RDg63yenRaQOEGEIP1FemHhw0ZwzXSYyDhYWnrUiMu9HEMqZHy4Yi9zLHfhDMxI1XaSjS+U+VUDzgIxf/kKsGgWjWZi2lc9ZylAH7qaPjrECOnuv5fiZ3Y7kbyNefmrq2qu1D76KBB+MdNTHZ0GNEbos8Tn/wxvvok0tR3njrLPU4qeRwwKYkZZS7Etgcg6jHSGgwf0dKMaSlDdK4WTltdI3F0pc/qz/GOBbef7qmr2th+9BMDqLLOMWSUon3f2R4bO1LN2dJufLeOxrofeec+iKiVmhB8ui0Q+WymaRsHhM+DYDxkzDf3NKqxHw5LhVlkeafSSU51aalHYbfPA2g2efpmzrY2A1M7smaD0E5JCG5GoerOOguIr/5FFTA1JfMcUKLPmr+hdP0pX7EHG7QaTxh99wa/taKzBr1X9hr9MufBYssbDmk6KVY7WOC7cWT1G3oyUVPiVWNgdC69DFMjAOpNo0FnBS0NIg1cRicYiJ+FA8j//H/MrXG1msQMIizEfGzlpOa6cdeYetdbKiFSquBqkb4JiERbb8OOabmCQtBlHqJcGCae5i8FQnnDtgv3VS3gWxTC/hvHuloxhMXvK4q+L7LARBY4Z6r7dELcciGVGX9479/eATk3N2YA+hy40Qvmm+AV+2PvMnct5linTeLaalelyHABi5Hg9g5sc5Fju4ijKtYEp207T4C7GR8Gbv2Yt8efGwwsKQtUWouiPeEijiDU6i/OiTKoYn1KGcfttxI8+gkyQrK1eo4Ibe1aZxoZW9T/g9G/J1Q+Teidw7cPCjMMvcBg+oOxn2hA0f51uMMXOCbVB5b6YSV8ic/FKvHd1EY8IcWoGR/uCPRvrm6EvEj2qNiHe/cDAuJRWCREPYpxMtj0vcTlvHmoUWZVBnnxx8qTAJ62VR4wwg/UDXu1qSy+9rQxSwNFk1qF5ddAFrNhTnQYN658jvpfWdMkKdyIy9bMAZ3iyaYGDncnhrL/U/qq5fsn728TpG/WNl+21DjnVKebWiBINb5O4WlW5HFdJK83Mii4gicmvJ+57VlFhQcF6O2V67c6PFqj2Q9427F/ssI3t0Gd+Wbyy/+CahHBSMF6HscuLo2C1PfkwDerjxHOB5oOQN8Vs+6D+lDIa10/DwemgAYlW7larhwGFRb95PAVYlYUhdRMbdiLS8Pwh/i1XjeErPGamYkSYxMFX01LsOTpGno69jZp6ShHZ3GI2FJASTntHeR4bnLs7KeWvuKBGfDSH9bfHkkXWlZAuDuDG/f9IOilAdRdzQBuWAlxzyOut7u4jsWCVzJDlXfE54blrYhAKRlUCjEbKdRFwruo+mejZNAgHctIZsRHdE22T5Mda01EnLCfCEN9sr/BkTTzgl3/2HE7FLhFo0P5carTPrlGced2uUP09TsumdrljiwZ+1aJnOdZzidbruub7/YuXDdjEyL+YPK+vhVjr+TE7gp2NUVr5LGqZkww9o8djk1JSwRDQjjyoQeEaL9nox21lXC6dLQbVkxCWlEIinRHGxZOfyfSThxufgnEuVrDxRtaP1uS8+ntJt/HtkVJJtqxWqCnWdskds8y5HcyWSZg+MDHa/Bhq1STeskY/5+GrDXAVw6jR7Rjgadhk4RQvV7SrLaJV4WEd9xSFYfcGD3cNI0KL1mrahyjw0PKsUJlqiPfIUKj4bTESGI7G2te4DnpGOjsd8j4Wh9SfCKN8oO8eifMP5p+rwCnuqAdnU7/pKx/X064Qpz8Rvanh3RLT4DIwvOTm/30kjoTVKuQ4arUH8WXZmlw/OEl3fqncJbyXiNFLRQdT1igIJINYxwGt7LEI3Re8oELDTogFEtt7NBCZM+vf0h4T6ys8Kuh9QHSxVkz+3+PonCMKzaIkDnyTOS/kNLgUvhth98LPfR95EfNC8Cjd+YM5mbi0lacKb1NF+JuOyg/JlL0D75FQFozJDl/HZZBeuOOXgRg38BWs5PzqMbZx3KdS0HgL/YRbauJ1bAiqYHyFDMqt/cKPc0nIX5jWRkZZ8OMLAoCOkwFQJIOnZNqJiec11Ozjo/kZXUtlq73kzylUT/fZi6VnLlqF8L6qSimwZxzLGKQcSmhAd0JY2Fc3BZlTS2y2vogoq2sXj7xsjzv2j0gfUlSYP7Ccp7/B291OyxuIolEl7m85udz+ZsLt8KVU/6NYNDxcg03EramxGhr1VynUmwPS/Mgo1Iu3e4icvWWx1rLzj88ttRswGnM0FgwYrbhNmxfn82nsscldlhzmXFHBINBDbLEuWr38h9o6dP1CbXi20HmSeII6WJxH046AL/JyJPyjpxHCI6HPT1LCftLJgaP2iqP6Yc9Mqr0HrKaRJg17OUYSxpbW37cnawJoYzJzGyuw77X0dH3R+SCU27SPkl+POeBNAHfJoeD/9tSiJ9W5S25wuXKv04z7bGLILmojUXjoKYWKaC6p775lsRSjebn63G4AyjVyJoy2SwNgCR9Maj/4ebVaYyobDQCYefRwMHyINSDxkFLE3qLp7jRJfxX1r0ptRGSyYYFE3wcZIUiXAGPpTCIanYhUftK1tmpPnRk+miQIt1T5Rd87vjC8C6Qn/5L9pSM5zt91mv2LnpnVxe3G7yAv9k2iqIQJTBF4HKl1KFxEq5k+4WZDZ4uMTUVDedEOQQDKLCTsVOcjf8aO8CMnjyN8gUVZKRi2KB0HSb7sN82U64Ox/LdX1u7qA7ibtIpCw2gbYaIsAkW2lCIvTBkzCtz28zpEsA1Pb4gjNOLnhYF7AWVoR7OW2vHxTZ2dxJC6nlc9WQncChnWGHo8+81+tcYC6LBS+nmMo/o0diVxZHbBneXMk6d9mhysXA5B+E+bFvciAB6hvcbA7OretvxsLNHly3u3PKJ6X2yKc4tBD5bZffKbrp5rn445it5DmQlJp3eZN9VSKoXvDCNEwzzgWGkj3rOytlh+xGcOPr8GvbQDh8c7Zn/Ef2SIOol1lWA9SUTHmgbTk85qF3XF6E5ThsmHPnwQGsqvwuZOt9mvKgbrGju4J6vYNYGE9ApIgZC4bJlf00+zQ5lBlwsuGZIyGkYHX/eSmPBhpcUa2NIkcjqyM5uQDCx+/gTZy018JsMfigLXNBBX/BLXIec6J3xo2Q1yIdLSwWWEbYASYlcwqnV6hj3p6SXWeNJwdL/0HQlrcQNNzL4od1UkNO2JSXYzT87dHp3zXD8CqfAFGrU9GOMjQDW0CybBF07oQlvxtUEIIOnc/BqrqAEpgHO2hXAyBEB6rWB3A3AKLaqoB6xANMJPaibzLYdaPzrcgKUwxTjZL0MGCS2f1tZi4pKSf0qymXXnaFdqlgsjDfrlPvYlK4JO7nPTiPduX74Iu2+NX7/bUxc/ga3G6oMDSsJTNzq3PgJOlTSzusdeTEjBTnMAHOxR+QCziwkpIBhmtA2zKNZRcnP5NwlxvdaalSYw4BOtXfRYE7XZRf9KXuUNn+TGB1OGCIPYAijhGbEbj+nSYgwzd1vogpjghdrbK4wCFc0EF5KlvE6OTBYNbtzKrddMsNtP2y9i98SCzT/cmjopBrS5MPNksiwOkkF5mnfp2M6gW986WlkJbt0KwZlQ5xIUMkRbBhJhlROk6o4iIgzomCl49fIpbiBGwS74CAefjaRefrPdKIRLcUULFJcWWLJ3ID4byHJNoFzc1j01poWdqDH65boNuPbdl5jqj7miYs0PeACx7ekAwVx6XlG5Lx15lJYDxEVf43NUh5qXPLS74tvQvoL+0trqkothmmNJnlKs52wfhrv02U8A1W7T4gzOq4Ag67cu7x3EuK8VttanCIzZjuARcoM36iCeexPhQD2gUYSFQlmu7O8VFegAjFkJeeRR78QAwPZ1U/1foshfXveeg1VxN/lDeKIEmkExzlh61y1mFGwrWubP7bMkcSaPtU+ogbL6Hj9cY5xAATGiMvwEPqEDJ2WVlBNGgyCoQH26BMe5zeInH5AEebX+96EexwzCzciWCYeXfJhZbK+5rz3MJhHVIymDGitQkTPcPXN09K/kiD6gMAAO6CAfqAWnKD8M5UwIBAoPgzBb5DAXLY7H26gkD7E+DwOEUR3a0YE4vLTuW4njwAcANRFpadHYWXAfl6MKuB+bMRW04BjLaMCBuIjLfjQfpV3mlYO363jPP5a/VmIw+W2S1BA270Li0pMxmnXldzIN7AZp2Q1mBaSXm1BxBYLgt1lzZQmUv6+PR/zeS82b2HZHid1pCpENShMRxBBYFIKXCBQrFKNIDUJQPorZXSkiRbnZvkovMjv7xXUX4aSXlAbbeuoabtrQKRzYvWFMzlh8J23vcff0+d3lwmYGHr20duva/BY1p71Z4Wl96hqB/e39e6+/vlz3WEMhvZ3ZJS04srsy9ompagqjMTJ8Mrz0F3HimqvQBFiWXPmb3uOfhLa1As3qxepFomz+XdRaaHljTEgBwqwS87qf1m3TTABSJAQMuXs5Z3Lt7+v5qvp6DfP6+qU/X4Bi6nu9fVp/4ZiCLwwIpNrT6Ka3p481zOTwZuytlzKtfL7cUZumMn1ffrMhuuioa5elG3Lb52VZZvXn0ddEkqumJD7O4Gb4y9lrLQ7xc9AoHDoPIVM4diX6W97PidwTs/Dng9jXBXb8NzZLULc29zO5wJQUE7mqt4UOZyNb0W2VCQAmIxR8sGaR7ftzM4Qu00nH5N5j91Fe2617tJLMS4sDOU7A1yxK/Znyo1y0oE2whwet+yIlAoLcS2OFAM/+kQxrtLMM5Hk/QmddRX6r9fo1ulR78fOETCcXy0PclS1Yqr0jau/Y+/XSMI+TCBV/ThNADaQIK2FFTVo7e/i5UOSOVOnLDK/W6J7ND2fb8vmVmP2rl8HsOXQLDkFCU/0VCSPHYMIt595ByGWiY1Ilx/2cIVbELGAZA14x+PeY+6yXYLLXW7T1df0Hb2FnLh4UJiK2upz3fRLveXM0CAQhk698BYBsuZLdg2QDHMC2XPvVT95WfLVNeYEM6wrnxxnX9DQrKsLkwuH/XhryX86PLemWh1tWof08QB8vdE4zkJxUq82rK6U3qugPrWiPzG9EgC5fiMvvL1ue5nEmQLg3MeTX3Lqk+WLisC+Hu0vNnyha7UBgZjI5wn0uFCn4F2sN94a33yCBL+hxfeiaFQMKLc7oQYpNeFP0/vg5IyloYj7owQmeDkwwFSSVQQwb/voJlXYjkZcFMIXqZL3RYoYl/7Vw3fklxmLfY+8iqdVRqW8yqkhDpbhtzGS9RV4EYzkEaAFpm26+HBdrnBARx/9vuAxnuic+KYKxFIkJhOcSBSVuYRYQA3KUT8dmjuJ5TpukDTiefSgZqCHG2nvmKcyXe+/hXoZWlQD1FSmDzGCD7/e6hNIyPmEtiPycgYM8b3wDzaM/6sGo3nwdFeK0kBlBolC3rosSxD7D0+dpY6LOLNYc4Fi9rkDdqL04I2lprH+B2Idw1eqwC4qzFCF1WoqmmGSw96DyWtZsxcPkdRqG4HNBqIgCGczdTafwylsuBwIxhywj4xKvgKEo+D24BBSg7LT0uIKsBqmr/2Cm+H1+IlkL6kZfXTu2Z2CnvVvSx+B58ipMpt44BjghgmetmaJkOGuVdsq6U4cjXaw2MEYXMNhcm+LVkiR5dy79SCvKFrHYVoM/6dX/jsr5lvRt52K84CiktPr5o2y5xI4jH8a38snpgoJyXiEiDEE3BIGjE8FRt/zhnE5iE6b7+2gNDteIoqK9vAgYC3LhbGVi4aayXh9B8JMJy6X68h+u3frWbF85CYDMdm32ZDWJlExUgoMPx/38bJl0nP/BgrIWe4d/2O+wDf2uEZQJhyESkqSZOucnymBXjzrMYv9eoOY9uyCPtr3AFJxpSU4rd/1NV8eOweEXdWfB+FBQQuulBwu+0wwnlniuKK0UlMcfA/gfmqPdX6gfVjaDtJftLajbFQWh93FWi0/+nM1wCTYCFH+IGA6jfKG+SW0dnZTrtao0L8+H+nB1jiB7hff9OkzCC96fWGjMsmarQVE+QExYa3h/N1taoyTiJl/05DCMn0/SaC4HEHq1f7LqosuzsThb/MldY5FmX8vClu1EdKOByZqrk6IIOE0JyEVN8Jsx1N5SUlxNeKu9FLwRn30EEsWPX6QTMuLigTufpoatyVn+RiPF7TU6Bf8lKw5YZlX/9RPwL8xoaFWCZaZiqnJrfyAPEcNrxzbCIkFC+WloQB5JAUHlYm7kzbSAQX6f+OlZqcAuWX4BBSnfl+C7zAuvIkROQlHe52KXcCcCZmbp2ZylAXU+xghDenEo1bR8w2zg6dZ4yPS2JWUUL1NPL8Q6BE8rLwNn8DuquJV8ybnx6jW7ndHXgL50mf+BP7H8HfcQIobR3QTN2U2PfstHo3te4JU9cETpDDd6yFzOaE2lvpVo248TbKmGZQDz4vDFpsS+0qDwgVuRF7h///k8pNAHu+fYhWSvmZqpLC7K944YNfx3gJWuSsH2WMYHbIi2yEYMuoT0yT7daO1l+SytYIJsptx56yV8UPL5hQ9I2GOo64c9z5mRLLVMZyzGJcJyvEtxJiwn1CFjy3yTFc4/WShNyYg0hGZURo5Lq5L+TcRpq/BWqpmQ4JKv5+QeQAnAWwhYl2GnyBH5cm1KSLHSA6WPpY15UjotOPCSLmd0iXksWC0lJ8cXuS4kpahR4B6bMVRLDvBfVCv6Dp1N5UB4YYXFEo3PU/j8URvB11kD+oSkdZn3B/q/k/1a4fpiWJf+iU43IyU7S+KuDp1/3xpmzmiXa5XQLl/P4Wr//Lsfl2F60Pc8xD3x45uqKJUZNss6o0pLThJxoa70q0N+2dL3c8h3r158/0sJz3BQl8eNaskpKiPCYQ9FwaFJm6bLwElxh480SVAhdlzReKKqYEQsWCNCg2bDFuCVkit2zFs2IZgiQ+0CIRuy6sHWChcKy3JqwNOZ+FBZw+VudakgAq9+x/Wy7Ric8/aZRMOfPhUrH41uz+lFRqSJpp2kPxyIwynknh6SNZrzqsPDNgsWj6rKNR3kQePa1cCsZgcbL4e+YXXpirXRl8jnuJJncdGqplnzTPPzk7r/ve0XWWD8zzUwFb2lkiyAS4utW3od5zkKPa3XaXJdyswohkmVS4/E9MZDGRQkYcahHPhrkFe1XpPGTyvNP2p0+cj4rcL3V/6qUuD/flGseEzED3/nr/UXfGf1r6zYmqnkOFqbInCpqGXRnz8k3f2Yi6IDUkEgIwyx5a7TsPxyqnAyYVHQC5r6QumdUXV69+8X/4thtGnVkmmTO1ratCYWEdY7tAVLPgRCkYxysATaKyH1wprkGxQIg4dNx+xuvGYWFkoZvqxFeqlyw2My7XmhBvM8tfd8n5L1Id0NdMjOHxIlK3B9hXaM8ACbmQqlwWSdm3Rmja8gwALabxyG6lALD6LBUgHJ5HtKnRLgYB5GTscMk/FTAAifNbXB/dYnsWsHXqV603Jfl5KlwK411B/4TppLeMzJpanKasK2YI6JTxZ8c2qpapNsQuDV/5BDZSeCZfz0HYgxg/PrVzIq739CMeHqNw9PybNuq2Mac/I1vRFtJNyVS3ZFjNkz38SIQzh7JSG40EPd2r33v7S9+pmE9Yu1c0//UAkobHJFPdMG0v9i75hyimgonXdVfzxQKiID1dKocsmcxkmdsv2GLcTsHQdOUHIcsxXdomI4KKC5UcMnqmCpPMxo3SUlCv0G/EYCyFrx6UWQRlZcg/DRV268nv5USKS+kHhmSj6BrTTyhzk7H18ywrao+U3eDVBTisaSeWTGWfEWQnl2ZSWmaJEqTMn+YIzaNMmlkVjlp2KYefWxUtOVn1BFylBHazUltsxFMTnKmdPIW+Z+vzdIqyXFDstKIp3C+yFhmVDpu2ZXV76ZsW0qkt70klnqksv1aA1lNVNwsnci5flFUKhIWfokpZOrz3yml/tTx/kEEtZf8n5RGpaAV2lvGEFGyXGNdGhWHhRluzQdzXjG6w2VlSlmtqWcBvyMPTBpDByN46j9GSmMesQpT5hjNgoBUhYDKEe2y3FuXC+gEq/CMxedDb3MMx25dNwStqRa9NlVNjhAWDDyxgxRGmvHkrFdVFrHsqjTN7XsiNSokuaBcWPlFtq/05Vcn8cKxLVJNgcqclsRgURvIwF8+JDLuP6JcWPPOfCgkkO2TZjg9L8tcooOvXBSVKlrXtf3si35dn1lx6YBCr3dJ0yU/wCZJ/sC4+GSDu1p6mA3a7aGMLGfm/v2ZQnl3atPVqQTI/iJlwaL3r2bSNb7fwJ1E5VTSjtxbn65PwEjd34WHOhorvOeusQTrnyDVQ1XvOGguK+WFR3OusMT7bn10T8Jzcs73wQxfmICQzWWXn2upqfa9dvWuJCWdTPlqU35MQKGg9POqcCjMx59a7dk+LEo3+/EagCh0sjtV2PxpmL0VirOAkNT69alj9b6WWvqGdIgdedgnx+v0b5IpnGoGjIYa4KrNwQWzsfnzsiAYfNztIAY4bNzmhMETjz5ZVTx7cl/TxFMA9G9o4Qrd+unK9+md8Vki0OvhQde51yE/Z2VPWjyzRTjMY6Ke9u8HpbLJ9wZqk13FPeK1+ORpSJEKrlyZUarTCwVOEwdzYO75QBT6gCKmW9WNI1xqVvhZ5AalJZeBVgqAxfOTUMcsUdcGdtF4AiCdpBc2gsOMPGDThJ/G6BhAYfy3CLzgU9EvhexxjRacvXkiuYrPi5J7wOJ78qN9UNeZcQQEYJbAbRmTyySEoIst6UJgzjPPfZdY8zGUASa4HEEHC0pezd1YhC1BJqiITi8UGh1cdnDPXp+nho+NuPUPQTQu1Ltr3VlxXRL9KKsLgdU74VxM0MUGpXy4BYf1Or1+R3fHkBGcf+VoTDhvNH0nDdqPIzV752d8V4PRWNsl6+H823Ntk/wqjwSA9JgmphUw5z7i+c9eQAu5pjW3dqx6dgMwFcT8pIZA0Gar8ln3rAfM1kcijeyi/KSGSA0K03ww8SVEKoEvnS6upwDFkf0hClY67TqVSp/DUbwLZosFw9vTJdywnkXtL2yem3XqqfEkEiZBcnpZ2cIYwzeQW7m7o30+jOZBfET1tDb/ZZ87aSakR9n90Nt0kbobkPKjbLoOnqQ99GD3ihWSBmkTUa3uSc053VNq+vpg6ir+aPtCYb2sG3PS4kqwtsS/tX/1UaqYkntYNAaFoWrueNyhubdqZTyGOW60TyAwVd183YdBVcfZXvgpKvrLw//rSxFWKXmocmVT7VLbXyBV03cJLLeCILG4ikyqc2Xlv/n85SzVeOYTWxv5D6PV1le2vLPzlGxP8uEaIvON2zzx2ZQ065oSvnzHpRQovvSAvr9fMe/Z7DcEn7UZlN5iNRgvDWzlRzteTTuH+IIafPBe53pFV98iVYXCkcYITCAIwhCc6mXLgn3fSBvHltfRySiM0wmYvYzftpLEN7V2Ax8By+VqJ0NbXWYWBd8A715HbZAgL64Jq8rHuWomuLGgdu5vQcnR/G5v2npLxBrIi7dX1DqCj5oRhhIwoO5Y4OJ0AaOT6mJsY7WhitHV18c5padmWJkVya6t9uYqV3WFu9xrb/ISM/wUC9vDiRjpHH+QCgf2etfSXLhYtSDQcoEDhe/p2LeHKiRRAcVjN544qOB4JH6TKxpMLffX0KH/Y0ZUv/n+Bh58F3HVBMSOOSy1NShvLPFcw8x3UhV/Lfd33MrK4vIgnMWbd9kpknizAqvEZCCiupGA4IPjJYrY/7Y2PT8K3UXKqkLFtrw5sy+jcPemTS2ircr6JE9O2f9pInfAVBT3iVpkMgK5U0p/XlK7QB6tdrK4CJZf6LA3dN6PdLML9QfM1VqO6YPJxvbZ3ZFw9n9kEC6ieLCDdrTW7xIow/8tSdC1H8gRMLTQ2GTv9AGYSJiAQTp8MHt3WMXx4H5Zd76dhatQ1ibzpijIy31mB3mR5tvedPKzrVzNF0v46W1jZq0/ry0tZgodfEXJScOjlnJQFSA6GkIrniMHTMbKOMJP/So4KAY66Qel0eTMv9KVnj1JPTn6e08VbGvU6peR7rPuhcHpIX4S/7aYk9fYbHfkuv8eTTb/7/qqnWM9Wn1wpjlzWOz9eIFqRMi7WWhPALCWBNZGpu7ZCaZzP18S5Dapdv73TvKUSkFgbChAs9QwAGFYCxYZ4JCR7a/y1WuwAW3n1emRji10uSx7blC3alnqrz/7McVPW/4ZJJS1nxuM/oYePiu64jvF7Y2Uwek65qC5TRnL7G9L5qy7GjSvCnfyPUb0ZYL9Ns7L/7Dgu9xbjAgTcMa+pNMv26Wl18DXWfEP+rqUWsGqvEU6X0Pvw/eknPRX/Uut243/GlxR7Fo+0ZWjS9Poh0v5gLUF8AgCwkDm245n2ZqlJZ7xc0SK2WHxpObvFka41PAvfW1J7JRT43psn6427fQMdUuD6UTsqdSjxraLEiyEsougDQeS4TgrJ7qSyNzF+dRwXPhisQv45M23OMdeu2nMSJHnKsnVBCLd/mpFZ99NFmSbElLuVIV7LiU5Ksb+Xkv4zTEhBxwnUE5Vec4aLTkWXg0Xf/qBDs7PGCBpUnSablWfOCLgkPXQCuiVInD2yTgCJzybJub+AxV5fhZd7L1KGBnRUt/GtR6n2wm204XFWrzoO/KGTDOrp5Crv1JcENmTcGSvPvccFVky+jchsgrQGT/FBcvlK/lNo5BF3Dj9Ou0z3G/YlH8rErxYTt5+7IwnMp+CMaaNaTcdelI97zWT0CHiupNXfn57p2E1Cv8KxthQ2kXzpdJwHBMwk2HTB7CXtQklQVKcqKHdviqooGT4Y37AqRGapUJkevcLF6b1YFYnnsgpqe/yyh4yCwMq/3P00XwYYR8lvMeNHMf7Moum5v/R/LlW7fbccaBXjrdOP8UHbsQ1ll3PeEyq0BpCJL2xkrlWwayymiFgeZX1340vGvFXaPGpRrPbyGd7pK1uqA0GS+eZncAL72mlExSf/1LogG5olEn5snmF3B8VkChyyNPj5LW+f9iaS2v/GylzMHx/Zr3G35pV8I5OjXZsS/qz3ZuoE0KXEckD5WUJZ/346VpJtohvqG1QLJS1jI/+3fh7SK0zeAsrP5a2Ye6hxxhTVpTy537iw2sIiRpbV4kd4XtgkTxdHFreHRa6ZVagQcT/WNBy8k9dYKhmJ4xmX8B3xW2Axw326FIyU1px+p6Q+xKHPVTrfhT1xuo9OWt3JWJZ43eADeuLCO23kaLiIJ05EI+PBsQdB5lwomR9D9U8LEs7nJz76nq67qLZpKRREACn7A5r2huRo4ed2RJh6jORhyBAc0R7iqo6ItbpUNuRY4ra9jhosTm6E/5o/v77pDGJbB+TRIS+C5WsqFOzCNE28SAslJqXGZqZ88PIYlnHdKl/p/zqt6ywpP9kpv2Hy/upwBLC/MEHebnZfzyeX1RZSmqxjvLKoL+OfJ5RQNqT/sAJ0W1AJMw9AzCM1UXWNgeoctUKh1NIc5Hxv2RzNrDkVWyX0kpg0U5FosvS1/jWimPmWY8tUa303RaGNt5m15VnTuI/PiYJuZsoFBl8wlEhv/jqtGJuPQh//Ec0AhM4h6DGV42t3MwsNVXpXBLRrkjqIM0sSnPTyX+J+dEfX0lZO5Hz0c8uO5tzls0ywqPHb17SOoNvAu0QtdVfYd84/FiK2EBpMpaxU0edCakQCodiIUAnpDi8sDPih9g09euCxaSrF0tb7hd0PFmUlu9npKNCR6uiyuGoq2lGJXOkc0GaECYgVsaDcAvnILVCxG43dtjTeOTHffgrGFs1H+eVK6vz9tSrJNKwugKsebs8G6NrvxQ78zTpF6m2rMq3tj/y0Dsizh/eFrSSJc7alyII/1U0SrL37DvfxtMaUfO+8mbWpWlbskVJV3XRmcJZrlj4Ta3Efk0bcKuf7Fr2kCwmqcOgCHbz3Ute/zfL5VY+fvQf8/zKwptKBQhjWwe3Wu0QzGmzop6j5JwFDw4vSds0LCjCJHFZRw4YX216x1cXe7Lkj0xr3DqOku/tSn0DVC7y7b6Uw+UKExBHvaj/XmlZeMDFa/C/45TVb9/dSz+MI9ImaTNu2p8iLLpe0ghyoTuOW1Hfsw6FbeJYR+RNh5YFq8c1izXS3E88HMvVjCehwS5xTkT51b3xBvumr2+DcMYTmVchEADB7RcW2uQbQ0McXm6ur4jL5LoXtBKTUtzhpdosb1J+m7uOTuljphBgQi//eyX5nBMyAmSxs5SaFbo1tX7ensHzNmb+TV9xBVHRL4+WmbwfBPrFDpNOJEpAEAiz4VvJ86pceYGCqujLF3zu1PwM89u/QMYd2jR9qVkUpiOmYD4ol5ez62jluiffKRgznKUFSnNMJEywuMMoSviRF25ByRC7ULHDmNLKJMWIfO7WvnXvbkkN/LBQJ37mj96dMLe0Sl/fMmM2lehL6srqvuf3FL6JpZi+EuMUZjBZm1GmuejKTZTMeyT/0zseNvX/wvmfKi4G4jA93T7LRgjZmhPcDHwOhZw5+4dc+pVuQoYj+32Qm6SaKKC9RNXJONf0tzLzeVCWQOfadKli+tfQ0RfURRZpVU4b0LGG8B5zrAl1R0YN9egbAfZAbtRbW+lBZNKriHv02aNFOrOoB3S2OtHHZgFuUHePak/+Ws66nVop0ST0oyufluWbDgrQlFtHgIAgpIIQwiUA1nOabRIgtQfVmTCo30BXtlxtUmq1nwSh1LuFFHsGohzl9VwkEIY+qMr5aqPUi932HqWyqYuU0RTNUjMnWCeIYetuJrMWhVh3M4nTKy6NaC9O3oqk7T+eP1/VtCLbuMQiCGqQWoUaUeNSmmpqoVPVTR34SSZo/YJA2UVZbtSc7qmHlCbrc016V4FahrZKiX5NvuLQuWJdqrv3z9Xl6bGnYQjcSke2SqsMq5GGJCbJplqIxYZywSLz2gWKHEXfKaJdqG4UJIlejcDkAPRrKKpqUGtS6deRURA6d2aXbhH07x/uT8fdViHXtxT7nqmva3ibLdbTeE5wCrVn6TE8xXtALZmmCikzPEUfZuwJYywO3NGjLThjvpZvAY8WtNmzD0FUh+zFcbegUqCDNAPWEBKmtIwSrYDPV246nK7kNYTu/LBVpdlUkWHkWMsCL/LFspePcot1nqPKKG6ow6Xu/cGBWmGMDV8OCbBR8zAVSSI0vvPET98iHYMSjQRrrYP9gjke6LPXQkB4984d2zasve/l4zuXJ/NJr14ujl2Z4QHaSMIHwIMv2ptNBjNbW/MPq2c8uVRXYrGThfBskQ7GFfoKYZYKjQHj6E89lTklOLAMmHCMB5vG1/XS7WK2weAwryR6cXhn6ELi6dtglS1Xm6BiMwDqwYzoL8uikX6Oqs/fY66XukH/kH02PosuftrMDAI+/dAJlvJM3Mqp6Gy5yTzmpl7TlHJvoCw058nG6NzA2lqkY1BfR2+HmIg+Ajlcfcv3ryuePbx/Lh7s762MIbr/yXE9v6rTqrIuCAayAzqdFlKp6j24T5YO1znOo0U6QepBfCRlLZiDNz77YKXk3eXC7x7e1zMUK3ps+ZENc+h8sCLVdPbcykYxf/Jwcqqx/euyxeHF52/fOjnaHfc6tJQe4tA2twN4PV7PO067FMWS6FFSXLxc7Q3O5OTysvmMQk65MB4t9nBbLC54z6GUckRRp05UyoXboYiRqW1qOXCF59+k9scwggh6ADYJqDIfnMFtfdrKlqtNyo50oKDyLgg3WIubAIhC+hlYN1/MUCast/A/bElCOT2Rb82Q5CFPI0E0yf0gCtiaZpNF34bzaJEO7nBAkCRjMwE43RD5ia77q7CPXudpZU7rqxcyTMqrCoHKXFoUNCEpqoKOnDz3EdGaeMYgU+ppYkZApF6YRqryL+nRqq1NSu1hL56DoIwqsssFaVHkXIAIZ/SfmQsmjs9Iy/S7VPK3XybiVKxVkuPzmDqqjC7T8pwgWOIuk1BQ2MM1KpRwLX2PgQrKvSJ84prpv5X0aFV2erSFicoYXo4fqyKfcstH8yInBYGJ3X1oNQOrZ37z8vH964vj1XTcbWfTTZVydiVYNtzqykmcML0mms41XJCgSBpQ++Ke5Ia9F3TfxLbXcozkDa9sZQZNrw7BBLwX491iGNK9JTCvZ1ggOfow0uYrNo27AddDN/mm32vWw0FKQt8y0Dw18nWRxtMd2rENTKnGKl8Os1EzERLdvK9VH4ACcG011/4i71UVaeYwf33Qi4YZ9uzt4EANd+NOkdiGXa2e6krZAiib7bdc4qqk9IIiGwUAb+k1IypbrjaBavbQ58Eg7OsHoK5qjhnm7yaMkHT541f8bvKfaX2Yr3S7HkGDEDmziROcmpNMfHK1zGUa94K2AREzVevc8FcJYgUkEM12lWDskHhB6Y10zTdKDxeGXNxG0wBwGidXWH4KjHu2eCkwb3/8tVu4F33zQD7wlTLO1txQ1gu0wZ+TCjbfkmU50506x7hapB2geNos5QsaNEiavDcrxx5ko8i3gH+Xvrx7++Ls6PBgOegJz3Lhf8PgboTT4c6XHkGmvCoyfC37kDLUuC3Z5ljhsl2yl2XW2bOeE+bZkp/cVdWle049Pu6qj2+eP726PNmdTeq1fPYydu0zJuzW6Ymc1jd3skqcnMHCl78RafZK7BSlcqbJ2+xu2HXNDfJokY5J7b9TOZiAfS3yVTzB/I1mvVx6uOkaTiNHOy4L3LGF2inRwwenqGEnUDnLkykKUzS+Bn/PwW7yHVzZIp0BKRp30gJQ0H+HNHATk0/skyyVBidBOkengGQrIPCWwp7gFcymBFJanThFdPHBERa3i5omtVQJ5DEWQx85hChLVCWnGFl6vv8e9pitjC6b0PrZXYGhHoBvYcF0lU5tP3e4bPmcbiA15bQnIGoqiVEKPiUEoCVTu46PXLgCnPRmgmRj14iAFlKo0HSI+bQx1wLXqSiih4gtgswRTc4jL5nHpIWF43VAuHlj0Gs1KuVUnyehr59WNVec5qmXWBE0xQUnOURdqj55BfdRnW/CyZLP6e48zBTmIArSpYbBXNwWkRsTxSLcb62bNCMYClMbzwvIeVtDRI/KGVIdh5sFquMxLo9Za2BaCBmKDgDv426ELN75BBBwnVUnjplcPcGMGRGk/2vamIJ0RoAH6mZi0R8nRvAtOyI1QbA7s3FfgPu2kmxpQaHDL2B1yD6yqGmoRSXdJcGuy3h2JC5RGsLxo9lMVVAc+oYGM3aysy25H2U5oXOkXCAEmYk5VaADjIvyjVMyD6R+6ZaCdQv6B7HHrBWkuQQWSBBYWuY1ntUEl+vI4WK+qRjByHf106rEaZ5+IWv1YXBojxSaYilR986ANr5lV2zpZYY3ek1OEY7O4nKw/6XILjUq64cOZMciI8g2VicHTm60L+jYpWyCxDQq+0ihPpQUBJUQunfUSCkeq4PhK+Ncpj+Qte4hqcMlkZaOgWgugWsg1vkXpBmbXraff3xxYDdc3aQtHk1SjQwUIAoWFk0qi0iuyZdiKWhLJZUMlQuYRS+TZ/RyI7vHpOoYpUtV9xbc6xRXDOcoGONTHQxUqrXDM6CoUKu0g9SHuoQz0dp3rMMGu9ldOnIJP3ntonCWSHIGwkTZWMKkWiGktg1M1U1dAL0y13WiYp595+nxct5tV2ghV5ecBp6ePe1X+MrAxJM/3WY5J4WAwOrF9qXMT6bx7navS74q5R27a6uit5V22MGMS7z03o531pIeZODlU9sq16eRdtAsM6PT100ZFxlrKJKcmUV2smSKIlJRZaoeJ4Et6UBKUxnVJEwXATzz9HIBV3F5yv3T1z4jW7I5e6o6MbY1I0Jl6hU+efQxJMwwXZzh9MlSoasSFkemtirxVDHbUog1o3SS9BbbwCn0RQgoWApLNM0Y3ToatJxSHbSbNfbOmyJj2LWPu3lgP/sbSHqYNmpHCSWJOyqKSaaLaSDxGGbaN2xBOd6OBZ0MM1Adh27g0mF1qX6LrnQ6mack3m1wnudTGs+3pfWiOc905ZMJPg9X37WrnGTHTOGBnitz657xQC8Cvx/UoQ+HSQS7wFEcmvLop5vT+aXAShm+flVWxh4p8wUgXLxvT1wvzsfa1cEt8jjWewtWUgqUSzAfEYqgpZ0/Wylnz2UWeJaxHcgJN3ij5ESTQIj0BmWIs89m8MC+o3ORhb6prWo4zMNJatHF7Rs+rcysyV2xsaUHK90t6aVcneszLjjP4bmXSpLJ4iKL5DOYpYmSet3xqFnLZ8qcE9va1PGIj1Y53GpFL6IXnsKWXWuUJIjWVBbrrLnW0Aoy5B1ms/y4pGrALbygWSwktNNHwYFr1SFmyPl8xi+lmQB4hEf3jmcTwUlxyjBh66taNS8xfAs5moKQ9DZNQHj2yBXEVGXRK5pBzjUmxVayENyGhXskhY8AE62OGfTiWjln6IIss/+aC7eG/YJFFvnH/bLAYz5+if/QQJGBdCoyJAdyfFe9BAPE0EegLKLse6DEZq5b0avXpCja7TkA87hxbTroOu3Zh9gdo8xuMdjCOpPynvLt7gSIdMGlp3XRYYRl2nrrMN+FnAGH9XVpZbr8R8CE3u3au+ceNxJHjq0dp53goRxrmikkXVwD5Gg+AMgK1M09UNtwf0Sgd9zIBP7fkwqfV7vtSv1rs60UEzmtumdxiqO7sBsDXLVfSjc1X0SCebIHwtpwS6xhLI9ry51tZ1MZ1zix8sAeoNVBoIY9XIhOPyvpbLnlpLlIrkYwDGvdwmDw+/ecCYbv8q8TK4zPsNNq9taQRA8TUhI5mEB1VLMwlT6YM+um4cOPfrj/Itwf3MgEPvLkRZ+nOqeaCQ4djNUZLv5StwPhOG7HCx9b9wKVhTvDXC8x4SJSLnJarLEoy+IxACGkj3bs3AdBs3s4UJb1hQHW6yPDuvrKTnD4c1EuHWSjPLeHW3UQqS2/RxXVsROJwwQ19HvOMv9x/m7+9unjO9eH+wZXPJQjz9AmVl39I2nOOmhuHt2/SO6OMhN+Gjf5DhT1lM4GLY1Mk9+jDHJgw+HWzemw3Sil25pgUeCJP+TdWtweZjvik1DIBnf2BgDZT0JQQJXDrhFBcg1GACee9aVro2ACW0IP0zr/aOwlXMD6ibaZnag9UwjM7QxmtqTDo5o9lFrByNI1R8EETUolzl9vNcqZrklYFFjGImGBvTK6wDVJqN45Yiyx1IAAAdiqUgJTYm4wzWrCGSPlJ3kgFhfSBZzsYfmP0CaqsWLVD+9329V8qif7nyI+nsgJnmWgjJTVAX/HyJFyZa0PovpwCbNqJ7BMkDkXPRTFSKtZvVeGa2KiDec8JR5HSiaWQdlgHHfUSIj+R+qGq2l59fLR7auLo8PFrNtMJ+uqTDDKd9LQhoSDTkhNWAkRHRczgrXbw5J4KDlnmV2zDTxsAVZHVwYx498aRgDejrf19vrdWjWbStgvljSW5fR1I+GcGbFqJqq3SJ3O02lC5J8JX0JEgOhN2kq0yHE/R1y6UMxXGQod87gHs8w2Pjb85vhhwSCH7t4SPd7Xu5qH+nCjKJ6pOjadlLq42C1v9ChUOt0flBfG035nO2cMcOyIFiriT3EbrLf1Z18saYhOTmLuyZRMfL1anEFu6ELz8pk1inPbozGieqTERL6r+V3S5XBXl0aFEhWavNpSmpILrOC454jOxtU2vNSYDgGumfp8eXVQGJ5/FF9TZHufu+bBQKqe5bQ8uCTmyBdyeDLDW26pK2LkxGBtZuQTLpyQmXK/o6g1bUAW9OXa7QTSVOelagVx+EzIPXnqh2PrSg9j3zVZwkgU0EO0IGULZhNi7colhDojrOAr8AqEGKXvDWwy3kDd3r0xSQ51vTsU620nxZHDxcLQsadIPUvL3Y7Q18AS3aNyNfn4pxU1ynPE3GNdkvgrFn/UrXdMQWGudp8/Zfljh5ZxSB9CZHe3a2uIUrn91RR0c4SmPN6Z2LhjaMuMDk+W0w/1pXVbVGmNkjQnPFlyn6VOwMcqAypb1yxS/VlYGC/h4oVGLZ/tW9c2tFngOq/ToDVtpBKbowVVjZtEskRrC/hjk/b/K6X7n0/bSI5uzOgMBUZKC+VWXK2CAVJ02XFTcwJjmlkvw25tDh1I9mWuk3z3sLGEUzxV7Ag2UGTKhVvVIKMJVCoSaAqIjPhTJ/8PE1t1/7u0BDW79H1IUDm6LymZdlfhcO1dgNMKhN9JO0SfxUiIOEi31mhY60Ieh//V53ODaccTc6c97FfKXc9zpRie4TM5OlmVzfJxEqXXAcG4al2EyRkYQUMVKmQOjI1J5L6tfJeLcp6gWTRz6ry2aDPLWyyHfqMU5Q3iWWOpprauYQ1rKn1ETpGJy24Mvb+p6iqO3o+dJwSQGXZ3Ri2aGc59G3i2dTqAfeyr5+AcxedjF+SYVzU57wWnj0L/tF+XWMnK0/GB1GhrXbrCuYmX9SzV8bO0ax/4rnYMvP8MMzWbuKAygmsaVFzUq+jhtsNZnzfxpOtyd4NSP6mhsAkYJkx4uAV0s5ajJNkUkTU0cC+BOHGsVGhqjA77VYk55vbM2Bn7vMMR6dCOdcmgZzrOCSRLuHhHUs4AmxnR6J/PaJTPmsgpdkpCXcMr8ezveKo8hE6BwtXvymp1s3rsVcfjKXXxbh4r840EZGrQMVoExIwMBua7cQUD6jYsFPGtzyJz6G7+gqD0nMZDF8jzr7mHS5dXSujdHA8KuXOfJafjuo77vB/vV2EUgBgO7/BKakOk6pnng+EnQ2H/hOFO+ol6PlsVlCOAdvrgFHk8qkNNd3+qQg1stxuGjSulobLeKAv7q8WwV6tk046JZ0xrVTsFFRcPFiTqBoQwUW8slb3xPt+RbWUagXNkD0GcBC2ieP7RzAcwH6fsvA0802jkUxbxDcOkPLMKZZ5GFpX8jJApSTQ1uVyXsMe04AWeIEvsHuTmjX6vXi3k8/TCgsVYFhQKevbqdwBx2gETcIZ7SktnBMZqUlxqLLc9PZgB25gnjxfzdcmIqW3qmGXniz04BLszcGR4GLsPsx5RjzFjJ48b+huKCW6Zb9jnvfvCryivBAiAY7hSn32p+tsT8b557vUvAPCTuZFmO7Prx2VN/+arYnj3hkBAvjkLt/RrbmjiXdlr/BH+p60n8Dz8r538S+z/riN/XRv7bJ3/TuDvEsToNfRBW8MX2N6xubjsqPlBYXxNHBuG8P9r/S1RTEzg3y+D/gg7/RQa/mH3fhI74xO62Gcr/DhW+4fd+oit46M4n4Q8Yx3fw/ibkV+Ccghb6aLB+87/bbGVJ60VS2j4TTT4I8S/z3o+FPFVGj80MGX0Qrb4QS8IXvYuJhnyXSy3xZ3q+IV2TqxGJj8i7lcGnbmNJ0Bh/ai6j9kO6CEIdwJqrknLBj9fgXOHk0fk+UXZkvG0Ya0D27ZkZhuR5kc9AGrYPdBCI8uCNP1oW2TaPOxQldG9X9sh5N1A6wLEvQjdOOYVMyTc2YmjP5j2ZgDQoYGpud9xSCsDIAyrUQCw6HmXdaYkomRChN2oBqEi1RC2xmqYTms1AjdVzSK0rTv7gWphttvhahFF7nTHFLhwBdYJl6LlKH9oq0FU76+GCPr+apirF6sR+v5czaIY0Z3dVgv7cEmvFsm+bumOtQKeUZ7Oxt+pePQQ9YVeQ5pm2KKlclPLSV3V9Atcwi96xHvotJN64vxy9wR+qXzyg/wcx6j4Cj26vqxHKevwNiTQg33uexjUGMW6LU/ZG9h33kcZfv+iYdEvWLfEF9g2dn8p1WrGqfbbdLGTuI0cohaRwUehNwjzJsNsK4SiWEelB+WiE5RBamSgt7Niwf6JDFBqdhLjsst+W9lRmo+5wVrgIUrrvqBzYm0dzqFoVFj5PCmLYGjyYQxX+/oP3UbgttCAcUN6desxjJGiXSqGnZVVgYyrqk07Mjw6LSJWFwjEvJl0qu1DIh0jWO8/C1T0g22ySb5aDtJaxRJnuFWHzptvXPmCxKfVaVapDgPDQcNXeJ7eO+yzMEwbvhIe0p1QgWYxd98LMQJ6ZIxdJVFrsjbkuGthxMpy2DmzA7hzpY8oKFJsdGuxmG+Y2jdpGWNx9pekVGqoc6ms6yfr0Tpkq1bTNTKq17AII+oYBkpdPKgdl5yajTOqtJrfebDx6aKiZrUn91zEqMampEsdvciQzpCwtIgCC5gydUS0DvUaI1TrZA8HVWSr2gBxtuieFSIgPXeSiQ1szLROFc9jtFqcwr3mDdCGd2aGRGtVmXCKYFy1CqHp8W7qwELN7JFF2tOmDkhkEYv6hnlBPuNnquZTwWRC1qc6u1KrofPPpks1SmKSLEWqNGbpMlhkPl3+vLHLki1Hrjz5ChQqUqyEh5ePX0BQSLkKlapUC4uIiolLqFGrTr0GjeaYG4iK00ToDCZmFixZwyEKOMBBDnEYHAISChqJ7aIUGXLbRwVKVKjRoIVBhx4DRpIwkUwKqaTVI/VmxPqeleXPd++KbNwvn4hcRb57diHiusDhYGNxfVeUJPrjm3fu32PCfpMJj5ss0pYAaYObbDcrRUHTKOmkC5AlHs48yoclhklvm8/fnx88ELl5wjsumHgsJAuRzCTfY4b8PrdIkRnJxrpUYHzLCGdEJxlQ21/etcKKiHV2t7KlBmyIx7Sx79JsfgSzfFeEnHW8Pp+n3LsyH1D+GHDzSt0VELy//jKIYMBp4ArAdj2YqYSAtGn+h/VcERfijmuls2Xsobiuq9zr8HUAAngK6NqAA3AMDgOeK0ZwbaTusmNt3Qc6BFObJ7gTAIjYrPZ4HQ19c3JEIxfjQoK0x8DZ6T+QTVegUIvV4QE=`; \ No newline at end of file diff --git a/ReactNativeClient/pluginAssets/katex/fonts/KaTeX_Size1-Regular.woff2.base64.js b/ReactNativeClient/pluginAssets/katex/fonts/KaTeX_Size1-Regular.woff2.base64.js new file mode 100644 index 000000000..ee6f98c1b --- /dev/null +++ b/ReactNativeClient/pluginAssets/katex/fonts/KaTeX_Size1-Regular.woff2.base64.js @@ -0,0 +1 @@ +module.exports = `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`; \ No newline at end of file diff --git a/ReactNativeClient/pluginAssets/katex/fonts/KaTeX_Size2-Regular.woff2.base64.js b/ReactNativeClient/pluginAssets/katex/fonts/KaTeX_Size2-Regular.woff2.base64.js new file mode 100644 index 000000000..464fc5124 --- /dev/null +++ b/ReactNativeClient/pluginAssets/katex/fonts/KaTeX_Size2-Regular.woff2.base64.js @@ -0,0 +1 @@ +module.exports = `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`; \ No newline at end of file diff --git a/ReactNativeClient/pluginAssets/katex/katex.css.base64.js b/ReactNativeClient/pluginAssets/katex/katex.css.base64.js new file mode 100644 index 000000000..b9a7a405f --- /dev/null +++ b/ReactNativeClient/pluginAssets/katex/katex.css.base64.js @@ -0,0 +1 @@ +module.exports = `QGZvbnQtZmFjZXtmb250LWZhbWlseTpLYVRlWF9BTVM7c3JjOnVybChmb250cy9LYVRlWF9BTVMtUmVndWxhci53b2ZmMikgZm9ybWF0KCJ3b2ZmMiIpLHVybChmb250cy9LYVRlWF9BTVMtUmVndWxhci53b2ZmKSBmb3JtYXQoIndvZmYiKSx1cmwoZm9udHMvS2FUZVhfQU1TLVJlZ3VsYXIudHRmKSBmb3JtYXQoInRydWV0eXBlIik7Zm9udC13ZWlnaHQ6NDAwO2ZvbnQtc3R5bGU6bm9ybWFsfUBmb250LWZhY2V7Zm9udC1mYW1pbHk6S2FUZVhfQ2FsaWdyYXBoaWM7c3JjOnVybChmb250cy9LYVRlWF9DYWxpZ3JhcGhpYy1Cb2xkLndvZmYyKSBmb3JtYXQoIndvZmYyIiksdXJsKGZvbnRzL0thVGVYX0NhbGlncmFwaGljLUJvbGQud29mZikgZm9ybWF0KCJ3b2ZmIiksdXJsKGZvbnRzL0thVGVYX0NhbGlncmFwaGljLUJvbGQudHRmKSBmb3JtYXQoInRydWV0eXBlIik7Zm9udC13ZWlnaHQ6NzAwO2ZvbnQtc3R5bGU6bm9ybWFsfUBmb250LWZhY2V7Zm9udC1mYW1pbHk6S2FUZVhfQ2FsaWdyYXBoaWM7c3JjOnVybChmb250cy9LYVRlWF9DYWxpZ3JhcGhpYy1SZWd1bGFyLndvZmYyKSBmb3JtYXQoIndvZmYyIiksdXJsKGZvbnRzL0thVGVYX0NhbGlncmFwaGljLVJlZ3VsYXIud29mZikgZm9ybWF0KCJ3b2ZmIiksdXJsKGZvbnRzL0thVGVYX0NhbGlncmFwaGljLVJlZ3VsYXIudHRmKSBmb3JtYXQoInRydWV0eXBlIik7Zm9udC13ZWlnaHQ6NDAwO2ZvbnQtc3R5bGU6bm9ybWFsfUBmb250LWZhY2V7Zm9udC1mYW1pbHk6S2FUZVhfRnJha3R1cjtzcmM6dXJsKGZvbnRzL0thVGVYX0ZyYWt0dXItQm9sZC53b2ZmMikgZm9ybWF0KCJ3b2ZmMiIpLHVybChmb250cy9LYVRlWF9GcmFrdHVyLUJvbGQud29mZikgZm9ybWF0KCJ3b2ZmIiksdXJsKGZvbnRzL0thVGVYX0ZyYWt0dXItQm9sZC50dGYpIGZvcm1hdCgidHJ1ZXR5cGUiKTtmb250LXdlaWdodDo3MDA7Zm9udC1zdHlsZTpub3JtYWx9QGZvbnQtZmFjZXtmb250LWZhbWlseTpLYVRlWF9GcmFrdHVyO3NyYzp1cmwoZm9udHMvS2FUZVhfRnJha3R1ci1SZWd1bGFyLndvZmYyKSBmb3JtYXQoIndvZmYyIiksdXJsKGZvbnRzL0thVGVYX0ZyYWt0dXItUmVndWxhci53b2ZmKSBmb3JtYXQoIndvZmYiKSx1cmwoZm9udHMvS2FUZVhfRnJha3R1ci1SZWd1bGFyLnR0ZikgZm9ybWF0KCJ0cnVldHlwZSIpO2ZvbnQtd2VpZ2h0OjQwMDtmb250LXN0eWxlOm5vcm1hbH1AZm9udC1mYWNle2ZvbnQtZmFtaWx5OkthVGVYX01haW47c3JjOnVybChmb250cy9LYVRlWF9NYWluLUJvbGQud29mZjIpIGZvcm1hdCgid29mZjIiKSx1cmwoZm9udHMvS2FUZVhfTWFpbi1Cb2xkLndvZmYpIGZvcm1hdCgid29mZiIpLHVybChmb250cy9LYVRlWF9NYWluLUJvbGQudHRmKSBmb3JtYXQoInRydWV0eXBlIik7Zm9udC13ZWlnaHQ6NzAwO2ZvbnQtc3R5bGU6bm9ybWFsfUBmb250LWZhY2V7Zm9udC1mYW1pbHk6S2FUZVhfTWFpbjtzcmM6dXJsKGZvbnRzL0thVGVYX01haW4tQm9sZEl0YWxpYy53b2ZmMikgZm9ybWF0KCJ3b2ZmMiIpLHVybChmb250cy9LYVRlWF9NYWluLUJvbGRJdGFsaWMud29mZikgZm9ybWF0KCJ3b2ZmIiksdXJsKGZvbnRzL0thVGVYX01haW4tQm9sZEl0YWxpYy50dGYpIGZvcm1hdCgidHJ1ZXR5cGUiKTtmb250LXdlaWdodDo3MDA7Zm9udC1zdHlsZTppdGFsaWN9QGZvbnQtZmFjZXtmb250LWZhbWlseTpLYVRlWF9NYWluO3NyYzp1cmwoZm9udHMvS2FUZVhfTWFpbi1JdGFsaWMud29mZjIpIGZvcm1hdCgid29mZjIiKSx1cmwoZm9udHMvS2FUZVhfTWFpbi1JdGFsaWMud29mZikgZm9ybWF0KCJ3b2ZmIiksdXJsKGZvbnRzL0thVGVYX01haW4tSXRhbGljLnR0ZikgZm9ybWF0KCJ0cnVldHlwZSIpO2ZvbnQtd2VpZ2h0OjQwMDtmb250LXN0eWxlOml0YWxpY31AZm9udC1mYWNle2ZvbnQtZmFtaWx5OkthVGVYX01haW47c3JjOnVybChmb250cy9LYVRlWF9NYWluLVJlZ3VsYXIud29mZjIpIGZvcm1hdCgid29mZjIiKSx1cmwoZm9udHMvS2FUZVhfTWFpbi1SZWd1bGFyLndvZmYpIGZvcm1hdCgid29mZiIpLHVybChmb250cy9LYVRlWF9NYWluLVJlZ3VsYXIudHRmKSBmb3JtYXQoInRydWV0eXBlIik7Zm9udC13ZWlnaHQ6NDAwO2ZvbnQtc3R5bGU6bm9ybWFsfUBmb250LWZhY2V7Zm9udC1mYW1pbHk6S2FUZVhfTWF0aDtzcmM6dXJsKGZvbnRzL0thVGVYX01hdGgtQm9sZEl0YWxpYy53b2ZmMikgZm9ybWF0KCJ3b2ZmMiIpLHVybChmb250cy9LYVRlWF9NYXRoLUJvbGRJdGFsaWMud29mZikgZm9ybWF0KCJ3b2ZmIiksdXJsKGZvbnRzL0thVGVYX01hdGgtQm9sZEl0YWxpYy50dGYpIGZvcm1hdCgidHJ1ZXR5cGUiKTtmb250LXdlaWdodDo3MDA7Zm9udC1zdHlsZTppdGFsaWN9QGZvbnQtZmFjZXtmb250LWZhbWlseTpLYVRlWF9NYXRoO3NyYzp1cmwoZm9udHMvS2FUZVhfTWF0aC1JdGFsaWMud29mZjIpIGZvcm1hdCgid29mZjIiKSx1cmwoZm9udHMvS2FUZVhfTWF0aC1JdGFsaWMud29mZikgZm9ybWF0KCJ3b2ZmIiksdXJsKGZvbnRzL0thVGVYX01hdGgtSXRhbGljLnR0ZikgZm9ybWF0KCJ0cnVldHlwZSIpO2ZvbnQtd2VpZ2h0OjQwMDtmb250LXN0eWxlOml0YWxpY31AZm9udC1mYWNle2ZvbnQtZmFtaWx5OiJLYVRlWF9TYW5zU2VyaWYiO3NyYzp1cmwoZm9udHMvS2FUZVhfU2Fuc1NlcmlmLUJvbGQud29mZjIpIGZvcm1hdCgid29mZjIiKSx1cmwoZm9udHMvS2FUZVhfU2Fuc1NlcmlmLUJvbGQud29mZikgZm9ybWF0KCJ3b2ZmIiksdXJsKGZvbnRzL0thVGVYX1NhbnNTZXJpZi1Cb2xkLnR0ZikgZm9ybWF0KCJ0cnVldHlwZSIpO2ZvbnQtd2VpZ2h0OjcwMDtmb250LXN0eWxlOm5vcm1hbH1AZm9udC1mYWNle2ZvbnQtZmFtaWx5OiJLYVRlWF9TYW5zU2VyaWYiO3NyYzp1cmwoZm9udHMvS2FUZVhfU2Fuc1NlcmlmLUl0YWxpYy53b2ZmMikgZm9ybWF0KCJ3b2ZmMiIpLHVybChmb250cy9LYVRlWF9TYW5zU2VyaWYtSXRhbGljLndvZmYpIGZvcm1hdCgid29mZiIpLHVybChmb250cy9LYVRlWF9TYW5zU2VyaWYtSXRhbGljLnR0ZikgZm9ybWF0KCJ0cnVldHlwZSIpO2ZvbnQtd2VpZ2h0OjQwMDtmb250LXN0eWxlOml0YWxpY31AZm9udC1mYWNle2ZvbnQtZmFtaWx5OiJLYVRlWF9TYW5zU2VyaWYiO3NyYzp1cmwoZm9udHMvS2FUZVhfU2Fuc1NlcmlmLVJlZ3VsYXIud29mZjIpIGZvcm1hdCgid29mZjIiKSx1cmwoZm9udHMvS2FUZVhfU2Fuc1NlcmlmLVJlZ3VsYXIud29mZikgZm9ybWF0KCJ3b2ZmIiksdXJsKGZvbnRzL0thVGVYX1NhbnNTZXJpZi1SZWd1bGFyLnR0ZikgZm9ybWF0KCJ0cnVldHlwZSIpO2ZvbnQtd2VpZ2h0OjQwMDtmb250LXN0eWxlOm5vcm1hbH1AZm9udC1mYWNle2ZvbnQtZmFtaWx5OkthVGVYX1NjcmlwdDtzcmM6dXJsKGZvbnRzL0thVGVYX1NjcmlwdC1SZWd1bGFyLndvZmYyKSBmb3JtYXQoIndvZmYyIiksdXJsKGZvbnRzL0thVGVYX1NjcmlwdC1SZWd1bGFyLndvZmYpIGZvcm1hdCgid29mZiIpLHVybChmb250cy9LYVRlWF9TY3JpcHQtUmVndWxhci50dGYpIGZvcm1hdCgidHJ1ZXR5cGUiKTtmb250LXdlaWdodDo0MDA7Zm9udC1zdHlsZTpub3JtYWx9QGZvbnQtZmFjZXtmb250LWZhbWlseTpLYVRlWF9TaXplMTtzcmM6dXJsKGZvbnRzL0thVGVYX1NpemUxLVJlZ3VsYXIud29mZjIpIGZvcm1hdCgid29mZjIiKSx1cmwoZm9udHMvS2FUZVhfU2l6ZTEtUmVndWxhci53b2ZmKSBmb3JtYXQoIndvZmYiKSx1cmwoZm9udHMvS2FUZVhfU2l6ZTEtUmVndWxhci50dGYpIGZvcm1hdCgidHJ1ZXR5cGUiKTtmb250LXdlaWdodDo0MDA7Zm9udC1zdHlsZTpub3JtYWx9QGZvbnQtZmFjZXtmb250LWZhbWlseTpLYVRlWF9TaXplMjtzcmM6dXJsKGZvbnRzL0thVGVYX1NpemUyLVJlZ3VsYXIud29mZjIpIGZvcm1hdCgid29mZjIiKSx1cmwoZm9udHMvS2FUZVhfU2l6ZTItUmVndWxhci53b2ZmKSBmb3JtYXQoIndvZmYiKSx1cmwoZm9udHMvS2FUZVhfU2l6ZTItUmVndWxhci50dGYpIGZvcm1hdCgidHJ1ZXR5cGUiKTtmb250LXdlaWdodDo0MDA7Zm9udC1zdHlsZTpub3JtYWx9QGZvbnQtZmFjZXtmb250LWZhbWlseTpLYVRlWF9TaXplMztzcmM6dXJsKGZvbnRzL0thVGVYX1NpemUzLVJlZ3VsYXIud29mZjIpIGZvcm1hdCgid29mZjIiKSx1cmwoZm9udHMvS2FUZVhfU2l6ZTMtUmVndWxhci53b2ZmKSBmb3JtYXQoIndvZmYiKSx1cmwoZm9udHMvS2FUZVhfU2l6ZTMtUmVndWxhci50dGYpIGZvcm1hdCgidHJ1ZXR5cGUiKTtmb250LXdlaWdodDo0MDA7Zm9udC1zdHlsZTpub3JtYWx9QGZvbnQtZmFjZXtmb250LWZhbWlseTpLYVRlWF9TaXplNDtzcmM6dXJsKGZvbnRzL0thVGVYX1NpemU0LVJlZ3VsYXIud29mZjIpIGZvcm1hdCgid29mZjIiKSx1cmwoZm9udHMvS2FUZVhfU2l6ZTQtUmVndWxhci53b2ZmKSBmb3JtYXQoIndvZmYiKSx1cmwoZm9udHMvS2FUZVhfU2l6ZTQtUmVndWxhci50dGYpIGZvcm1hdCgidHJ1ZXR5cGUiKTtmb250LXdlaWdodDo0MDA7Zm9udC1zdHlsZTpub3JtYWx9QGZvbnQtZmFjZXtmb250LWZhbWlseTpLYVRlWF9UeXBld3JpdGVyO3NyYzp1cmwoZm9udHMvS2FUZVhfVHlwZXdyaXRlci1SZWd1bGFyLndvZmYyKSBmb3JtYXQoIndvZmYyIiksdXJsKGZvbnRzL0thVGVYX1R5cGV3cml0ZXItUmVndWxhci53b2ZmKSBmb3JtYXQoIndvZmYiKSx1cmwoZm9udHMvS2FUZVhfVHlwZXdyaXRlci1SZWd1bGFyLnR0ZikgZm9ybWF0KCJ0cnVldHlwZSIpO2ZvbnQtd2VpZ2h0OjQwMDtmb250LXN0eWxlOm5vcm1hbH0ua2F0ZXh7Zm9udDpub3JtYWwgMS4yMWVtIEthVGVYX01haW4sVGltZXMgTmV3IFJvbWFuLHNlcmlmO2xpbmUtaGVpZ2h0OjEuMjt0ZXh0LWluZGVudDowO3RleHQtcmVuZGVyaW5nOmF1dG99LmthdGV4ICp7LW1zLWhpZ2gtY29udHJhc3QtYWRqdXN0Om5vbmUhaW1wb3J0YW50fS5rYXRleCAua2F0ZXgtdmVyc2lvbjphZnRlcntjb250ZW50OiIwLjExLjEifS5rYXRleCAua2F0ZXgtbWF0aG1se3Bvc2l0aW9uOmFic29sdXRlO2NsaXA6cmVjdCgxcHgsMXB4LDFweCwxcHgpO3BhZGRpbmc6MDtib3JkZXI6MDtoZWlnaHQ6MXB4O3dpZHRoOjFweDtvdmVyZmxvdzpoaWRkZW59LmthdGV4IC5rYXRleC1odG1sPi5uZXdsaW5le2Rpc3BsYXk6YmxvY2t9LmthdGV4IC5iYXNle3Bvc2l0aW9uOnJlbGF0aXZlO3doaXRlLXNwYWNlOm5vd3JhcDt3aWR0aDptaW4tY29udGVudH0ua2F0ZXggLmJhc2UsLmthdGV4IC5zdHJ1dHtkaXNwbGF5OmlubGluZS1ibG9ja30ua2F0ZXggLnRleHRiZntmb250LXdlaWdodDo3MDB9LmthdGV4IC50ZXh0aXR7Zm9udC1zdHlsZTppdGFsaWN9LmthdGV4IC50ZXh0cm17Zm9udC1mYW1pbHk6S2FUZVhfTWFpbn0ua2F0ZXggLnRleHRzZntmb250LWZhbWlseTpLYVRlWF9TYW5zU2VyaWZ9LmthdGV4IC50ZXh0dHR7Zm9udC1mYW1pbHk6S2FUZVhfVHlwZXdyaXRlcn0ua2F0ZXggLm1hdGhkZWZhdWx0e2ZvbnQtZmFtaWx5OkthVGVYX01hdGg7Zm9udC1zdHlsZTppdGFsaWN9LmthdGV4IC5tYXRoaXR7Zm9udC1mYW1pbHk6S2FUZVhfTWFpbjtmb250LXN0eWxlOml0YWxpY30ua2F0ZXggLm1hdGhybXtmb250LXN0eWxlOm5vcm1hbH0ua2F0ZXggLm1hdGhiZntmb250LWZhbWlseTpLYVRlWF9NYWluO2ZvbnQtd2VpZ2h0OjcwMH0ua2F0ZXggLmJvbGRzeW1ib2x7Zm9udC1mYW1pbHk6S2FUZVhfTWF0aDtmb250LXdlaWdodDo3MDA7Zm9udC1zdHlsZTppdGFsaWN9LmthdGV4IC5hbXNybSwua2F0ZXggLm1hdGhiYiwua2F0ZXggLnRleHRiYntmb250LWZhbWlseTpLYVRlWF9BTVN9LmthdGV4IC5tYXRoY2Fse2ZvbnQtZmFtaWx5OkthVGVYX0NhbGlncmFwaGljfS5rYXRleCAubWF0aGZyYWssLmthdGV4IC50ZXh0ZnJha3tmb250LWZhbWlseTpLYVRlWF9GcmFrdHVyfS5rYXRleCAubWF0aHR0e2ZvbnQtZmFtaWx5OkthVGVYX1R5cGV3cml0ZXJ9LmthdGV4IC5tYXRoc2NyLC5rYXRleCAudGV4dHNjcntmb250LWZhbWlseTpLYVRlWF9TY3JpcHR9LmthdGV4IC5tYXRoc2YsLmthdGV4IC50ZXh0c2Z7Zm9udC1mYW1pbHk6S2FUZVhfU2Fuc1NlcmlmfS5rYXRleCAubWF0aGJvbGRzZiwua2F0ZXggLnRleHRib2xkc2Z7Zm9udC1mYW1pbHk6S2FUZVhfU2Fuc1NlcmlmO2ZvbnQtd2VpZ2h0OjcwMH0ua2F0ZXggLm1hdGhpdHNmLC5rYXRleCAudGV4dGl0c2Z7Zm9udC1mYW1pbHk6S2FUZVhfU2Fuc1NlcmlmO2ZvbnQtc3R5bGU6aXRhbGljfS5rYXRleCAubWFpbnJte2ZvbnQtZmFtaWx5OkthVGVYX01haW47Zm9udC1zdHlsZTpub3JtYWx9LmthdGV4IC52bGlzdC10e2Rpc3BsYXk6aW5saW5lLXRhYmxlO3RhYmxlLWxheW91dDpmaXhlZH0ua2F0ZXggLnZsaXN0LXJ7ZGlzcGxheTp0YWJsZS1yb3d9LmthdGV4IC52bGlzdHtkaXNwbGF5OnRhYmxlLWNlbGw7dmVydGljYWwtYWxpZ246Ym90dG9tO3Bvc2l0aW9uOnJlbGF0aXZlfS5rYXRleCAudmxpc3Q+c3BhbntkaXNwbGF5OmJsb2NrO2hlaWdodDowO3Bvc2l0aW9uOnJlbGF0aXZlfS5rYXRleCAudmxpc3Q+c3Bhbj5zcGFue2Rpc3BsYXk6aW5saW5lLWJsb2NrfS5rYXRleCAudmxpc3Q+c3Bhbj4ucHN0cnV0e292ZXJmbG93OmhpZGRlbjt3aWR0aDowfS5rYXRleCAudmxpc3QtdDJ7bWFyZ2luLXJpZ2h0Oi0ycHh9LmthdGV4IC52bGlzdC1ze2Rpc3BsYXk6dGFibGUtY2VsbDt2ZXJ0aWNhbC1hbGlnbjpib3R0b207Zm9udC1zaXplOjFweDt3aWR0aDoycHg7bWluLXdpZHRoOjJweH0ua2F0ZXggLm1zdXBzdWJ7dGV4dC1hbGlnbjpsZWZ0fS5rYXRleCAubWZyYWM+c3Bhbj5zcGFue3RleHQtYWxpZ246Y2VudGVyfS5rYXRleCAubWZyYWMgLmZyYWMtbGluZXtkaXNwbGF5OmlubGluZS1ibG9jazt3aWR0aDoxMDAlO2JvcmRlci1ib3R0b20tc3R5bGU6c29saWR9LmthdGV4IC5oZGFzaGxpbmUsLmthdGV4IC5obGluZSwua2F0ZXggLm1mcmFjIC5mcmFjLWxpbmUsLmthdGV4IC5vdmVybGluZSAub3ZlcmxpbmUtbGluZSwua2F0ZXggLnJ1bGUsLmthdGV4IC51bmRlcmxpbmUgLnVuZGVybGluZS1saW5le21pbi1oZWlnaHQ6MXB4fS5rYXRleCAubXNwYWNle2Rpc3BsYXk6aW5saW5lLWJsb2NrfS5rYXRleCAuY2xhcCwua2F0ZXggLmxsYXAsLmthdGV4IC5ybGFwe3dpZHRoOjA7cG9zaXRpb246cmVsYXRpdmV9LmthdGV4IC5jbGFwPi5pbm5lciwua2F0ZXggLmxsYXA+LmlubmVyLC5rYXRleCAucmxhcD4uaW5uZXJ7cG9zaXRpb246YWJzb2x1dGV9LmthdGV4IC5jbGFwPi5maXgsLmthdGV4IC5sbGFwPi5maXgsLmthdGV4IC5ybGFwPi5maXh7ZGlzcGxheTppbmxpbmUtYmxvY2t9LmthdGV4IC5sbGFwPi5pbm5lcntyaWdodDowfS5rYXRleCAuY2xhcD4uaW5uZXIsLmthdGV4IC5ybGFwPi5pbm5lcntsZWZ0OjB9LmthdGV4IC5jbGFwPi5pbm5lcj5zcGFue21hcmdpbi1sZWZ0Oi01MCU7bWFyZ2luLXJpZ2h0OjUwJX0ua2F0ZXggLnJ1bGV7ZGlzcGxheTppbmxpbmUtYmxvY2s7Ym9yZGVyOjAgc29saWQ7cG9zaXRpb246cmVsYXRpdmV9LmthdGV4IC5obGluZSwua2F0ZXggLm92ZXJsaW5lIC5vdmVybGluZS1saW5lLC5rYXRleCAudW5kZXJsaW5lIC51bmRlcmxpbmUtbGluZXtkaXNwbGF5OmlubGluZS1ibG9jazt3aWR0aDoxMDAlO2JvcmRlci1ib3R0b20tc3R5bGU6c29saWR9LmthdGV4IC5oZGFzaGxpbmV7ZGlzcGxheTppbmxpbmUtYmxvY2s7d2lkdGg6MTAwJTtib3JkZXItYm90dG9tLXN0eWxlOmRhc2hlZH0ua2F0ZXggLnNxcnQ+LnJvb3R7bWFyZ2luLWxlZnQ6LjI3Nzc3Nzc4ZW07bWFyZ2luLXJpZ2h0Oi0uNTU1NTU1NTZlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTEuc2l6ZTEsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTEuc2l6ZTF7Zm9udC1zaXplOjFlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTEuc2l6ZTIsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTEuc2l6ZTJ7Zm9udC1zaXplOjEuMmVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMS5zaXplMywua2F0ZXggLnNpemluZy5yZXNldC1zaXplMS5zaXplM3tmb250LXNpemU6MS40ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUxLnNpemU0LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUxLnNpemU0e2ZvbnQtc2l6ZToxLjZlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTEuc2l6ZTUsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTEuc2l6ZTV7Zm9udC1zaXplOjEuOGVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMS5zaXplNiwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMS5zaXplNntmb250LXNpemU6MmVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMS5zaXplNywua2F0ZXggLnNpemluZy5yZXNldC1zaXplMS5zaXplN3tmb250LXNpemU6Mi40ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUxLnNpemU4LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUxLnNpemU4e2ZvbnQtc2l6ZToyLjg4ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUxLnNpemU5LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUxLnNpemU5e2ZvbnQtc2l6ZTozLjQ1NmVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMS5zaXplMTAsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTEuc2l6ZTEwe2ZvbnQtc2l6ZTo0LjE0OGVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMS5zaXplMTEsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTEuc2l6ZTExe2ZvbnQtc2l6ZTo0Ljk3NmVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMi5zaXplMSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMi5zaXplMXtmb250LXNpemU6LjgzMzMzMzMzZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUyLnNpemUyLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUyLnNpemUye2ZvbnQtc2l6ZToxZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUyLnNpemUzLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUyLnNpemUze2ZvbnQtc2l6ZToxLjE2NjY2NjY3ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUyLnNpemU0LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUyLnNpemU0e2ZvbnQtc2l6ZToxLjMzMzMzMzMzZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUyLnNpemU1LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUyLnNpemU1e2ZvbnQtc2l6ZToxLjVlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTIuc2l6ZTYsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTIuc2l6ZTZ7Zm9udC1zaXplOjEuNjY2NjY2NjdlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTIuc2l6ZTcsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTIuc2l6ZTd7Zm9udC1zaXplOjJlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTIuc2l6ZTgsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTIuc2l6ZTh7Zm9udC1zaXplOjIuNGVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMi5zaXplOSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMi5zaXplOXtmb250LXNpemU6Mi44OGVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMi5zaXplMTAsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTIuc2l6ZTEwe2ZvbnQtc2l6ZTozLjQ1NjY2NjY3ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUyLnNpemUxMSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMi5zaXplMTF7Zm9udC1zaXplOjQuMTQ2NjY2NjdlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTMuc2l6ZTEsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTMuc2l6ZTF7Zm9udC1zaXplOi43MTQyODU3MWVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMy5zaXplMiwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMy5zaXplMntmb250LXNpemU6Ljg1NzE0Mjg2ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUzLnNpemUzLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUzLnNpemUze2ZvbnQtc2l6ZToxZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUzLnNpemU0LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUzLnNpemU0e2ZvbnQtc2l6ZToxLjE0Mjg1NzE0ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUzLnNpemU1LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUzLnNpemU1e2ZvbnQtc2l6ZToxLjI4NTcxNDI5ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUzLnNpemU2LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUzLnNpemU2e2ZvbnQtc2l6ZToxLjQyODU3MTQzZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUzLnNpemU3LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUzLnNpemU3e2ZvbnQtc2l6ZToxLjcxNDI4NTcxZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUzLnNpemU4LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUzLnNpemU4e2ZvbnQtc2l6ZToyLjA1NzE0Mjg2ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUzLnNpemU5LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUzLnNpemU5e2ZvbnQtc2l6ZToyLjQ2ODU3MTQzZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUzLnNpemUxMCwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMy5zaXplMTB7Zm9udC1zaXplOjIuOTYyODU3MTRlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTMuc2l6ZTExLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUzLnNpemUxMXtmb250LXNpemU6My41NTQyODU3MWVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNC5zaXplMSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNC5zaXplMXtmb250LXNpemU6LjYyNWVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNC5zaXplMiwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNC5zaXplMntmb250LXNpemU6Ljc1ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU0LnNpemUzLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU0LnNpemUze2ZvbnQtc2l6ZTouODc1ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU0LnNpemU0LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU0LnNpemU0e2ZvbnQtc2l6ZToxZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU0LnNpemU1LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU0LnNpemU1e2ZvbnQtc2l6ZToxLjEyNWVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNC5zaXplNiwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNC5zaXplNntmb250LXNpemU6MS4yNWVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNC5zaXplNywua2F0ZXggLnNpemluZy5yZXNldC1zaXplNC5zaXplN3tmb250LXNpemU6MS41ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU0LnNpemU4LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU0LnNpemU4e2ZvbnQtc2l6ZToxLjhlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTQuc2l6ZTksLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTQuc2l6ZTl7Zm9udC1zaXplOjIuMTZlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTQuc2l6ZTEwLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU0LnNpemUxMHtmb250LXNpemU6Mi41OTI1ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU0LnNpemUxMSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNC5zaXplMTF7Zm9udC1zaXplOjMuMTFlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTUuc2l6ZTEsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTUuc2l6ZTF7Zm9udC1zaXplOi41NTU1NTU1NmVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNS5zaXplMiwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNS5zaXplMntmb250LXNpemU6LjY2NjY2NjY3ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU1LnNpemUzLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU1LnNpemUze2ZvbnQtc2l6ZTouNzc3Nzc3NzhlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTUuc2l6ZTQsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTUuc2l6ZTR7Zm9udC1zaXplOi44ODg4ODg4OWVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNS5zaXplNSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNS5zaXplNXtmb250LXNpemU6MWVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNS5zaXplNiwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNS5zaXplNntmb250LXNpemU6MS4xMTExMTExMWVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNS5zaXplNywua2F0ZXggLnNpemluZy5yZXNldC1zaXplNS5zaXplN3tmb250LXNpemU6MS4zMzMzMzMzM2VtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNS5zaXplOCwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNS5zaXplOHtmb250LXNpemU6MS42ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU1LnNpemU5LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU1LnNpemU5e2ZvbnQtc2l6ZToxLjkyZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU1LnNpemUxMCwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNS5zaXplMTB7Zm9udC1zaXplOjIuMzA0NDQ0NDRlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTUuc2l6ZTExLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU1LnNpemUxMXtmb250LXNpemU6Mi43NjQ0NDQ0NGVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNi5zaXplMSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNi5zaXplMXtmb250LXNpemU6LjVlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTYuc2l6ZTIsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTYuc2l6ZTJ7Zm9udC1zaXplOi42ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU2LnNpemUzLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU2LnNpemUze2ZvbnQtc2l6ZTouN2VtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNi5zaXplNCwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNi5zaXplNHtmb250LXNpemU6LjhlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTYuc2l6ZTUsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTYuc2l6ZTV7Zm9udC1zaXplOi45ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU2LnNpemU2LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU2LnNpemU2e2ZvbnQtc2l6ZToxZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU2LnNpemU3LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU2LnNpemU3e2ZvbnQtc2l6ZToxLjJlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTYuc2l6ZTgsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTYuc2l6ZTh7Zm9udC1zaXplOjEuNDRlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTYuc2l6ZTksLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTYuc2l6ZTl7Zm9udC1zaXplOjEuNzI4ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU2LnNpemUxMCwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNi5zaXplMTB7Zm9udC1zaXplOjIuMDc0ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU2LnNpemUxMSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNi5zaXplMTF7Zm9udC1zaXplOjIuNDg4ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU3LnNpemUxLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU3LnNpemUxe2ZvbnQtc2l6ZTouNDE2NjY2NjdlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTcuc2l6ZTIsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTcuc2l6ZTJ7Zm9udC1zaXplOi41ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU3LnNpemUzLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU3LnNpemUze2ZvbnQtc2l6ZTouNTgzMzMzMzNlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTcuc2l6ZTQsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTcuc2l6ZTR7Zm9udC1zaXplOi42NjY2NjY2N2VtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNy5zaXplNSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNy5zaXplNXtmb250LXNpemU6Ljc1ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU3LnNpemU2LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU3LnNpemU2e2ZvbnQtc2l6ZTouODMzMzMzMzNlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTcuc2l6ZTcsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTcuc2l6ZTd7Zm9udC1zaXplOjFlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTcuc2l6ZTgsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTcuc2l6ZTh7Zm9udC1zaXplOjEuMmVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNy5zaXplOSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNy5zaXplOXtmb250LXNpemU6MS40NGVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplNy5zaXplMTAsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTcuc2l6ZTEwe2ZvbnQtc2l6ZToxLjcyODMzMzMzZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU3LnNpemUxMSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplNy5zaXplMTF7Zm9udC1zaXplOjIuMDczMzMzMzNlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTguc2l6ZTEsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTguc2l6ZTF7Zm9udC1zaXplOi4zNDcyMjIyMmVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplOC5zaXplMiwua2F0ZXggLnNpemluZy5yZXNldC1zaXplOC5zaXplMntmb250LXNpemU6LjQxNjY2NjY3ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU4LnNpemUzLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU4LnNpemUze2ZvbnQtc2l6ZTouNDg2MTExMTFlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTguc2l6ZTQsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTguc2l6ZTR7Zm9udC1zaXplOi41NTU1NTU1NmVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplOC5zaXplNSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplOC5zaXplNXtmb250LXNpemU6LjYyNWVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplOC5zaXplNiwua2F0ZXggLnNpemluZy5yZXNldC1zaXplOC5zaXplNntmb250LXNpemU6LjY5NDQ0NDQ0ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU4LnNpemU3LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU4LnNpemU3e2ZvbnQtc2l6ZTouODMzMzMzMzNlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTguc2l6ZTgsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTguc2l6ZTh7Zm9udC1zaXplOjFlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTguc2l6ZTksLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTguc2l6ZTl7Zm9udC1zaXplOjEuMmVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplOC5zaXplMTAsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTguc2l6ZTEwe2ZvbnQtc2l6ZToxLjQ0MDI3Nzc4ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU4LnNpemUxMSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplOC5zaXplMTF7Zm9udC1zaXplOjEuNzI3Nzc3NzhlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTkuc2l6ZTEsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTkuc2l6ZTF7Zm9udC1zaXplOi4yODkzNTE4NWVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplOS5zaXplMiwua2F0ZXggLnNpemluZy5yZXNldC1zaXplOS5zaXplMntmb250LXNpemU6LjM0NzIyMjIyZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU5LnNpemUzLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU5LnNpemUze2ZvbnQtc2l6ZTouNDA1MDkyNTllbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTkuc2l6ZTQsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTkuc2l6ZTR7Zm9udC1zaXplOi40NjI5NjI5NmVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplOS5zaXplNSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplOS5zaXplNXtmb250LXNpemU6LjUyMDgzMzMzZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU5LnNpemU2LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU5LnNpemU2e2ZvbnQtc2l6ZTouNTc4NzAzN2VtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplOS5zaXplNywua2F0ZXggLnNpemluZy5yZXNldC1zaXplOS5zaXplN3tmb250LXNpemU6LjY5NDQ0NDQ0ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemU5LnNpemU4LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU5LnNpemU4e2ZvbnQtc2l6ZTouODMzMzMzMzNlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTkuc2l6ZTksLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTkuc2l6ZTl7Zm9udC1zaXplOjFlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTkuc2l6ZTEwLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemU5LnNpemUxMHtmb250LXNpemU6MS4yMDAyMzE0OGVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplOS5zaXplMTEsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTkuc2l6ZTExe2ZvbnQtc2l6ZToxLjQzOTgxNDgxZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUxMC5zaXplMSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMTAuc2l6ZTF7Zm9udC1zaXplOi4yNDEwODAwNGVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMTAuc2l6ZTIsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTEwLnNpemUye2ZvbnQtc2l6ZTouMjg5Mjk2MDVlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTEwLnNpemUzLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUxMC5zaXplM3tmb250LXNpemU6LjMzNzUxMjA1ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUxMC5zaXplNCwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMTAuc2l6ZTR7Zm9udC1zaXplOi4zODU3MjgwNmVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMTAuc2l6ZTUsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTEwLnNpemU1e2ZvbnQtc2l6ZTouNDMzOTQ0MDdlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTEwLnNpemU2LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUxMC5zaXplNntmb250LXNpemU6LjQ4MjE2MDA4ZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUxMC5zaXplNywua2F0ZXggLnNpemluZy5yZXNldC1zaXplMTAuc2l6ZTd7Zm9udC1zaXplOi41Nzg1OTIwOWVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMTAuc2l6ZTgsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTEwLnNpemU4e2ZvbnQtc2l6ZTouNjk0MzEwNTFlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTEwLnNpemU5LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUxMC5zaXplOXtmb250LXNpemU6LjgzMzE3MjYxZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUxMC5zaXplMTAsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTEwLnNpemUxMHtmb250LXNpemU6MWVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMTAuc2l6ZTExLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUxMC5zaXplMTF7Zm9udC1zaXplOjEuMTk5NjE0MjdlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTExLnNpemUxLC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUxMS5zaXplMXtmb250LXNpemU6LjIwMDk2NDYzZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUxMS5zaXplMiwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMTEuc2l6ZTJ7Zm9udC1zaXplOi4yNDExNTc1NmVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMTEuc2l6ZTMsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTExLnNpemUze2ZvbnQtc2l6ZTouMjgxMzUwNDhlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTExLnNpemU0LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUxMS5zaXplNHtmb250LXNpemU6LjMyMTU0MzQxZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUxMS5zaXplNSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMTEuc2l6ZTV7Zm9udC1zaXplOi4zNjE3MzYzM2VtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMTEuc2l6ZTYsLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTExLnNpemU2e2ZvbnQtc2l6ZTouNDAxOTI5MjZlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTExLnNpemU3LC5rYXRleCAuc2l6aW5nLnJlc2V0LXNpemUxMS5zaXplN3tmb250LXNpemU6LjQ4MjMxNTExZW19LmthdGV4IC5mb250c2l6ZS1lbnN1cmVyLnJlc2V0LXNpemUxMS5zaXplOCwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMTEuc2l6ZTh7Zm9udC1zaXplOi41Nzg3NzgxNGVtfS5rYXRleCAuZm9udHNpemUtZW5zdXJlci5yZXNldC1zaXplMTEuc2l6ZTksLmthdGV4IC5zaXppbmcucmVzZXQtc2l6ZTExLnNpemU5e2ZvbnQtc2l6ZTouNjk0NTMzNzZlbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTExLnNpemUxMCwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMTEuc2l6ZTEwe2ZvbnQtc2l6ZTouODMzNjAxMjllbX0ua2F0ZXggLmZvbnRzaXplLWVuc3VyZXIucmVzZXQtc2l6ZTExLnNpemUxMSwua2F0ZXggLnNpemluZy5yZXNldC1zaXplMTEuc2l6ZTExe2ZvbnQtc2l6ZToxZW19LmthdGV4IC5kZWxpbXNpemluZy5zaXplMXtmb250LWZhbWlseTpLYVRlWF9TaXplMX0ua2F0ZXggLmRlbGltc2l6aW5nLnNpemUye2ZvbnQtZmFtaWx5OkthVGVYX1NpemUyfS5rYXRleCAuZGVsaW1zaXppbmcuc2l6ZTN7Zm9udC1mYW1pbHk6S2FUZVhfU2l6ZTN9LmthdGV4IC5kZWxpbXNpemluZy5zaXplNHtmb250LWZhbWlseTpLYVRlWF9TaXplNH0ua2F0ZXggLmRlbGltc2l6aW5nLm11bHQgLmRlbGltLXNpemUxPnNwYW57Zm9udC1mYW1pbHk6S2FUZVhfU2l6ZTF9LmthdGV4IC5kZWxpbXNpemluZy5tdWx0IC5kZWxpbS1zaXplND5zcGFue2ZvbnQtZmFtaWx5OkthVGVYX1NpemU0fS5rYXRleCAubnVsbGRlbGltaXRlcntkaXNwbGF5OmlubGluZS1ibG9jazt3aWR0aDouMTJlbX0ua2F0ZXggLmRlbGltY2VudGVyLC5rYXRleCAub3Atc3ltYm9se3Bvc2l0aW9uOnJlbGF0aXZlfS5rYXRleCAub3Atc3ltYm9sLnNtYWxsLW9we2ZvbnQtZmFtaWx5OkthVGVYX1NpemUxfS5rYXRleCAub3Atc3ltYm9sLmxhcmdlLW9we2ZvbnQtZmFtaWx5OkthVGVYX1NpemUyfS5rYXRleCAub3AtbGltaXRzPi52bGlzdC10e3RleHQtYWxpZ246Y2VudGVyfS5rYXRleCAuYWNjZW50Pi52bGlzdC10e3RleHQtYWxpZ246Y2VudGVyfS5rYXRleCAuYWNjZW50IC5hY2NlbnQtYm9keXtwb3NpdGlvbjpyZWxhdGl2ZX0ua2F0ZXggLmFjY2VudCAuYWNjZW50LWJvZHk6bm90KC5hY2NlbnQtZnVsbCl7d2lkdGg6MH0ua2F0ZXggLm92ZXJsYXl7ZGlzcGxheTpibG9ja30ua2F0ZXggLm10YWJsZSAudmVydGljYWwtc2VwYXJhdG9ye2Rpc3BsYXk6aW5saW5lLWJsb2NrO21pbi13aWR0aDoxcHh9LmthdGV4IC5tdGFibGUgLmFycmF5Y29sc2Vwe2Rpc3BsYXk6aW5saW5lLWJsb2NrfS5rYXRleCAubXRhYmxlIC5jb2wtYWxpZ24tYz4udmxpc3QtdHt0ZXh0LWFsaWduOmNlbnRlcn0ua2F0ZXggLm10YWJsZSAuY29sLWFsaWduLWw+LnZsaXN0LXR7dGV4dC1hbGlnbjpsZWZ0fS5rYXRleCAubXRhYmxlIC5jb2wtYWxpZ24tcj4udmxpc3QtdHt0ZXh0LWFsaWduOnJpZ2h0fS5rYXRleCAuc3ZnLWFsaWdue3RleHQtYWxpZ246bGVmdH0ua2F0ZXggc3Zne2Rpc3BsYXk6YmxvY2s7cG9zaXRpb246YWJzb2x1dGU7d2lkdGg6MTAwJTtoZWlnaHQ6aW5oZXJpdDtmaWxsOmN1cnJlbnRDb2xvcjtzdHJva2U6Y3VycmVudENvbG9yO2ZpbGwtcnVsZTpub256ZXJvO2ZpbGwtb3BhY2l0eToxO3N0cm9rZS13aWR0aDoxO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MX0ua2F0ZXggc3ZnIHBhdGh7c3Ryb2tlOm5vbmV9LmthdGV4IGltZ3tib3JkZXItc3R5bGU6bm9uZTttaW4td2lkdGg6MDttaW4taGVpZ2h0OjA7bWF4LXdpZHRoOm5vbmU7bWF4LWhlaWdodDpub25lfS5rYXRleCAuc3RyZXRjaHl7d2lkdGg6MTAwJTtkaXNwbGF5OmJsb2NrO3Bvc2l0aW9uOnJlbGF0aXZlO292ZXJmbG93OmhpZGRlbn0ua2F0ZXggLnN0cmV0Y2h5OmFmdGVyLC5rYXRleCAuc3RyZXRjaHk6YmVmb3Jle2NvbnRlbnQ6IiJ9LmthdGV4IC5oaWRlLXRhaWx7d2lkdGg6MTAwJTtwb3NpdGlvbjpyZWxhdGl2ZTtvdmVyZmxvdzpoaWRkZW59LmthdGV4IC5oYWxmYXJyb3ctbGVmdHtwb3NpdGlvbjphYnNvbHV0ZTtsZWZ0OjA7d2lkdGg6NTAuMiU7b3ZlcmZsb3c6aGlkZGVufS5rYXRleCAuaGFsZmFycm93LXJpZ2h0e3Bvc2l0aW9uOmFic29sdXRlO3JpZ2h0OjA7d2lkdGg6NTAuMiU7b3ZlcmZsb3c6aGlkZGVufS5rYXRleCAuYnJhY2UtbGVmdHtwb3NpdGlvbjphYnNvbHV0ZTtsZWZ0OjA7d2lkdGg6MjUuMSU7b3ZlcmZsb3c6aGlkZGVufS5rYXRleCAuYnJhY2UtY2VudGVye3Bvc2l0aW9uOmFic29sdXRlO2xlZnQ6MjUlO3dpZHRoOjUwJTtvdmVyZmxvdzpoaWRkZW59LmthdGV4IC5icmFjZS1yaWdodHtwb3NpdGlvbjphYnNvbHV0ZTtyaWdodDowO3dpZHRoOjI1LjElO292ZXJmbG93OmhpZGRlbn0ua2F0ZXggLngtYXJyb3ctcGFke3BhZGRpbmc6MCAuNWVtfS5rYXRleCAubW92ZXIsLmthdGV4IC5tdW5kZXIsLmthdGV4IC54LWFycm93e3RleHQtYWxpZ246Y2VudGVyfS5rYXRleCAuYm94cGFke3BhZGRpbmc6MCAuM2VtfS5rYXRleCAuZmJveCwua2F0ZXggLmZjb2xvcmJveHtib3gtc2l6aW5nOmJvcmRlci1ib3g7Ym9yZGVyOi4wNGVtIHNvbGlkfS5rYXRleCAuY2FuY2VsLXBhZHtwYWRkaW5nOjAgLjJlbX0ua2F0ZXggLmNhbmNlbC1sYXB7bWFyZ2luLWxlZnQ6LS4yZW07bWFyZ2luLXJpZ2h0Oi0uMmVtfS5rYXRleCAuc291dHtib3JkZXItYm90dG9tLXN0eWxlOnNvbGlkO2JvcmRlci1ib3R0b20td2lkdGg6LjA4ZW19LmthdGV4LWRpc3BsYXl7ZGlzcGxheTpibG9jazttYXJnaW46MWVtIDA7dGV4dC1hbGlnbjpjZW50ZXJ9LmthdGV4LWRpc3BsYXk+LmthdGV4e2Rpc3BsYXk6YmxvY2s7dGV4dC1hbGlnbjpjZW50ZXI7d2hpdGUtc3BhY2U6bm93cmFwfS5rYXRleC1kaXNwbGF5Pi5rYXRleD4ua2F0ZXgtaHRtbHtkaXNwbGF5OmJsb2NrO3Bvc2l0aW9uOnJlbGF0aXZlfS5rYXRleC1kaXNwbGF5Pi5rYXRleD4ua2F0ZXgtaHRtbD4udGFne3Bvc2l0aW9uOmFic29sdXRlO3JpZ2h0OjB9LmthdGV4LWRpc3BsYXkubGVxbm8+LmthdGV4Pi5rYXRleC1odG1sPi50YWd7bGVmdDowO3JpZ2h0OmF1dG99LmthdGV4LWRpc3BsYXkuZmxlcW4+LmthdGV4e3RleHQtYWxpZ246bGVmdH0K`; \ No newline at end of file diff --git a/ReactNativeClient/root.js b/ReactNativeClient/root.js index 3a9d4001b..fbb13c932 100644 --- a/ReactNativeClient/root.js +++ b/ReactNativeClient/root.js @@ -80,6 +80,8 @@ const DecryptionWorker = require('lib/services/DecryptionWorker'); const EncryptionService = require('lib/services/EncryptionService'); const MigrationService = require('lib/services/MigrationService'); +import PluginAssetsLoader from './PluginAssetsLoader'; + let storeDispatch = function() {}; const logReducerAction = function(action) { @@ -461,6 +463,9 @@ async function initialize(dispatch) { Setting.setValue('welcome.enabled', false); } + PluginAssetsLoader.instance().setLogger(mainLogger); + await PluginAssetsLoader.instance().importAssets(); + // eslint-disable-next-line require-atomic-updates BaseItem.revisionService_ = RevisionService.instance(); diff --git a/Tools/copycss.js b/Tools/copycss.js deleted file mode 100644 index b4f4676fc..000000000 --- a/Tools/copycss.js +++ /dev/null @@ -1,30 +0,0 @@ -const fs = require('fs-extra'); - -const cwd = process.cwd(); -const outputDir = `${cwd}/lib/csstojs`; - -async function createJsFromCss(name, filePath) { - let css = await fs.readFile(filePath, 'utf-8'); - // eslint-disable-next-line no-useless-escape - css = css.replace(/\`/g, '\\`'); - const js = `module.exports = \`${css}\`;`; - - const outputPath = `${outputDir}/${name}.css.js`; - await fs.writeFile(outputPath, js); -} - -async function main(argv) { - await fs.mkdirp(outputDir); - await createJsFromCss('katex', `${cwd}/node_modules/katex/dist/katex.min.css`); - await createJsFromCss('hljs-atom-one-light', `${cwd}/node_modules/highlight.js/styles/atom-one-light.css`); - await createJsFromCss('hljs-atom-one-dark-reasonable', `${cwd}/node_modules/highlight.js/styles/atom-one-dark-reasonable.css`); - - if (argv.indexOf('--copy-fonts') >= 0) { - await fs.copy(`${cwd}/node_modules/katex/dist/fonts`, `${cwd}/gui/note-viewer/fonts`); - } -} - -main(process.argv).catch((error) => { - console.error(error); - process.exit(1); -}); diff --git a/joplin.code-workspace b/joplin.code-workspace index 133feaac1..8d3035529 100644 --- a/joplin.code-workspace +++ b/joplin.code-workspace @@ -2,11 +2,15 @@ "folders": [ { "name": "Joplin", - "path": ".", - }, { - "name": "Joplin Nextcloud App", - "path": "D:/Web/www/nextcloud/apps/joplin", + "path": "." }, + { + "name": "Joplin Nextcloud App", + "path": "D:/Web/www/nextcloud/apps/joplin" + }, + { + "path": "D:/Docs/PROGS/Node/joplin-renderer" + } ], "settings": { "files.exclude": {