{ "version": 3, "sources": ["../../../../../../../src/node_modules/markdown-it/lib/common/entities.js", "../../../../../../../src/node_modules/uc.micro/categories/P/regex.js", "../../../../../../../src/node_modules/mdurl/encode.js", "../../../../../../../src/node_modules/mdurl/decode.js", "../../../../../../../src/node_modules/mdurl/format.js", "../../../../../../../src/node_modules/mdurl/parse.js", "../../../../../../../src/node_modules/mdurl/index.js", "../../../../../../../src/node_modules/uc.micro/properties/Any/regex.js", "../../../../../../../src/node_modules/uc.micro/categories/Cc/regex.js", "../../../../../../../src/node_modules/uc.micro/categories/Cf/regex.js", "../../../../../../../src/node_modules/uc.micro/categories/Z/regex.js", "../../../../../../../src/node_modules/uc.micro/index.js", "../../../../../../../src/node_modules/markdown-it/lib/common/utils.js", "../../../../../../../src/node_modules/markdown-it/lib/helpers/parse_link_label.js", "../../../../../../../src/node_modules/markdown-it/lib/helpers/parse_link_destination.js", "../../../../../../../src/node_modules/markdown-it/lib/helpers/parse_link_title.js", "../../../../../../../src/node_modules/markdown-it/lib/helpers/index.js", "../../../../../../../src/node_modules/markdown-it/lib/renderer.js", "../../../../../../../src/node_modules/markdown-it/lib/ruler.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_core/normalize.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_core/block.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_core/inline.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_core/linkify.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_core/replacements.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_core/smartquotes.js", "../../../../../../../src/node_modules/markdown-it/lib/token.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_core/state_core.js", "../../../../../../../src/node_modules/markdown-it/lib/parser_core.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_block/table.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_block/code.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_block/fence.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_block/blockquote.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_block/hr.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_block/list.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_block/reference.js", "../../../../../../../src/node_modules/markdown-it/lib/common/html_blocks.js", "../../../../../../../src/node_modules/markdown-it/lib/common/html_re.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_block/html_block.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_block/heading.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_block/lheading.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_block/paragraph.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_block/state_block.js", "../../../../../../../src/node_modules/markdown-it/lib/parser_block.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/text.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/newline.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/escape.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/backticks.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/strikethrough.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/emphasis.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/link.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/image.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/autolink.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/html_inline.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/entity.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/balance_pairs.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/text_collapse.js", "../../../../../../../src/node_modules/markdown-it/lib/rules_inline/state_inline.js", "../../../../../../../src/node_modules/markdown-it/lib/parser_inline.js", "../../../../../../../src/node_modules/linkify-it/lib/re.js", "../../../../../../../src/node_modules/linkify-it/index.js", "../../../../../../../src/node_modules/punycode/punycode.js", "../../../../../../../src/node_modules/markdown-it/lib/presets/default.js", "../../../../../../../src/node_modules/markdown-it/lib/presets/zero.js", "../../../../../../../src/node_modules/markdown-it/lib/presets/commonmark.js", "../../../../../../../src/node_modules/markdown-it/lib/index.js", "../../../../../../../src/node_modules/markdown-it/index.js", "../../../../../../../src/js/i18n/datepicker/jquery.ui.datepicker-nl.js", "../../../../../../../src/js/lib/gettext.js", "../../../../../../../src/js/i18n/nl.js", "../../../../../../../src/js/lib/polyfills/url-search-params.js", "../../../../../../../src/js/lib/text-utils.js", "../../../../../../../src/js/lib/errors.js", "../../../../../../../src/js/lib/collect-values.js", "../../../../../../../src/js/lib/vars.js", "../../../../../../../src/js/lib/case-exit.js", "../../../../../../../src/js/lib/a11y.js", "../../../../../../../src/js/lib/escape.js", "../../../../../../../src/js/lib/notify.js", "../../../../../../../src/js/lib/conf.js", "../../../../../../../src/js/lib/location.js", "../../../../../../../src/js/lib/ajax.js", "../../../../../../../src/js/lib/settled.js", "../../../../../../../src/js/lib/bbi.js", "../../../../../../../src/js/lib/control-helpers.js", "../../../../../../../src/js/lib/quotable.js", "../../../../../../../src/js/lib/dates.js", "../../../../../../../src/js/lib/feature-queries.js", "../../../../../../../src/js/lib/form-widgets.js", "../../../../../../../src/js/lib/dynprops.js", "../../../../../../../src/js/lib/hooks.js", "../../../../../../../src/js/lib/control.js", "../../../../../../../src/js/lib/types.js", "../../../../../../../src/js/lib/control-validation.js", "../../../../../../../src/js/lib/groupings.js", "../../../../../../../src/js/lib/font-classes.js", "../../../../../../../src/js/lib/names.js", "../../../../../../../src/js/lib/form-groups.js", "../../../../../../../src/js/lib/form-widgets-definitions.js", "../../../../../../../src/js/lib/numerals.js", "../../../../../../../src/js/lib/url-utils.js", "../../../../../../../src/js/lib/utils.js", "../../../../../../../src/js/lib/jumplist.js", "../../../../../../../src/js/lib/user-info.js", "../../../../../../../src/js/lib/permissions.js", "../../../../../../../src/js/lib/$.scrollTo.js", "../../../../../../../src/js/json.js", "../../../../../../../src/plugins/00reset/00reset.js", "../../../../../../../src/plugins/a11y-describedby/a11y-describedby.js", "../../../../../../../src/plugins/asterisk/asterisk.js", "../../../../../../../src/plugins/bb-xarea/bb-xarea.js", "../../../../../../../src/plugins/detect-iframe/detect-iframe.js", "../../../../../../../src/node_modules/dialog-polyfill/dist/dialog-polyfill.esm.js", "../../../../../../../src/custom/goes/plugins/expand-next/expand-next.js", "../../../../../../../src/plugins/faux-ajax/faux-ajax.js", "../../../../../../../src/plugins/grid-rowspan-first-col/grid-rowspan-first-col.js", "../../../../../../../src/custom/sb/plugins/has-no-next/has-no-next.js", "../../../../../../../src/plugins/has-required/has-required.js", "../../../../../../../src/plugins/headings/headings.js", "../../../../../../../src/plugins/history/history.js", "../../../../../../../src/plugins/jquery.xarea/jquery.xarea.js", "../../../../../../../src/plugins/markdown-it-converter/markdown-it-converter.js", "../../../../../../../src/plugins/md-labels/md-labels.js", "../../../../../../../src/plugins/model-filter/model-filter.js", "../../../../../../../src/plugins/modelitem/modelitem.js", "../../../../../../../src/plugins/mustache/mustache.js", "../../../../../../../src/plugins/non-indenting-jumplist/non-indenting-jumplist.js", "../../../../../../../src/plugins/option-filter/option-filter.js", "../../../../../../../src/plugins/optional/optional.js", "../../../../../../../src/plugins/postcode-soap/postcode-soap.js", "../../../../../../../src/plugins/progressbar/progressbar.js", "../../../../../../../src/plugins/questionlabelgroup-wrapping-input/questionlabelgroup-wrapping-input.js", "../../../../../../../src/plugins/savecase-native-dialog/savecase-native-dialog.js", "../../../../../../../src/custom/sb/plugins/geen-toestemmingen/geen-toestemmingen.js", "../../../../../../../src/custom/sb/plugins/open/open.js", "../../../../../../../src/custom/sb/plugins/smart-attachments/smart-attachments.js", "../../../../../../../src/custom/sb/plugins/toelichtingen/toelichtingen.js", "../../../../../../../src/plugins/selected-model/selected-model.js", "../../../../../../../src/plugins/show-server-side-validation/show-server-side-validation.js", "../../../../../../../src/plugins/xsl-to-pdf/xsl-to-pdf.js"], "sourcesContent": ["// HTML5 entities map: { name -> utf16string }\n//\n'use strict';\n\n/*eslint quotes:0*/\nmodule.exports = require('entities/lib/maps/entities.json');\n", "module.exports=/[!-#%-\\*,-\\/:;\\?@\\[-\\]_\\{\\}\\xA1\\xA7\\xAB\\xB6\\xB7\\xBB\\xBF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u09FD\\u0A76\\u0AF0\\u0C84\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2308-\\u230B\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E4E\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA8FC\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]|\\uD800[\\uDD00-\\uDD02\\uDF9F\\uDFD0]|\\uD801\\uDD6F|\\uD802[\\uDC57\\uDD1F\\uDD3F\\uDE50-\\uDE58\\uDE7F\\uDEF0-\\uDEF6\\uDF39-\\uDF3F\\uDF99-\\uDF9C]|\\uD803[\\uDF55-\\uDF59]|\\uD804[\\uDC47-\\uDC4D\\uDCBB\\uDCBC\\uDCBE-\\uDCC1\\uDD40-\\uDD43\\uDD74\\uDD75\\uDDC5-\\uDDC8\\uDDCD\\uDDDB\\uDDDD-\\uDDDF\\uDE38-\\uDE3D\\uDEA9]|\\uD805[\\uDC4B-\\uDC4F\\uDC5B\\uDC5D\\uDCC6\\uDDC1-\\uDDD7\\uDE41-\\uDE43\\uDE60-\\uDE6C\\uDF3C-\\uDF3E]|\\uD806[\\uDC3B\\uDE3F-\\uDE46\\uDE9A-\\uDE9C\\uDE9E-\\uDEA2]|\\uD807[\\uDC41-\\uDC45\\uDC70\\uDC71\\uDEF7\\uDEF8]|\\uD809[\\uDC70-\\uDC74]|\\uD81A[\\uDE6E\\uDE6F\\uDEF5\\uDF37-\\uDF3B\\uDF44]|\\uD81B[\\uDE97-\\uDE9A]|\\uD82F\\uDC9F|\\uD836[\\uDE87-\\uDE8B]|\\uD83A[\\uDD5E\\uDD5F]/", "\n'use strict';\n\n\nvar encodeCache = {};\n\n\n// Create a lookup array where anything but characters in `chars` string\n// and alphanumeric chars is percent-encoded.\n//\nfunction getEncodeCache(exclude) {\n var i, ch, cache = encodeCache[exclude];\n if (cache) { return cache; }\n\n cache = encodeCache[exclude] = [];\n\n for (i = 0; i < 128; i++) {\n ch = String.fromCharCode(i);\n\n if (/^[0-9a-z]$/i.test(ch)) {\n // always allow unencoded alphanumeric characters\n cache.push(ch);\n } else {\n cache.push('%' + ('0' + i.toString(16).toUpperCase()).slice(-2));\n }\n }\n\n for (i = 0; i < exclude.length; i++) {\n cache[exclude.charCodeAt(i)] = exclude[i];\n }\n\n return cache;\n}\n\n\n// Encode unsafe characters with percent-encoding, skipping already\n// encoded sequences.\n//\n// - string - string to encode\n// - exclude - list of characters to ignore (in addition to a-zA-Z0-9)\n// - keepEscaped - don't encode '%' in a correct escape sequence (default: true)\n//\nfunction encode(string, exclude, keepEscaped) {\n var i, l, code, nextCode, cache,\n result = '';\n\n if (typeof exclude !== 'string') {\n // encode(string, keepEscaped)\n keepEscaped = exclude;\n exclude = encode.defaultChars;\n }\n\n if (typeof keepEscaped === 'undefined') {\n keepEscaped = true;\n }\n\n cache = getEncodeCache(exclude);\n\n for (i = 0, l = string.length; i < l; i++) {\n code = string.charCodeAt(i);\n\n if (keepEscaped && code === 0x25 /* % */ && i + 2 < l) {\n if (/^[0-9a-f]{2}$/i.test(string.slice(i + 1, i + 3))) {\n result += string.slice(i, i + 3);\n i += 2;\n continue;\n }\n }\n\n if (code < 128) {\n result += cache[code];\n continue;\n }\n\n if (code >= 0xD800 && code <= 0xDFFF) {\n if (code >= 0xD800 && code <= 0xDBFF && i + 1 < l) {\n nextCode = string.charCodeAt(i + 1);\n if (nextCode >= 0xDC00 && nextCode <= 0xDFFF) {\n result += encodeURIComponent(string[i] + string[i + 1]);\n i++;\n continue;\n }\n }\n result += '%EF%BF%BD';\n continue;\n }\n\n result += encodeURIComponent(string[i]);\n }\n\n return result;\n}\n\nencode.defaultChars = \";/?:@&=+$,-_.!~*'()#\";\nencode.componentChars = \"-_.!~*'()\";\n\n\nmodule.exports = encode;\n", "\n'use strict';\n\n\n/* eslint-disable no-bitwise */\n\nvar decodeCache = {};\n\nfunction getDecodeCache(exclude) {\n var i, ch, cache = decodeCache[exclude];\n if (cache) { return cache; }\n\n cache = decodeCache[exclude] = [];\n\n for (i = 0; i < 128; i++) {\n ch = String.fromCharCode(i);\n cache.push(ch);\n }\n\n for (i = 0; i < exclude.length; i++) {\n ch = exclude.charCodeAt(i);\n cache[ch] = '%' + ('0' + ch.toString(16).toUpperCase()).slice(-2);\n }\n\n return cache;\n}\n\n\n// Decode percent-encoded string.\n//\nfunction decode(string, exclude) {\n var cache;\n\n if (typeof exclude !== 'string') {\n exclude = decode.defaultChars;\n }\n\n cache = getDecodeCache(exclude);\n\n return string.replace(/(%[a-f0-9]{2})+/gi, function(seq) {\n var i, l, b1, b2, b3, b4, chr,\n result = '';\n\n for (i = 0, l = seq.length; i < l; i += 3) {\n b1 = parseInt(seq.slice(i + 1, i + 3), 16);\n\n if (b1 < 0x80) {\n result += cache[b1];\n continue;\n }\n\n if ((b1 & 0xE0) === 0xC0 && (i + 3 < l)) {\n // 110xxxxx 10xxxxxx\n b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n\n if ((b2 & 0xC0) === 0x80) {\n chr = ((b1 << 6) & 0x7C0) | (b2 & 0x3F);\n\n if (chr < 0x80) {\n result += '\\ufffd\\ufffd';\n } else {\n result += String.fromCharCode(chr);\n }\n\n i += 3;\n continue;\n }\n }\n\n if ((b1 & 0xF0) === 0xE0 && (i + 6 < l)) {\n // 1110xxxx 10xxxxxx 10xxxxxx\n b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n b3 = parseInt(seq.slice(i + 7, i + 9), 16);\n\n if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {\n chr = ((b1 << 12) & 0xF000) | ((b2 << 6) & 0xFC0) | (b3 & 0x3F);\n\n if (chr < 0x800 || (chr >= 0xD800 && chr <= 0xDFFF)) {\n result += '\\ufffd\\ufffd\\ufffd';\n } else {\n result += String.fromCharCode(chr);\n }\n\n i += 6;\n continue;\n }\n }\n\n if ((b1 & 0xF8) === 0xF0 && (i + 9 < l)) {\n // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx\n b2 = parseInt(seq.slice(i + 4, i + 6), 16);\n b3 = parseInt(seq.slice(i + 7, i + 9), 16);\n b4 = parseInt(seq.slice(i + 10, i + 12), 16);\n\n if ((b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80 && (b4 & 0xC0) === 0x80) {\n chr = ((b1 << 18) & 0x1C0000) | ((b2 << 12) & 0x3F000) | ((b3 << 6) & 0xFC0) | (b4 & 0x3F);\n\n if (chr < 0x10000 || chr > 0x10FFFF) {\n result += '\\ufffd\\ufffd\\ufffd\\ufffd';\n } else {\n chr -= 0x10000;\n result += String.fromCharCode(0xD800 + (chr >> 10), 0xDC00 + (chr & 0x3FF));\n }\n\n i += 9;\n continue;\n }\n }\n\n result += '\\ufffd';\n }\n\n return result;\n });\n}\n\n\ndecode.defaultChars = ';/?:@&=+$,#';\ndecode.componentChars = '';\n\n\nmodule.exports = decode;\n", "\n'use strict';\n\n\nmodule.exports = function format(url) {\n var result = '';\n\n result += url.protocol || '';\n result += url.slashes ? '//' : '';\n result += url.auth ? url.auth + '@' : '';\n\n if (url.hostname && url.hostname.indexOf(':') !== -1) {\n // ipv6 address\n result += '[' + url.hostname + ']';\n } else {\n result += url.hostname || '';\n }\n\n result += url.port ? ':' + url.port : '';\n result += url.pathname || '';\n result += url.search || '';\n result += url.hash || '';\n\n return result;\n};\n", "// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\n//\n// Changes from joyent/node:\n//\n// 1. No leading slash in paths,\n// e.g. in `url.parse('http://foo?bar')` pathname is ``, not `/`\n//\n// 2. Backslashes are not replaced with slashes,\n// so `http:\\\\example.org\\` is treated like a relative path\n//\n// 3. Trailing colon is treated like a part of the path,\n// i.e. in `http://example.org:foo` pathname is `:foo`\n//\n// 4. Nothing is URL-encoded in the resulting object,\n// (in joyent/node some chars in auth and paths are encoded)\n//\n// 5. `url.parse()` does not have `parseQueryString` argument\n//\n// 6. Removed extraneous result properties: `host`, `path`, `query`, etc.,\n// which can be constructed using other parts of the url.\n//\n\n\nfunction Url() {\n this.protocol = null;\n this.slashes = null;\n this.auth = null;\n this.port = null;\n this.hostname = null;\n this.hash = null;\n this.search = null;\n this.pathname = null;\n}\n\n// Reference: RFC 3986, RFC 1808, RFC 2396\n\n// define these here so at least they only have to be\n// compiled once on the first module load.\nvar protocolPattern = /^([a-z0-9.+-]+:)/i,\n portPattern = /:[0-9]*$/,\n\n // Special case for a simple path URL\n simplePathPattern = /^(\\/\\/?(?!\\/)[^\\?\\s]*)(\\?[^\\s]*)?$/,\n\n // RFC 2396: characters reserved for delimiting URLs.\n // We actually just auto-escape these.\n delims = [ '<', '>', '\"', '`', ' ', '\\r', '\\n', '\\t' ],\n\n // RFC 2396: characters not allowed for various reasons.\n unwise = [ '{', '}', '|', '\\\\', '^', '`' ].concat(delims),\n\n // Allowed by RFCs, but cause of XSS attacks. Always escape these.\n autoEscape = [ '\\'' ].concat(unwise),\n // Characters that are never ever allowed in a hostname.\n // Note that any invalid chars are also handled, but these\n // are the ones that are *expected* to be seen, so we fast-path\n // them.\n nonHostChars = [ '%', '/', '?', ';', '#' ].concat(autoEscape),\n hostEndingChars = [ '/', '?', '#' ],\n hostnameMaxLen = 255,\n hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,\n hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,\n // protocols that can allow \"unsafe\" and \"unwise\" chars.\n /* eslint-disable no-script-url */\n // protocols that never have a hostname.\n hostlessProtocol = {\n 'javascript': true,\n 'javascript:': true\n },\n // protocols that always contain a // bit.\n slashedProtocol = {\n 'http': true,\n 'https': true,\n 'ftp': true,\n 'gopher': true,\n 'file': true,\n 'http:': true,\n 'https:': true,\n 'ftp:': true,\n 'gopher:': true,\n 'file:': true\n };\n /* eslint-enable no-script-url */\n\nfunction urlParse(url, slashesDenoteHost) {\n if (url && url instanceof Url) { return url; }\n\n var u = new Url();\n u.parse(url, slashesDenoteHost);\n return u;\n}\n\nUrl.prototype.parse = function(url, slashesDenoteHost) {\n var i, l, lowerProto, hec, slashes,\n rest = url;\n\n // trim before proceeding.\n // This is to support parse stuff like \" http://foo.com \\n\"\n rest = rest.trim();\n\n if (!slashesDenoteHost && url.split('#').length === 1) {\n // Try fast path regexp\n var simplePath = simplePathPattern.exec(rest);\n if (simplePath) {\n this.pathname = simplePath[1];\n if (simplePath[2]) {\n this.search = simplePath[2];\n }\n return this;\n }\n }\n\n var proto = protocolPattern.exec(rest);\n if (proto) {\n proto = proto[0];\n lowerProto = proto.toLowerCase();\n this.protocol = proto;\n rest = rest.substr(proto.length);\n }\n\n // figure out if it's got a host\n // user@server is *always* interpreted as a hostname, and url\n // resolution will treat //foo/bar as host=foo,path=bar because that's\n // how the browser resolves relative URLs.\n if (slashesDenoteHost || proto || rest.match(/^\\/\\/[^@\\/]+@[^@\\/]+/)) {\n slashes = rest.substr(0, 2) === '//';\n if (slashes && !(proto && hostlessProtocol[proto])) {\n rest = rest.substr(2);\n this.slashes = true;\n }\n }\n\n if (!hostlessProtocol[proto] &&\n (slashes || (proto && !slashedProtocol[proto]))) {\n\n // there's a hostname.\n // the first instance of /, ?, ;, or # ends the host.\n //\n // If there is an @ in the hostname, then non-host chars *are* allowed\n // to the left of the last @ sign, unless some host-ending character\n // comes *before* the @-sign.\n // URLs are obnoxious.\n //\n // ex:\n // http://a@b@c/ => user:a@b host:c\n // http://a@b?@c => user:a host:c path:/?@c\n\n // v0.12 TODO(isaacs): This is not quite how Chrome does things.\n // Review our test case against browsers more comprehensively.\n\n // find the first instance of any hostEndingChars\n var hostEnd = -1;\n for (i = 0; i < hostEndingChars.length; i++) {\n hec = rest.indexOf(hostEndingChars[i]);\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {\n hostEnd = hec;\n }\n }\n\n // at this point, either we have an explicit point where the\n // auth portion cannot go past, or the last @ char is the decider.\n var auth, atSign;\n if (hostEnd === -1) {\n // atSign can be anywhere.\n atSign = rest.lastIndexOf('@');\n } else {\n // atSign must be in auth portion.\n // http://a@b/c@d => host:b auth:a path:/c@d\n atSign = rest.lastIndexOf('@', hostEnd);\n }\n\n // Now we have a portion which is definitely the auth.\n // Pull that off.\n if (atSign !== -1) {\n auth = rest.slice(0, atSign);\n rest = rest.slice(atSign + 1);\n this.auth = auth;\n }\n\n // the host is the remaining to the left of the first non-host char\n hostEnd = -1;\n for (i = 0; i < nonHostChars.length; i++) {\n hec = rest.indexOf(nonHostChars[i]);\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {\n hostEnd = hec;\n }\n }\n // if we still have not hit it, then the entire thing is a host.\n if (hostEnd === -1) {\n hostEnd = rest.length;\n }\n\n if (rest[hostEnd - 1] === ':') { hostEnd--; }\n var host = rest.slice(0, hostEnd);\n rest = rest.slice(hostEnd);\n\n // pull out port.\n this.parseHost(host);\n\n // we've indicated that there is a hostname,\n // so even if it's empty, it has to be present.\n this.hostname = this.hostname || '';\n\n // if hostname begins with [ and ends with ]\n // assume that it's an IPv6 address.\n var ipv6Hostname = this.hostname[0] === '[' &&\n this.hostname[this.hostname.length - 1] === ']';\n\n // validate a little.\n if (!ipv6Hostname) {\n var hostparts = this.hostname.split(/\\./);\n for (i = 0, l = hostparts.length; i < l; i++) {\n var part = hostparts[i];\n if (!part) { continue; }\n if (!part.match(hostnamePartPattern)) {\n var newpart = '';\n for (var j = 0, k = part.length; j < k; j++) {\n if (part.charCodeAt(j) > 127) {\n // we replace non-ASCII char with a temporary placeholder\n // we need this to make sure size of hostname is not\n // broken by replacing non-ASCII by nothing\n newpart += 'x';\n } else {\n newpart += part[j];\n }\n }\n // we test again with ASCII char only\n if (!newpart.match(hostnamePartPattern)) {\n var validParts = hostparts.slice(0, i);\n var notHost = hostparts.slice(i + 1);\n var bit = part.match(hostnamePartStart);\n if (bit) {\n validParts.push(bit[1]);\n notHost.unshift(bit[2]);\n }\n if (notHost.length) {\n rest = notHost.join('.') + rest;\n }\n this.hostname = validParts.join('.');\n break;\n }\n }\n }\n }\n\n if (this.hostname.length > hostnameMaxLen) {\n this.hostname = '';\n }\n\n // strip [ and ] from the hostname\n // the host field still retains them, though\n if (ipv6Hostname) {\n this.hostname = this.hostname.substr(1, this.hostname.length - 2);\n }\n }\n\n // chop off from the tail first.\n var hash = rest.indexOf('#');\n if (hash !== -1) {\n // got a fragment string.\n this.hash = rest.substr(hash);\n rest = rest.slice(0, hash);\n }\n var qm = rest.indexOf('?');\n if (qm !== -1) {\n this.search = rest.substr(qm);\n rest = rest.slice(0, qm);\n }\n if (rest) { this.pathname = rest; }\n if (slashedProtocol[lowerProto] &&\n this.hostname && !this.pathname) {\n this.pathname = '';\n }\n\n return this;\n};\n\nUrl.prototype.parseHost = function(host) {\n var port = portPattern.exec(host);\n if (port) {\n port = port[0];\n if (port !== ':') {\n this.port = port.substr(1);\n }\n host = host.substr(0, host.length - port.length);\n }\n if (host) { this.hostname = host; }\n};\n\nmodule.exports = urlParse;\n", "'use strict';\n\n\nmodule.exports.encode = require('./encode');\nmodule.exports.decode = require('./decode');\nmodule.exports.format = require('./format');\nmodule.exports.parse = require('./parse');\n", "module.exports=/[\\0-\\uD7FF\\uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/", "module.exports=/[\\0-\\x1F\\x7F-\\x9F]/", "module.exports=/[\\xAD\\u0600-\\u0605\\u061C\\u06DD\\u070F\\u08E2\\u180E\\u200B-\\u200F\\u202A-\\u202E\\u2060-\\u2064\\u2066-\\u206F\\uFEFF\\uFFF9-\\uFFFB]|\\uD804[\\uDCBD\\uDCCD]|\\uD82F[\\uDCA0-\\uDCA3]|\\uD834[\\uDD73-\\uDD7A]|\\uDB40[\\uDC01\\uDC20-\\uDC7F]/", "module.exports=/[ \\xA0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]/", "'use strict';\n\nexports.Any = require('./properties/Any/regex');\nexports.Cc = require('./categories/Cc/regex');\nexports.Cf = require('./categories/Cf/regex');\nexports.P = require('./categories/P/regex');\nexports.Z = require('./categories/Z/regex');\n", "// Utilities\n//\n'use strict';\n\n\nfunction _class(obj) { return Object.prototype.toString.call(obj); }\n\nfunction isString(obj) { return _class(obj) === '[object String]'; }\n\nvar _hasOwnProperty = Object.prototype.hasOwnProperty;\n\nfunction has(object, key) {\n return _hasOwnProperty.call(object, key);\n}\n\n// Merge objects\n//\nfunction assign(obj /*from1, from2, from3, ...*/) {\n var sources = Array.prototype.slice.call(arguments, 1);\n\n sources.forEach(function (source) {\n if (!source) { return; }\n\n if (typeof source !== 'object') {\n throw new TypeError(source + 'must be object');\n }\n\n Object.keys(source).forEach(function (key) {\n obj[key] = source[key];\n });\n });\n\n return obj;\n}\n\n// Remove element from array and put another array at those position.\n// Useful for some operations with tokens\nfunction arrayReplaceAt(src, pos, newElements) {\n return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1));\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nfunction isValidEntityCode(c) {\n /*eslint no-bitwise:0*/\n // broken sequence\n if (c >= 0xD800 && c <= 0xDFFF) { return false; }\n // never used\n if (c >= 0xFDD0 && c <= 0xFDEF) { return false; }\n if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false; }\n // control codes\n if (c >= 0x00 && c <= 0x08) { return false; }\n if (c === 0x0B) { return false; }\n if (c >= 0x0E && c <= 0x1F) { return false; }\n if (c >= 0x7F && c <= 0x9F) { return false; }\n // out of range\n if (c > 0x10FFFF) { return false; }\n return true;\n}\n\nfunction fromCodePoint(c) {\n /*eslint no-bitwise:0*/\n if (c > 0xffff) {\n c -= 0x10000;\n var surrogate1 = 0xd800 + (c >> 10),\n surrogate2 = 0xdc00 + (c & 0x3ff);\n\n return String.fromCharCode(surrogate1, surrogate2);\n }\n return String.fromCharCode(c);\n}\n\n\nvar UNESCAPE_MD_RE = /\\\\([!\"#$%&'()*+,\\-.\\/:;<=>?@[\\\\\\]^_`{|}~])/g;\nvar ENTITY_RE = /&([a-z#][a-z0-9]{1,31});/gi;\nvar UNESCAPE_ALL_RE = new RegExp(UNESCAPE_MD_RE.source + '|' + ENTITY_RE.source, 'gi');\n\nvar DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i;\n\nvar entities = require('./entities');\n\nfunction replaceEntityPattern(match, name) {\n var code = 0;\n\n if (has(entities, name)) {\n return entities[name];\n }\n\n if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) {\n code = name[1].toLowerCase() === 'x' ?\n parseInt(name.slice(2), 16) : parseInt(name.slice(1), 10);\n\n if (isValidEntityCode(code)) {\n return fromCodePoint(code);\n }\n }\n\n return match;\n}\n\n/*function replaceEntities(str) {\n if (str.indexOf('&') < 0) { return str; }\n\n return str.replace(ENTITY_RE, replaceEntityPattern);\n}*/\n\nfunction unescapeMd(str) {\n if (str.indexOf('\\\\') < 0) { return str; }\n return str.replace(UNESCAPE_MD_RE, '$1');\n}\n\nfunction unescapeAll(str) {\n if (str.indexOf('\\\\') < 0 && str.indexOf('&') < 0) { return str; }\n\n return str.replace(UNESCAPE_ALL_RE, function (match, escaped, entity) {\n if (escaped) { return escaped; }\n return replaceEntityPattern(match, entity);\n });\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nvar HTML_ESCAPE_TEST_RE = /[&<>\"]/;\nvar HTML_ESCAPE_REPLACE_RE = /[&<>\"]/g;\nvar HTML_REPLACEMENTS = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"'\n};\n\nfunction replaceUnsafeChar(ch) {\n return HTML_REPLACEMENTS[ch];\n}\n\nfunction escapeHtml(str) {\n if (HTML_ESCAPE_TEST_RE.test(str)) {\n return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar);\n }\n return str;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nvar REGEXP_ESCAPE_RE = /[.?*+^$[\\]\\\\(){}|-]/g;\n\nfunction escapeRE(str) {\n return str.replace(REGEXP_ESCAPE_RE, '\\\\$&');\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nfunction isSpace(code) {\n switch (code) {\n case 0x09:\n case 0x20:\n return true;\n }\n return false;\n}\n\n// Zs (unicode class) || [\\t\\f\\v\\r\\n]\nfunction isWhiteSpace(code) {\n if (code >= 0x2000 && code <= 0x200A) { return true; }\n switch (code) {\n case 0x09: // \\t\n case 0x0A: // \\n\n case 0x0B: // \\v\n case 0x0C: // \\f\n case 0x0D: // \\r\n case 0x20:\n case 0xA0:\n case 0x1680:\n case 0x202F:\n case 0x205F:\n case 0x3000:\n return true;\n }\n return false;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\n/*eslint-disable max-len*/\nvar UNICODE_PUNCT_RE = require('uc.micro/categories/P/regex');\n\n// Currently without astral characters support.\nfunction isPunctChar(ch) {\n return UNICODE_PUNCT_RE.test(ch);\n}\n\n\n// Markdown ASCII punctuation characters.\n//\n// !, \", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \\, ], ^, _, `, {, |, }, or ~\n// http://spec.commonmark.org/0.15/#ascii-punctuation-character\n//\n// Don't confuse with unicode punctuation !!! It lacks some chars in ascii range.\n//\nfunction isMdAsciiPunct(ch) {\n switch (ch) {\n case 0x21/* ! */:\n case 0x22/* \" */:\n case 0x23/* # */:\n case 0x24/* $ */:\n case 0x25/* % */:\n case 0x26/* & */:\n case 0x27/* ' */:\n case 0x28/* ( */:\n case 0x29/* ) */:\n case 0x2A/* * */:\n case 0x2B/* + */:\n case 0x2C/* , */:\n case 0x2D/* - */:\n case 0x2E/* . */:\n case 0x2F/* / */:\n case 0x3A/* : */:\n case 0x3B/* ; */:\n case 0x3C/* < */:\n case 0x3D/* = */:\n case 0x3E/* > */:\n case 0x3F/* ? */:\n case 0x40/* @ */:\n case 0x5B/* [ */:\n case 0x5C/* \\ */:\n case 0x5D/* ] */:\n case 0x5E/* ^ */:\n case 0x5F/* _ */:\n case 0x60/* ` */:\n case 0x7B/* { */:\n case 0x7C/* | */:\n case 0x7D/* } */:\n case 0x7E/* ~ */:\n return true;\n default:\n return false;\n }\n}\n\n// Hepler to unify [reference labels].\n//\nfunction normalizeReference(str) {\n // Trim and collapse whitespace\n //\n str = str.trim().replace(/\\s+/g, ' ');\n\n // In node v10 '\u1E9E'.toLowerCase() === '\u1E7E', which is presumed to be a bug\n // fixed in v12 (couldn't find any details).\n //\n // So treat this one as a special case\n // (remove this when node v10 is no longer supported).\n //\n if ('\u1E9E'.toLowerCase() === '\u1E7E') {\n str = str.replace(/\u1E9E/g, '\u00DF');\n }\n\n // .toLowerCase().toUpperCase() should get rid of all differences\n // between letter variants.\n //\n // Simple .toLowerCase() doesn't normalize 125 code points correctly,\n // and .toUpperCase doesn't normalize 6 of them (list of exceptions:\n // \u0130, \u03F4, \u1E9E, \u2126, \u212A, \u212B - those are already uppercased, but have differently\n // uppercased versions).\n //\n // Here's an example showing how it happens. Lets take greek letter omega:\n // uppercase U+0398 (\u0398), U+03f4 (\u03F4) and lowercase U+03b8 (\u03B8), U+03d1 (\u03D1)\n //\n // Unicode entries:\n // 0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;\n // 03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398\n // 03D1;GREEK THETA SYMBOL;Ll;0;L; 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398\n // 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L; 0398;;;;N;;;;03B8;\n //\n // Case-insensitive comparison should treat all of them as equivalent.\n //\n // But .toLowerCase() doesn't change \u03D1 (it's already lowercase),\n // and .toUpperCase() doesn't change \u03F4 (already uppercase).\n //\n // Applying first lower then upper case normalizes any character:\n // '\\u0398\\u03f4\\u03b8\\u03d1'.toLowerCase().toUpperCase() === '\\u0398\\u0398\\u0398\\u0398'\n //\n // Note: this is equivalent to unicode case folding; unicode normalization\n // is a different step that is not required here.\n //\n // Final result should be uppercased, because it's later stored in an object\n // (this avoid a conflict with Object.prototype members,\n // most notably, `__proto__`)\n //\n return str.toLowerCase().toUpperCase();\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\n// Re-export libraries commonly used in both markdown-it and its plugins,\n// so plugins won't have to depend on them explicitly, which reduces their\n// bundled size (e.g. a browser build).\n//\nexports.lib = {};\nexports.lib.mdurl = require('mdurl');\nexports.lib.ucmicro = require('uc.micro');\n\nexports.assign = assign;\nexports.isString = isString;\nexports.has = has;\nexports.unescapeMd = unescapeMd;\nexports.unescapeAll = unescapeAll;\nexports.isValidEntityCode = isValidEntityCode;\nexports.fromCodePoint = fromCodePoint;\n// exports.replaceEntities = replaceEntities;\nexports.escapeHtml = escapeHtml;\nexports.arrayReplaceAt = arrayReplaceAt;\nexports.isSpace = isSpace;\nexports.isWhiteSpace = isWhiteSpace;\nexports.isMdAsciiPunct = isMdAsciiPunct;\nexports.isPunctChar = isPunctChar;\nexports.escapeRE = escapeRE;\nexports.normalizeReference = normalizeReference;\n", "// Parse link label\n//\n// this function assumes that first character (\"[\") already matches;\n// returns the end of the label\n//\n'use strict';\n\nmodule.exports = function parseLinkLabel(state, start, disableNested) {\n var level, found, marker, prevPos,\n labelEnd = -1,\n max = state.posMax,\n oldPos = state.pos;\n\n state.pos = start + 1;\n level = 1;\n\n while (state.pos < max) {\n marker = state.src.charCodeAt(state.pos);\n if (marker === 0x5D /* ] */) {\n level--;\n if (level === 0) {\n found = true;\n break;\n }\n }\n\n prevPos = state.pos;\n state.md.inline.skipToken(state);\n if (marker === 0x5B /* [ */) {\n if (prevPos === state.pos - 1) {\n // increase level if we find text `[`, which is not a part of any token\n level++;\n } else if (disableNested) {\n state.pos = oldPos;\n return -1;\n }\n }\n }\n\n if (found) {\n labelEnd = state.pos;\n }\n\n // restore old state\n state.pos = oldPos;\n\n return labelEnd;\n};\n", "// Parse link destination\n//\n'use strict';\n\n\nvar unescapeAll = require('../common/utils').unescapeAll;\n\n\nmodule.exports = function parseLinkDestination(str, pos, max) {\n var code, level,\n lines = 0,\n start = pos,\n result = {\n ok: false,\n pos: 0,\n lines: 0,\n str: ''\n };\n\n if (str.charCodeAt(pos) === 0x3C /* < */) {\n pos++;\n while (pos < max) {\n code = str.charCodeAt(pos);\n if (code === 0x0A /* \\n */) { return result; }\n if (code === 0x3C /* < */) { return result; }\n if (code === 0x3E /* > */) {\n result.pos = pos + 1;\n result.str = unescapeAll(str.slice(start + 1, pos));\n result.ok = true;\n return result;\n }\n if (code === 0x5C /* \\ */ && pos + 1 < max) {\n pos += 2;\n continue;\n }\n\n pos++;\n }\n\n // no closing '>'\n return result;\n }\n\n // this should be ... } else { ... branch\n\n level = 0;\n while (pos < max) {\n code = str.charCodeAt(pos);\n\n if (code === 0x20) { break; }\n\n // ascii control characters\n if (code < 0x20 || code === 0x7F) { break; }\n\n if (code === 0x5C /* \\ */ && pos + 1 < max) {\n if (str.charCodeAt(pos + 1) === 0x20) { break; }\n pos += 2;\n continue;\n }\n\n if (code === 0x28 /* ( */) {\n level++;\n if (level > 32) { return result; }\n }\n\n if (code === 0x29 /* ) */) {\n if (level === 0) { break; }\n level--;\n }\n\n pos++;\n }\n\n if (start === pos) { return result; }\n if (level !== 0) { return result; }\n\n result.str = unescapeAll(str.slice(start, pos));\n result.lines = lines;\n result.pos = pos;\n result.ok = true;\n return result;\n};\n", "// Parse link title\n//\n'use strict';\n\n\nvar unescapeAll = require('../common/utils').unescapeAll;\n\n\nmodule.exports = function parseLinkTitle(str, pos, max) {\n var code,\n marker,\n lines = 0,\n start = pos,\n result = {\n ok: false,\n pos: 0,\n lines: 0,\n str: ''\n };\n\n if (pos >= max) { return result; }\n\n marker = str.charCodeAt(pos);\n\n if (marker !== 0x22 /* \" */ && marker !== 0x27 /* ' */ && marker !== 0x28 /* ( */) { return result; }\n\n pos++;\n\n // if opening marker is \"(\", switch it to closing marker \")\"\n if (marker === 0x28) { marker = 0x29; }\n\n while (pos < max) {\n code = str.charCodeAt(pos);\n if (code === marker) {\n result.pos = pos + 1;\n result.lines = lines;\n result.str = unescapeAll(str.slice(start + 1, pos));\n result.ok = true;\n return result;\n } else if (code === 0x28 /* ( */ && marker === 0x29 /* ) */) {\n return result;\n } else if (code === 0x0A) {\n lines++;\n } else if (code === 0x5C /* \\ */ && pos + 1 < max) {\n pos++;\n if (str.charCodeAt(pos) === 0x0A) {\n lines++;\n }\n }\n\n pos++;\n }\n\n return result;\n};\n", "// Just a shortcut for bulk export\n'use strict';\n\n\nexports.parseLinkLabel = require('./parse_link_label');\nexports.parseLinkDestination = require('./parse_link_destination');\nexports.parseLinkTitle = require('./parse_link_title');\n", "/**\n * class Renderer\n *\n * Generates HTML from parsed token stream. Each instance has independent\n * copy of rules. Those can be rewritten with ease. Also, you can add new\n * rules if you create plugin and adds new token types.\n **/\n'use strict';\n\n\nvar assign = require('./common/utils').assign;\nvar unescapeAll = require('./common/utils').unescapeAll;\nvar escapeHtml = require('./common/utils').escapeHtml;\n\n\n////////////////////////////////////////////////////////////////////////////////\n\nvar default_rules = {};\n\n\ndefault_rules.code_inline = function (tokens, idx, options, env, slf) {\n var token = tokens[idx];\n\n return '' +\n escapeHtml(tokens[idx].content) +\n '';\n};\n\n\ndefault_rules.code_block = function (tokens, idx, options, env, slf) {\n var token = tokens[idx];\n\n return '' +\n escapeHtml(tokens[idx].content) +\n '\\n';\n};\n\n\ndefault_rules.fence = function (tokens, idx, options, env, slf) {\n var token = tokens[idx],\n info = token.info ? unescapeAll(token.info).trim() : '',\n langName = '',\n langAttrs = '',\n highlighted, i, arr, tmpAttrs, tmpToken;\n\n if (info) {\n arr = info.split(/(\\s+)/g);\n langName = arr[0];\n langAttrs = arr.slice(2).join('');\n }\n\n if (options.highlight) {\n highlighted = options.highlight(token.content, langName, langAttrs) || escapeHtml(token.content);\n } else {\n highlighted = escapeHtml(token.content);\n }\n\n if (highlighted.indexOf(''\n + highlighted\n + '\\n';\n }\n\n\n return '
'\n        + highlighted\n        + '
\\n';\n};\n\n\ndefault_rules.image = function (tokens, idx, options, env, slf) {\n var token = tokens[idx];\n\n // \"alt\" attr MUST be set, even if empty. Because it's mandatory and\n // should be placed on proper position for tests.\n //\n // Replace content with actual value\n\n token.attrs[token.attrIndex('alt')][1] =\n slf.renderInlineAsText(token.children, options, env);\n\n return slf.renderToken(tokens, idx, options);\n};\n\n\ndefault_rules.hardbreak = function (tokens, idx, options /*, env */) {\n return options.xhtmlOut ? '
\\n' : '
\\n';\n};\ndefault_rules.softbreak = function (tokens, idx, options /*, env */) {\n return options.breaks ? (options.xhtmlOut ? '
\\n' : '
\\n') : '\\n';\n};\n\n\ndefault_rules.text = function (tokens, idx /*, options, env */) {\n return escapeHtml(tokens[idx].content);\n};\n\n\ndefault_rules.html_block = function (tokens, idx /*, options, env */) {\n return tokens[idx].content;\n};\ndefault_rules.html_inline = function (tokens, idx /*, options, env */) {\n return tokens[idx].content;\n};\n\n\n/**\n * new Renderer()\n *\n * Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults.\n **/\nfunction Renderer() {\n\n /**\n * Renderer#rules -> Object\n *\n * Contains render rules for tokens. Can be updated and extended.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * md.renderer.rules.strong_open = function () { return ''; };\n * md.renderer.rules.strong_close = function () { return ''; };\n *\n * var result = md.renderInline(...);\n * ```\n *\n * Each rule is called as independent static function with fixed signature:\n *\n * ```javascript\n * function my_token_render(tokens, idx, options, env, renderer) {\n * // ...\n * return renderedHTML;\n * }\n * ```\n *\n * See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js)\n * for more details and examples.\n **/\n this.rules = assign({}, default_rules);\n}\n\n\n/**\n * Renderer.renderAttrs(token) -> String\n *\n * Render token attributes to string.\n **/\nRenderer.prototype.renderAttrs = function renderAttrs(token) {\n var i, l, result;\n\n if (!token.attrs) { return ''; }\n\n result = '';\n\n for (i = 0, l = token.attrs.length; i < l; i++) {\n result += ' ' + escapeHtml(token.attrs[i][0]) + '=\"' + escapeHtml(token.attrs[i][1]) + '\"';\n }\n\n return result;\n};\n\n\n/**\n * Renderer.renderToken(tokens, idx, options) -> String\n * - tokens (Array): list of tokens\n * - idx (Numbed): token index to render\n * - options (Object): params of parser instance\n *\n * Default token renderer. Can be overriden by custom function\n * in [[Renderer#rules]].\n **/\nRenderer.prototype.renderToken = function renderToken(tokens, idx, options) {\n var nextToken,\n result = '',\n needLf = false,\n token = tokens[idx];\n\n // Tight list paragraphs\n if (token.hidden) {\n return '';\n }\n\n // Insert a newline between hidden paragraph and subsequent opening\n // block-level tag.\n //\n // For example, here we should insert a newline before blockquote:\n // - a\n // >\n //\n if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) {\n result += '\\n';\n }\n\n // Add token name, e.g. ``.\n //\n needLf = false;\n }\n }\n }\n }\n\n result += needLf ? '>\\n' : '>';\n\n return result;\n};\n\n\n/**\n * Renderer.renderInline(tokens, options, env) -> String\n * - tokens (Array): list on block tokens to render\n * - options (Object): params of parser instance\n * - env (Object): additional data from parsed input (references, for example)\n *\n * The same as [[Renderer.render]], but for single token of `inline` type.\n **/\nRenderer.prototype.renderInline = function (tokens, options, env) {\n var type,\n result = '',\n rules = this.rules;\n\n for (var i = 0, len = tokens.length; i < len; i++) {\n type = tokens[i].type;\n\n if (typeof rules[type] !== 'undefined') {\n result += rules[type](tokens, i, options, env, this);\n } else {\n result += this.renderToken(tokens, i, options);\n }\n }\n\n return result;\n};\n\n\n/** internal\n * Renderer.renderInlineAsText(tokens, options, env) -> String\n * - tokens (Array): list on block tokens to render\n * - options (Object): params of parser instance\n * - env (Object): additional data from parsed input (references, for example)\n *\n * Special kludge for image `alt` attributes to conform CommonMark spec.\n * Don't try to use it! Spec requires to show `alt` content with stripped markup,\n * instead of simple escaping.\n **/\nRenderer.prototype.renderInlineAsText = function (tokens, options, env) {\n var result = '';\n\n for (var i = 0, len = tokens.length; i < len; i++) {\n if (tokens[i].type === 'text') {\n result += tokens[i].content;\n } else if (tokens[i].type === 'image') {\n result += this.renderInlineAsText(tokens[i].children, options, env);\n } else if (tokens[i].type === 'softbreak') {\n result += '\\n';\n }\n }\n\n return result;\n};\n\n\n/**\n * Renderer.render(tokens, options, env) -> String\n * - tokens (Array): list on block tokens to render\n * - options (Object): params of parser instance\n * - env (Object): additional data from parsed input (references, for example)\n *\n * Takes token stream and generates HTML. Probably, you will never need to call\n * this method directly.\n **/\nRenderer.prototype.render = function (tokens, options, env) {\n var i, len, type,\n result = '',\n rules = this.rules;\n\n for (i = 0, len = tokens.length; i < len; i++) {\n type = tokens[i].type;\n\n if (type === 'inline') {\n result += this.renderInline(tokens[i].children, options, env);\n } else if (typeof rules[type] !== 'undefined') {\n result += rules[tokens[i].type](tokens, i, options, env, this);\n } else {\n result += this.renderToken(tokens, i, options, env);\n }\n }\n\n return result;\n};\n\nmodule.exports = Renderer;\n", "/**\n * class Ruler\n *\n * Helper class, used by [[MarkdownIt#core]], [[MarkdownIt#block]] and\n * [[MarkdownIt#inline]] to manage sequences of functions (rules):\n *\n * - keep rules in defined order\n * - assign the name to each rule\n * - enable/disable rules\n * - add/replace rules\n * - allow assign rules to additional named chains (in the same)\n * - cacheing lists of active rules\n *\n * You will not need use this class directly until write plugins. For simple\n * rules control use [[MarkdownIt.disable]], [[MarkdownIt.enable]] and\n * [[MarkdownIt.use]].\n **/\n'use strict';\n\n\n/**\n * new Ruler()\n **/\nfunction Ruler() {\n // List of added rules. Each element is:\n //\n // {\n // name: XXX,\n // enabled: Boolean,\n // fn: Function(),\n // alt: [ name2, name3 ]\n // }\n //\n this.__rules__ = [];\n\n // Cached rule chains.\n //\n // First level - chain name, '' for default.\n // Second level - diginal anchor for fast filtering by charcodes.\n //\n this.__cache__ = null;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Helper methods, should not be used directly\n\n\n// Find rule index by name\n//\nRuler.prototype.__find__ = function (name) {\n for (var i = 0; i < this.__rules__.length; i++) {\n if (this.__rules__[i].name === name) {\n return i;\n }\n }\n return -1;\n};\n\n\n// Build rules lookup cache\n//\nRuler.prototype.__compile__ = function () {\n var self = this;\n var chains = [ '' ];\n\n // collect unique names\n self.__rules__.forEach(function (rule) {\n if (!rule.enabled) { return; }\n\n rule.alt.forEach(function (altName) {\n if (chains.indexOf(altName) < 0) {\n chains.push(altName);\n }\n });\n });\n\n self.__cache__ = {};\n\n chains.forEach(function (chain) {\n self.__cache__[chain] = [];\n self.__rules__.forEach(function (rule) {\n if (!rule.enabled) { return; }\n\n if (chain && rule.alt.indexOf(chain) < 0) { return; }\n\n self.__cache__[chain].push(rule.fn);\n });\n });\n};\n\n\n/**\n * Ruler.at(name, fn [, options])\n * - name (String): rule name to replace.\n * - fn (Function): new rule function.\n * - options (Object): new rule options (not mandatory).\n *\n * Replace rule by name with new function & options. Throws error if name not\n * found.\n *\n * ##### Options:\n *\n * - __alt__ - array with names of \"alternate\" chains.\n *\n * ##### Example\n *\n * Replace existing typographer replacement rule with new one:\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * md.core.ruler.at('replacements', function replace(state) {\n * //...\n * });\n * ```\n **/\nRuler.prototype.at = function (name, fn, options) {\n var index = this.__find__(name);\n var opt = options || {};\n\n if (index === -1) { throw new Error('Parser rule not found: ' + name); }\n\n this.__rules__[index].fn = fn;\n this.__rules__[index].alt = opt.alt || [];\n this.__cache__ = null;\n};\n\n\n/**\n * Ruler.before(beforeName, ruleName, fn [, options])\n * - beforeName (String): new rule will be added before this one.\n * - ruleName (String): name of added rule.\n * - fn (Function): rule function.\n * - options (Object): rule options (not mandatory).\n *\n * Add new rule to chain before one with given name. See also\n * [[Ruler.after]], [[Ruler.push]].\n *\n * ##### Options:\n *\n * - __alt__ - array with names of \"alternate\" chains.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * md.block.ruler.before('paragraph', 'my_rule', function replace(state) {\n * //...\n * });\n * ```\n **/\nRuler.prototype.before = function (beforeName, ruleName, fn, options) {\n var index = this.__find__(beforeName);\n var opt = options || {};\n\n if (index === -1) { throw new Error('Parser rule not found: ' + beforeName); }\n\n this.__rules__.splice(index, 0, {\n name: ruleName,\n enabled: true,\n fn: fn,\n alt: opt.alt || []\n });\n\n this.__cache__ = null;\n};\n\n\n/**\n * Ruler.after(afterName, ruleName, fn [, options])\n * - afterName (String): new rule will be added after this one.\n * - ruleName (String): name of added rule.\n * - fn (Function): rule function.\n * - options (Object): rule options (not mandatory).\n *\n * Add new rule to chain after one with given name. See also\n * [[Ruler.before]], [[Ruler.push]].\n *\n * ##### Options:\n *\n * - __alt__ - array with names of \"alternate\" chains.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * md.inline.ruler.after('text', 'my_rule', function replace(state) {\n * //...\n * });\n * ```\n **/\nRuler.prototype.after = function (afterName, ruleName, fn, options) {\n var index = this.__find__(afterName);\n var opt = options || {};\n\n if (index === -1) { throw new Error('Parser rule not found: ' + afterName); }\n\n this.__rules__.splice(index + 1, 0, {\n name: ruleName,\n enabled: true,\n fn: fn,\n alt: opt.alt || []\n });\n\n this.__cache__ = null;\n};\n\n/**\n * Ruler.push(ruleName, fn [, options])\n * - ruleName (String): name of added rule.\n * - fn (Function): rule function.\n * - options (Object): rule options (not mandatory).\n *\n * Push new rule to the end of chain. See also\n * [[Ruler.before]], [[Ruler.after]].\n *\n * ##### Options:\n *\n * - __alt__ - array with names of \"alternate\" chains.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * md.core.ruler.push('my_rule', function replace(state) {\n * //...\n * });\n * ```\n **/\nRuler.prototype.push = function (ruleName, fn, options) {\n var opt = options || {};\n\n this.__rules__.push({\n name: ruleName,\n enabled: true,\n fn: fn,\n alt: opt.alt || []\n });\n\n this.__cache__ = null;\n};\n\n\n/**\n * Ruler.enable(list [, ignoreInvalid]) -> Array\n * - list (String|Array): list of rule names to enable.\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\n *\n * Enable rules with given names. If any rule name not found - throw Error.\n * Errors can be disabled by second param.\n *\n * Returns list of found rule names (if no exception happened).\n *\n * See also [[Ruler.disable]], [[Ruler.enableOnly]].\n **/\nRuler.prototype.enable = function (list, ignoreInvalid) {\n if (!Array.isArray(list)) { list = [ list ]; }\n\n var result = [];\n\n // Search by name and enable\n list.forEach(function (name) {\n var idx = this.__find__(name);\n\n if (idx < 0) {\n if (ignoreInvalid) { return; }\n throw new Error('Rules manager: invalid rule name ' + name);\n }\n this.__rules__[idx].enabled = true;\n result.push(name);\n }, this);\n\n this.__cache__ = null;\n return result;\n};\n\n\n/**\n * Ruler.enableOnly(list [, ignoreInvalid])\n * - list (String|Array): list of rule names to enable (whitelist).\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\n *\n * Enable rules with given names, and disable everything else. If any rule name\n * not found - throw Error. Errors can be disabled by second param.\n *\n * See also [[Ruler.disable]], [[Ruler.enable]].\n **/\nRuler.prototype.enableOnly = function (list, ignoreInvalid) {\n if (!Array.isArray(list)) { list = [ list ]; }\n\n this.__rules__.forEach(function (rule) { rule.enabled = false; });\n\n this.enable(list, ignoreInvalid);\n};\n\n\n/**\n * Ruler.disable(list [, ignoreInvalid]) -> Array\n * - list (String|Array): list of rule names to disable.\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\n *\n * Disable rules with given names. If any rule name not found - throw Error.\n * Errors can be disabled by second param.\n *\n * Returns list of found rule names (if no exception happened).\n *\n * See also [[Ruler.enable]], [[Ruler.enableOnly]].\n **/\nRuler.prototype.disable = function (list, ignoreInvalid) {\n if (!Array.isArray(list)) { list = [ list ]; }\n\n var result = [];\n\n // Search by name and disable\n list.forEach(function (name) {\n var idx = this.__find__(name);\n\n if (idx < 0) {\n if (ignoreInvalid) { return; }\n throw new Error('Rules manager: invalid rule name ' + name);\n }\n this.__rules__[idx].enabled = false;\n result.push(name);\n }, this);\n\n this.__cache__ = null;\n return result;\n};\n\n\n/**\n * Ruler.getRules(chainName) -> Array\n *\n * Return array of active functions (rules) for given chain name. It analyzes\n * rules configuration, compiles caches if not exists and returns result.\n *\n * Default chain name is `''` (empty string). It can't be skipped. That's\n * done intentionally, to keep signature monomorphic for high speed.\n **/\nRuler.prototype.getRules = function (chainName) {\n if (this.__cache__ === null) {\n this.__compile__();\n }\n\n // Chain can be empty, if rules disabled. But we still have to return Array.\n return this.__cache__[chainName] || [];\n};\n\nmodule.exports = Ruler;\n", "// Normalize input string\n\n'use strict';\n\n\n// https://spec.commonmark.org/0.29/#line-ending\nvar NEWLINES_RE = /\\r\\n?|\\n/g;\nvar NULL_RE = /\\0/g;\n\n\nmodule.exports = function normalize(state) {\n var str;\n\n // Normalize newlines\n str = state.src.replace(NEWLINES_RE, '\\n');\n\n // Replace NULL characters\n str = str.replace(NULL_RE, '\\uFFFD');\n\n state.src = str;\n};\n", "'use strict';\n\n\nmodule.exports = function block(state) {\n var token;\n\n if (state.inlineMode) {\n token = new state.Token('inline', '', 0);\n token.content = state.src;\n token.map = [ 0, 1 ];\n token.children = [];\n state.tokens.push(token);\n } else {\n state.md.block.parse(state.src, state.md, state.env, state.tokens);\n }\n};\n", "'use strict';\n\nmodule.exports = function inline(state) {\n var tokens = state.tokens, tok, i, l;\n\n // Parse inlines\n for (i = 0, l = tokens.length; i < l; i++) {\n tok = tokens[i];\n if (tok.type === 'inline') {\n state.md.inline.parse(tok.content, state.md, state.env, tok.children);\n }\n }\n};\n", "// Replace link-like texts with link nodes.\n//\n// Currently restricted by `md.validateLink()` to http/https/ftp\n//\n'use strict';\n\n\nvar arrayReplaceAt = require('../common/utils').arrayReplaceAt;\n\n\nfunction isLinkOpen(str) {\n return /^\\s]/i.test(str);\n}\nfunction isLinkClose(str) {\n return /^<\\/a\\s*>/i.test(str);\n}\n\n\nmodule.exports = function linkify(state) {\n var i, j, l, tokens, token, currentToken, nodes, ln, text, pos, lastPos,\n level, htmlLinkLevel, url, fullUrl, urlText,\n blockTokens = state.tokens,\n links;\n\n if (!state.md.options.linkify) { return; }\n\n for (j = 0, l = blockTokens.length; j < l; j++) {\n if (blockTokens[j].type !== 'inline' ||\n !state.md.linkify.pretest(blockTokens[j].content)) {\n continue;\n }\n\n tokens = blockTokens[j].children;\n\n htmlLinkLevel = 0;\n\n // We scan from the end, to keep position when new tags added.\n // Use reversed logic in links start/end match\n for (i = tokens.length - 1; i >= 0; i--) {\n currentToken = tokens[i];\n\n // Skip content of markdown links\n if (currentToken.type === 'link_close') {\n i--;\n while (tokens[i].level !== currentToken.level && tokens[i].type !== 'link_open') {\n i--;\n }\n continue;\n }\n\n // Skip content of html tag links\n if (currentToken.type === 'html_inline') {\n if (isLinkOpen(currentToken.content) && htmlLinkLevel > 0) {\n htmlLinkLevel--;\n }\n if (isLinkClose(currentToken.content)) {\n htmlLinkLevel++;\n }\n }\n if (htmlLinkLevel > 0) { continue; }\n\n if (currentToken.type === 'text' && state.md.linkify.test(currentToken.content)) {\n\n text = currentToken.content;\n links = state.md.linkify.match(text);\n\n // Now split string to nodes\n nodes = [];\n level = currentToken.level;\n lastPos = 0;\n\n for (ln = 0; ln < links.length; ln++) {\n\n url = links[ln].url;\n fullUrl = state.md.normalizeLink(url);\n if (!state.md.validateLink(fullUrl)) { continue; }\n\n urlText = links[ln].text;\n\n // Linkifier might send raw hostnames like \"example.com\", where url\n // starts with domain name. So we prepend http:// in those cases,\n // and remove it afterwards.\n //\n if (!links[ln].schema) {\n urlText = state.md.normalizeLinkText('http://' + urlText).replace(/^http:\\/\\//, '');\n } else if (links[ln].schema === 'mailto:' && !/^mailto:/i.test(urlText)) {\n urlText = state.md.normalizeLinkText('mailto:' + urlText).replace(/^mailto:/, '');\n } else {\n urlText = state.md.normalizeLinkText(urlText);\n }\n\n pos = links[ln].index;\n\n if (pos > lastPos) {\n token = new state.Token('text', '', 0);\n token.content = text.slice(lastPos, pos);\n token.level = level;\n nodes.push(token);\n }\n\n token = new state.Token('link_open', 'a', 1);\n token.attrs = [ [ 'href', fullUrl ] ];\n token.level = level++;\n token.markup = 'linkify';\n token.info = 'auto';\n nodes.push(token);\n\n token = new state.Token('text', '', 0);\n token.content = urlText;\n token.level = level;\n nodes.push(token);\n\n token = new state.Token('link_close', 'a', -1);\n token.level = --level;\n token.markup = 'linkify';\n token.info = 'auto';\n nodes.push(token);\n\n lastPos = links[ln].lastIndex;\n }\n if (lastPos < text.length) {\n token = new state.Token('text', '', 0);\n token.content = text.slice(lastPos);\n token.level = level;\n nodes.push(token);\n }\n\n // replace current node\n blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes);\n }\n }\n }\n};\n", "// Simple typographic replacements\n//\n// (c) (C) \u2192 \u00A9\n// (tm) (TM) \u2192 \u2122\n// (r) (R) \u2192 \u00AE\n// +- \u2192 \u00B1\n// (p) (P) -> \u00A7\n// ... \u2192 \u2026 (also ?.... \u2192 ?.., !.... \u2192 !..)\n// ???????? \u2192 ???, !!!!! \u2192 !!!, `,,` \u2192 `,`\n// -- \u2192 –, --- \u2192 —\n//\n'use strict';\n\n// TODO:\n// - fractionals 1/2, 1/4, 3/4 -> \u00BD, \u00BC, \u00BE\n// - miltiplication 2 x 4 -> 2 \u00D7 4\n\nvar RARE_RE = /\\+-|\\.\\.|\\?\\?\\?\\?|!!!!|,,|--/;\n\n// Workaround for phantomjs - need regex without /g flag,\n// or root check will fail every second time\nvar SCOPED_ABBR_TEST_RE = /\\((c|tm|r|p)\\)/i;\n\nvar SCOPED_ABBR_RE = /\\((c|tm|r|p)\\)/ig;\nvar SCOPED_ABBR = {\n c: '\u00A9',\n r: '\u00AE',\n p: '\u00A7',\n tm: '\u2122'\n};\n\nfunction replaceFn(match, name) {\n return SCOPED_ABBR[name.toLowerCase()];\n}\n\nfunction replace_scoped(inlineTokens) {\n var i, token, inside_autolink = 0;\n\n for (i = inlineTokens.length - 1; i >= 0; i--) {\n token = inlineTokens[i];\n\n if (token.type === 'text' && !inside_autolink) {\n token.content = token.content.replace(SCOPED_ABBR_RE, replaceFn);\n }\n\n if (token.type === 'link_open' && token.info === 'auto') {\n inside_autolink--;\n }\n\n if (token.type === 'link_close' && token.info === 'auto') {\n inside_autolink++;\n }\n }\n}\n\nfunction replace_rare(inlineTokens) {\n var i, token, inside_autolink = 0;\n\n for (i = inlineTokens.length - 1; i >= 0; i--) {\n token = inlineTokens[i];\n\n if (token.type === 'text' && !inside_autolink) {\n if (RARE_RE.test(token.content)) {\n token.content = token.content\n .replace(/\\+-/g, '\u00B1')\n // .., ..., ....... -> \u2026\n // but ?..... & !..... -> ?.. & !..\n .replace(/\\.{2,}/g, '\u2026').replace(/([?!])\u2026/g, '$1..')\n .replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',')\n // em-dash\n .replace(/(^|[^-])---(?=[^-]|$)/mg, '$1\\u2014')\n // en-dash\n .replace(/(^|\\s)--(?=\\s|$)/mg, '$1\\u2013')\n .replace(/(^|[^-\\s])--(?=[^-\\s]|$)/mg, '$1\\u2013');\n }\n }\n\n if (token.type === 'link_open' && token.info === 'auto') {\n inside_autolink--;\n }\n\n if (token.type === 'link_close' && token.info === 'auto') {\n inside_autolink++;\n }\n }\n}\n\n\nmodule.exports = function replace(state) {\n var blkIdx;\n\n if (!state.md.options.typographer) { return; }\n\n for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {\n\n if (state.tokens[blkIdx].type !== 'inline') { continue; }\n\n if (SCOPED_ABBR_TEST_RE.test(state.tokens[blkIdx].content)) {\n replace_scoped(state.tokens[blkIdx].children);\n }\n\n if (RARE_RE.test(state.tokens[blkIdx].content)) {\n replace_rare(state.tokens[blkIdx].children);\n }\n\n }\n};\n", "// Convert straight quotation marks to typographic ones\n//\n'use strict';\n\n\nvar isWhiteSpace = require('../common/utils').isWhiteSpace;\nvar isPunctChar = require('../common/utils').isPunctChar;\nvar isMdAsciiPunct = require('../common/utils').isMdAsciiPunct;\n\nvar QUOTE_TEST_RE = /['\"]/;\nvar QUOTE_RE = /['\"]/g;\nvar APOSTROPHE = '\\u2019'; /* \u2019 */\n\n\nfunction replaceAt(str, index, ch) {\n return str.substr(0, index) + ch + str.substr(index + 1);\n}\n\nfunction process_inlines(tokens, state) {\n var i, token, text, t, pos, max, thisLevel, item, lastChar, nextChar,\n isLastPunctChar, isNextPunctChar, isLastWhiteSpace, isNextWhiteSpace,\n canOpen, canClose, j, isSingle, stack, openQuote, closeQuote;\n\n stack = [];\n\n for (i = 0; i < tokens.length; i++) {\n token = tokens[i];\n\n thisLevel = tokens[i].level;\n\n for (j = stack.length - 1; j >= 0; j--) {\n if (stack[j].level <= thisLevel) { break; }\n }\n stack.length = j + 1;\n\n if (token.type !== 'text') { continue; }\n\n text = token.content;\n pos = 0;\n max = text.length;\n\n /*eslint no-labels:0,block-scoped-var:0*/\n OUTER:\n while (pos < max) {\n QUOTE_RE.lastIndex = pos;\n t = QUOTE_RE.exec(text);\n if (!t) { break; }\n\n canOpen = canClose = true;\n pos = t.index + 1;\n isSingle = (t[0] === \"'\");\n\n // Find previous character,\n // default to space if it's the beginning of the line\n //\n lastChar = 0x20;\n\n if (t.index - 1 >= 0) {\n lastChar = text.charCodeAt(t.index - 1);\n } else {\n for (j = i - 1; j >= 0; j--) {\n if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break; // lastChar defaults to 0x20\n if (!tokens[j].content) continue; // should skip all tokens except 'text', 'html_inline' or 'code_inline'\n\n lastChar = tokens[j].content.charCodeAt(tokens[j].content.length - 1);\n break;\n }\n }\n\n // Find next character,\n // default to space if it's the end of the line\n //\n nextChar = 0x20;\n\n if (pos < max) {\n nextChar = text.charCodeAt(pos);\n } else {\n for (j = i + 1; j < tokens.length; j++) {\n if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break; // nextChar defaults to 0x20\n if (!tokens[j].content) continue; // should skip all tokens except 'text', 'html_inline' or 'code_inline'\n\n nextChar = tokens[j].content.charCodeAt(0);\n break;\n }\n }\n\n isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar));\n isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar));\n\n isLastWhiteSpace = isWhiteSpace(lastChar);\n isNextWhiteSpace = isWhiteSpace(nextChar);\n\n if (isNextWhiteSpace) {\n canOpen = false;\n } else if (isNextPunctChar) {\n if (!(isLastWhiteSpace || isLastPunctChar)) {\n canOpen = false;\n }\n }\n\n if (isLastWhiteSpace) {\n canClose = false;\n } else if (isLastPunctChar) {\n if (!(isNextWhiteSpace || isNextPunctChar)) {\n canClose = false;\n }\n }\n\n if (nextChar === 0x22 /* \" */ && t[0] === '\"') {\n if (lastChar >= 0x30 /* 0 */ && lastChar <= 0x39 /* 9 */) {\n // special case: 1\"\" - count first quote as an inch\n canClose = canOpen = false;\n }\n }\n\n if (canOpen && canClose) {\n // Replace quotes in the middle of punctuation sequence, but not\n // in the middle of the words, i.e.:\n //\n // 1. foo \" bar \" baz - not replaced\n // 2. foo-\"-bar-\"-baz - replaced\n // 3. foo\"bar\"baz - not replaced\n //\n canOpen = isLastPunctChar;\n canClose = isNextPunctChar;\n }\n\n if (!canOpen && !canClose) {\n // middle of word\n if (isSingle) {\n token.content = replaceAt(token.content, t.index, APOSTROPHE);\n }\n continue;\n }\n\n if (canClose) {\n // this could be a closing quote, rewind the stack to get a match\n for (j = stack.length - 1; j >= 0; j--) {\n item = stack[j];\n if (stack[j].level < thisLevel) { break; }\n if (item.single === isSingle && stack[j].level === thisLevel) {\n item = stack[j];\n\n if (isSingle) {\n openQuote = state.md.options.quotes[2];\n closeQuote = state.md.options.quotes[3];\n } else {\n openQuote = state.md.options.quotes[0];\n closeQuote = state.md.options.quotes[1];\n }\n\n // replace token.content *before* tokens[item.token].content,\n // because, if they are pointing at the same token, replaceAt\n // could mess up indices when quote length != 1\n token.content = replaceAt(token.content, t.index, closeQuote);\n tokens[item.token].content = replaceAt(\n tokens[item.token].content, item.pos, openQuote);\n\n pos += closeQuote.length - 1;\n if (item.token === i) { pos += openQuote.length - 1; }\n\n text = token.content;\n max = text.length;\n\n stack.length = j;\n continue OUTER;\n }\n }\n }\n\n if (canOpen) {\n stack.push({\n token: i,\n pos: t.index,\n single: isSingle,\n level: thisLevel\n });\n } else if (canClose && isSingle) {\n token.content = replaceAt(token.content, t.index, APOSTROPHE);\n }\n }\n }\n}\n\n\nmodule.exports = function smartquotes(state) {\n /*eslint max-depth:0*/\n var blkIdx;\n\n if (!state.md.options.typographer) { return; }\n\n for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {\n\n if (state.tokens[blkIdx].type !== 'inline' ||\n !QUOTE_TEST_RE.test(state.tokens[blkIdx].content)) {\n continue;\n }\n\n process_inlines(state.tokens[blkIdx].children, state);\n }\n};\n", "// Token class\n\n'use strict';\n\n\n/**\n * class Token\n **/\n\n/**\n * new Token(type, tag, nesting)\n *\n * Create new token and fill passed properties.\n **/\nfunction Token(type, tag, nesting) {\n /**\n * Token#type -> String\n *\n * Type of the token (string, e.g. \"paragraph_open\")\n **/\n this.type = type;\n\n /**\n * Token#tag -> String\n *\n * html tag name, e.g. \"p\"\n **/\n this.tag = tag;\n\n /**\n * Token#attrs -> Array\n *\n * Html attributes. Format: `[ [ name1, value1 ], [ name2, value2 ] ]`\n **/\n this.attrs = null;\n\n /**\n * Token#map -> Array\n *\n * Source map info. Format: `[ line_begin, line_end ]`\n **/\n this.map = null;\n\n /**\n * Token#nesting -> Number\n *\n * Level change (number in {-1, 0, 1} set), where:\n *\n * - `1` means the tag is opening\n * - `0` means the tag is self-closing\n * - `-1` means the tag is closing\n **/\n this.nesting = nesting;\n\n /**\n * Token#level -> Number\n *\n * nesting level, the same as `state.level`\n **/\n this.level = 0;\n\n /**\n * Token#children -> Array\n *\n * An array of child nodes (inline and img tokens)\n **/\n this.children = null;\n\n /**\n * Token#content -> String\n *\n * In a case of self-closing tag (code, html, fence, etc.),\n * it has contents of this tag.\n **/\n this.content = '';\n\n /**\n * Token#markup -> String\n *\n * '*' or '_' for emphasis, fence string for fence, etc.\n **/\n this.markup = '';\n\n /**\n * Token#info -> String\n *\n * Additional information:\n *\n * - Info string for \"fence\" tokens\n * - The value \"auto\" for autolink \"link_open\" and \"link_close\" tokens\n * - The string value of the item marker for ordered-list \"list_item_open\" tokens\n **/\n this.info = '';\n\n /**\n * Token#meta -> Object\n *\n * A place for plugins to store an arbitrary data\n **/\n this.meta = null;\n\n /**\n * Token#block -> Boolean\n *\n * True for block-level tokens, false for inline tokens.\n * Used in renderer to calculate line breaks\n **/\n this.block = false;\n\n /**\n * Token#hidden -> Boolean\n *\n * If it's true, ignore this element when rendering. Used for tight lists\n * to hide paragraphs.\n **/\n this.hidden = false;\n}\n\n\n/**\n * Token.attrIndex(name) -> Number\n *\n * Search attribute index by name.\n **/\nToken.prototype.attrIndex = function attrIndex(name) {\n var attrs, i, len;\n\n if (!this.attrs) { return -1; }\n\n attrs = this.attrs;\n\n for (i = 0, len = attrs.length; i < len; i++) {\n if (attrs[i][0] === name) { return i; }\n }\n return -1;\n};\n\n\n/**\n * Token.attrPush(attrData)\n *\n * Add `[ name, value ]` attribute to list. Init attrs if necessary\n **/\nToken.prototype.attrPush = function attrPush(attrData) {\n if (this.attrs) {\n this.attrs.push(attrData);\n } else {\n this.attrs = [ attrData ];\n }\n};\n\n\n/**\n * Token.attrSet(name, value)\n *\n * Set `name` attribute to `value`. Override old value if exists.\n **/\nToken.prototype.attrSet = function attrSet(name, value) {\n var idx = this.attrIndex(name),\n attrData = [ name, value ];\n\n if (idx < 0) {\n this.attrPush(attrData);\n } else {\n this.attrs[idx] = attrData;\n }\n};\n\n\n/**\n * Token.attrGet(name)\n *\n * Get the value of attribute `name`, or null if it does not exist.\n **/\nToken.prototype.attrGet = function attrGet(name) {\n var idx = this.attrIndex(name), value = null;\n if (idx >= 0) {\n value = this.attrs[idx][1];\n }\n return value;\n};\n\n\n/**\n * Token.attrJoin(name, value)\n *\n * Join value to existing attribute via space. Or create new attribute if not\n * exists. Useful to operate with token classes.\n **/\nToken.prototype.attrJoin = function attrJoin(name, value) {\n var idx = this.attrIndex(name);\n\n if (idx < 0) {\n this.attrPush([ name, value ]);\n } else {\n this.attrs[idx][1] = this.attrs[idx][1] + ' ' + value;\n }\n};\n\n\nmodule.exports = Token;\n", "// Core state object\n//\n'use strict';\n\nvar Token = require('../token');\n\n\nfunction StateCore(src, md, env) {\n this.src = src;\n this.env = env;\n this.tokens = [];\n this.inlineMode = false;\n this.md = md; // link to parser instance\n}\n\n// re-export Token class to use in core rules\nStateCore.prototype.Token = Token;\n\n\nmodule.exports = StateCore;\n", "/** internal\n * class Core\n *\n * Top-level rules executor. Glues block/inline parsers and does intermediate\n * transformations.\n **/\n'use strict';\n\n\nvar Ruler = require('./ruler');\n\n\nvar _rules = [\n [ 'normalize', require('./rules_core/normalize') ],\n [ 'block', require('./rules_core/block') ],\n [ 'inline', require('./rules_core/inline') ],\n [ 'linkify', require('./rules_core/linkify') ],\n [ 'replacements', require('./rules_core/replacements') ],\n [ 'smartquotes', require('./rules_core/smartquotes') ]\n];\n\n\n/**\n * new Core()\n **/\nfunction Core() {\n /**\n * Core#ruler -> Ruler\n *\n * [[Ruler]] instance. Keep configuration of core rules.\n **/\n this.ruler = new Ruler();\n\n for (var i = 0; i < _rules.length; i++) {\n this.ruler.push(_rules[i][0], _rules[i][1]);\n }\n}\n\n\n/**\n * Core.process(state)\n *\n * Executes core chain rules.\n **/\nCore.prototype.process = function (state) {\n var i, l, rules;\n\n rules = this.ruler.getRules('');\n\n for (i = 0, l = rules.length; i < l; i++) {\n rules[i](state);\n }\n};\n\nCore.prototype.State = require('./rules_core/state_core');\n\n\nmodule.exports = Core;\n", "// GFM table, https://github.github.com/gfm/#tables-extension-\n\n'use strict';\n\nvar isSpace = require('../common/utils').isSpace;\n\n\nfunction getLine(state, line) {\n var pos = state.bMarks[line] + state.tShift[line],\n max = state.eMarks[line];\n\n return state.src.substr(pos, max - pos);\n}\n\nfunction escapedSplit(str) {\n var result = [],\n pos = 0,\n max = str.length,\n ch,\n isEscaped = false,\n lastPos = 0,\n current = '';\n\n ch = str.charCodeAt(pos);\n\n while (pos < max) {\n if (ch === 0x7c/* | */) {\n if (!isEscaped) {\n // pipe separating cells, '|'\n result.push(current + str.substring(lastPos, pos));\n current = '';\n lastPos = pos + 1;\n } else {\n // escaped pipe, '\\|'\n current += str.substring(lastPos, pos - 1);\n lastPos = pos;\n }\n }\n\n isEscaped = (ch === 0x5c/* \\ */);\n pos++;\n\n ch = str.charCodeAt(pos);\n }\n\n result.push(current + str.substring(lastPos));\n\n return result;\n}\n\n\nmodule.exports = function table(state, startLine, endLine, silent) {\n var ch, lineText, pos, i, l, nextLine, columns, columnCount, token,\n aligns, t, tableLines, tbodyLines, oldParentType, terminate,\n terminatorRules, firstCh, secondCh;\n\n // should have at least two lines\n if (startLine + 2 > endLine) { return false; }\n\n nextLine = startLine + 1;\n\n if (state.sCount[nextLine] < state.blkIndent) { return false; }\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[nextLine] - state.blkIndent >= 4) { return false; }\n\n // first character of the second line should be '|', '-', ':',\n // and no other characters are allowed but spaces;\n // basically, this is the equivalent of /^[-:|][-:|\\s]*$/ regexp\n\n pos = state.bMarks[nextLine] + state.tShift[nextLine];\n if (pos >= state.eMarks[nextLine]) { return false; }\n\n firstCh = state.src.charCodeAt(pos++);\n if (firstCh !== 0x7C/* | */ && firstCh !== 0x2D/* - */ && firstCh !== 0x3A/* : */) { return false; }\n\n if (pos >= state.eMarks[nextLine]) { return false; }\n\n secondCh = state.src.charCodeAt(pos++);\n if (secondCh !== 0x7C/* | */ && secondCh !== 0x2D/* - */ && secondCh !== 0x3A/* : */ && !isSpace(secondCh)) {\n return false;\n }\n\n // if first character is '-', then second character must not be a space\n // (due to parsing ambiguity with list)\n if (firstCh === 0x2D/* - */ && isSpace(secondCh)) { return false; }\n\n while (pos < state.eMarks[nextLine]) {\n ch = state.src.charCodeAt(pos);\n\n if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */ && !isSpace(ch)) { return false; }\n\n pos++;\n }\n\n lineText = getLine(state, startLine + 1);\n\n columns = lineText.split('|');\n aligns = [];\n for (i = 0; i < columns.length; i++) {\n t = columns[i].trim();\n if (!t) {\n // allow empty columns before and after table, but not in between columns;\n // e.g. allow ` |---| `, disallow ` ---||--- `\n if (i === 0 || i === columns.length - 1) {\n continue;\n } else {\n return false;\n }\n }\n\n if (!/^:?-+:?$/.test(t)) { return false; }\n if (t.charCodeAt(t.length - 1) === 0x3A/* : */) {\n aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right');\n } else if (t.charCodeAt(0) === 0x3A/* : */) {\n aligns.push('left');\n } else {\n aligns.push('');\n }\n }\n\n lineText = getLine(state, startLine).trim();\n if (lineText.indexOf('|') === -1) { return false; }\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n columns = escapedSplit(lineText);\n if (columns.length && columns[0] === '') columns.shift();\n if (columns.length && columns[columns.length - 1] === '') columns.pop();\n\n // header row will define an amount of columns in the entire table,\n // and align row should be exactly the same (the rest of the rows can differ)\n columnCount = columns.length;\n if (columnCount === 0 || columnCount !== aligns.length) { return false; }\n\n if (silent) { return true; }\n\n oldParentType = state.parentType;\n state.parentType = 'table';\n\n // use 'blockquote' lists for termination because it's\n // the most similar to tables\n terminatorRules = state.md.block.ruler.getRules('blockquote');\n\n token = state.push('table_open', 'table', 1);\n token.map = tableLines = [ startLine, 0 ];\n\n token = state.push('thead_open', 'thead', 1);\n token.map = [ startLine, startLine + 1 ];\n\n token = state.push('tr_open', 'tr', 1);\n token.map = [ startLine, startLine + 1 ];\n\n for (i = 0; i < columns.length; i++) {\n token = state.push('th_open', 'th', 1);\n if (aligns[i]) {\n token.attrs = [ [ 'style', 'text-align:' + aligns[i] ] ];\n }\n\n token = state.push('inline', '', 0);\n token.content = columns[i].trim();\n token.children = [];\n\n token = state.push('th_close', 'th', -1);\n }\n\n token = state.push('tr_close', 'tr', -1);\n token = state.push('thead_close', 'thead', -1);\n\n for (nextLine = startLine + 2; nextLine < endLine; nextLine++) {\n if (state.sCount[nextLine] < state.blkIndent) { break; }\n\n terminate = false;\n for (i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n\n if (terminate) { break; }\n lineText = getLine(state, nextLine).trim();\n if (!lineText) { break; }\n if (state.sCount[nextLine] - state.blkIndent >= 4) { break; }\n columns = escapedSplit(lineText);\n if (columns.length && columns[0] === '') columns.shift();\n if (columns.length && columns[columns.length - 1] === '') columns.pop();\n\n if (nextLine === startLine + 2) {\n token = state.push('tbody_open', 'tbody', 1);\n token.map = tbodyLines = [ startLine + 2, 0 ];\n }\n\n token = state.push('tr_open', 'tr', 1);\n token.map = [ nextLine, nextLine + 1 ];\n\n for (i = 0; i < columnCount; i++) {\n token = state.push('td_open', 'td', 1);\n if (aligns[i]) {\n token.attrs = [ [ 'style', 'text-align:' + aligns[i] ] ];\n }\n\n token = state.push('inline', '', 0);\n token.content = columns[i] ? columns[i].trim() : '';\n token.children = [];\n\n token = state.push('td_close', 'td', -1);\n }\n token = state.push('tr_close', 'tr', -1);\n }\n\n if (tbodyLines) {\n token = state.push('tbody_close', 'tbody', -1);\n tbodyLines[1] = nextLine;\n }\n\n token = state.push('table_close', 'table', -1);\n tableLines[1] = nextLine;\n\n state.parentType = oldParentType;\n state.line = nextLine;\n return true;\n};\n", "// Code block (4 spaces padded)\n\n'use strict';\n\n\nmodule.exports = function code(state, startLine, endLine/*, silent*/) {\n var nextLine, last, token;\n\n if (state.sCount[startLine] - state.blkIndent < 4) { return false; }\n\n last = nextLine = startLine + 1;\n\n while (nextLine < endLine) {\n if (state.isEmpty(nextLine)) {\n nextLine++;\n continue;\n }\n\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n nextLine++;\n last = nextLine;\n continue;\n }\n break;\n }\n\n state.line = last;\n\n token = state.push('code_block', 'code', 0);\n token.content = state.getLines(startLine, last, 4 + state.blkIndent, false) + '\\n';\n token.map = [ startLine, state.line ];\n\n return true;\n};\n", "// fences (``` lang, ~~~ lang)\n\n'use strict';\n\n\nmodule.exports = function fence(state, startLine, endLine, silent) {\n var marker, len, params, nextLine, mem, token, markup,\n haveEndMarker = false,\n pos = state.bMarks[startLine] + state.tShift[startLine],\n max = state.eMarks[startLine];\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n if (pos + 3 > max) { return false; }\n\n marker = state.src.charCodeAt(pos);\n\n if (marker !== 0x7E/* ~ */ && marker !== 0x60 /* ` */) {\n return false;\n }\n\n // scan marker length\n mem = pos;\n pos = state.skipChars(pos, marker);\n\n len = pos - mem;\n\n if (len < 3) { return false; }\n\n markup = state.src.slice(mem, pos);\n params = state.src.slice(pos, max);\n\n if (marker === 0x60 /* ` */) {\n if (params.indexOf(String.fromCharCode(marker)) >= 0) {\n return false;\n }\n }\n\n // Since start is found, we can report success here in validation mode\n if (silent) { return true; }\n\n // search end of block\n nextLine = startLine;\n\n for (;;) {\n nextLine++;\n if (nextLine >= endLine) {\n // unclosed block should be autoclosed by end of document.\n // also block seems to be autoclosed by end of parent\n break;\n }\n\n pos = mem = state.bMarks[nextLine] + state.tShift[nextLine];\n max = state.eMarks[nextLine];\n\n if (pos < max && state.sCount[nextLine] < state.blkIndent) {\n // non-empty line with negative indent should stop the list:\n // - ```\n // test\n break;\n }\n\n if (state.src.charCodeAt(pos) !== marker) { continue; }\n\n if (state.sCount[nextLine] - state.blkIndent >= 4) {\n // closing fence should be indented less than 4 spaces\n continue;\n }\n\n pos = state.skipChars(pos, marker);\n\n // closing code fence must be at least as long as the opening one\n if (pos - mem < len) { continue; }\n\n // make sure tail has spaces only\n pos = state.skipSpaces(pos);\n\n if (pos < max) { continue; }\n\n haveEndMarker = true;\n // found!\n break;\n }\n\n // If a fence has heading spaces, they should be removed from its inner block\n len = state.sCount[startLine];\n\n state.line = nextLine + (haveEndMarker ? 1 : 0);\n\n token = state.push('fence', 'code', 0);\n token.info = params;\n token.content = state.getLines(startLine + 1, nextLine, len, true);\n token.markup = markup;\n token.map = [ startLine, state.line ];\n\n return true;\n};\n", "// Block quotes\n\n'use strict';\n\nvar isSpace = require('../common/utils').isSpace;\n\n\nmodule.exports = function blockquote(state, startLine, endLine, silent) {\n var adjustTab,\n ch,\n i,\n initial,\n l,\n lastLineEmpty,\n lines,\n nextLine,\n offset,\n oldBMarks,\n oldBSCount,\n oldIndent,\n oldParentType,\n oldSCount,\n oldTShift,\n spaceAfterMarker,\n terminate,\n terminatorRules,\n token,\n isOutdented,\n oldLineMax = state.lineMax,\n pos = state.bMarks[startLine] + state.tShift[startLine],\n max = state.eMarks[startLine];\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n // check the block quote marker\n if (state.src.charCodeAt(pos++) !== 0x3E/* > */) { return false; }\n\n // we know that it's going to be a valid blockquote,\n // so no point trying to find the end of it in silent mode\n if (silent) { return true; }\n\n // set offset past spaces and \">\"\n initial = offset = state.sCount[startLine] + 1;\n\n // skip one optional space after '>'\n if (state.src.charCodeAt(pos) === 0x20 /* space */) {\n // ' > test '\n // ^ -- position start of line here:\n pos++;\n initial++;\n offset++;\n adjustTab = false;\n spaceAfterMarker = true;\n } else if (state.src.charCodeAt(pos) === 0x09 /* tab */) {\n spaceAfterMarker = true;\n\n if ((state.bsCount[startLine] + offset) % 4 === 3) {\n // ' >\\t test '\n // ^ -- position start of line here (tab has width===1)\n pos++;\n initial++;\n offset++;\n adjustTab = false;\n } else {\n // ' >\\t test '\n // ^ -- position start of line here + shift bsCount slightly\n // to make extra space appear\n adjustTab = true;\n }\n } else {\n spaceAfterMarker = false;\n }\n\n oldBMarks = [ state.bMarks[startLine] ];\n state.bMarks[startLine] = pos;\n\n while (pos < max) {\n ch = state.src.charCodeAt(pos);\n\n if (isSpace(ch)) {\n if (ch === 0x09) {\n offset += 4 - (offset + state.bsCount[startLine] + (adjustTab ? 1 : 0)) % 4;\n } else {\n offset++;\n }\n } else {\n break;\n }\n\n pos++;\n }\n\n oldBSCount = [ state.bsCount[startLine] ];\n state.bsCount[startLine] = state.sCount[startLine] + 1 + (spaceAfterMarker ? 1 : 0);\n\n lastLineEmpty = pos >= max;\n\n oldSCount = [ state.sCount[startLine] ];\n state.sCount[startLine] = offset - initial;\n\n oldTShift = [ state.tShift[startLine] ];\n state.tShift[startLine] = pos - state.bMarks[startLine];\n\n terminatorRules = state.md.block.ruler.getRules('blockquote');\n\n oldParentType = state.parentType;\n state.parentType = 'blockquote';\n\n // Search the end of the block\n //\n // Block ends with either:\n // 1. an empty line outside:\n // ```\n // > test\n //\n // ```\n // 2. an empty line inside:\n // ```\n // >\n // test\n // ```\n // 3. another tag:\n // ```\n // > test\n // - - -\n // ```\n for (nextLine = startLine + 1; nextLine < endLine; nextLine++) {\n // check if it's outdented, i.e. it's inside list item and indented\n // less than said list item:\n //\n // ```\n // 1. anything\n // > current blockquote\n // 2. checking this line\n // ```\n isOutdented = state.sCount[nextLine] < state.blkIndent;\n\n pos = state.bMarks[nextLine] + state.tShift[nextLine];\n max = state.eMarks[nextLine];\n\n if (pos >= max) {\n // Case 1: line is not inside the blockquote, and this line is empty.\n break;\n }\n\n if (state.src.charCodeAt(pos++) === 0x3E/* > */ && !isOutdented) {\n // This line is inside the blockquote.\n\n // set offset past spaces and \">\"\n initial = offset = state.sCount[nextLine] + 1;\n\n // skip one optional space after '>'\n if (state.src.charCodeAt(pos) === 0x20 /* space */) {\n // ' > test '\n // ^ -- position start of line here:\n pos++;\n initial++;\n offset++;\n adjustTab = false;\n spaceAfterMarker = true;\n } else if (state.src.charCodeAt(pos) === 0x09 /* tab */) {\n spaceAfterMarker = true;\n\n if ((state.bsCount[nextLine] + offset) % 4 === 3) {\n // ' >\\t test '\n // ^ -- position start of line here (tab has width===1)\n pos++;\n initial++;\n offset++;\n adjustTab = false;\n } else {\n // ' >\\t test '\n // ^ -- position start of line here + shift bsCount slightly\n // to make extra space appear\n adjustTab = true;\n }\n } else {\n spaceAfterMarker = false;\n }\n\n oldBMarks.push(state.bMarks[nextLine]);\n state.bMarks[nextLine] = pos;\n\n while (pos < max) {\n ch = state.src.charCodeAt(pos);\n\n if (isSpace(ch)) {\n if (ch === 0x09) {\n offset += 4 - (offset + state.bsCount[nextLine] + (adjustTab ? 1 : 0)) % 4;\n } else {\n offset++;\n }\n } else {\n break;\n }\n\n pos++;\n }\n\n lastLineEmpty = pos >= max;\n\n oldBSCount.push(state.bsCount[nextLine]);\n state.bsCount[nextLine] = state.sCount[nextLine] + 1 + (spaceAfterMarker ? 1 : 0);\n\n oldSCount.push(state.sCount[nextLine]);\n state.sCount[nextLine] = offset - initial;\n\n oldTShift.push(state.tShift[nextLine]);\n state.tShift[nextLine] = pos - state.bMarks[nextLine];\n continue;\n }\n\n // Case 2: line is not inside the blockquote, and the last line was empty.\n if (lastLineEmpty) { break; }\n\n // Case 3: another tag found.\n terminate = false;\n for (i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n\n if (terminate) {\n // Quirk to enforce \"hard termination mode\" for paragraphs;\n // normally if you call `tokenize(state, startLine, nextLine)`,\n // paragraphs will look below nextLine for paragraph continuation,\n // but if blockquote is terminated by another tag, they shouldn't\n state.lineMax = nextLine;\n\n if (state.blkIndent !== 0) {\n // state.blkIndent was non-zero, we now set it to zero,\n // so we need to re-calculate all offsets to appear as\n // if indent wasn't changed\n oldBMarks.push(state.bMarks[nextLine]);\n oldBSCount.push(state.bsCount[nextLine]);\n oldTShift.push(state.tShift[nextLine]);\n oldSCount.push(state.sCount[nextLine]);\n state.sCount[nextLine] -= state.blkIndent;\n }\n\n break;\n }\n\n oldBMarks.push(state.bMarks[nextLine]);\n oldBSCount.push(state.bsCount[nextLine]);\n oldTShift.push(state.tShift[nextLine]);\n oldSCount.push(state.sCount[nextLine]);\n\n // A negative indentation means that this is a paragraph continuation\n //\n state.sCount[nextLine] = -1;\n }\n\n oldIndent = state.blkIndent;\n state.blkIndent = 0;\n\n token = state.push('blockquote_open', 'blockquote', 1);\n token.markup = '>';\n token.map = lines = [ startLine, 0 ];\n\n state.md.block.tokenize(state, startLine, nextLine);\n\n token = state.push('blockquote_close', 'blockquote', -1);\n token.markup = '>';\n\n state.lineMax = oldLineMax;\n state.parentType = oldParentType;\n lines[1] = state.line;\n\n // Restore original tShift; this might not be necessary since the parser\n // has already been here, but just to make sure we can do that.\n for (i = 0; i < oldTShift.length; i++) {\n state.bMarks[i + startLine] = oldBMarks[i];\n state.tShift[i + startLine] = oldTShift[i];\n state.sCount[i + startLine] = oldSCount[i];\n state.bsCount[i + startLine] = oldBSCount[i];\n }\n state.blkIndent = oldIndent;\n\n return true;\n};\n", "// Horizontal rule\n\n'use strict';\n\nvar isSpace = require('../common/utils').isSpace;\n\n\nmodule.exports = function hr(state, startLine, endLine, silent) {\n var marker, cnt, ch, token,\n pos = state.bMarks[startLine] + state.tShift[startLine],\n max = state.eMarks[startLine];\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n marker = state.src.charCodeAt(pos++);\n\n // Check hr marker\n if (marker !== 0x2A/* * */ &&\n marker !== 0x2D/* - */ &&\n marker !== 0x5F/* _ */) {\n return false;\n }\n\n // markers can be mixed with spaces, but there should be at least 3 of them\n\n cnt = 1;\n while (pos < max) {\n ch = state.src.charCodeAt(pos++);\n if (ch !== marker && !isSpace(ch)) { return false; }\n if (ch === marker) { cnt++; }\n }\n\n if (cnt < 3) { return false; }\n\n if (silent) { return true; }\n\n state.line = startLine + 1;\n\n token = state.push('hr', 'hr', 0);\n token.map = [ startLine, state.line ];\n token.markup = Array(cnt + 1).join(String.fromCharCode(marker));\n\n return true;\n};\n", "// Lists\n\n'use strict';\n\nvar isSpace = require('../common/utils').isSpace;\n\n\n// Search `[-+*][\\n ]`, returns next pos after marker on success\n// or -1 on fail.\nfunction skipBulletListMarker(state, startLine) {\n var marker, pos, max, ch;\n\n pos = state.bMarks[startLine] + state.tShift[startLine];\n max = state.eMarks[startLine];\n\n marker = state.src.charCodeAt(pos++);\n // Check bullet\n if (marker !== 0x2A/* * */ &&\n marker !== 0x2D/* - */ &&\n marker !== 0x2B/* + */) {\n return -1;\n }\n\n if (pos < max) {\n ch = state.src.charCodeAt(pos);\n\n if (!isSpace(ch)) {\n // \" -test \" - is not a list item\n return -1;\n }\n }\n\n return pos;\n}\n\n// Search `\\d+[.)][\\n ]`, returns next pos after marker on success\n// or -1 on fail.\nfunction skipOrderedListMarker(state, startLine) {\n var ch,\n start = state.bMarks[startLine] + state.tShift[startLine],\n pos = start,\n max = state.eMarks[startLine];\n\n // List marker should have at least 2 chars (digit + dot)\n if (pos + 1 >= max) { return -1; }\n\n ch = state.src.charCodeAt(pos++);\n\n if (ch < 0x30/* 0 */ || ch > 0x39/* 9 */) { return -1; }\n\n for (;;) {\n // EOL -> fail\n if (pos >= max) { return -1; }\n\n ch = state.src.charCodeAt(pos++);\n\n if (ch >= 0x30/* 0 */ && ch <= 0x39/* 9 */) {\n\n // List marker should have no more than 9 digits\n // (prevents integer overflow in browsers)\n if (pos - start >= 10) { return -1; }\n\n continue;\n }\n\n // found valid marker\n if (ch === 0x29/* ) */ || ch === 0x2e/* . */) {\n break;\n }\n\n return -1;\n }\n\n\n if (pos < max) {\n ch = state.src.charCodeAt(pos);\n\n if (!isSpace(ch)) {\n // \" 1.test \" - is not a list item\n return -1;\n }\n }\n return pos;\n}\n\nfunction markTightParagraphs(state, idx) {\n var i, l,\n level = state.level + 2;\n\n for (i = idx + 2, l = state.tokens.length - 2; i < l; i++) {\n if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') {\n state.tokens[i + 2].hidden = true;\n state.tokens[i].hidden = true;\n i += 2;\n }\n }\n}\n\n\nmodule.exports = function list(state, startLine, endLine, silent) {\n var ch,\n contentStart,\n i,\n indent,\n indentAfterMarker,\n initial,\n isOrdered,\n itemLines,\n l,\n listLines,\n listTokIdx,\n markerCharCode,\n markerValue,\n max,\n nextLine,\n offset,\n oldListIndent,\n oldParentType,\n oldSCount,\n oldTShift,\n oldTight,\n pos,\n posAfterMarker,\n prevEmptyEnd,\n start,\n terminate,\n terminatorRules,\n token,\n isTerminatingParagraph = false,\n tight = true;\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n // Special case:\n // - item 1\n // - item 2\n // - item 3\n // - item 4\n // - this one is a paragraph continuation\n if (state.listIndent >= 0 &&\n state.sCount[startLine] - state.listIndent >= 4 &&\n state.sCount[startLine] < state.blkIndent) {\n return false;\n }\n\n // limit conditions when list can interrupt\n // a paragraph (validation mode only)\n if (silent && state.parentType === 'paragraph') {\n // Next list item should still terminate previous list item;\n //\n // This code can fail if plugins use blkIndent as well as lists,\n // but I hope the spec gets fixed long before that happens.\n //\n if (state.sCount[startLine] >= state.blkIndent) {\n isTerminatingParagraph = true;\n }\n }\n\n // Detect list type and position after marker\n if ((posAfterMarker = skipOrderedListMarker(state, startLine)) >= 0) {\n isOrdered = true;\n start = state.bMarks[startLine] + state.tShift[startLine];\n markerValue = Number(state.src.slice(start, posAfterMarker - 1));\n\n // If we're starting a new ordered list right after\n // a paragraph, it should start with 1.\n if (isTerminatingParagraph && markerValue !== 1) return false;\n\n } else if ((posAfterMarker = skipBulletListMarker(state, startLine)) >= 0) {\n isOrdered = false;\n\n } else {\n return false;\n }\n\n // If we're starting a new unordered list right after\n // a paragraph, first line should not be empty.\n if (isTerminatingParagraph) {\n if (state.skipSpaces(posAfterMarker) >= state.eMarks[startLine]) return false;\n }\n\n // We should terminate list on style change. Remember first one to compare.\n markerCharCode = state.src.charCodeAt(posAfterMarker - 1);\n\n // For validation mode we can terminate immediately\n if (silent) { return true; }\n\n // Start list\n listTokIdx = state.tokens.length;\n\n if (isOrdered) {\n token = state.push('ordered_list_open', 'ol', 1);\n if (markerValue !== 1) {\n token.attrs = [ [ 'start', markerValue ] ];\n }\n\n } else {\n token = state.push('bullet_list_open', 'ul', 1);\n }\n\n token.map = listLines = [ startLine, 0 ];\n token.markup = String.fromCharCode(markerCharCode);\n\n //\n // Iterate list items\n //\n\n nextLine = startLine;\n prevEmptyEnd = false;\n terminatorRules = state.md.block.ruler.getRules('list');\n\n oldParentType = state.parentType;\n state.parentType = 'list';\n\n while (nextLine < endLine) {\n pos = posAfterMarker;\n max = state.eMarks[nextLine];\n\n initial = offset = state.sCount[nextLine] + posAfterMarker - (state.bMarks[startLine] + state.tShift[startLine]);\n\n while (pos < max) {\n ch = state.src.charCodeAt(pos);\n\n if (ch === 0x09) {\n offset += 4 - (offset + state.bsCount[nextLine]) % 4;\n } else if (ch === 0x20) {\n offset++;\n } else {\n break;\n }\n\n pos++;\n }\n\n contentStart = pos;\n\n if (contentStart >= max) {\n // trimming space in \"- \\n 3\" case, indent is 1 here\n indentAfterMarker = 1;\n } else {\n indentAfterMarker = offset - initial;\n }\n\n // If we have more than 4 spaces, the indent is 1\n // (the rest is just indented code block)\n if (indentAfterMarker > 4) { indentAfterMarker = 1; }\n\n // \" - test\"\n // ^^^^^ - calculating total length of this thing\n indent = initial + indentAfterMarker;\n\n // Run subparser & write tokens\n token = state.push('list_item_open', 'li', 1);\n token.markup = String.fromCharCode(markerCharCode);\n token.map = itemLines = [ startLine, 0 ];\n if (isOrdered) {\n token.info = state.src.slice(start, posAfterMarker - 1);\n }\n\n // change current state, then restore it after parser subcall\n oldTight = state.tight;\n oldTShift = state.tShift[startLine];\n oldSCount = state.sCount[startLine];\n\n // - example list\n // ^ listIndent position will be here\n // ^ blkIndent position will be here\n //\n oldListIndent = state.listIndent;\n state.listIndent = state.blkIndent;\n state.blkIndent = indent;\n\n state.tight = true;\n state.tShift[startLine] = contentStart - state.bMarks[startLine];\n state.sCount[startLine] = offset;\n\n if (contentStart >= max && state.isEmpty(startLine + 1)) {\n // workaround for this case\n // (list item is empty, list terminates before \"foo\"):\n // ~~~~~~~~\n // -\n //\n // foo\n // ~~~~~~~~\n state.line = Math.min(state.line + 2, endLine);\n } else {\n state.md.block.tokenize(state, startLine, endLine, true);\n }\n\n // If any of list item is tight, mark list as tight\n if (!state.tight || prevEmptyEnd) {\n tight = false;\n }\n // Item become loose if finish with empty line,\n // but we should filter last element, because it means list finish\n prevEmptyEnd = (state.line - startLine) > 1 && state.isEmpty(state.line - 1);\n\n state.blkIndent = state.listIndent;\n state.listIndent = oldListIndent;\n state.tShift[startLine] = oldTShift;\n state.sCount[startLine] = oldSCount;\n state.tight = oldTight;\n\n token = state.push('list_item_close', 'li', -1);\n token.markup = String.fromCharCode(markerCharCode);\n\n nextLine = startLine = state.line;\n itemLines[1] = nextLine;\n contentStart = state.bMarks[startLine];\n\n if (nextLine >= endLine) { break; }\n\n //\n // Try to check if list is terminated or continued.\n //\n if (state.sCount[nextLine] < state.blkIndent) { break; }\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { break; }\n\n // fail if terminating block found\n terminate = false;\n for (i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) { break; }\n\n // fail if list has another type\n if (isOrdered) {\n posAfterMarker = skipOrderedListMarker(state, nextLine);\n if (posAfterMarker < 0) { break; }\n start = state.bMarks[nextLine] + state.tShift[nextLine];\n } else {\n posAfterMarker = skipBulletListMarker(state, nextLine);\n if (posAfterMarker < 0) { break; }\n }\n\n if (markerCharCode !== state.src.charCodeAt(posAfterMarker - 1)) { break; }\n }\n\n // Finalize list\n if (isOrdered) {\n token = state.push('ordered_list_close', 'ol', -1);\n } else {\n token = state.push('bullet_list_close', 'ul', -1);\n }\n token.markup = String.fromCharCode(markerCharCode);\n\n listLines[1] = nextLine;\n state.line = nextLine;\n\n state.parentType = oldParentType;\n\n // mark paragraphs tight if needed\n if (tight) {\n markTightParagraphs(state, listTokIdx);\n }\n\n return true;\n};\n", "'use strict';\n\n\nvar normalizeReference = require('../common/utils').normalizeReference;\nvar isSpace = require('../common/utils').isSpace;\n\n\nmodule.exports = function reference(state, startLine, _endLine, silent) {\n var ch,\n destEndPos,\n destEndLineNo,\n endLine,\n href,\n i,\n l,\n label,\n labelEnd,\n oldParentType,\n res,\n start,\n str,\n terminate,\n terminatorRules,\n title,\n lines = 0,\n pos = state.bMarks[startLine] + state.tShift[startLine],\n max = state.eMarks[startLine],\n nextLine = startLine + 1;\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n if (state.src.charCodeAt(pos) !== 0x5B/* [ */) { return false; }\n\n // Simple check to quickly interrupt scan on [link](url) at the start of line.\n // Can be useful on practice: https://github.com/markdown-it/markdown-it/issues/54\n while (++pos < max) {\n if (state.src.charCodeAt(pos) === 0x5D /* ] */ &&\n state.src.charCodeAt(pos - 1) !== 0x5C/* \\ */) {\n if (pos + 1 === max) { return false; }\n if (state.src.charCodeAt(pos + 1) !== 0x3A/* : */) { return false; }\n break;\n }\n }\n\n endLine = state.lineMax;\n\n // jump line-by-line until empty one or EOF\n terminatorRules = state.md.block.ruler.getRules('reference');\n\n oldParentType = state.parentType;\n state.parentType = 'reference';\n\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\n // this would be a code block normally, but after paragraph\n // it's considered a lazy continuation regardless of what's there\n if (state.sCount[nextLine] - state.blkIndent > 3) { continue; }\n\n // quirk for blockquotes, this line should already be checked by that rule\n if (state.sCount[nextLine] < 0) { continue; }\n\n // Some tags can terminate paragraph without empty line.\n terminate = false;\n for (i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) { break; }\n }\n\n str = state.getLines(startLine, nextLine, state.blkIndent, false).trim();\n max = str.length;\n\n for (pos = 1; pos < max; pos++) {\n ch = str.charCodeAt(pos);\n if (ch === 0x5B /* [ */) {\n return false;\n } else if (ch === 0x5D /* ] */) {\n labelEnd = pos;\n break;\n } else if (ch === 0x0A /* \\n */) {\n lines++;\n } else if (ch === 0x5C /* \\ */) {\n pos++;\n if (pos < max && str.charCodeAt(pos) === 0x0A) {\n lines++;\n }\n }\n }\n\n if (labelEnd < 0 || str.charCodeAt(labelEnd + 1) !== 0x3A/* : */) { return false; }\n\n // [label]: destination 'title'\n // ^^^ skip optional whitespace here\n for (pos = labelEnd + 2; pos < max; pos++) {\n ch = str.charCodeAt(pos);\n if (ch === 0x0A) {\n lines++;\n } else if (isSpace(ch)) {\n /*eslint no-empty:0*/\n } else {\n break;\n }\n }\n\n // [label]: destination 'title'\n // ^^^^^^^^^^^ parse this\n res = state.md.helpers.parseLinkDestination(str, pos, max);\n if (!res.ok) { return false; }\n\n href = state.md.normalizeLink(res.str);\n if (!state.md.validateLink(href)) { return false; }\n\n pos = res.pos;\n lines += res.lines;\n\n // save cursor state, we could require to rollback later\n destEndPos = pos;\n destEndLineNo = lines;\n\n // [label]: destination 'title'\n // ^^^ skipping those spaces\n start = pos;\n for (; pos < max; pos++) {\n ch = str.charCodeAt(pos);\n if (ch === 0x0A) {\n lines++;\n } else if (isSpace(ch)) {\n /*eslint no-empty:0*/\n } else {\n break;\n }\n }\n\n // [label]: destination 'title'\n // ^^^^^^^ parse this\n res = state.md.helpers.parseLinkTitle(str, pos, max);\n if (pos < max && start !== pos && res.ok) {\n title = res.str;\n pos = res.pos;\n lines += res.lines;\n } else {\n title = '';\n pos = destEndPos;\n lines = destEndLineNo;\n }\n\n // skip trailing spaces until the rest of the line\n while (pos < max) {\n ch = str.charCodeAt(pos);\n if (!isSpace(ch)) { break; }\n pos++;\n }\n\n if (pos < max && str.charCodeAt(pos) !== 0x0A) {\n if (title) {\n // garbage at the end of the line after title,\n // but it could still be a valid reference if we roll back\n title = '';\n pos = destEndPos;\n lines = destEndLineNo;\n while (pos < max) {\n ch = str.charCodeAt(pos);\n if (!isSpace(ch)) { break; }\n pos++;\n }\n }\n }\n\n if (pos < max && str.charCodeAt(pos) !== 0x0A) {\n // garbage at the end of the line\n return false;\n }\n\n label = normalizeReference(str.slice(1, labelEnd));\n if (!label) {\n // CommonMark 0.20 disallows empty labels\n return false;\n }\n\n // Reference can not terminate anything. This check is for safety only.\n /*istanbul ignore if*/\n if (silent) { return true; }\n\n if (typeof state.env.references === 'undefined') {\n state.env.references = {};\n }\n if (typeof state.env.references[label] === 'undefined') {\n state.env.references[label] = { title: title, href: href };\n }\n\n state.parentType = oldParentType;\n\n state.line = startLine + lines + 1;\n return true;\n};\n", "// List of valid html blocks names, accorting to commonmark spec\n// http://jgm.github.io/CommonMark/spec.html#html-blocks\n\n'use strict';\n\n\nmodule.exports = [\n 'address',\n 'article',\n 'aside',\n 'base',\n 'basefont',\n 'blockquote',\n 'body',\n 'caption',\n 'center',\n 'col',\n 'colgroup',\n 'dd',\n 'details',\n 'dialog',\n 'dir',\n 'div',\n 'dl',\n 'dt',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'frame',\n 'frameset',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'head',\n 'header',\n 'hr',\n 'html',\n 'iframe',\n 'legend',\n 'li',\n 'link',\n 'main',\n 'menu',\n 'menuitem',\n 'nav',\n 'noframes',\n 'ol',\n 'optgroup',\n 'option',\n 'p',\n 'param',\n 'section',\n 'source',\n 'summary',\n 'table',\n 'tbody',\n 'td',\n 'tfoot',\n 'th',\n 'thead',\n 'title',\n 'tr',\n 'track',\n 'ul'\n];\n", "// Regexps to match html elements\n\n'use strict';\n\nvar attr_name = '[a-zA-Z_:][a-zA-Z0-9:._-]*';\n\nvar unquoted = '[^\"\\'=<>`\\\\x00-\\\\x20]+';\nvar single_quoted = \"'[^']*'\";\nvar double_quoted = '\"[^\"]*\"';\n\nvar attr_value = '(?:' + unquoted + '|' + single_quoted + '|' + double_quoted + ')';\n\nvar attribute = '(?:\\\\s+' + attr_name + '(?:\\\\s*=\\\\s*' + attr_value + ')?)';\n\nvar open_tag = '<[A-Za-z][A-Za-z0-9\\\\-]*' + attribute + '*\\\\s*\\\\/?>';\n\nvar close_tag = '<\\\\/[A-Za-z][A-Za-z0-9\\\\-]*\\\\s*>';\nvar comment = '|';\nvar processing = '<[?][\\\\s\\\\S]*?[?]>';\nvar declaration = ']*>';\nvar cdata = '';\n\nvar HTML_TAG_RE = new RegExp('^(?:' + open_tag + '|' + close_tag + '|' + comment +\n '|' + processing + '|' + declaration + '|' + cdata + ')');\nvar HTML_OPEN_CLOSE_TAG_RE = new RegExp('^(?:' + open_tag + '|' + close_tag + ')');\n\nmodule.exports.HTML_TAG_RE = HTML_TAG_RE;\nmodule.exports.HTML_OPEN_CLOSE_TAG_RE = HTML_OPEN_CLOSE_TAG_RE;\n", "// HTML block\n\n'use strict';\n\n\nvar block_names = require('../common/html_blocks');\nvar HTML_OPEN_CLOSE_TAG_RE = require('../common/html_re').HTML_OPEN_CLOSE_TAG_RE;\n\n// An array of opening and corresponding closing sequences for html tags,\n// last argument defines whether it can terminate a paragraph or not\n//\nvar HTML_SEQUENCES = [\n [ /^<(script|pre|style|textarea)(?=(\\s|>|$))/i, /<\\/(script|pre|style|textarea)>/i, true ],\n [ /^/, true ],\n [ /^<\\?/, /\\?>/, true ],\n [ /^/, true ],\n [ /^/, true ],\n [ new RegExp('^|$))', 'i'), /^$/, true ],\n [ new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + '\\\\s*$'), /^$/, false ]\n];\n\n\nmodule.exports = function html_block(state, startLine, endLine, silent) {\n var i, nextLine, token, lineText,\n pos = state.bMarks[startLine] + state.tShift[startLine],\n max = state.eMarks[startLine];\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n if (!state.md.options.html) { return false; }\n\n if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; }\n\n lineText = state.src.slice(pos, max);\n\n for (i = 0; i < HTML_SEQUENCES.length; i++) {\n if (HTML_SEQUENCES[i][0].test(lineText)) { break; }\n }\n\n if (i === HTML_SEQUENCES.length) { return false; }\n\n if (silent) {\n // true if this sequence can be a terminator, false otherwise\n return HTML_SEQUENCES[i][2];\n }\n\n nextLine = startLine + 1;\n\n // If we are here - we detected HTML block.\n // Let's roll down till block end.\n if (!HTML_SEQUENCES[i][1].test(lineText)) {\n for (; nextLine < endLine; nextLine++) {\n if (state.sCount[nextLine] < state.blkIndent) { break; }\n\n pos = state.bMarks[nextLine] + state.tShift[nextLine];\n max = state.eMarks[nextLine];\n lineText = state.src.slice(pos, max);\n\n if (HTML_SEQUENCES[i][1].test(lineText)) {\n if (lineText.length !== 0) { nextLine++; }\n break;\n }\n }\n }\n\n state.line = nextLine;\n\n token = state.push('html_block', '', 0);\n token.map = [ startLine, nextLine ];\n token.content = state.getLines(startLine, nextLine, state.blkIndent, true);\n\n return true;\n};\n", "// heading (#, ##, ...)\n\n'use strict';\n\nvar isSpace = require('../common/utils').isSpace;\n\n\nmodule.exports = function heading(state, startLine, endLine, silent) {\n var ch, level, tmp, token,\n pos = state.bMarks[startLine] + state.tShift[startLine],\n max = state.eMarks[startLine];\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n ch = state.src.charCodeAt(pos);\n\n if (ch !== 0x23/* # */ || pos >= max) { return false; }\n\n // count heading level\n level = 1;\n ch = state.src.charCodeAt(++pos);\n while (ch === 0x23/* # */ && pos < max && level <= 6) {\n level++;\n ch = state.src.charCodeAt(++pos);\n }\n\n if (level > 6 || (pos < max && !isSpace(ch))) { return false; }\n\n if (silent) { return true; }\n\n // Let's cut tails like ' ### ' from the end of string\n\n max = state.skipSpacesBack(max, pos);\n tmp = state.skipCharsBack(max, 0x23, pos); // #\n if (tmp > pos && isSpace(state.src.charCodeAt(tmp - 1))) {\n max = tmp;\n }\n\n state.line = startLine + 1;\n\n token = state.push('heading_open', 'h' + String(level), 1);\n token.markup = '########'.slice(0, level);\n token.map = [ startLine, state.line ];\n\n token = state.push('inline', '', 0);\n token.content = state.src.slice(pos, max).trim();\n token.map = [ startLine, state.line ];\n token.children = [];\n\n token = state.push('heading_close', 'h' + String(level), -1);\n token.markup = '########'.slice(0, level);\n\n return true;\n};\n", "// lheading (---, ===)\n\n'use strict';\n\n\nmodule.exports = function lheading(state, startLine, endLine/*, silent*/) {\n var content, terminate, i, l, token, pos, max, level, marker,\n nextLine = startLine + 1, oldParentType,\n terminatorRules = state.md.block.ruler.getRules('paragraph');\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }\n\n oldParentType = state.parentType;\n state.parentType = 'paragraph'; // use paragraph to match terminatorRules\n\n // jump line-by-line until empty one or EOF\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\n // this would be a code block normally, but after paragraph\n // it's considered a lazy continuation regardless of what's there\n if (state.sCount[nextLine] - state.blkIndent > 3) { continue; }\n\n //\n // Check for underline in setext header\n //\n if (state.sCount[nextLine] >= state.blkIndent) {\n pos = state.bMarks[nextLine] + state.tShift[nextLine];\n max = state.eMarks[nextLine];\n\n if (pos < max) {\n marker = state.src.charCodeAt(pos);\n\n if (marker === 0x2D/* - */ || marker === 0x3D/* = */) {\n pos = state.skipChars(pos, marker);\n pos = state.skipSpaces(pos);\n\n if (pos >= max) {\n level = (marker === 0x3D/* = */ ? 1 : 2);\n break;\n }\n }\n }\n }\n\n // quirk for blockquotes, this line should already be checked by that rule\n if (state.sCount[nextLine] < 0) { continue; }\n\n // Some tags can terminate paragraph without empty line.\n terminate = false;\n for (i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) { break; }\n }\n\n if (!level) {\n // Didn't find valid underline\n return false;\n }\n\n content = state.getLines(startLine, nextLine, state.blkIndent, false).trim();\n\n state.line = nextLine + 1;\n\n token = state.push('heading_open', 'h' + String(level), 1);\n token.markup = String.fromCharCode(marker);\n token.map = [ startLine, state.line ];\n\n token = state.push('inline', '', 0);\n token.content = content;\n token.map = [ startLine, state.line - 1 ];\n token.children = [];\n\n token = state.push('heading_close', 'h' + String(level), -1);\n token.markup = String.fromCharCode(marker);\n\n state.parentType = oldParentType;\n\n return true;\n};\n", "// Paragraph\n\n'use strict';\n\n\nmodule.exports = function paragraph(state, startLine/*, endLine*/) {\n var content, terminate, i, l, token, oldParentType,\n nextLine = startLine + 1,\n terminatorRules = state.md.block.ruler.getRules('paragraph'),\n endLine = state.lineMax;\n\n oldParentType = state.parentType;\n state.parentType = 'paragraph';\n\n // jump line-by-line until empty one or EOF\n for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {\n // this would be a code block normally, but after paragraph\n // it's considered a lazy continuation regardless of what's there\n if (state.sCount[nextLine] - state.blkIndent > 3) { continue; }\n\n // quirk for blockquotes, this line should already be checked by that rule\n if (state.sCount[nextLine] < 0) { continue; }\n\n // Some tags can terminate paragraph without empty line.\n terminate = false;\n for (i = 0, l = terminatorRules.length; i < l; i++) {\n if (terminatorRules[i](state, nextLine, endLine, true)) {\n terminate = true;\n break;\n }\n }\n if (terminate) { break; }\n }\n\n content = state.getLines(startLine, nextLine, state.blkIndent, false).trim();\n\n state.line = nextLine;\n\n token = state.push('paragraph_open', 'p', 1);\n token.map = [ startLine, state.line ];\n\n token = state.push('inline', '', 0);\n token.content = content;\n token.map = [ startLine, state.line ];\n token.children = [];\n\n token = state.push('paragraph_close', 'p', -1);\n\n state.parentType = oldParentType;\n\n return true;\n};\n", "// Parser state class\n\n'use strict';\n\nvar Token = require('../token');\nvar isSpace = require('../common/utils').isSpace;\n\n\nfunction StateBlock(src, md, env, tokens) {\n var ch, s, start, pos, len, indent, offset, indent_found;\n\n this.src = src;\n\n // link to parser instance\n this.md = md;\n\n this.env = env;\n\n //\n // Internal state vartiables\n //\n\n this.tokens = tokens;\n\n this.bMarks = []; // line begin offsets for fast jumps\n this.eMarks = []; // line end offsets for fast jumps\n this.tShift = []; // offsets of the first non-space characters (tabs not expanded)\n this.sCount = []; // indents for each line (tabs expanded)\n\n // An amount of virtual spaces (tabs expanded) between beginning\n // of each line (bMarks) and real beginning of that line.\n //\n // It exists only as a hack because blockquotes override bMarks\n // losing information in the process.\n //\n // It's used only when expanding tabs, you can think about it as\n // an initial tab length, e.g. bsCount=21 applied to string `\\t123`\n // means first tab should be expanded to 4-21%4 === 3 spaces.\n //\n this.bsCount = [];\n\n // block parser variables\n this.blkIndent = 0; // required block content indent (for example, if we are\n // inside a list, it would be positioned after list marker)\n this.line = 0; // line index in src\n this.lineMax = 0; // lines count\n this.tight = false; // loose/tight mode for lists\n this.ddIndent = -1; // indent of the current dd block (-1 if there isn't any)\n this.listIndent = -1; // indent of the current list block (-1 if there isn't any)\n\n // can be 'blockquote', 'list', 'root', 'paragraph' or 'reference'\n // used in lists to determine if they interrupt a paragraph\n this.parentType = 'root';\n\n this.level = 0;\n\n // renderer\n this.result = '';\n\n // Create caches\n // Generate markers.\n s = this.src;\n indent_found = false;\n\n for (start = pos = indent = offset = 0, len = s.length; pos < len; pos++) {\n ch = s.charCodeAt(pos);\n\n if (!indent_found) {\n if (isSpace(ch)) {\n indent++;\n\n if (ch === 0x09) {\n offset += 4 - offset % 4;\n } else {\n offset++;\n }\n continue;\n } else {\n indent_found = true;\n }\n }\n\n if (ch === 0x0A || pos === len - 1) {\n if (ch !== 0x0A) { pos++; }\n this.bMarks.push(start);\n this.eMarks.push(pos);\n this.tShift.push(indent);\n this.sCount.push(offset);\n this.bsCount.push(0);\n\n indent_found = false;\n indent = 0;\n offset = 0;\n start = pos + 1;\n }\n }\n\n // Push fake entry to simplify cache bounds checks\n this.bMarks.push(s.length);\n this.eMarks.push(s.length);\n this.tShift.push(0);\n this.sCount.push(0);\n this.bsCount.push(0);\n\n this.lineMax = this.bMarks.length - 1; // don't count last fake line\n}\n\n// Push new token to \"stream\".\n//\nStateBlock.prototype.push = function (type, tag, nesting) {\n var token = new Token(type, tag, nesting);\n token.block = true;\n\n if (nesting < 0) this.level--; // closing tag\n token.level = this.level;\n if (nesting > 0) this.level++; // opening tag\n\n this.tokens.push(token);\n return token;\n};\n\nStateBlock.prototype.isEmpty = function isEmpty(line) {\n return this.bMarks[line] + this.tShift[line] >= this.eMarks[line];\n};\n\nStateBlock.prototype.skipEmptyLines = function skipEmptyLines(from) {\n for (var max = this.lineMax; from < max; from++) {\n if (this.bMarks[from] + this.tShift[from] < this.eMarks[from]) {\n break;\n }\n }\n return from;\n};\n\n// Skip spaces from given position.\nStateBlock.prototype.skipSpaces = function skipSpaces(pos) {\n var ch;\n\n for (var max = this.src.length; pos < max; pos++) {\n ch = this.src.charCodeAt(pos);\n if (!isSpace(ch)) { break; }\n }\n return pos;\n};\n\n// Skip spaces from given position in reverse.\nStateBlock.prototype.skipSpacesBack = function skipSpacesBack(pos, min) {\n if (pos <= min) { return pos; }\n\n while (pos > min) {\n if (!isSpace(this.src.charCodeAt(--pos))) { return pos + 1; }\n }\n return pos;\n};\n\n// Skip char codes from given position\nStateBlock.prototype.skipChars = function skipChars(pos, code) {\n for (var max = this.src.length; pos < max; pos++) {\n if (this.src.charCodeAt(pos) !== code) { break; }\n }\n return pos;\n};\n\n// Skip char codes reverse from given position - 1\nStateBlock.prototype.skipCharsBack = function skipCharsBack(pos, code, min) {\n if (pos <= min) { return pos; }\n\n while (pos > min) {\n if (code !== this.src.charCodeAt(--pos)) { return pos + 1; }\n }\n return pos;\n};\n\n// cut lines range from source.\nStateBlock.prototype.getLines = function getLines(begin, end, indent, keepLastLF) {\n var i, lineIndent, ch, first, last, queue, lineStart,\n line = begin;\n\n if (begin >= end) {\n return '';\n }\n\n queue = new Array(end - begin);\n\n for (i = 0; line < end; line++, i++) {\n lineIndent = 0;\n lineStart = first = this.bMarks[line];\n\n if (line + 1 < end || keepLastLF) {\n // No need for bounds check because we have fake entry on tail.\n last = this.eMarks[line] + 1;\n } else {\n last = this.eMarks[line];\n }\n\n while (first < last && lineIndent < indent) {\n ch = this.src.charCodeAt(first);\n\n if (isSpace(ch)) {\n if (ch === 0x09) {\n lineIndent += 4 - (lineIndent + this.bsCount[line]) % 4;\n } else {\n lineIndent++;\n }\n } else if (first - lineStart < this.tShift[line]) {\n // patched tShift masked characters to look like spaces (blockquotes, list markers)\n lineIndent++;\n } else {\n break;\n }\n\n first++;\n }\n\n if (lineIndent > indent) {\n // partially expanding tabs in code blocks, e.g '\\t\\tfoobar'\n // with indent=2 becomes ' \\tfoobar'\n queue[i] = new Array(lineIndent - indent + 1).join(' ') + this.src.slice(first, last);\n } else {\n queue[i] = this.src.slice(first, last);\n }\n }\n\n return queue.join('');\n};\n\n// re-export Token class to use in block rules\nStateBlock.prototype.Token = Token;\n\n\nmodule.exports = StateBlock;\n", "/** internal\n * class ParserBlock\n *\n * Block-level tokenizer.\n **/\n'use strict';\n\n\nvar Ruler = require('./ruler');\n\n\nvar _rules = [\n // First 2 params - rule name & source. Secondary array - list of rules,\n // which can be terminated by this one.\n [ 'table', require('./rules_block/table'), [ 'paragraph', 'reference' ] ],\n [ 'code', require('./rules_block/code') ],\n [ 'fence', require('./rules_block/fence'), [ 'paragraph', 'reference', 'blockquote', 'list' ] ],\n [ 'blockquote', require('./rules_block/blockquote'), [ 'paragraph', 'reference', 'blockquote', 'list' ] ],\n [ 'hr', require('./rules_block/hr'), [ 'paragraph', 'reference', 'blockquote', 'list' ] ],\n [ 'list', require('./rules_block/list'), [ 'paragraph', 'reference', 'blockquote' ] ],\n [ 'reference', require('./rules_block/reference') ],\n [ 'html_block', require('./rules_block/html_block'), [ 'paragraph', 'reference', 'blockquote' ] ],\n [ 'heading', require('./rules_block/heading'), [ 'paragraph', 'reference', 'blockquote' ] ],\n [ 'lheading', require('./rules_block/lheading') ],\n [ 'paragraph', require('./rules_block/paragraph') ]\n];\n\n\n/**\n * new ParserBlock()\n **/\nfunction ParserBlock() {\n /**\n * ParserBlock#ruler -> Ruler\n *\n * [[Ruler]] instance. Keep configuration of block rules.\n **/\n this.ruler = new Ruler();\n\n for (var i = 0; i < _rules.length; i++) {\n this.ruler.push(_rules[i][0], _rules[i][1], { alt: (_rules[i][2] || []).slice() });\n }\n}\n\n\n// Generate tokens for input range\n//\nParserBlock.prototype.tokenize = function (state, startLine, endLine) {\n var ok, i,\n rules = this.ruler.getRules(''),\n len = rules.length,\n line = startLine,\n hasEmptyLines = false,\n maxNesting = state.md.options.maxNesting;\n\n while (line < endLine) {\n state.line = line = state.skipEmptyLines(line);\n if (line >= endLine) { break; }\n\n // Termination condition for nested calls.\n // Nested calls currently used for blockquotes & lists\n if (state.sCount[line] < state.blkIndent) { break; }\n\n // If nesting level exceeded - skip tail to the end. That's not ordinary\n // situation and we should not care about content.\n if (state.level >= maxNesting) {\n state.line = endLine;\n break;\n }\n\n // Try all possible rules.\n // On success, rule should:\n //\n // - update `state.line`\n // - update `state.tokens`\n // - return true\n\n for (i = 0; i < len; i++) {\n ok = rules[i](state, line, endLine, false);\n if (ok) { break; }\n }\n\n // set state.tight if we had an empty line before current tag\n // i.e. latest empty line should not count\n state.tight = !hasEmptyLines;\n\n // paragraph might \"eat\" one newline after it in nested lists\n if (state.isEmpty(state.line - 1)) {\n hasEmptyLines = true;\n }\n\n line = state.line;\n\n if (line < endLine && state.isEmpty(line)) {\n hasEmptyLines = true;\n line++;\n state.line = line;\n }\n }\n};\n\n\n/**\n * ParserBlock.parse(str, md, env, outTokens)\n *\n * Process input string and push block tokens into `outTokens`\n **/\nParserBlock.prototype.parse = function (src, md, env, outTokens) {\n var state;\n\n if (!src) { return; }\n\n state = new this.State(src, md, env, outTokens);\n\n this.tokenize(state, state.line, state.lineMax);\n};\n\n\nParserBlock.prototype.State = require('./rules_block/state_block');\n\n\nmodule.exports = ParserBlock;\n", "// Skip text characters for text token, place those to pending buffer\n// and increment current pos\n\n'use strict';\n\n\n// Rule to skip pure text\n// '{}$%@~+=:' reserved for extentions\n\n// !, \", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \\, ], ^, _, `, {, |, }, or ~\n\n// !!!! Don't confuse with \"Markdown ASCII Punctuation\" chars\n// http://spec.commonmark.org/0.15/#ascii-punctuation-character\nfunction isTerminatorChar(ch) {\n switch (ch) {\n case 0x0A/* \\n */:\n case 0x21/* ! */:\n case 0x23/* # */:\n case 0x24/* $ */:\n case 0x25/* % */:\n case 0x26/* & */:\n case 0x2A/* * */:\n case 0x2B/* + */:\n case 0x2D/* - */:\n case 0x3A/* : */:\n case 0x3C/* < */:\n case 0x3D/* = */:\n case 0x3E/* > */:\n case 0x40/* @ */:\n case 0x5B/* [ */:\n case 0x5C/* \\ */:\n case 0x5D/* ] */:\n case 0x5E/* ^ */:\n case 0x5F/* _ */:\n case 0x60/* ` */:\n case 0x7B/* { */:\n case 0x7D/* } */:\n case 0x7E/* ~ */:\n return true;\n default:\n return false;\n }\n}\n\nmodule.exports = function text(state, silent) {\n var pos = state.pos;\n\n while (pos < state.posMax && !isTerminatorChar(state.src.charCodeAt(pos))) {\n pos++;\n }\n\n if (pos === state.pos) { return false; }\n\n if (!silent) { state.pending += state.src.slice(state.pos, pos); }\n\n state.pos = pos;\n\n return true;\n};\n\n// Alternative implementation, for memory.\n//\n// It costs 10% of performance, but allows extend terminators list, if place it\n// to `ParcerInline` property. Probably, will switch to it sometime, such\n// flexibility required.\n\n/*\nvar TERMINATOR_RE = /[\\n!#$%&*+\\-:<=>@[\\\\\\]^_`{}~]/;\n\nmodule.exports = function text(state, silent) {\n var pos = state.pos,\n idx = state.src.slice(pos).search(TERMINATOR_RE);\n\n // first char is terminator -> empty text\n if (idx === 0) { return false; }\n\n // no terminator -> text till end of string\n if (idx < 0) {\n if (!silent) { state.pending += state.src.slice(pos); }\n state.pos = state.src.length;\n return true;\n }\n\n if (!silent) { state.pending += state.src.slice(pos, pos + idx); }\n\n state.pos += idx;\n\n return true;\n};*/\n", "// Proceess '\\n'\n\n'use strict';\n\nvar isSpace = require('../common/utils').isSpace;\n\n\nmodule.exports = function newline(state, silent) {\n var pmax, max, ws, pos = state.pos;\n\n if (state.src.charCodeAt(pos) !== 0x0A/* \\n */) { return false; }\n\n pmax = state.pending.length - 1;\n max = state.posMax;\n\n // ' \\n' -> hardbreak\n // Lookup in pending chars is bad practice! Don't copy to other rules!\n // Pending string is stored in concat mode, indexed lookups will cause\n // convertion to flat mode.\n if (!silent) {\n if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) {\n if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) {\n // Find whitespaces tail of pending chars.\n ws = pmax - 1;\n while (ws >= 1 && state.pending.charCodeAt(ws - 1) === 0x20) ws--;\n\n state.pending = state.pending.slice(0, ws);\n state.push('hardbreak', 'br', 0);\n } else {\n state.pending = state.pending.slice(0, -1);\n state.push('softbreak', 'br', 0);\n }\n\n } else {\n state.push('softbreak', 'br', 0);\n }\n }\n\n pos++;\n\n // skip heading spaces for next line\n while (pos < max && isSpace(state.src.charCodeAt(pos))) { pos++; }\n\n state.pos = pos;\n return true;\n};\n", "// Process escaped chars and hardbreaks\n\n'use strict';\n\nvar isSpace = require('../common/utils').isSpace;\n\nvar ESCAPED = [];\n\nfor (var i = 0; i < 256; i++) { ESCAPED.push(0); }\n\n'\\\\!\"#$%&\\'()*+,./:;<=>?@[]^_`{|}~-'\n .split('').forEach(function (ch) { ESCAPED[ch.charCodeAt(0)] = 1; });\n\n\nmodule.exports = function escape(state, silent) {\n var ch, pos = state.pos, max = state.posMax;\n\n if (state.src.charCodeAt(pos) !== 0x5C/* \\ */) { return false; }\n\n pos++;\n\n if (pos < max) {\n ch = state.src.charCodeAt(pos);\n\n if (ch < 256 && ESCAPED[ch] !== 0) {\n if (!silent) { state.pending += state.src[pos]; }\n state.pos += 2;\n return true;\n }\n\n if (ch === 0x0A) {\n if (!silent) {\n state.push('hardbreak', 'br', 0);\n }\n\n pos++;\n // skip leading whitespaces from next line\n while (pos < max) {\n ch = state.src.charCodeAt(pos);\n if (!isSpace(ch)) { break; }\n pos++;\n }\n\n state.pos = pos;\n return true;\n }\n }\n\n if (!silent) { state.pending += '\\\\'; }\n state.pos++;\n return true;\n};\n", "// Parse backticks\n\n'use strict';\n\n\nmodule.exports = function backtick(state, silent) {\n var start, max, marker, token, matchStart, matchEnd, openerLength, closerLength,\n pos = state.pos,\n ch = state.src.charCodeAt(pos);\n\n if (ch !== 0x60/* ` */) { return false; }\n\n start = pos;\n pos++;\n max = state.posMax;\n\n // scan marker length\n while (pos < max && state.src.charCodeAt(pos) === 0x60/* ` */) { pos++; }\n\n marker = state.src.slice(start, pos);\n openerLength = marker.length;\n\n if (state.backticksScanned && (state.backticks[openerLength] || 0) <= start) {\n if (!silent) state.pending += marker;\n state.pos += openerLength;\n return true;\n }\n\n matchStart = matchEnd = pos;\n\n // Nothing found in the cache, scan until the end of the line (or until marker is found)\n while ((matchStart = state.src.indexOf('`', matchEnd)) !== -1) {\n matchEnd = matchStart + 1;\n\n // scan marker length\n while (matchEnd < max && state.src.charCodeAt(matchEnd) === 0x60/* ` */) { matchEnd++; }\n\n closerLength = matchEnd - matchStart;\n\n if (closerLength === openerLength) {\n // Found matching closer length.\n if (!silent) {\n token = state.push('code_inline', 'code', 0);\n token.markup = marker;\n token.content = state.src.slice(pos, matchStart)\n .replace(/\\n/g, ' ')\n .replace(/^ (.+) $/, '$1');\n }\n state.pos = matchEnd;\n return true;\n }\n\n // Some different length found, put it in cache as upper limit of where closer can be found\n state.backticks[closerLength] = matchStart;\n }\n\n // Scanned through the end, didn't find anything\n state.backticksScanned = true;\n\n if (!silent) state.pending += marker;\n state.pos += openerLength;\n return true;\n};\n", "// ~~strike through~~\n//\n'use strict';\n\n\n// Insert each marker as a separate text token, and add it to delimiter list\n//\nmodule.exports.tokenize = function strikethrough(state, silent) {\n var i, scanned, token, len, ch,\n start = state.pos,\n marker = state.src.charCodeAt(start);\n\n if (silent) { return false; }\n\n if (marker !== 0x7E/* ~ */) { return false; }\n\n scanned = state.scanDelims(state.pos, true);\n len = scanned.length;\n ch = String.fromCharCode(marker);\n\n if (len < 2) { return false; }\n\n if (len % 2) {\n token = state.push('text', '', 0);\n token.content = ch;\n len--;\n }\n\n for (i = 0; i < len; i += 2) {\n token = state.push('text', '', 0);\n token.content = ch + ch;\n\n state.delimiters.push({\n marker: marker,\n length: 0, // disable \"rule of 3\" length checks meant for emphasis\n token: state.tokens.length - 1,\n end: -1,\n open: scanned.can_open,\n close: scanned.can_close\n });\n }\n\n state.pos += scanned.length;\n\n return true;\n};\n\n\nfunction postProcess(state, delimiters) {\n var i, j,\n startDelim,\n endDelim,\n token,\n loneMarkers = [],\n max = delimiters.length;\n\n for (i = 0; i < max; i++) {\n startDelim = delimiters[i];\n\n if (startDelim.marker !== 0x7E/* ~ */) {\n continue;\n }\n\n if (startDelim.end === -1) {\n continue;\n }\n\n endDelim = delimiters[startDelim.end];\n\n token = state.tokens[startDelim.token];\n token.type = 's_open';\n token.tag = 's';\n token.nesting = 1;\n token.markup = '~~';\n token.content = '';\n\n token = state.tokens[endDelim.token];\n token.type = 's_close';\n token.tag = 's';\n token.nesting = -1;\n token.markup = '~~';\n token.content = '';\n\n if (state.tokens[endDelim.token - 1].type === 'text' &&\n state.tokens[endDelim.token - 1].content === '~') {\n\n loneMarkers.push(endDelim.token - 1);\n }\n }\n\n // If a marker sequence has an odd number of characters, it's splitted\n // like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the\n // start of the sequence.\n //\n // So, we have to move all those markers after subsequent s_close tags.\n //\n while (loneMarkers.length) {\n i = loneMarkers.pop();\n j = i + 1;\n\n while (j < state.tokens.length && state.tokens[j].type === 's_close') {\n j++;\n }\n\n j--;\n\n if (i !== j) {\n token = state.tokens[j];\n state.tokens[j] = state.tokens[i];\n state.tokens[i] = token;\n }\n }\n}\n\n\n// Walk through delimiter list and replace text tokens with tags\n//\nmodule.exports.postProcess = function strikethrough(state) {\n var curr,\n tokens_meta = state.tokens_meta,\n max = state.tokens_meta.length;\n\n postProcess(state, state.delimiters);\n\n for (curr = 0; curr < max; curr++) {\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\n postProcess(state, tokens_meta[curr].delimiters);\n }\n }\n};\n", "// Process *this* and _that_\n//\n'use strict';\n\n\n// Insert each marker as a separate text token, and add it to delimiter list\n//\nmodule.exports.tokenize = function emphasis(state, silent) {\n var i, scanned, token,\n start = state.pos,\n marker = state.src.charCodeAt(start);\n\n if (silent) { return false; }\n\n if (marker !== 0x5F /* _ */ && marker !== 0x2A /* * */) { return false; }\n\n scanned = state.scanDelims(state.pos, marker === 0x2A);\n\n for (i = 0; i < scanned.length; i++) {\n token = state.push('text', '', 0);\n token.content = String.fromCharCode(marker);\n\n state.delimiters.push({\n // Char code of the starting marker (number).\n //\n marker: marker,\n\n // Total length of these series of delimiters.\n //\n length: scanned.length,\n\n // A position of the token this delimiter corresponds to.\n //\n token: state.tokens.length - 1,\n\n // If this delimiter is matched as a valid opener, `end` will be\n // equal to its position, otherwise it's `-1`.\n //\n end: -1,\n\n // Boolean flags that determine if this delimiter could open or close\n // an emphasis.\n //\n open: scanned.can_open,\n close: scanned.can_close\n });\n }\n\n state.pos += scanned.length;\n\n return true;\n};\n\n\nfunction postProcess(state, delimiters) {\n var i,\n startDelim,\n endDelim,\n token,\n ch,\n isStrong,\n max = delimiters.length;\n\n for (i = max - 1; i >= 0; i--) {\n startDelim = delimiters[i];\n\n if (startDelim.marker !== 0x5F/* _ */ && startDelim.marker !== 0x2A/* * */) {\n continue;\n }\n\n // Process only opening markers\n if (startDelim.end === -1) {\n continue;\n }\n\n endDelim = delimiters[startDelim.end];\n\n // If the previous delimiter has the same marker and is adjacent to this one,\n // merge those into one strong delimiter.\n //\n // `whatever` -> `whatever`\n //\n isStrong = i > 0 &&\n delimiters[i - 1].end === startDelim.end + 1 &&\n // check that first two markers match and adjacent\n delimiters[i - 1].marker === startDelim.marker &&\n delimiters[i - 1].token === startDelim.token - 1 &&\n // check that last two markers are adjacent (we can safely assume they match)\n delimiters[startDelim.end + 1].token === endDelim.token + 1;\n\n ch = String.fromCharCode(startDelim.marker);\n\n token = state.tokens[startDelim.token];\n token.type = isStrong ? 'strong_open' : 'em_open';\n token.tag = isStrong ? 'strong' : 'em';\n token.nesting = 1;\n token.markup = isStrong ? ch + ch : ch;\n token.content = '';\n\n token = state.tokens[endDelim.token];\n token.type = isStrong ? 'strong_close' : 'em_close';\n token.tag = isStrong ? 'strong' : 'em';\n token.nesting = -1;\n token.markup = isStrong ? ch + ch : ch;\n token.content = '';\n\n if (isStrong) {\n state.tokens[delimiters[i - 1].token].content = '';\n state.tokens[delimiters[startDelim.end + 1].token].content = '';\n i--;\n }\n }\n}\n\n\n// Walk through delimiter list and replace text tokens with tags\n//\nmodule.exports.postProcess = function emphasis(state) {\n var curr,\n tokens_meta = state.tokens_meta,\n max = state.tokens_meta.length;\n\n postProcess(state, state.delimiters);\n\n for (curr = 0; curr < max; curr++) {\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\n postProcess(state, tokens_meta[curr].delimiters);\n }\n }\n};\n", "// Process [link]( \"stuff\")\n\n'use strict';\n\nvar normalizeReference = require('../common/utils').normalizeReference;\nvar isSpace = require('../common/utils').isSpace;\n\n\nmodule.exports = function link(state, silent) {\n var attrs,\n code,\n label,\n labelEnd,\n labelStart,\n pos,\n res,\n ref,\n token,\n href = '',\n title = '',\n oldPos = state.pos,\n max = state.posMax,\n start = state.pos,\n parseReference = true;\n\n if (state.src.charCodeAt(state.pos) !== 0x5B/* [ */) { return false; }\n\n labelStart = state.pos + 1;\n labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true);\n\n // parser failed to find ']', so it's not a valid link\n if (labelEnd < 0) { return false; }\n\n pos = labelEnd + 1;\n if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {\n //\n // Inline link\n //\n\n // might have found a valid shortcut link, disable reference parsing\n parseReference = false;\n\n // [link]( \"title\" )\n // ^^ skipping these spaces\n pos++;\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (!isSpace(code) && code !== 0x0A) { break; }\n }\n if (pos >= max) { return false; }\n\n // [link]( \"title\" )\n // ^^^^^^ parsing link destination\n start = pos;\n res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);\n if (res.ok) {\n href = state.md.normalizeLink(res.str);\n if (state.md.validateLink(href)) {\n pos = res.pos;\n } else {\n href = '';\n }\n\n // [link]( \"title\" )\n // ^^ skipping these spaces\n start = pos;\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (!isSpace(code) && code !== 0x0A) { break; }\n }\n\n // [link]( \"title\" )\n // ^^^^^^^ parsing link title\n res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);\n if (pos < max && start !== pos && res.ok) {\n title = res.str;\n pos = res.pos;\n\n // [link]( \"title\" )\n // ^^ skipping these spaces\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (!isSpace(code) && code !== 0x0A) { break; }\n }\n }\n }\n\n if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {\n // parsing a valid shortcut link failed, fallback to reference\n parseReference = true;\n }\n pos++;\n }\n\n if (parseReference) {\n //\n // Link reference\n //\n if (typeof state.env.references === 'undefined') { return false; }\n\n if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {\n start = pos + 1;\n pos = state.md.helpers.parseLinkLabel(state, pos);\n if (pos >= 0) {\n label = state.src.slice(start, pos++);\n } else {\n pos = labelEnd + 1;\n }\n } else {\n pos = labelEnd + 1;\n }\n\n // covers label === '' and label === undefined\n // (collapsed reference link and shortcut reference link respectively)\n if (!label) { label = state.src.slice(labelStart, labelEnd); }\n\n ref = state.env.references[normalizeReference(label)];\n if (!ref) {\n state.pos = oldPos;\n return false;\n }\n href = ref.href;\n title = ref.title;\n }\n\n //\n // We found the end of the link, and know for a fact it's a valid link;\n // so all that's left to do is to call tokenizer.\n //\n if (!silent) {\n state.pos = labelStart;\n state.posMax = labelEnd;\n\n token = state.push('link_open', 'a', 1);\n token.attrs = attrs = [ [ 'href', href ] ];\n if (title) {\n attrs.push([ 'title', title ]);\n }\n\n state.md.inline.tokenize(state);\n\n token = state.push('link_close', 'a', -1);\n }\n\n state.pos = pos;\n state.posMax = max;\n return true;\n};\n", "// Process ![image]( \"title\")\n\n'use strict';\n\nvar normalizeReference = require('../common/utils').normalizeReference;\nvar isSpace = require('../common/utils').isSpace;\n\n\nmodule.exports = function image(state, silent) {\n var attrs,\n code,\n content,\n label,\n labelEnd,\n labelStart,\n pos,\n ref,\n res,\n title,\n token,\n tokens,\n start,\n href = '',\n oldPos = state.pos,\n max = state.posMax;\n\n if (state.src.charCodeAt(state.pos) !== 0x21/* ! */) { return false; }\n if (state.src.charCodeAt(state.pos + 1) !== 0x5B/* [ */) { return false; }\n\n labelStart = state.pos + 2;\n labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false);\n\n // parser failed to find ']', so it's not a valid link\n if (labelEnd < 0) { return false; }\n\n pos = labelEnd + 1;\n if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {\n //\n // Inline link\n //\n\n // [link]( \"title\" )\n // ^^ skipping these spaces\n pos++;\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (!isSpace(code) && code !== 0x0A) { break; }\n }\n if (pos >= max) { return false; }\n\n // [link]( \"title\" )\n // ^^^^^^ parsing link destination\n start = pos;\n res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);\n if (res.ok) {\n href = state.md.normalizeLink(res.str);\n if (state.md.validateLink(href)) {\n pos = res.pos;\n } else {\n href = '';\n }\n }\n\n // [link]( \"title\" )\n // ^^ skipping these spaces\n start = pos;\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (!isSpace(code) && code !== 0x0A) { break; }\n }\n\n // [link]( \"title\" )\n // ^^^^^^^ parsing link title\n res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);\n if (pos < max && start !== pos && res.ok) {\n title = res.str;\n pos = res.pos;\n\n // [link]( \"title\" )\n // ^^ skipping these spaces\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (!isSpace(code) && code !== 0x0A) { break; }\n }\n } else {\n title = '';\n }\n\n if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {\n state.pos = oldPos;\n return false;\n }\n pos++;\n } else {\n //\n // Link reference\n //\n if (typeof state.env.references === 'undefined') { return false; }\n\n if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {\n start = pos + 1;\n pos = state.md.helpers.parseLinkLabel(state, pos);\n if (pos >= 0) {\n label = state.src.slice(start, pos++);\n } else {\n pos = labelEnd + 1;\n }\n } else {\n pos = labelEnd + 1;\n }\n\n // covers label === '' and label === undefined\n // (collapsed reference link and shortcut reference link respectively)\n if (!label) { label = state.src.slice(labelStart, labelEnd); }\n\n ref = state.env.references[normalizeReference(label)];\n if (!ref) {\n state.pos = oldPos;\n return false;\n }\n href = ref.href;\n title = ref.title;\n }\n\n //\n // We found the end of the link, and know for a fact it's a valid link;\n // so all that's left to do is to call tokenizer.\n //\n if (!silent) {\n content = state.src.slice(labelStart, labelEnd);\n\n state.md.inline.parse(\n content,\n state.md,\n state.env,\n tokens = []\n );\n\n token = state.push('image', 'img', 0);\n token.attrs = attrs = [ [ 'src', href ], [ 'alt', '' ] ];\n token.children = tokens;\n token.content = content;\n\n if (title) {\n attrs.push([ 'title', title ]);\n }\n }\n\n state.pos = pos;\n state.posMax = max;\n return true;\n};\n", "// Process autolinks ''\n\n'use strict';\n\n\n/*eslint max-len:0*/\nvar EMAIL_RE = /^([a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/;\nvar AUTOLINK_RE = /^([a-zA-Z][a-zA-Z0-9+.\\-]{1,31}):([^<>\\x00-\\x20]*)$/;\n\n\nmodule.exports = function autolink(state, silent) {\n var url, fullUrl, token, ch, start, max,\n pos = state.pos;\n\n if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; }\n\n start = state.pos;\n max = state.posMax;\n\n for (;;) {\n if (++pos >= max) return false;\n\n ch = state.src.charCodeAt(pos);\n\n if (ch === 0x3C /* < */) return false;\n if (ch === 0x3E /* > */) break;\n }\n\n url = state.src.slice(start + 1, pos);\n\n if (AUTOLINK_RE.test(url)) {\n fullUrl = state.md.normalizeLink(url);\n if (!state.md.validateLink(fullUrl)) { return false; }\n\n if (!silent) {\n token = state.push('link_open', 'a', 1);\n token.attrs = [ [ 'href', fullUrl ] ];\n token.markup = 'autolink';\n token.info = 'auto';\n\n token = state.push('text', '', 0);\n token.content = state.md.normalizeLinkText(url);\n\n token = state.push('link_close', 'a', -1);\n token.markup = 'autolink';\n token.info = 'auto';\n }\n\n state.pos += url.length + 2;\n return true;\n }\n\n if (EMAIL_RE.test(url)) {\n fullUrl = state.md.normalizeLink('mailto:' + url);\n if (!state.md.validateLink(fullUrl)) { return false; }\n\n if (!silent) {\n token = state.push('link_open', 'a', 1);\n token.attrs = [ [ 'href', fullUrl ] ];\n token.markup = 'autolink';\n token.info = 'auto';\n\n token = state.push('text', '', 0);\n token.content = state.md.normalizeLinkText(url);\n\n token = state.push('link_close', 'a', -1);\n token.markup = 'autolink';\n token.info = 'auto';\n }\n\n state.pos += url.length + 2;\n return true;\n }\n\n return false;\n};\n", "// Process html tags\n\n'use strict';\n\n\nvar HTML_TAG_RE = require('../common/html_re').HTML_TAG_RE;\n\n\nfunction isLetter(ch) {\n /*eslint no-bitwise:0*/\n var lc = ch | 0x20; // to lower case\n return (lc >= 0x61/* a */) && (lc <= 0x7a/* z */);\n}\n\n\nmodule.exports = function html_inline(state, silent) {\n var ch, match, max, token,\n pos = state.pos;\n\n if (!state.md.options.html) { return false; }\n\n // Check start\n max = state.posMax;\n if (state.src.charCodeAt(pos) !== 0x3C/* < */ ||\n pos + 2 >= max) {\n return false;\n }\n\n // Quick fail on second char\n ch = state.src.charCodeAt(pos + 1);\n if (ch !== 0x21/* ! */ &&\n ch !== 0x3F/* ? */ &&\n ch !== 0x2F/* / */ &&\n !isLetter(ch)) {\n return false;\n }\n\n match = state.src.slice(pos).match(HTML_TAG_RE);\n if (!match) { return false; }\n\n if (!silent) {\n token = state.push('html_inline', '', 0);\n token.content = state.src.slice(pos, pos + match[0].length);\n }\n state.pos += match[0].length;\n return true;\n};\n", "// Process html entity - {, ¯, ", ...\n\n'use strict';\n\nvar entities = require('../common/entities');\nvar has = require('../common/utils').has;\nvar isValidEntityCode = require('../common/utils').isValidEntityCode;\nvar fromCodePoint = require('../common/utils').fromCodePoint;\n\n\nvar DIGITAL_RE = /^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i;\nvar NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i;\n\n\nmodule.exports = function entity(state, silent) {\n var ch, code, match, pos = state.pos, max = state.posMax;\n\n if (state.src.charCodeAt(pos) !== 0x26/* & */) { return false; }\n\n if (pos + 1 < max) {\n ch = state.src.charCodeAt(pos + 1);\n\n if (ch === 0x23 /* # */) {\n match = state.src.slice(pos).match(DIGITAL_RE);\n if (match) {\n if (!silent) {\n code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10);\n state.pending += isValidEntityCode(code) ? fromCodePoint(code) : fromCodePoint(0xFFFD);\n }\n state.pos += match[0].length;\n return true;\n }\n } else {\n match = state.src.slice(pos).match(NAMED_RE);\n if (match) {\n if (has(entities, match[1])) {\n if (!silent) { state.pending += entities[match[1]]; }\n state.pos += match[0].length;\n return true;\n }\n }\n }\n }\n\n if (!silent) { state.pending += '&'; }\n state.pos++;\n return true;\n};\n", "// For each opening emphasis-like marker find a matching closing one\n//\n'use strict';\n\n\nfunction processDelimiters(state, delimiters) {\n var closerIdx, openerIdx, closer, opener, minOpenerIdx, newMinOpenerIdx,\n isOddMatch, lastJump,\n openersBottom = {},\n max = delimiters.length;\n\n if (!max) return;\n\n // headerIdx is the first delimiter of the current (where closer is) delimiter run\n var headerIdx = 0;\n var lastTokenIdx = -2; // needs any value lower than -1\n var jumps = [];\n\n for (closerIdx = 0; closerIdx < max; closerIdx++) {\n closer = delimiters[closerIdx];\n\n jumps.push(0);\n\n // markers belong to same delimiter run if:\n // - they have adjacent tokens\n // - AND markers are the same\n //\n if (delimiters[headerIdx].marker !== closer.marker || lastTokenIdx !== closer.token - 1) {\n headerIdx = closerIdx;\n }\n\n lastTokenIdx = closer.token;\n\n // Length is only used for emphasis-specific \"rule of 3\",\n // if it's not defined (in strikethrough or 3rd party plugins),\n // we can default it to 0 to disable those checks.\n //\n closer.length = closer.length || 0;\n\n if (!closer.close) continue;\n\n // Previously calculated lower bounds (previous fails)\n // for each marker, each delimiter length modulo 3,\n // and for whether this closer can be an opener;\n // https://github.com/commonmark/cmark/commit/34250e12ccebdc6372b8b49c44fab57c72443460\n if (!openersBottom.hasOwnProperty(closer.marker)) {\n openersBottom[closer.marker] = [ -1, -1, -1, -1, -1, -1 ];\n }\n\n minOpenerIdx = openersBottom[closer.marker][(closer.open ? 3 : 0) + (closer.length % 3)];\n\n openerIdx = headerIdx - jumps[headerIdx] - 1;\n\n newMinOpenerIdx = openerIdx;\n\n for (; openerIdx > minOpenerIdx; openerIdx -= jumps[openerIdx] + 1) {\n opener = delimiters[openerIdx];\n\n if (opener.marker !== closer.marker) continue;\n\n if (opener.open && opener.end < 0) {\n\n isOddMatch = false;\n\n // from spec:\n //\n // If one of the delimiters can both open and close emphasis, then the\n // sum of the lengths of the delimiter runs containing the opening and\n // closing delimiters must not be a multiple of 3 unless both lengths\n // are multiples of 3.\n //\n if (opener.close || closer.open) {\n if ((opener.length + closer.length) % 3 === 0) {\n if (opener.length % 3 !== 0 || closer.length % 3 !== 0) {\n isOddMatch = true;\n }\n }\n }\n\n if (!isOddMatch) {\n // If previous delimiter cannot be an opener, we can safely skip\n // the entire sequence in future checks. This is required to make\n // sure algorithm has linear complexity (see *_*_*_*_*_... case).\n //\n lastJump = openerIdx > 0 && !delimiters[openerIdx - 1].open ?\n jumps[openerIdx - 1] + 1 :\n 0;\n\n jumps[closerIdx] = closerIdx - openerIdx + lastJump;\n jumps[openerIdx] = lastJump;\n\n closer.open = false;\n opener.end = closerIdx;\n opener.close = false;\n newMinOpenerIdx = -1;\n // treat next token as start of run,\n // it optimizes skips in **<...>**a**<...>** pathological case\n lastTokenIdx = -2;\n break;\n }\n }\n }\n\n if (newMinOpenerIdx !== -1) {\n // If match for this delimiter run failed, we want to set lower bound for\n // future lookups. This is required to make sure algorithm has linear\n // complexity.\n //\n // See details here:\n // https://github.com/commonmark/cmark/issues/178#issuecomment-270417442\n //\n openersBottom[closer.marker][(closer.open ? 3 : 0) + ((closer.length || 0) % 3)] = newMinOpenerIdx;\n }\n }\n}\n\n\nmodule.exports = function link_pairs(state) {\n var curr,\n tokens_meta = state.tokens_meta,\n max = state.tokens_meta.length;\n\n processDelimiters(state, state.delimiters);\n\n for (curr = 0; curr < max; curr++) {\n if (tokens_meta[curr] && tokens_meta[curr].delimiters) {\n processDelimiters(state, tokens_meta[curr].delimiters);\n }\n }\n};\n", "// Clean up tokens after emphasis and strikethrough postprocessing:\n// merge adjacent text nodes into one and re-calculate all token levels\n//\n// This is necessary because initially emphasis delimiter markers (*, _, ~)\n// are treated as their own separate text tokens. Then emphasis rule either\n// leaves them as text (needed to merge with adjacent text) or turns them\n// into opening/closing tags (which messes up levels inside).\n//\n'use strict';\n\n\nmodule.exports = function text_collapse(state) {\n var curr, last,\n level = 0,\n tokens = state.tokens,\n max = state.tokens.length;\n\n for (curr = last = 0; curr < max; curr++) {\n // re-calculate levels after emphasis/strikethrough turns some text nodes\n // into opening/closing tags\n if (tokens[curr].nesting < 0) level--; // closing tag\n tokens[curr].level = level;\n if (tokens[curr].nesting > 0) level++; // opening tag\n\n if (tokens[curr].type === 'text' &&\n curr + 1 < max &&\n tokens[curr + 1].type === 'text') {\n\n // collapse two adjacent text nodes\n tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content;\n } else {\n if (curr !== last) { tokens[last] = tokens[curr]; }\n\n last++;\n }\n }\n\n if (curr !== last) {\n tokens.length = last;\n }\n};\n", "// Inline parser state\n\n'use strict';\n\n\nvar Token = require('../token');\nvar isWhiteSpace = require('../common/utils').isWhiteSpace;\nvar isPunctChar = require('../common/utils').isPunctChar;\nvar isMdAsciiPunct = require('../common/utils').isMdAsciiPunct;\n\n\nfunction StateInline(src, md, env, outTokens) {\n this.src = src;\n this.env = env;\n this.md = md;\n this.tokens = outTokens;\n this.tokens_meta = Array(outTokens.length);\n\n this.pos = 0;\n this.posMax = this.src.length;\n this.level = 0;\n this.pending = '';\n this.pendingLevel = 0;\n\n // Stores { start: end } pairs. Useful for backtrack\n // optimization of pairs parse (emphasis, strikes).\n this.cache = {};\n\n // List of emphasis-like delimiters for current tag\n this.delimiters = [];\n\n // Stack of delimiter lists for upper level tags\n this._prev_delimiters = [];\n\n // backtick length => last seen position\n this.backticks = {};\n this.backticksScanned = false;\n}\n\n\n// Flush pending text\n//\nStateInline.prototype.pushPending = function () {\n var token = new Token('text', '', 0);\n token.content = this.pending;\n token.level = this.pendingLevel;\n this.tokens.push(token);\n this.pending = '';\n return token;\n};\n\n\n// Push new token to \"stream\".\n// If pending text exists - flush it as text token\n//\nStateInline.prototype.push = function (type, tag, nesting) {\n if (this.pending) {\n this.pushPending();\n }\n\n var token = new Token(type, tag, nesting);\n var token_meta = null;\n\n if (nesting < 0) {\n // closing tag\n this.level--;\n this.delimiters = this._prev_delimiters.pop();\n }\n\n token.level = this.level;\n\n if (nesting > 0) {\n // opening tag\n this.level++;\n this._prev_delimiters.push(this.delimiters);\n this.delimiters = [];\n token_meta = { delimiters: this.delimiters };\n }\n\n this.pendingLevel = this.level;\n this.tokens.push(token);\n this.tokens_meta.push(token_meta);\n return token;\n};\n\n\n// Scan a sequence of emphasis-like markers, and determine whether\n// it can start an emphasis sequence or end an emphasis sequence.\n//\n// - start - position to scan from (it should point at a valid marker);\n// - canSplitWord - determine if these markers can be found inside a word\n//\nStateInline.prototype.scanDelims = function (start, canSplitWord) {\n var pos = start, lastChar, nextChar, count, can_open, can_close,\n isLastWhiteSpace, isLastPunctChar,\n isNextWhiteSpace, isNextPunctChar,\n left_flanking = true,\n right_flanking = true,\n max = this.posMax,\n marker = this.src.charCodeAt(start);\n\n // treat beginning of the line as a whitespace\n lastChar = start > 0 ? this.src.charCodeAt(start - 1) : 0x20;\n\n while (pos < max && this.src.charCodeAt(pos) === marker) { pos++; }\n\n count = pos - start;\n\n // treat end of the line as a whitespace\n nextChar = pos < max ? this.src.charCodeAt(pos) : 0x20;\n\n isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar));\n isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar));\n\n isLastWhiteSpace = isWhiteSpace(lastChar);\n isNextWhiteSpace = isWhiteSpace(nextChar);\n\n if (isNextWhiteSpace) {\n left_flanking = false;\n } else if (isNextPunctChar) {\n if (!(isLastWhiteSpace || isLastPunctChar)) {\n left_flanking = false;\n }\n }\n\n if (isLastWhiteSpace) {\n right_flanking = false;\n } else if (isLastPunctChar) {\n if (!(isNextWhiteSpace || isNextPunctChar)) {\n right_flanking = false;\n }\n }\n\n if (!canSplitWord) {\n can_open = left_flanking && (!right_flanking || isLastPunctChar);\n can_close = right_flanking && (!left_flanking || isNextPunctChar);\n } else {\n can_open = left_flanking;\n can_close = right_flanking;\n }\n\n return {\n can_open: can_open,\n can_close: can_close,\n length: count\n };\n};\n\n\n// re-export Token class to use in block rules\nStateInline.prototype.Token = Token;\n\n\nmodule.exports = StateInline;\n", "/** internal\n * class ParserInline\n *\n * Tokenizes paragraph content.\n **/\n'use strict';\n\n\nvar Ruler = require('./ruler');\n\n\n////////////////////////////////////////////////////////////////////////////////\n// Parser rules\n\nvar _rules = [\n [ 'text', require('./rules_inline/text') ],\n [ 'newline', require('./rules_inline/newline') ],\n [ 'escape', require('./rules_inline/escape') ],\n [ 'backticks', require('./rules_inline/backticks') ],\n [ 'strikethrough', require('./rules_inline/strikethrough').tokenize ],\n [ 'emphasis', require('./rules_inline/emphasis').tokenize ],\n [ 'link', require('./rules_inline/link') ],\n [ 'image', require('./rules_inline/image') ],\n [ 'autolink', require('./rules_inline/autolink') ],\n [ 'html_inline', require('./rules_inline/html_inline') ],\n [ 'entity', require('./rules_inline/entity') ]\n];\n\nvar _rules2 = [\n [ 'balance_pairs', require('./rules_inline/balance_pairs') ],\n [ 'strikethrough', require('./rules_inline/strikethrough').postProcess ],\n [ 'emphasis', require('./rules_inline/emphasis').postProcess ],\n [ 'text_collapse', require('./rules_inline/text_collapse') ]\n];\n\n\n/**\n * new ParserInline()\n **/\nfunction ParserInline() {\n var i;\n\n /**\n * ParserInline#ruler -> Ruler\n *\n * [[Ruler]] instance. Keep configuration of inline rules.\n **/\n this.ruler = new Ruler();\n\n for (i = 0; i < _rules.length; i++) {\n this.ruler.push(_rules[i][0], _rules[i][1]);\n }\n\n /**\n * ParserInline#ruler2 -> Ruler\n *\n * [[Ruler]] instance. Second ruler used for post-processing\n * (e.g. in emphasis-like rules).\n **/\n this.ruler2 = new Ruler();\n\n for (i = 0; i < _rules2.length; i++) {\n this.ruler2.push(_rules2[i][0], _rules2[i][1]);\n }\n}\n\n\n// Skip single token by running all rules in validation mode;\n// returns `true` if any rule reported success\n//\nParserInline.prototype.skipToken = function (state) {\n var ok, i, pos = state.pos,\n rules = this.ruler.getRules(''),\n len = rules.length,\n maxNesting = state.md.options.maxNesting,\n cache = state.cache;\n\n\n if (typeof cache[pos] !== 'undefined') {\n state.pos = cache[pos];\n return;\n }\n\n if (state.level < maxNesting) {\n for (i = 0; i < len; i++) {\n // Increment state.level and decrement it later to limit recursion.\n // It's harmless to do here, because no tokens are created. But ideally,\n // we'd need a separate private state variable for this purpose.\n //\n state.level++;\n ok = rules[i](state, true);\n state.level--;\n\n if (ok) { break; }\n }\n } else {\n // Too much nesting, just skip until the end of the paragraph.\n //\n // NOTE: this will cause links to behave incorrectly in the following case,\n // when an amount of `[` is exactly equal to `maxNesting + 1`:\n //\n // [[[[[[[[[[[[[[[[[[[[[foo]()\n //\n // TODO: remove this workaround when CM standard will allow nested links\n // (we can replace it by preventing links from being parsed in\n // validation mode)\n //\n state.pos = state.posMax;\n }\n\n if (!ok) { state.pos++; }\n cache[pos] = state.pos;\n};\n\n\n// Generate tokens for input range\n//\nParserInline.prototype.tokenize = function (state) {\n var ok, i,\n rules = this.ruler.getRules(''),\n len = rules.length,\n end = state.posMax,\n maxNesting = state.md.options.maxNesting;\n\n while (state.pos < end) {\n // Try all possible rules.\n // On success, rule should:\n //\n // - update `state.pos`\n // - update `state.tokens`\n // - return true\n\n if (state.level < maxNesting) {\n for (i = 0; i < len; i++) {\n ok = rules[i](state, false);\n if (ok) { break; }\n }\n }\n\n if (ok) {\n if (state.pos >= end) { break; }\n continue;\n }\n\n state.pending += state.src[state.pos++];\n }\n\n if (state.pending) {\n state.pushPending();\n }\n};\n\n\n/**\n * ParserInline.parse(str, md, env, outTokens)\n *\n * Process input string and push inline tokens into `outTokens`\n **/\nParserInline.prototype.parse = function (str, md, env, outTokens) {\n var i, rules, len;\n var state = new this.State(str, md, env, outTokens);\n\n this.tokenize(state);\n\n rules = this.ruler2.getRules('');\n len = rules.length;\n\n for (i = 0; i < len; i++) {\n rules[i](state);\n }\n};\n\n\nParserInline.prototype.State = require('./rules_inline/state_inline');\n\n\nmodule.exports = ParserInline;\n", "'use strict';\n\n\nmodule.exports = function (opts) {\n var re = {};\n\n // Use direct extract instead of `regenerate` to reduse browserified size\n re.src_Any = require('uc.micro/properties/Any/regex').source;\n re.src_Cc = require('uc.micro/categories/Cc/regex').source;\n re.src_Z = require('uc.micro/categories/Z/regex').source;\n re.src_P = require('uc.micro/categories/P/regex').source;\n\n // \\p{\\Z\\P\\Cc\\CF} (white spaces + control + format + punctuation)\n re.src_ZPCc = [ re.src_Z, re.src_P, re.src_Cc ].join('|');\n\n // \\p{\\Z\\Cc} (white spaces + control)\n re.src_ZCc = [ re.src_Z, re.src_Cc ].join('|');\n\n // Experimental. List of chars, completely prohibited in links\n // because can separate it from other part of text\n var text_separators = '[><\\uff5c]';\n\n // All possible word characters (everything without punctuation, spaces & controls)\n // Defined via punctuation & spaces to save space\n // Should be something like \\p{\\L\\N\\S\\M} (\\w but without `_`)\n re.src_pseudo_letter = '(?:(?!' + text_separators + '|' + re.src_ZPCc + ')' + re.src_Any + ')';\n // The same as abothe but without [0-9]\n // var src_pseudo_letter_non_d = '(?:(?![0-9]|' + src_ZPCc + ')' + src_Any + ')';\n\n ////////////////////////////////////////////////////////////////////////////////\n\n re.src_ip4 =\n\n '(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)';\n\n // Prohibit any of \"@/[]()\" in user/pass to avoid wrong domain fetch.\n re.src_auth = '(?:(?:(?!' + re.src_ZCc + '|[@/\\\\[\\\\]()]).)+@)?';\n\n re.src_port =\n\n '(?::(?:6(?:[0-4]\\\\d{3}|5(?:[0-4]\\\\d{2}|5(?:[0-2]\\\\d|3[0-5])))|[1-5]?\\\\d{1,4}))?';\n\n re.src_host_terminator =\n\n '(?=$|' + text_separators + '|' + re.src_ZPCc + ')(?!-|_|:\\\\d|\\\\.-|\\\\.(?!$|' + re.src_ZPCc + '))';\n\n re.src_path =\n\n '(?:' +\n '[/?#]' +\n '(?:' +\n '(?!' + re.src_ZCc + '|' + text_separators + '|[()[\\\\]{}.,\"\\'?!\\\\-]).|' +\n '\\\\[(?:(?!' + re.src_ZCc + '|\\\\]).)*\\\\]|' +\n '\\\\((?:(?!' + re.src_ZCc + '|[)]).)*\\\\)|' +\n '\\\\{(?:(?!' + re.src_ZCc + '|[}]).)*\\\\}|' +\n '\\\\\"(?:(?!' + re.src_ZCc + '|[\"]).)+\\\\\"|' +\n \"\\\\'(?:(?!\" + re.src_ZCc + \"|[']).)+\\\\'|\" +\n \"\\\\'(?=\" + re.src_pseudo_letter + '|[-]).|' + // allow `I'm_king` if no pair found\n '\\\\.{2,}[a-zA-Z0-9%/&]|' + // google has many dots in \"google search\" links (#66, #81).\n // github has ... in commit range links,\n // Restrict to\n // - english\n // - percent-encoded\n // - parts of file path\n // - params separator\n // until more examples found.\n '\\\\.(?!' + re.src_ZCc + '|[.]).|' +\n (opts && opts['---'] ?\n '\\\\-(?!--(?:[^-]|$))(?:-*)|' // `---` => long dash, terminate\n :\n '\\\\-+|'\n ) +\n '\\\\,(?!' + re.src_ZCc + ').|' + // allow `,,,` in paths\n '\\\\!+(?!' + re.src_ZCc + '|[!]).|' + // allow `!!!` in paths, but not at the end\n '\\\\?(?!' + re.src_ZCc + '|[?]).' +\n ')+' +\n '|\\\\/' +\n ')?';\n\n // Allow anything in markdown spec, forbid quote (\") at the first position\n // because emails enclosed in quotes are far more common\n re.src_email_name =\n\n '[\\\\-;:&=\\\\+\\\\$,\\\\.a-zA-Z0-9_][\\\\-;:&=\\\\+\\\\$,\\\\\"\\\\.a-zA-Z0-9_]*';\n\n re.src_xn =\n\n 'xn--[a-z0-9\\\\-]{1,59}';\n\n // More to read about domain names\n // http://serverfault.com/questions/638260/\n\n re.src_domain_root =\n\n // Allow letters & digits (http://test1)\n '(?:' +\n re.src_xn +\n '|' +\n re.src_pseudo_letter + '{1,63}' +\n ')';\n\n re.src_domain =\n\n '(?:' +\n re.src_xn +\n '|' +\n '(?:' + re.src_pseudo_letter + ')' +\n '|' +\n '(?:' + re.src_pseudo_letter + '(?:-|' + re.src_pseudo_letter + '){0,61}' + re.src_pseudo_letter + ')' +\n ')';\n\n re.src_host =\n\n '(?:' +\n // Don't need IP check, because digits are already allowed in normal domain names\n // src_ip4 +\n // '|' +\n '(?:(?:(?:' + re.src_domain + ')\\\\.)*' + re.src_domain/*_root*/ + ')' +\n ')';\n\n re.tpl_host_fuzzy =\n\n '(?:' +\n re.src_ip4 +\n '|' +\n '(?:(?:(?:' + re.src_domain + ')\\\\.)+(?:%TLDS%))' +\n ')';\n\n re.tpl_host_no_ip_fuzzy =\n\n '(?:(?:(?:' + re.src_domain + ')\\\\.)+(?:%TLDS%))';\n\n re.src_host_strict =\n\n re.src_host + re.src_host_terminator;\n\n re.tpl_host_fuzzy_strict =\n\n re.tpl_host_fuzzy + re.src_host_terminator;\n\n re.src_host_port_strict =\n\n re.src_host + re.src_port + re.src_host_terminator;\n\n re.tpl_host_port_fuzzy_strict =\n\n re.tpl_host_fuzzy + re.src_port + re.src_host_terminator;\n\n re.tpl_host_port_no_ip_fuzzy_strict =\n\n re.tpl_host_no_ip_fuzzy + re.src_port + re.src_host_terminator;\n\n\n ////////////////////////////////////////////////////////////////////////////////\n // Main rules\n\n // Rude test fuzzy links by host, for quick deny\n re.tpl_host_fuzzy_test =\n\n 'localhost|www\\\\.|\\\\.\\\\d{1,3}\\\\.|(?:\\\\.(?:%TLDS%)(?:' + re.src_ZPCc + '|>|$))';\n\n re.tpl_email_fuzzy =\n\n '(^|' + text_separators + '|\"|\\\\(|' + re.src_ZCc + ')' +\n '(' + re.src_email_name + '@' + re.tpl_host_fuzzy_strict + ')';\n\n re.tpl_link_fuzzy =\n // Fuzzy link can't be prepended with .:/\\- and non punctuation.\n // but can start with > (markdown blockquote)\n '(^|(?![.:/\\\\-_@])(?:[$+<=>^`|\\uff5c]|' + re.src_ZPCc + '))' +\n '((?![$+<=>^`|\\uff5c])' + re.tpl_host_port_fuzzy_strict + re.src_path + ')';\n\n re.tpl_link_no_ip_fuzzy =\n // Fuzzy link can't be prepended with .:/\\- and non punctuation.\n // but can start with > (markdown blockquote)\n '(^|(?![.:/\\\\-_@])(?:[$+<=>^`|\\uff5c]|' + re.src_ZPCc + '))' +\n '((?![$+<=>^`|\\uff5c])' + re.tpl_host_port_no_ip_fuzzy_strict + re.src_path + ')';\n\n return re;\n};\n", "'use strict';\n\n\n////////////////////////////////////////////////////////////////////////////////\n// Helpers\n\n// Merge objects\n//\nfunction assign(obj /*from1, from2, from3, ...*/) {\n var sources = Array.prototype.slice.call(arguments, 1);\n\n sources.forEach(function (source) {\n if (!source) { return; }\n\n Object.keys(source).forEach(function (key) {\n obj[key] = source[key];\n });\n });\n\n return obj;\n}\n\nfunction _class(obj) { return Object.prototype.toString.call(obj); }\nfunction isString(obj) { return _class(obj) === '[object String]'; }\nfunction isObject(obj) { return _class(obj) === '[object Object]'; }\nfunction isRegExp(obj) { return _class(obj) === '[object RegExp]'; }\nfunction isFunction(obj) { return _class(obj) === '[object Function]'; }\n\n\nfunction escapeRE(str) { return str.replace(/[.?*+^$[\\]\\\\(){}|-]/g, '\\\\$&'); }\n\n////////////////////////////////////////////////////////////////////////////////\n\n\nvar defaultOptions = {\n fuzzyLink: true,\n fuzzyEmail: true,\n fuzzyIP: false\n};\n\n\nfunction isOptionsObj(obj) {\n return Object.keys(obj || {}).reduce(function (acc, k) {\n return acc || defaultOptions.hasOwnProperty(k);\n }, false);\n}\n\n\nvar defaultSchemas = {\n 'http:': {\n validate: function (text, pos, self) {\n var tail = text.slice(pos);\n\n if (!self.re.http) {\n // compile lazily, because \"host\"-containing variables can change on tlds update.\n self.re.http = new RegExp(\n '^\\\\/\\\\/' + self.re.src_auth + self.re.src_host_port_strict + self.re.src_path, 'i'\n );\n }\n if (self.re.http.test(tail)) {\n return tail.match(self.re.http)[0].length;\n }\n return 0;\n }\n },\n 'https:': 'http:',\n 'ftp:': 'http:',\n '//': {\n validate: function (text, pos, self) {\n var tail = text.slice(pos);\n\n if (!self.re.no_http) {\n // compile lazily, because \"host\"-containing variables can change on tlds update.\n self.re.no_http = new RegExp(\n '^' +\n self.re.src_auth +\n // Don't allow single-level domains, because of false positives like '//test'\n // with code comments\n '(?:localhost|(?:(?:' + self.re.src_domain + ')\\\\.)+' + self.re.src_domain_root + ')' +\n self.re.src_port +\n self.re.src_host_terminator +\n self.re.src_path,\n\n 'i'\n );\n }\n\n if (self.re.no_http.test(tail)) {\n // should not be `://` & `///`, that protects from errors in protocol name\n if (pos >= 3 && text[pos - 3] === ':') { return 0; }\n if (pos >= 3 && text[pos - 3] === '/') { return 0; }\n return tail.match(self.re.no_http)[0].length;\n }\n return 0;\n }\n },\n 'mailto:': {\n validate: function (text, pos, self) {\n var tail = text.slice(pos);\n\n if (!self.re.mailto) {\n self.re.mailto = new RegExp(\n '^' + self.re.src_email_name + '@' + self.re.src_host_strict, 'i'\n );\n }\n if (self.re.mailto.test(tail)) {\n return tail.match(self.re.mailto)[0].length;\n }\n return 0;\n }\n }\n};\n\n/*eslint-disable max-len*/\n\n// RE pattern for 2-character tlds (autogenerated by ./support/tlds_2char_gen.js)\nvar tlds_2ch_src_re = 'a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]';\n\n// DON'T try to make PRs with changes. Extend TLDs with LinkifyIt.tlds() instead\nvar tlds_default = 'biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|\u0440\u0444'.split('|');\n\n/*eslint-enable max-len*/\n\n////////////////////////////////////////////////////////////////////////////////\n\nfunction resetScanCache(self) {\n self.__index__ = -1;\n self.__text_cache__ = '';\n}\n\nfunction createValidator(re) {\n return function (text, pos) {\n var tail = text.slice(pos);\n\n if (re.test(tail)) {\n return tail.match(re)[0].length;\n }\n return 0;\n };\n}\n\nfunction createNormalizer() {\n return function (match, self) {\n self.normalize(match);\n };\n}\n\n// Schemas compiler. Build regexps.\n//\nfunction compile(self) {\n\n // Load & clone RE patterns.\n var re = self.re = require('./lib/re')(self.__opts__);\n\n // Define dynamic patterns\n var tlds = self.__tlds__.slice();\n\n self.onCompile();\n\n if (!self.__tlds_replaced__) {\n tlds.push(tlds_2ch_src_re);\n }\n tlds.push(re.src_xn);\n\n re.src_tlds = tlds.join('|');\n\n function untpl(tpl) { return tpl.replace('%TLDS%', re.src_tlds); }\n\n re.email_fuzzy = RegExp(untpl(re.tpl_email_fuzzy), 'i');\n re.link_fuzzy = RegExp(untpl(re.tpl_link_fuzzy), 'i');\n re.link_no_ip_fuzzy = RegExp(untpl(re.tpl_link_no_ip_fuzzy), 'i');\n re.host_fuzzy_test = RegExp(untpl(re.tpl_host_fuzzy_test), 'i');\n\n //\n // Compile each schema\n //\n\n var aliases = [];\n\n self.__compiled__ = {}; // Reset compiled data\n\n function schemaError(name, val) {\n throw new Error('(LinkifyIt) Invalid schema \"' + name + '\": ' + val);\n }\n\n Object.keys(self.__schemas__).forEach(function (name) {\n var val = self.__schemas__[name];\n\n // skip disabled methods\n if (val === null) { return; }\n\n var compiled = { validate: null, link: null };\n\n self.__compiled__[name] = compiled;\n\n if (isObject(val)) {\n if (isRegExp(val.validate)) {\n compiled.validate = createValidator(val.validate);\n } else if (isFunction(val.validate)) {\n compiled.validate = val.validate;\n } else {\n schemaError(name, val);\n }\n\n if (isFunction(val.normalize)) {\n compiled.normalize = val.normalize;\n } else if (!val.normalize) {\n compiled.normalize = createNormalizer();\n } else {\n schemaError(name, val);\n }\n\n return;\n }\n\n if (isString(val)) {\n aliases.push(name);\n return;\n }\n\n schemaError(name, val);\n });\n\n //\n // Compile postponed aliases\n //\n\n aliases.forEach(function (alias) {\n if (!self.__compiled__[self.__schemas__[alias]]) {\n // Silently fail on missed schemas to avoid errons on disable.\n // schemaError(alias, self.__schemas__[alias]);\n return;\n }\n\n self.__compiled__[alias].validate =\n self.__compiled__[self.__schemas__[alias]].validate;\n self.__compiled__[alias].normalize =\n self.__compiled__[self.__schemas__[alias]].normalize;\n });\n\n //\n // Fake record for guessed links\n //\n self.__compiled__[''] = { validate: null, normalize: createNormalizer() };\n\n //\n // Build schema condition\n //\n var slist = Object.keys(self.__compiled__)\n .filter(function (name) {\n // Filter disabled & fake schemas\n return name.length > 0 && self.__compiled__[name];\n })\n .map(escapeRE)\n .join('|');\n // (?!_) cause 1.5x slowdown\n self.re.schema_test = RegExp('(^|(?!_)(?:[><\\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'i');\n self.re.schema_search = RegExp('(^|(?!_)(?:[><\\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'ig');\n\n self.re.pretest = RegExp(\n '(' + self.re.schema_test.source + ')|(' + self.re.host_fuzzy_test.source + ')|@',\n 'i'\n );\n\n //\n // Cleanup\n //\n\n resetScanCache(self);\n}\n\n/**\n * class Match\n *\n * Match result. Single element of array, returned by [[LinkifyIt#match]]\n **/\nfunction Match(self, shift) {\n var start = self.__index__,\n end = self.__last_index__,\n text = self.__text_cache__.slice(start, end);\n\n /**\n * Match#schema -> String\n *\n * Prefix (protocol) for matched string.\n **/\n this.schema = self.__schema__.toLowerCase();\n /**\n * Match#index -> Number\n *\n * First position of matched string.\n **/\n this.index = start + shift;\n /**\n * Match#lastIndex -> Number\n *\n * Next position after matched string.\n **/\n this.lastIndex = end + shift;\n /**\n * Match#raw -> String\n *\n * Matched string.\n **/\n this.raw = text;\n /**\n * Match#text -> String\n *\n * Notmalized text of matched string.\n **/\n this.text = text;\n /**\n * Match#url -> String\n *\n * Normalized url of matched string.\n **/\n this.url = text;\n}\n\nfunction createMatch(self, shift) {\n var match = new Match(self, shift);\n\n self.__compiled__[match.schema].normalize(match, self);\n\n return match;\n}\n\n\n/**\n * class LinkifyIt\n **/\n\n/**\n * new LinkifyIt(schemas, options)\n * - schemas (Object): Optional. Additional schemas to validate (prefix/validator)\n * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false }\n *\n * Creates new linkifier instance with optional additional schemas.\n * Can be called without `new` keyword for convenience.\n *\n * By default understands:\n *\n * - `http(s)://...` , `ftp://...`, `mailto:...` & `//...` links\n * - \"fuzzy\" links and emails (example.com, foo@bar.com).\n *\n * `schemas` is an object, where each key/value describes protocol/rule:\n *\n * - __key__ - link prefix (usually, protocol name with `:` at the end, `skype:`\n * for example). `linkify-it` makes shure that prefix is not preceeded with\n * alphanumeric char and symbols. Only whitespaces and punctuation allowed.\n * - __value__ - rule to check tail after link prefix\n * - _String_ - just alias to existing rule\n * - _Object_\n * - _validate_ - validator function (should return matched length on success),\n * or `RegExp`.\n * - _normalize_ - optional function to normalize text & url of matched result\n * (for example, for @twitter mentions).\n *\n * `options`:\n *\n * - __fuzzyLink__ - recognige URL-s without `http(s):` prefix. Default `true`.\n * - __fuzzyIP__ - allow IPs in fuzzy links above. Can conflict with some texts\n * like version numbers. Default `false`.\n * - __fuzzyEmail__ - recognize emails without `mailto:` prefix.\n *\n **/\nfunction LinkifyIt(schemas, options) {\n if (!(this instanceof LinkifyIt)) {\n return new LinkifyIt(schemas, options);\n }\n\n if (!options) {\n if (isOptionsObj(schemas)) {\n options = schemas;\n schemas = {};\n }\n }\n\n this.__opts__ = assign({}, defaultOptions, options);\n\n // Cache last tested result. Used to skip repeating steps on next `match` call.\n this.__index__ = -1;\n this.__last_index__ = -1; // Next scan position\n this.__schema__ = '';\n this.__text_cache__ = '';\n\n this.__schemas__ = assign({}, defaultSchemas, schemas);\n this.__compiled__ = {};\n\n this.__tlds__ = tlds_default;\n this.__tlds_replaced__ = false;\n\n this.re = {};\n\n compile(this);\n}\n\n\n/** chainable\n * LinkifyIt#add(schema, definition)\n * - schema (String): rule name (fixed pattern prefix)\n * - definition (String|RegExp|Object): schema definition\n *\n * Add new rule definition. See constructor description for details.\n **/\nLinkifyIt.prototype.add = function add(schema, definition) {\n this.__schemas__[schema] = definition;\n compile(this);\n return this;\n};\n\n\n/** chainable\n * LinkifyIt#set(options)\n * - options (Object): { fuzzyLink|fuzzyEmail|fuzzyIP: true|false }\n *\n * Set recognition options for links without schema.\n **/\nLinkifyIt.prototype.set = function set(options) {\n this.__opts__ = assign(this.__opts__, options);\n return this;\n};\n\n\n/**\n * LinkifyIt#test(text) -> Boolean\n *\n * Searches linkifiable pattern and returns `true` on success or `false` on fail.\n **/\nLinkifyIt.prototype.test = function test(text) {\n // Reset scan cache\n this.__text_cache__ = text;\n this.__index__ = -1;\n\n if (!text.length) { return false; }\n\n var m, ml, me, len, shift, next, re, tld_pos, at_pos;\n\n // try to scan for link with schema - that's the most simple rule\n if (this.re.schema_test.test(text)) {\n re = this.re.schema_search;\n re.lastIndex = 0;\n while ((m = re.exec(text)) !== null) {\n len = this.testSchemaAt(text, m[2], re.lastIndex);\n if (len) {\n this.__schema__ = m[2];\n this.__index__ = m.index + m[1].length;\n this.__last_index__ = m.index + m[0].length + len;\n break;\n }\n }\n }\n\n if (this.__opts__.fuzzyLink && this.__compiled__['http:']) {\n // guess schemaless links\n tld_pos = text.search(this.re.host_fuzzy_test);\n if (tld_pos >= 0) {\n // if tld is located after found link - no need to check fuzzy pattern\n if (this.__index__ < 0 || tld_pos < this.__index__) {\n if ((ml = text.match(this.__opts__.fuzzyIP ? this.re.link_fuzzy : this.re.link_no_ip_fuzzy)) !== null) {\n\n shift = ml.index + ml[1].length;\n\n if (this.__index__ < 0 || shift < this.__index__) {\n this.__schema__ = '';\n this.__index__ = shift;\n this.__last_index__ = ml.index + ml[0].length;\n }\n }\n }\n }\n }\n\n if (this.__opts__.fuzzyEmail && this.__compiled__['mailto:']) {\n // guess schemaless emails\n at_pos = text.indexOf('@');\n if (at_pos >= 0) {\n // We can't skip this check, because this cases are possible:\n // 192.168.1.1@gmail.com, my.in@example.com\n if ((me = text.match(this.re.email_fuzzy)) !== null) {\n\n shift = me.index + me[1].length;\n next = me.index + me[0].length;\n\n if (this.__index__ < 0 || shift < this.__index__ ||\n (shift === this.__index__ && next > this.__last_index__)) {\n this.__schema__ = 'mailto:';\n this.__index__ = shift;\n this.__last_index__ = next;\n }\n }\n }\n }\n\n return this.__index__ >= 0;\n};\n\n\n/**\n * LinkifyIt#pretest(text) -> Boolean\n *\n * Very quick check, that can give false positives. Returns true if link MAY BE\n * can exists. Can be used for speed optimization, when you need to check that\n * link NOT exists.\n **/\nLinkifyIt.prototype.pretest = function pretest(text) {\n return this.re.pretest.test(text);\n};\n\n\n/**\n * LinkifyIt#testSchemaAt(text, name, position) -> Number\n * - text (String): text to scan\n * - name (String): rule (schema) name\n * - position (Number): text offset to check from\n *\n * Similar to [[LinkifyIt#test]] but checks only specific protocol tail exactly\n * at given position. Returns length of found pattern (0 on fail).\n **/\nLinkifyIt.prototype.testSchemaAt = function testSchemaAt(text, schema, pos) {\n // If not supported schema check requested - terminate\n if (!this.__compiled__[schema.toLowerCase()]) {\n return 0;\n }\n return this.__compiled__[schema.toLowerCase()].validate(text, pos, this);\n};\n\n\n/**\n * LinkifyIt#match(text) -> Array|null\n *\n * Returns array of found link descriptions or `null` on fail. We strongly\n * recommend to use [[LinkifyIt#test]] first, for best speed.\n *\n * ##### Result match description\n *\n * - __schema__ - link schema, can be empty for fuzzy links, or `//` for\n * protocol-neutral links.\n * - __index__ - offset of matched text\n * - __lastIndex__ - index of next char after mathch end\n * - __raw__ - matched text\n * - __text__ - normalized text\n * - __url__ - link, generated from matched text\n **/\nLinkifyIt.prototype.match = function match(text) {\n var shift = 0, result = [];\n\n // Try to take previous element from cache, if .test() called before\n if (this.__index__ >= 0 && this.__text_cache__ === text) {\n result.push(createMatch(this, shift));\n shift = this.__last_index__;\n }\n\n // Cut head if cache was used\n var tail = shift ? text.slice(shift) : text;\n\n // Scan string until end reached\n while (this.test(tail)) {\n result.push(createMatch(this, shift));\n\n tail = tail.slice(this.__last_index__);\n shift += this.__last_index__;\n }\n\n if (result.length) {\n return result;\n }\n\n return null;\n};\n\n\n/** chainable\n * LinkifyIt#tlds(list [, keepOld]) -> this\n * - list (Array): list of tlds\n * - keepOld (Boolean): merge with current list if `true` (`false` by default)\n *\n * Load (or merge) new tlds list. Those are user for fuzzy links (without prefix)\n * to avoid false positives. By default this algorythm used:\n *\n * - hostname with any 2-letter root zones are ok.\n * - biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|\u0440\u0444\n * are ok.\n * - encoded (`xn--...`) root zones are ok.\n *\n * If list is replaced, then exact match for 2-chars root zones will be checked.\n **/\nLinkifyIt.prototype.tlds = function tlds(list, keepOld) {\n list = Array.isArray(list) ? list : [ list ];\n\n if (!keepOld) {\n this.__tlds__ = list.slice();\n this.__tlds_replaced__ = true;\n compile(this);\n return this;\n }\n\n this.__tlds__ = this.__tlds__.concat(list)\n .sort()\n .filter(function (el, idx, arr) {\n return el !== arr[idx - 1];\n })\n .reverse();\n\n compile(this);\n return this;\n};\n\n/**\n * LinkifyIt#normalize(match)\n *\n * Default normalizer (if schema does not define it's own).\n **/\nLinkifyIt.prototype.normalize = function normalize(match) {\n\n // Do minimal possible changes by default. Need to collect feedback prior\n // to move forward https://github.com/markdown-it/linkify-it/issues/1\n\n if (!match.schema) { match.url = 'http://' + match.url; }\n\n if (match.schema === 'mailto:' && !/^mailto:/i.test(match.url)) {\n match.url = 'mailto:' + match.url;\n }\n};\n\n\n/**\n * LinkifyIt#onCompile()\n *\n * Override to modify basic RegExp-s.\n **/\nLinkifyIt.prototype.onCompile = function onCompile() {\n};\n\n\nmodule.exports = LinkifyIt;\n", "'use strict';\n\n/** Highest positive signed 32-bit float value */\nconst maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1\n\n/** Bootstring parameters */\nconst base = 36;\nconst tMin = 1;\nconst tMax = 26;\nconst skew = 38;\nconst damp = 700;\nconst initialBias = 72;\nconst initialN = 128; // 0x80\nconst delimiter = '-'; // '\\x2D'\n\n/** Regular expressions */\nconst regexPunycode = /^xn--/;\nconst regexNonASCII = /[^\\0-\\x7E]/; // non-ASCII chars\nconst regexSeparators = /[\\x2E\\u3002\\uFF0E\\uFF61]/g; // RFC 3490 separators\n\n/** Error messages */\nconst errors = {\n\t'overflow': 'Overflow: input needs wider integers to process',\n\t'not-basic': 'Illegal input >= 0x80 (not a basic code point)',\n\t'invalid-input': 'Invalid input'\n};\n\n/** Convenience shortcuts */\nconst baseMinusTMin = base - tMin;\nconst floor = Math.floor;\nconst stringFromCharCode = String.fromCharCode;\n\n/*--------------------------------------------------------------------------*/\n\n/**\n * A generic error utility function.\n * @private\n * @param {String} type The error type.\n * @returns {Error} Throws a `RangeError` with the applicable error message.\n */\nfunction error(type) {\n\tthrow new RangeError(errors[type]);\n}\n\n/**\n * A generic `Array#map` utility function.\n * @private\n * @param {Array} array The array to iterate over.\n * @param {Function} callback The function that gets called for every array\n * item.\n * @returns {Array} A new array of values returned by the callback function.\n */\nfunction map(array, fn) {\n\tconst result = [];\n\tlet length = array.length;\n\twhile (length--) {\n\t\tresult[length] = fn(array[length]);\n\t}\n\treturn result;\n}\n\n/**\n * A simple `Array#map`-like wrapper to work with domain name strings or email\n * addresses.\n * @private\n * @param {String} domain The domain name or email address.\n * @param {Function} callback The function that gets called for every\n * character.\n * @returns {Array} A new string of characters returned by the callback\n * function.\n */\nfunction mapDomain(string, fn) {\n\tconst parts = string.split('@');\n\tlet result = '';\n\tif (parts.length > 1) {\n\t\t// In email addresses, only the domain name should be punycoded. Leave\n\t\t// the local part (i.e. everything up to `@`) intact.\n\t\tresult = parts[0] + '@';\n\t\tstring = parts[1];\n\t}\n\t// Avoid `split(regex)` for IE8 compatibility. See #17.\n\tstring = string.replace(regexSeparators, '\\x2E');\n\tconst labels = string.split('.');\n\tconst encoded = map(labels, fn).join('.');\n\treturn result + encoded;\n}\n\n/**\n * Creates an array containing the numeric code points of each Unicode\n * character in the string. While JavaScript uses UCS-2 internally,\n * this function will convert a pair of surrogate halves (each of which\n * UCS-2 exposes as separate characters) into a single code point,\n * matching UTF-16.\n * @see `punycode.ucs2.encode`\n * @see \n * @memberOf punycode.ucs2\n * @name decode\n * @param {String} string The Unicode input string (UCS-2).\n * @returns {Array} The new array of code points.\n */\nfunction ucs2decode(string) {\n\tconst output = [];\n\tlet counter = 0;\n\tconst length = string.length;\n\twhile (counter < length) {\n\t\tconst value = string.charCodeAt(counter++);\n\t\tif (value >= 0xD800 && value <= 0xDBFF && counter < length) {\n\t\t\t// It's a high surrogate, and there is a next character.\n\t\t\tconst extra = string.charCodeAt(counter++);\n\t\t\tif ((extra & 0xFC00) == 0xDC00) { // Low surrogate.\n\t\t\t\toutput.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);\n\t\t\t} else {\n\t\t\t\t// It's an unmatched surrogate; only append this code unit, in case the\n\t\t\t\t// next code unit is the high surrogate of a surrogate pair.\n\t\t\t\toutput.push(value);\n\t\t\t\tcounter--;\n\t\t\t}\n\t\t} else {\n\t\t\toutput.push(value);\n\t\t}\n\t}\n\treturn output;\n}\n\n/**\n * Creates a string based on an array of numeric code points.\n * @see `punycode.ucs2.decode`\n * @memberOf punycode.ucs2\n * @name encode\n * @param {Array} codePoints The array of numeric code points.\n * @returns {String} The new Unicode string (UCS-2).\n */\nconst ucs2encode = array => String.fromCodePoint(...array);\n\n/**\n * Converts a basic code point into a digit/integer.\n * @see `digitToBasic()`\n * @private\n * @param {Number} codePoint The basic numeric code point value.\n * @returns {Number} The numeric value of a basic code point (for use in\n * representing integers) in the range `0` to `base - 1`, or `base` if\n * the code point does not represent a value.\n */\nconst basicToDigit = function(codePoint) {\n\tif (codePoint - 0x30 < 0x0A) {\n\t\treturn codePoint - 0x16;\n\t}\n\tif (codePoint - 0x41 < 0x1A) {\n\t\treturn codePoint - 0x41;\n\t}\n\tif (codePoint - 0x61 < 0x1A) {\n\t\treturn codePoint - 0x61;\n\t}\n\treturn base;\n};\n\n/**\n * Converts a digit/integer into a basic code point.\n * @see `basicToDigit()`\n * @private\n * @param {Number} digit The numeric value of a basic code point.\n * @returns {Number} The basic code point whose value (when used for\n * representing integers) is `digit`, which needs to be in the range\n * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is\n * used; else, the lowercase form is used. The behavior is undefined\n * if `flag` is non-zero and `digit` has no uppercase form.\n */\nconst digitToBasic = function(digit, flag) {\n\t// 0..25 map to ASCII a..z or A..Z\n\t// 26..35 map to ASCII 0..9\n\treturn digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);\n};\n\n/**\n * Bias adaptation function as per section 3.4 of RFC 3492.\n * https://tools.ietf.org/html/rfc3492#section-3.4\n * @private\n */\nconst adapt = function(delta, numPoints, firstTime) {\n\tlet k = 0;\n\tdelta = firstTime ? floor(delta / damp) : delta >> 1;\n\tdelta += floor(delta / numPoints);\n\tfor (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {\n\t\tdelta = floor(delta / baseMinusTMin);\n\t}\n\treturn floor(k + (baseMinusTMin + 1) * delta / (delta + skew));\n};\n\n/**\n * Converts a Punycode string of ASCII-only symbols to a string of Unicode\n * symbols.\n * @memberOf punycode\n * @param {String} input The Punycode string of ASCII-only symbols.\n * @returns {String} The resulting string of Unicode symbols.\n */\nconst decode = function(input) {\n\t// Don't use UCS-2.\n\tconst output = [];\n\tconst inputLength = input.length;\n\tlet i = 0;\n\tlet n = initialN;\n\tlet bias = initialBias;\n\n\t// Handle the basic code points: let `basic` be the number of input code\n\t// points before the last delimiter, or `0` if there is none, then copy\n\t// the first basic code points to the output.\n\n\tlet basic = input.lastIndexOf(delimiter);\n\tif (basic < 0) {\n\t\tbasic = 0;\n\t}\n\n\tfor (let j = 0; j < basic; ++j) {\n\t\t// if it's not a basic code point\n\t\tif (input.charCodeAt(j) >= 0x80) {\n\t\t\terror('not-basic');\n\t\t}\n\t\toutput.push(input.charCodeAt(j));\n\t}\n\n\t// Main decoding loop: start just after the last delimiter if any basic code\n\t// points were copied; start at the beginning otherwise.\n\n\tfor (let index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {\n\n\t\t// `index` is the index of the next character to be consumed.\n\t\t// Decode a generalized variable-length integer into `delta`,\n\t\t// which gets added to `i`. The overflow checking is easier\n\t\t// if we increase `i` as we go, then subtract off its starting\n\t\t// value at the end to obtain `delta`.\n\t\tlet oldi = i;\n\t\tfor (let w = 1, k = base; /* no condition */; k += base) {\n\n\t\t\tif (index >= inputLength) {\n\t\t\t\terror('invalid-input');\n\t\t\t}\n\n\t\t\tconst digit = basicToDigit(input.charCodeAt(index++));\n\n\t\t\tif (digit >= base || digit > floor((maxInt - i) / w)) {\n\t\t\t\terror('overflow');\n\t\t\t}\n\n\t\t\ti += digit * w;\n\t\t\tconst t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);\n\n\t\t\tif (digit < t) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst baseMinusT = base - t;\n\t\t\tif (w > floor(maxInt / baseMinusT)) {\n\t\t\t\terror('overflow');\n\t\t\t}\n\n\t\t\tw *= baseMinusT;\n\n\t\t}\n\n\t\tconst out = output.length + 1;\n\t\tbias = adapt(i - oldi, out, oldi == 0);\n\n\t\t// `i` was supposed to wrap around from `out` to `0`,\n\t\t// incrementing `n` each time, so we'll fix that now:\n\t\tif (floor(i / out) > maxInt - n) {\n\t\t\terror('overflow');\n\t\t}\n\n\t\tn += floor(i / out);\n\t\ti %= out;\n\n\t\t// Insert `n` at position `i` of the output.\n\t\toutput.splice(i++, 0, n);\n\n\t}\n\n\treturn String.fromCodePoint(...output);\n};\n\n/**\n * Converts a string of Unicode symbols (e.g. a domain name label) to a\n * Punycode string of ASCII-only symbols.\n * @memberOf punycode\n * @param {String} input The string of Unicode symbols.\n * @returns {String} The resulting Punycode string of ASCII-only symbols.\n */\nconst encode = function(input) {\n\tconst output = [];\n\n\t// Convert the input in UCS-2 to an array of Unicode code points.\n\tinput = ucs2decode(input);\n\n\t// Cache the length.\n\tlet inputLength = input.length;\n\n\t// Initialize the state.\n\tlet n = initialN;\n\tlet delta = 0;\n\tlet bias = initialBias;\n\n\t// Handle the basic code points.\n\tfor (const currentValue of input) {\n\t\tif (currentValue < 0x80) {\n\t\t\toutput.push(stringFromCharCode(currentValue));\n\t\t}\n\t}\n\n\tlet basicLength = output.length;\n\tlet handledCPCount = basicLength;\n\n\t// `handledCPCount` is the number of code points that have been handled;\n\t// `basicLength` is the number of basic code points.\n\n\t// Finish the basic string with a delimiter unless it's empty.\n\tif (basicLength) {\n\t\toutput.push(delimiter);\n\t}\n\n\t// Main encoding loop:\n\twhile (handledCPCount < inputLength) {\n\n\t\t// All non-basic code points < n have been handled already. Find the next\n\t\t// larger one:\n\t\tlet m = maxInt;\n\t\tfor (const currentValue of input) {\n\t\t\tif (currentValue >= n && currentValue < m) {\n\t\t\t\tm = currentValue;\n\t\t\t}\n\t\t}\n\n\t\t// Increase `delta` enough to advance the decoder's state to ,\n\t\t// but guard against overflow.\n\t\tconst handledCPCountPlusOne = handledCPCount + 1;\n\t\tif (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {\n\t\t\terror('overflow');\n\t\t}\n\n\t\tdelta += (m - n) * handledCPCountPlusOne;\n\t\tn = m;\n\n\t\tfor (const currentValue of input) {\n\t\t\tif (currentValue < n && ++delta > maxInt) {\n\t\t\t\terror('overflow');\n\t\t\t}\n\t\t\tif (currentValue == n) {\n\t\t\t\t// Represent delta as a generalized variable-length integer.\n\t\t\t\tlet q = delta;\n\t\t\t\tfor (let k = base; /* no condition */; k += base) {\n\t\t\t\t\tconst t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);\n\t\t\t\t\tif (q < t) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst qMinusT = q - t;\n\t\t\t\t\tconst baseMinusT = base - t;\n\t\t\t\t\toutput.push(\n\t\t\t\t\t\tstringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))\n\t\t\t\t\t);\n\t\t\t\t\tq = floor(qMinusT / baseMinusT);\n\t\t\t\t}\n\n\t\t\t\toutput.push(stringFromCharCode(digitToBasic(q, 0)));\n\t\t\t\tbias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);\n\t\t\t\tdelta = 0;\n\t\t\t\t++handledCPCount;\n\t\t\t}\n\t\t}\n\n\t\t++delta;\n\t\t++n;\n\n\t}\n\treturn output.join('');\n};\n\n/**\n * Converts a Punycode string representing a domain name or an email address\n * to Unicode. Only the Punycoded parts of the input will be converted, i.e.\n * it doesn't matter if you call it on a string that has already been\n * converted to Unicode.\n * @memberOf punycode\n * @param {String} input The Punycoded domain name or email address to\n * convert to Unicode.\n * @returns {String} The Unicode representation of the given Punycode\n * string.\n */\nconst toUnicode = function(input) {\n\treturn mapDomain(input, function(string) {\n\t\treturn regexPunycode.test(string)\n\t\t\t? decode(string.slice(4).toLowerCase())\n\t\t\t: string;\n\t});\n};\n\n/**\n * Converts a Unicode string representing a domain name or an email address to\n * Punycode. Only the non-ASCII parts of the domain name will be converted,\n * i.e. it doesn't matter if you call it with a domain that's already in\n * ASCII.\n * @memberOf punycode\n * @param {String} input The domain name or email address to convert, as a\n * Unicode string.\n * @returns {String} The Punycode representation of the given domain name or\n * email address.\n */\nconst toASCII = function(input) {\n\treturn mapDomain(input, function(string) {\n\t\treturn regexNonASCII.test(string)\n\t\t\t? 'xn--' + encode(string)\n\t\t\t: string;\n\t});\n};\n\n/*--------------------------------------------------------------------------*/\n\n/** Define the public API */\nconst punycode = {\n\t/**\n\t * A string representing the current Punycode.js version number.\n\t * @memberOf punycode\n\t * @type String\n\t */\n\t'version': '2.1.0',\n\t/**\n\t * An object of methods to convert from JavaScript's internal character\n\t * representation (UCS-2) to Unicode code points, and back.\n\t * @see \n\t * @memberOf punycode\n\t * @type Object\n\t */\n\t'ucs2': {\n\t\t'decode': ucs2decode,\n\t\t'encode': ucs2encode\n\t},\n\t'decode': decode,\n\t'encode': encode,\n\t'toASCII': toASCII,\n\t'toUnicode': toUnicode\n};\n\nmodule.exports = punycode;\n", "// markdown-it default options\n\n'use strict';\n\n\nmodule.exports = {\n options: {\n html: false, // Enable HTML tags in source\n xhtmlOut: false, // Use '/' to close single tags (
)\n breaks: false, // Convert '\\n' in paragraphs into
\n langPrefix: 'language-', // CSS language prefix for fenced blocks\n linkify: false, // autoconvert URL-like texts to links\n\n // Enable some language-neutral replacements + quotes beautification\n typographer: false,\n\n // Double + single quotes replacement pairs, when typographer enabled,\n // and smartquotes on. Could be either a String or an Array.\n //\n // For example, you can use '\u00AB\u00BB\u201E\u201C' for Russian, '\u201E\u201C\u201A\u2018' for German,\n // and ['\u00AB\\xA0', '\\xA0\u00BB', '\u2039\\xA0', '\\xA0\u203A'] for French (including nbsp).\n quotes: '\\u201c\\u201d\\u2018\\u2019', /* \u201C\u201D\u2018\u2019 */\n\n // Highlighter function. Should return escaped HTML,\n // or '' if the source string is not changed and should be escaped externaly.\n // If result starts with )\n breaks: false, // Convert '\\n' in paragraphs into
\n langPrefix: 'language-', // CSS language prefix for fenced blocks\n linkify: false, // autoconvert URL-like texts to links\n\n // Enable some language-neutral replacements + quotes beautification\n typographer: false,\n\n // Double + single quotes replacement pairs, when typographer enabled,\n // and smartquotes on. Could be either a String or an Array.\n //\n // For example, you can use '\u00AB\u00BB\u201E\u201C' for Russian, '\u201E\u201C\u201A\u2018' for German,\n // and ['\u00AB\\xA0', '\\xA0\u00BB', '\u2039\\xA0', '\\xA0\u203A'] for French (including nbsp).\n quotes: '\\u201c\\u201d\\u2018\\u2019', /* \u201C\u201D\u2018\u2019 */\n\n // Highlighter function. Should return escaped HTML,\n // or '' if the source string is not changed and should be escaped externaly.\n // If result starts with )\n breaks: false, // Convert '\\n' in paragraphs into
\n langPrefix: 'language-', // CSS language prefix for fenced blocks\n linkify: false, // autoconvert URL-like texts to links\n\n // Enable some language-neutral replacements + quotes beautification\n typographer: false,\n\n // Double + single quotes replacement pairs, when typographer enabled,\n // and smartquotes on. Could be either a String or an Array.\n //\n // For example, you can use '\u00AB\u00BB\u201E\u201C' for Russian, '\u201E\u201C\u201A\u2018' for German,\n // and ['\u00AB\\xA0', '\\xA0\u00BB', '\u2039\\xA0', '\\xA0\u203A'] for French (including nbsp).\n quotes: '\\u201c\\u201d\\u2018\\u2019', /* \u201C\u201D\u2018\u2019 */\n\n // Highlighter function. Should return escaped HTML,\n // or '' if the source string is not changed and should be escaped externaly.\n // If result starts with = 0) {\n try {\n parsed.hostname = punycode.toASCII(parsed.hostname);\n } catch (er) { /**/ }\n }\n }\n\n return mdurl.encode(mdurl.format(parsed));\n}\n\nfunction normalizeLinkText(url) {\n var parsed = mdurl.parse(url, true);\n\n if (parsed.hostname) {\n // Encode hostnames in urls like:\n // `http://host/`, `https://host/`, `mailto:user@host`, `//host/`\n //\n // We don't encode unknown schemas, because it's likely that we encode\n // something we shouldn't (e.g. `skype:name` treated as `skype:host`)\n //\n if (!parsed.protocol || RECODE_HOSTNAME_FOR.indexOf(parsed.protocol) >= 0) {\n try {\n parsed.hostname = punycode.toUnicode(parsed.hostname);\n } catch (er) { /**/ }\n }\n }\n\n // add '%' to exclude list because of https://github.com/markdown-it/markdown-it/issues/720\n return mdurl.decode(mdurl.format(parsed), mdurl.decode.defaultChars + '%');\n}\n\n\n/**\n * class MarkdownIt\n *\n * Main parser/renderer class.\n *\n * ##### Usage\n *\n * ```javascript\n * // node.js, \"classic\" way:\n * var MarkdownIt = require('markdown-it'),\n * md = new MarkdownIt();\n * var result = md.render('# markdown-it rulezz!');\n *\n * // node.js, the same, but with sugar:\n * var md = require('markdown-it')();\n * var result = md.render('# markdown-it rulezz!');\n *\n * // browser without AMD, added to \"window\" on script load\n * // Note, there are no dash.\n * var md = window.markdownit();\n * var result = md.render('# markdown-it rulezz!');\n * ```\n *\n * Single line rendering, without paragraph wrap:\n *\n * ```javascript\n * var md = require('markdown-it')();\n * var result = md.renderInline('__markdown-it__ rulezz!');\n * ```\n **/\n\n/**\n * new MarkdownIt([presetName, options])\n * - presetName (String): optional, `commonmark` / `zero`\n * - options (Object)\n *\n * Creates parser instanse with given config. Can be called without `new`.\n *\n * ##### presetName\n *\n * MarkdownIt provides named presets as a convenience to quickly\n * enable/disable active syntax rules and options for common use cases.\n *\n * - [\"commonmark\"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/commonmark.js) -\n * configures parser to strict [CommonMark](http://commonmark.org/) mode.\n * - [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.js) -\n * similar to GFM, used when no preset name given. Enables all available rules,\n * but still without html, typographer & autolinker.\n * - [\"zero\"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.js) -\n * all rules disabled. Useful to quickly setup your config via `.enable()`.\n * For example, when you need only `bold` and `italic` markup and nothing else.\n *\n * ##### options:\n *\n * - __html__ - `false`. Set `true` to enable HTML tags in source. Be careful!\n * That's not safe! You may need external sanitizer to protect output from XSS.\n * It's better to extend features via plugins, instead of enabling HTML.\n * - __xhtmlOut__ - `false`. Set `true` to add '/' when closing single tags\n * (`
`). This is needed only for full CommonMark compatibility. In real\n * world you will need HTML output.\n * - __breaks__ - `false`. Set `true` to convert `\\n` in paragraphs into `
`.\n * - __langPrefix__ - `language-`. CSS language class prefix for fenced blocks.\n * Can be useful for external highlighters.\n * - __linkify__ - `false`. Set `true` to autoconvert URL-like text to links.\n * - __typographer__ - `false`. Set `true` to enable [some language-neutral\n * replacement](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/replacements.js) +\n * quotes beautification (smartquotes).\n * - __quotes__ - `\u201C\u201D\u2018\u2019`, String or Array. Double + single quotes replacement\n * pairs, when typographer enabled and smartquotes on. For example, you can\n * use `'\u00AB\u00BB\u201E\u201C'` for Russian, `'\u201E\u201C\u201A\u2018'` for German, and\n * `['\u00AB\\xA0', '\\xA0\u00BB', '\u2039\\xA0', '\\xA0\u203A']` for French (including nbsp).\n * - __highlight__ - `null`. Highlighter function for fenced code blocks.\n * Highlighter `function (str, lang)` should return escaped HTML. It can also\n * return empty string if the source was not changed and should be escaped\n * externaly. If result starts with `):\n *\n * ```javascript\n * var hljs = require('highlight.js') // https://highlightjs.org/\n *\n * // Actual default values\n * var md = require('markdown-it')({\n * highlight: function (str, lang) {\n * if (lang && hljs.getLanguage(lang)) {\n * try {\n * return '
' +\n *                hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +\n *                '
';\n * } catch (__) {}\n * }\n *\n * return '
' + md.utils.escapeHtml(str) + '
';\n * }\n * });\n * ```\n *\n **/\nfunction MarkdownIt(presetName, options) {\n if (!(this instanceof MarkdownIt)) {\n return new MarkdownIt(presetName, options);\n }\n\n if (!options) {\n if (!utils.isString(presetName)) {\n options = presetName || {};\n presetName = 'default';\n }\n }\n\n /**\n * MarkdownIt#inline -> ParserInline\n *\n * Instance of [[ParserInline]]. You may need it to add new rules when\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\n * [[MarkdownIt.enable]].\n **/\n this.inline = new ParserInline();\n\n /**\n * MarkdownIt#block -> ParserBlock\n *\n * Instance of [[ParserBlock]]. You may need it to add new rules when\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\n * [[MarkdownIt.enable]].\n **/\n this.block = new ParserBlock();\n\n /**\n * MarkdownIt#core -> Core\n *\n * Instance of [[Core]] chain executor. You may need it to add new rules when\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\n * [[MarkdownIt.enable]].\n **/\n this.core = new ParserCore();\n\n /**\n * MarkdownIt#renderer -> Renderer\n *\n * Instance of [[Renderer]]. Use it to modify output look. Or to add rendering\n * rules for new token types, generated by plugins.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * function myToken(tokens, idx, options, env, self) {\n * //...\n * return result;\n * };\n *\n * md.renderer.rules['my_token'] = myToken\n * ```\n *\n * See [[Renderer]] docs and [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js).\n **/\n this.renderer = new Renderer();\n\n /**\n * MarkdownIt#linkify -> LinkifyIt\n *\n * [linkify-it](https://github.com/markdown-it/linkify-it) instance.\n * Used by [linkify](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/linkify.js)\n * rule.\n **/\n this.linkify = new LinkifyIt();\n\n /**\n * MarkdownIt#validateLink(url) -> Boolean\n *\n * Link validation function. CommonMark allows too much in links. By default\n * we disable `javascript:`, `vbscript:`, `file:` schemas, and almost all `data:...` schemas\n * except some embedded image types.\n *\n * You can change this behaviour:\n *\n * ```javascript\n * var md = require('markdown-it')();\n * // enable everything\n * md.validateLink = function () { return true; }\n * ```\n **/\n this.validateLink = validateLink;\n\n /**\n * MarkdownIt#normalizeLink(url) -> String\n *\n * Function used to encode link url to a machine-readable format,\n * which includes url-encoding, punycode, etc.\n **/\n this.normalizeLink = normalizeLink;\n\n /**\n * MarkdownIt#normalizeLinkText(url) -> String\n *\n * Function used to decode link url to a human-readable format`\n **/\n this.normalizeLinkText = normalizeLinkText;\n\n\n // Expose utils & helpers for easy acces from plugins\n\n /**\n * MarkdownIt#utils -> utils\n *\n * Assorted utility functions, useful to write plugins. See details\n * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.js).\n **/\n this.utils = utils;\n\n /**\n * MarkdownIt#helpers -> helpers\n *\n * Link components parser functions, useful to write plugins. See details\n * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers).\n **/\n this.helpers = utils.assign({}, helpers);\n\n\n this.options = {};\n this.configure(presetName);\n\n if (options) { this.set(options); }\n}\n\n\n/** chainable\n * MarkdownIt.set(options)\n *\n * Set parser options (in the same format as in constructor). Probably, you\n * will never need it, but you can change options after constructor call.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')()\n * .set({ html: true, breaks: true })\n * .set({ typographer, true });\n * ```\n *\n * __Note:__ To achieve the best possible performance, don't modify a\n * `markdown-it` instance options on the fly. If you need multiple configurations\n * it's best to create multiple instances and initialize each with separate\n * config.\n **/\nMarkdownIt.prototype.set = function (options) {\n utils.assign(this.options, options);\n return this;\n};\n\n\n/** chainable, internal\n * MarkdownIt.configure(presets)\n *\n * Batch load of all options and compenent settings. This is internal method,\n * and you probably will not need it. But if you will - see available presets\n * and data structure [here](https://github.com/markdown-it/markdown-it/tree/master/lib/presets)\n *\n * We strongly recommend to use presets instead of direct config loads. That\n * will give better compatibility with next versions.\n **/\nMarkdownIt.prototype.configure = function (presets) {\n var self = this, presetName;\n\n if (utils.isString(presets)) {\n presetName = presets;\n presets = config[presetName];\n if (!presets) { throw new Error('Wrong `markdown-it` preset \"' + presetName + '\", check name'); }\n }\n\n if (!presets) { throw new Error('Wrong `markdown-it` preset, can\\'t be empty'); }\n\n if (presets.options) { self.set(presets.options); }\n\n if (presets.components) {\n Object.keys(presets.components).forEach(function (name) {\n if (presets.components[name].rules) {\n self[name].ruler.enableOnly(presets.components[name].rules);\n }\n if (presets.components[name].rules2) {\n self[name].ruler2.enableOnly(presets.components[name].rules2);\n }\n });\n }\n return this;\n};\n\n\n/** chainable\n * MarkdownIt.enable(list, ignoreInvalid)\n * - list (String|Array): rule name or list of rule names to enable\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\n *\n * Enable list or rules. It will automatically find appropriate components,\n * containing rules with given names. If rule not found, and `ignoreInvalid`\n * not set - throws exception.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')()\n * .enable(['sub', 'sup'])\n * .disable('smartquotes');\n * ```\n **/\nMarkdownIt.prototype.enable = function (list, ignoreInvalid) {\n var result = [];\n\n if (!Array.isArray(list)) { list = [ list ]; }\n\n [ 'core', 'block', 'inline' ].forEach(function (chain) {\n result = result.concat(this[chain].ruler.enable(list, true));\n }, this);\n\n result = result.concat(this.inline.ruler2.enable(list, true));\n\n var missed = list.filter(function (name) { return result.indexOf(name) < 0; });\n\n if (missed.length && !ignoreInvalid) {\n throw new Error('MarkdownIt. Failed to enable unknown rule(s): ' + missed);\n }\n\n return this;\n};\n\n\n/** chainable\n * MarkdownIt.disable(list, ignoreInvalid)\n * - list (String|Array): rule name or list of rule names to disable.\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\n *\n * The same as [[MarkdownIt.enable]], but turn specified rules off.\n **/\nMarkdownIt.prototype.disable = function (list, ignoreInvalid) {\n var result = [];\n\n if (!Array.isArray(list)) { list = [ list ]; }\n\n [ 'core', 'block', 'inline' ].forEach(function (chain) {\n result = result.concat(this[chain].ruler.disable(list, true));\n }, this);\n\n result = result.concat(this.inline.ruler2.disable(list, true));\n\n var missed = list.filter(function (name) { return result.indexOf(name) < 0; });\n\n if (missed.length && !ignoreInvalid) {\n throw new Error('MarkdownIt. Failed to disable unknown rule(s): ' + missed);\n }\n return this;\n};\n\n\n/** chainable\n * MarkdownIt.use(plugin, params)\n *\n * Load specified plugin with given params into current parser instance.\n * It's just a sugar to call `plugin(md, params)` with curring.\n *\n * ##### Example\n *\n * ```javascript\n * var iterator = require('markdown-it-for-inline');\n * var md = require('markdown-it')()\n * .use(iterator, 'foo_replace', 'text', function (tokens, idx) {\n * tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar');\n * });\n * ```\n **/\nMarkdownIt.prototype.use = function (plugin /*, params, ... */) {\n var args = [ this ].concat(Array.prototype.slice.call(arguments, 1));\n plugin.apply(plugin, args);\n return this;\n};\n\n\n/** internal\n * MarkdownIt.parse(src, env) -> Array\n * - src (String): source string\n * - env (Object): environment sandbox\n *\n * Parse input string and return list of block tokens (special token type\n * \"inline\" will contain list of inline tokens). You should not call this\n * method directly, until you write custom renderer (for example, to produce\n * AST).\n *\n * `env` is used to pass data between \"distributed\" rules and return additional\n * metadata like reference info, needed for the renderer. It also can be used to\n * inject data in specific cases. Usually, you will be ok to pass `{}`,\n * and then pass updated object to renderer.\n **/\nMarkdownIt.prototype.parse = function (src, env) {\n if (typeof src !== 'string') {\n throw new Error('Input data should be a String');\n }\n\n var state = new this.core.State(src, this, env);\n\n this.core.process(state);\n\n return state.tokens;\n};\n\n\n/**\n * MarkdownIt.render(src [, env]) -> String\n * - src (String): source string\n * - env (Object): environment sandbox\n *\n * Render markdown string into html. It does all magic for you :).\n *\n * `env` can be used to inject additional metadata (`{}` by default).\n * But you will not need it with high probability. See also comment\n * in [[MarkdownIt.parse]].\n **/\nMarkdownIt.prototype.render = function (src, env) {\n env = env || {};\n\n return this.renderer.render(this.parse(src, env), this.options, env);\n};\n\n\n/** internal\n * MarkdownIt.parseInline(src, env) -> Array\n * - src (String): source string\n * - env (Object): environment sandbox\n *\n * The same as [[MarkdownIt.parse]] but skip all block rules. It returns the\n * block tokens list with the single `inline` element, containing parsed inline\n * tokens in `children` property. Also updates `env` object.\n **/\nMarkdownIt.prototype.parseInline = function (src, env) {\n var state = new this.core.State(src, this, env);\n\n state.inlineMode = true;\n this.core.process(state);\n\n return state.tokens;\n};\n\n\n/**\n * MarkdownIt.renderInline(src [, env]) -> String\n * - src (String): source string\n * - env (Object): environment sandbox\n *\n * Similar to [[MarkdownIt.render]] but for single paragraph content. Result\n * will NOT be wrapped into `

` tags.\n **/\nMarkdownIt.prototype.renderInline = function (src, env) {\n env = env || {};\n\n return this.renderer.render(this.parseInline(src, env), this.options, env);\n};\n\n\nmodule.exports = MarkdownIt;\n", "'use strict';\n\n\nmodule.exports = require('./lib/');\n", "/* Dutch (UTF-8) initialisation for the jQuery UI date picker plugin. */\n/* Written by Mathias Bynens */\njQuery(function($){\n\t$.datepicker.regional.nl = {\n\t\tcloseText: 'Sluiten',\n\t\tprevText: '\u2190',\n\t\tnextText: '\u2192',\n\t\tcurrentText: 'Vandaag',\n\t\tmonthNames: ['januari', 'februari', 'maart', 'april', 'mei', 'juni',\n\t\t'juli', 'augustus', 'september', 'oktober', 'november', 'december'],\n\t\tmonthNamesShort: ['jan', 'feb', 'mrt', 'apr', 'mei', 'jun',\n\t\t'jul', 'aug', 'sep', 'okt', 'nov', 'dec'],\n\t\tdayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'],\n\t\tdayNamesShort: ['zon', 'maa', 'din', 'woe', 'don', 'vri', 'zat'],\n\t\tdayNamesMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'],\n\t\tweekHeader: 'Wk',\n\t\tdateFormat: 'dd-mm-yy',\n\t\tfirstDay: 1,\n\t\tisRTL: false,\n\t\tshowMonthAfterYear: false,\n\t\tyearSuffix: ''};\n\t$.datepicker.setDefaults($.datepicker.regional.nl);\n});\n", "/******* Translations ******/\n\nconst dicts = {};\n\nlet dict = {};\n\n// gettext stub\nfunction _(s, fb) {\n return dict[s] || fb || s;\n}\n\n_.tagged = (strings, ...values) =>\n strings.reduce((acc, cur, idx) => acc + cur + _(values[idx] || \"\"), \"\");\n\n_.taggedWithin =\n prefix =>\n (strings, ...values) =>\n strings.reduce(\n (acc, cur, idx) =>\n acc +\n cur +\n (_(prefix, { [values[idx]]: values[idx] })[values[idx]] ||\n values[idx] ||\n \"\"),\n \"\"\n );\n\n_.set = function (ob) {\n const lang = ob[\"lang\"] || _(\"lang\"); // Either provided or current lang?\n if (!dicts[lang]) {\n dicts[lang] = {};\n }\n for (let [key, val] of Object.entries(ob)) {\n // Set only if not set before (by _.set, or by _.addTranslations)\n dicts[lang][key] || (dicts[lang][key] = val);\n }\n dict = dicts[lang];\n};\n\n_.addTranslations = function (translations) {\n for (var term in translations) {\n if (translations.hasOwnProperty(term))\n for (var lang in translations[term]) {\n if (!dicts[lang]) dicts[lang] = {};\n // Always override what has been set before\n dicts[lang][term] = translations[term][lang];\n }\n }\n};\n\nObject.freeze(_);\n\nexport { _ };\n", "import { _ } from \"$json/lib/gettext\";\n\nconst strings = {\n \"lang\": \"nl\",\n \"Doubleclick to go back to this question\":\n \"Dubbelklikken om naar deze vraag terug te springen\",\n \"create a new case\": \"maak een nieuwe casus aan\",\n \"new\": \"nieuw\",\n \"Delete\": \"Verwijder\",\n \"case\": \"casus\",\n \"cases\": \"casus\",\n \"Last opened\": \"Laatst geopend\",\n \"created\": \"gemaakt\",\n \"report\": \"rapport\",\n \"Sun\": \"Zo\",\n \"Mon\": \"Ma\",\n \"Tue\": \"Di\",\n \"Wed\": \"Wo\",\n \"Thu\": \"Do\",\n \"Fri\": \"Vr\",\n \"Sat\": \"Za\",\n \"Jan\": \"Jan\",\n \"Feb\": \"Feb\",\n \"Mar\": \"Maart\",\n \"Apr\": \"April\",\n \"May\": \"Mei\",\n \"June\": \"Juni\",\n \"July\": \"Juli\",\n \"Aug\": \"Aug\",\n \"Sep\": \"Sep\",\n \"Oct\": \"Okt\",\n \"Nov\": \"Nov\",\n \"Dec\": \"Dec\",\n \"press enter to accept\": \"accepteer met ENTER\",\n \"filter cases by name\": \"zoek casus op naam\",\n \"field--value\": \"deze waarde\",\n \"field--date\": \"deze datum\",\n \"field--field\": \"dit veld\",\n \"field--list\": \"deze opties\",\n \"quoted--value\": \"de waarde \u201C{quotable}\u201D\",\n \"quoted--date\": \"de datum \u201C{quotable}\u201D\",\n \"quoted--field\": \"het veld \u201C{quotable}\u201D\",\n \"quoted--list\": \"de opties in \u201C{quotable}\u201D\",\n \"Date required\":\n \"{quotable--init} is verplicht; gebruik het formaat dd\u200A-\u200Amm\u200A-\u200Aj\u200Aj\u200Aj\u200Aj.\",\n \"Input required\": \"{quotable--init} is verplicht\",\n \"Choice required\": \"Keuze uit {quotable} is verplicht\",\n \"Field required\": \"{quotable--init} is verplicht\",\n \"Value has to lie between {minimum} and {maximum}\":\n \"{quotable--init} moet tussen {minimum} en {maximum} liggen\",\n \"Date has to lie between {minimum} and {maximum}\":\n \"{quotable--init} moet tussen {minimum} en {maximum} liggen; gebruik het formaat dd-mm-jjjj.\",\n \"Negative number or zero expected\":\n \"{quotable--init} moet negatief zijn of nul\",\n \"Negative number expected\": \"{quotable--init} moet negatief zijn\",\n \"Value has to lie below {maximum}\":\n \"{quotable--init} moet lager zijn dan {maximum+1}\",\n \"Positive number or zero expected\": \"{quotable} moet positief zijn of nul\",\n \"Positive number expected\": \"{quotable} moet hoger zijn dan nul\",\n \"Value has to lie above {minimum}\":\n \"{quotable--init} moet hoger zijn dan {minimum-1}\",\n \"A date after {maximum} is not allowed\":\n \"{quotable--init} n\u00E1 {maximum} is niet toegestaan; gebruik het formaat dd-mm-jjjj.\",\n \"A date before {minimum} is not allowed\":\n \"{quotable--init} v\u00F3\u00F3r {minimum} is niet toegestaan; gebruik het formaat dd-mm-jjjj.\",\n \"Invalid date\":\n \"{quotable--init} is ongeldig; gebruik het formaat dd-mm-jjjj.\",\n \"Invalid number\": \"{quotable--init} is geen getal\",\n \"Text length exceeds the maximum of {0} characters\":\n \"{quotable--init} mag maximaal {maxlength} karakters bevatten\",\n \"click for more...\": \"klik voor meer...\",\n \" (click to open link)\": \" (klik om link te openen)\",\n \"Are you sure? This will reset all values.\":\n \"Weet u het zeker? Dit zal alle ingevulde velden leegmaken.\",\n \"Yesterday\": \"Gisteren\",\n \"No valid session\": \"Ongeldige gebruikersnaam of wachtwoord\",\n \"Maximum allowed characters: {0}\": \"Maximaal {0} karakters toegestaan\",\n \"No interfaces to show\":\n \"Geen zichtbare elementen (vragen, tekstvelden) gedefinieerd\",\n // feedback\n \"Feedback\": \"Feedback\",\n \"describe the problem\": \"omschrijf het probleem\",\n \"Please do not collate issues.\": \"Een melding per keer!\",\n \"Please send only feedback about the currently visible question or questions; information about these will be sent back to the developers.\":\n \"Geef alleen feedback over de vraag of vragen die je op dit moment op je scherm ziet; informatie over die vragen wordt namelijk meegezonden naar de ontwikkelaars.\",\n \"send\": \"verstuur\",\n \"Thanks for your feedback!\": \"Bedankt voor uw melding!\",\n \"Interface has failed (probably a failing SOAP or database connection)\":\n \"Interface gefaald (waarschijnlijk een falende SOAP- of databasekoppeling)\",\n \"Choose...\": \"Kies...\",\n \"Choose or type...\": \"Kies of typ...\",\n \"cUMWrongUserNamePassword\": \"Ongeldige gebruikersnaam of wachtwoord\",\n \"cWebCaseIsRunning\":\n \"Casus laden is niet gelukt; deze casus wordt al gedraaid in een andere sessie\",\n \"The model you are trying to open does not exist\":\n \"Het beslismodel dat u probeert te openen bestaat niet\",\n \"You may now safely close this window\": \"U kunt het venster nu sluiten\",\n \"user name\": \"gebruikersnaam\",\n \"password\": \"wachtwoord\",\n \"Your models\": \"Uw modellen\",\n \"Your sessions\": \"Uw sessies\",\n \"log in\": \"inloggen\",\n \"load session\": \"Lees uw gegevens in\",\n \"load\": \"inlezen\",\n \"Choose the session file you saved earlier\":\n \"Kies het gegevensbestand dat u de vorige keer hebt opgeslagen\",\n \"Error loading session (wrong data)\":\n \"Inlezen gegevens mislukt (verkeerde gegevens).\",\n \"Please login\": \"Gelieve in te loggen\",\n \"open\": \"open\",\n \"copy\": \"kopie\",\n 'You have no tickets left for model \"{0}\"':\n 'Uw strippenkaart voor model \"{0}\" is op',\n \"__digitgroupingchar__\": \".\",\n \"__radixpoint__\": \",\",\n \"__digitgroupingrules__\": [3],\n \"attachments\": \"bijlagen\",\n \"your documents\": \"uw documenten\",\n \"saved sessions\": \"bewaarde sessies\",\n \"We are currently updating. Please try again later.\":\n \"Er is momenteel een update aan de gang, probeert u het binnenkort nogmaals.\",\n \"case name\": \"casusnaam\",\n \"dateplaceholder\": \"dd\u200A-\u200Amm\u200A-\u200Aj\u200Aj\u200Aj\u200Aj\",\n \"Error: No response from server, server probably down\":\n \"Fout: Server is tijdelijk buiten gebruik. U moet zich opnieuw aanmelden.\",\n \"Session has timed out. Please log in again.\":\n \"De sessie is afgelopen. U moet zich opnieuw aanmelden.\",\n \"first {0} results\": \"eerste {0} resultaten\",\n \"previous {0} results\": \"vorige {0} resultaten\",\n \"next {0} results\": \"volgende {0} resultaten\",\n \"last {0} results\": \"laatste {0} resultaten\",\n \"results {0} to {1} from {2}\": \"resultaten {0} tot {1} van {2}\",\n \"add row\": \"Voeg rij toe\",\n \"insert row\": \"voeg rij in\",\n \"delete row\": \"verwijder rij\",\n \"There are errors, please double check your answers.\":\n \"Er zijn nog fouten, gelieve uw antwoorden nogmaals na te gaan.\",\n \"cancel\": \"annuleer\",\n \"Something went wrong; see the server log for more information.\":\n \"Er is iets misgegaan; bekijk de server log voor meer informatie\"\n};\n\n_.set(strings);\n\nexport { strings };\n", "/*! (c) Andrea Giammarchi - ISC */\nvar self = window || /* istanbul ignore next */ {};\ntry {\n (function (URLSearchParams, plus) {\n if (\n new URLSearchParams(\"q=%2B\").get(\"q\") !== plus ||\n new URLSearchParams({ q: plus }).get(\"q\") !== plus ||\n new URLSearchParams([[\"q\", plus]]).get(\"q\") !== plus ||\n new URLSearchParams(\"q=\\n\").toString() !== \"q=%0A\" ||\n new URLSearchParams({ q: \" &\" }).toString() !== \"q=+%26\" ||\n new URLSearchParams({ q: \"%zx\" }).toString() !== \"q=%25zx\"\n )\n throw URLSearchParams;\n self.URLSearchParams = URLSearchParams;\n })(URLSearchParams, \"+\");\n} catch (URLSearchParams) {\n (function (Object, String, isArray) {\n \"use strict\";\n var create = Object.create;\n var defineProperty = Object.defineProperty;\n var find = /[!'\\(\\)~]|%20|%00/g;\n var findPercentSign = /%(?![0-9a-fA-F]{2})/g;\n var plus = /\\+/g;\n var replace = {\n \"!\": \"%21\",\n \"'\": \"%27\",\n \"(\": \"%28\",\n \")\": \"%29\",\n \"~\": \"%7E\",\n \"%20\": \"+\",\n \"%00\": \"\\x00\"\n };\n var proto = {\n append: function (key, value) {\n appendTo(this._ungap, key, value);\n },\n delete: function (key) {\n delete this._ungap[key];\n },\n get: function (key) {\n return this.has(key) ? this._ungap[key][0] : null;\n },\n getAll: function (key) {\n return this.has(key) ? this._ungap[key].slice(0) : [];\n },\n has: function (key) {\n return key in this._ungap;\n },\n set: function (key, value) {\n this._ungap[key] = [String(value)];\n },\n forEach: function (callback, thisArg) {\n var self = this;\n for (var key in self._ungap) self._ungap[key].forEach(invoke, key);\n function invoke(value) {\n callback.call(thisArg, value, String(key), self);\n }\n },\n toJSON: function () {\n return {};\n },\n toString: function () {\n var query = [];\n for (var key in this._ungap) {\n var encoded = encode(key);\n for (var i = 0, value = this._ungap[key]; i < value.length; i++) {\n query.push(encoded + \"=\" + encode(value[i]));\n }\n }\n return query.join(\"&\");\n }\n };\n for (var key in proto)\n defineProperty(URLSearchParams.prototype, key, {\n configurable: true,\n writable: true,\n value: proto[key]\n });\n self.URLSearchParams = URLSearchParams;\n function URLSearchParams(query) {\n var dict = create(null);\n defineProperty(this, \"_ungap\", { value: dict });\n switch (true) {\n case !query:\n break;\n case typeof query === \"string\":\n if (query.charAt(0) === \"?\") {\n query = query.slice(1);\n }\n for (\n var pairs = query.split(\"&\"), i = 0, length = pairs.length;\n i < length;\n i++\n ) {\n var value = pairs[i];\n var index = value.indexOf(\"=\");\n if (-1 < index) {\n appendTo(\n dict,\n decode(value.slice(0, index)),\n decode(value.slice(index + 1))\n );\n } else if (value.length) {\n appendTo(dict, decode(value), \"\");\n }\n }\n break;\n case isArray(query):\n for (var i = 0, length = query.length; i < length; i++) {\n var value = query[i];\n appendTo(dict, value[0], value[1]);\n }\n break;\n case \"forEach\" in query:\n query.forEach(addEach, dict);\n break;\n default:\n for (var key in query) appendTo(dict, key, query[key]);\n }\n }\n\n function addEach(value, key) {\n appendTo(this, key, value);\n }\n\n function appendTo(dict, key, value) {\n var res = isArray(value) ? value.join(\",\") : value;\n if (key in dict) dict[key].push(res);\n else dict[key] = [res];\n }\n\n function decode(str) {\n return decodeURIComponent(\n str.replace(findPercentSign, \"%25\").replace(plus, \" \")\n );\n }\n\n function encode(str) {\n return encodeURIComponent(str).replace(find, replacer);\n }\n\n function replacer(match) {\n return replace[match];\n }\n })(Object, String, Array.isArray);\n}\n\n(function (URLSearchParamsProto) {\n var iterable = false;\n try {\n iterable = !!Symbol.iterator;\n } catch (o_O) {}\n\n /* istanbul ignore else */\n if (!(\"forEach\" in URLSearchParamsProto)) {\n URLSearchParamsProto.forEach = function forEach(callback, thisArg) {\n var self = this;\n var names = Object.create(null);\n this.toString()\n .replace(/=[\\s\\S]*?(?:&|$)/g, \"=\")\n .split(\"=\")\n .forEach(function (name) {\n if (!name.length || name in names) return;\n (names[name] = self.getAll(name)).forEach(function (value) {\n callback.call(thisArg, value, name, self);\n });\n });\n };\n }\n\n /* istanbul ignore else */\n if (!(\"keys\" in URLSearchParamsProto)) {\n URLSearchParamsProto.keys = function keys() {\n return iterator(this, function (value, key) {\n this.push(key);\n });\n };\n }\n\n /* istanbul ignore else */\n if (!(\"values\" in URLSearchParamsProto)) {\n URLSearchParamsProto.values = function values() {\n return iterator(this, function (value, key) {\n this.push(value);\n });\n };\n }\n\n /* istanbul ignore else */\n if (!(\"entries\" in URLSearchParamsProto)) {\n URLSearchParamsProto.entries = function entries() {\n return iterator(this, function (value, key) {\n this.push([key, value]);\n });\n };\n }\n\n /* istanbul ignore else */\n if (iterable && !(Symbol.iterator in URLSearchParamsProto)) {\n URLSearchParamsProto[Symbol.iterator] = URLSearchParamsProto.entries;\n }\n\n /* istanbul ignore else */\n if (!(\"sort\" in URLSearchParamsProto)) {\n URLSearchParamsProto.sort = function sort() {\n var entries = this.entries(),\n entry = entries.next(),\n done = entry.done,\n keys = [],\n values = Object.create(null),\n i,\n key,\n value;\n while (!done) {\n value = entry.value;\n key = value[0];\n keys.push(key);\n if (!(key in values)) {\n values[key] = [];\n }\n values[key].push(value[1]);\n entry = entries.next();\n done = entry.done;\n }\n // not the champion in efficiency\n // but these two bits just do the job\n keys.sort();\n for (i = 0; i < keys.length; i++) {\n this.delete(keys[i]);\n }\n for (i = 0; i < keys.length; i++) {\n key = keys[i];\n this.append(key, values[key].shift());\n }\n };\n }\n\n function iterator(self, callback) {\n var items = [];\n self.forEach(callback, items);\n return iterable\n ? items[Symbol.iterator]()\n : {\n next: function () {\n var value = items.shift();\n return { done: value === undefined, value: value };\n }\n };\n }\n\n /* istanbul ignore next */\n (function (Object) {\n var dP = Object.defineProperty,\n gOPD = Object.getOwnPropertyDescriptor,\n createSearchParamsPollute = function (search) {\n function append(name, value) {\n URLSearchParamsProto.append.call(this, name, value);\n name = this.toString();\n search.set.call(this._usp, name ? \"?\" + name : \"\");\n }\n function del(name) {\n URLSearchParamsProto.delete.call(this, name);\n name = this.toString();\n search.set.call(this._usp, name ? \"?\" + name : \"\");\n }\n function set(name, value) {\n URLSearchParamsProto.set.call(this, name, value);\n name = this.toString();\n search.set.call(this._usp, name ? \"?\" + name : \"\");\n }\n return function (sp, value) {\n sp.append = append;\n sp.delete = del;\n sp.set = set;\n return dP(sp, \"_usp\", {\n configurable: true,\n writable: true,\n value: value\n });\n };\n },\n createSearchParamsCreate = function (polluteSearchParams) {\n return function (obj, sp) {\n dP(obj, \"_searchParams\", {\n configurable: true,\n writable: true,\n value: polluteSearchParams(sp, obj)\n });\n return sp;\n };\n },\n updateSearchParams = function (sp) {\n var append = sp.append;\n sp.append = URLSearchParamsProto.append;\n URLSearchParams.call(sp, sp._usp.search.slice(1));\n sp.append = append;\n },\n verifySearchParams = function (obj, Class) {\n if (!(obj instanceof Class))\n throw new TypeError(\n \"'searchParams' accessed on an object that \" +\n \"does not implement interface \" +\n Class.name\n );\n },\n upgradeClass = function (Class) {\n var ClassProto = Class.prototype,\n searchParams = gOPD(ClassProto, \"searchParams\"),\n href = gOPD(ClassProto, \"href\"),\n search = gOPD(ClassProto, \"search\"),\n createSearchParams;\n if (!searchParams && search && search.set) {\n createSearchParams = createSearchParamsCreate(\n createSearchParamsPollute(search)\n );\n Object.defineProperties(ClassProto, {\n href: {\n get: function () {\n return href.get.call(this);\n },\n set: function (value) {\n var sp = this._searchParams;\n href.set.call(this, value);\n if (sp) updateSearchParams(sp);\n }\n },\n search: {\n get: function () {\n return search.get.call(this);\n },\n set: function (value) {\n var sp = this._searchParams;\n search.set.call(this, value);\n if (sp) updateSearchParams(sp);\n }\n },\n searchParams: {\n get: function () {\n verifySearchParams(this, Class);\n return (\n this._searchParams ||\n createSearchParams(\n this,\n new URLSearchParams(this.search.slice(1))\n )\n );\n },\n set: function (sp) {\n verifySearchParams(this, Class);\n createSearchParams(this, sp);\n }\n }\n });\n }\n };\n try {\n upgradeClass(HTMLAnchorElement);\n if (/^function|object$/.test(typeof URL) && URL.prototype)\n upgradeClass(URL);\n } catch (meh) {}\n })(Object);\n})(self.URLSearchParams.prototype, Object);\nexport default self.URLSearchParams;\n", "/******* positionalFormat() BEGIN ******/\n\n/* https://github.com/pft/javascript/blob/master/positionalformat.js\n *\n * Copyright (C) 2006-2013 Niels Giesen.\n *\n * Contact: \n *\n * Author: Niels Giesen\n * Keywords: JavaScript, formatting, String\n *\n * This file is dual-licensed under either the BSD license or the\n * GNU Affero General Public License.\n *\n * positionalFormat enables you to replace numbers enclosed in curly braces (C# format\n * apparently) with positional arguments (that can be reused), like\n * this:\n *\n * positionalFormat('argument { 1 } (or is it { 2 }, or { 0 }?) comes { 1 }',3,'first',1)\n *\n * evals to:\n *\n * \"argument first (or is it 1, or 3?) comes first\"\n */\n\nexport function positionalFormat(str) {\n var args = arguments;\n return str.replace(/{\\s*(\\d+)\\s*}/g, function (match, num) {\n return args[parseInt(num) + 1] !== undefined\n ? args[parseInt(num) + 1]\n : match;\n });\n}\n\n/******* positionalFormat() END ******/\n\nexport function format(str, ob = {}) {\n return str.replace(/{\\s*([^{]+?)\\s*}/g, function (match, sub) {\n return ob[sub] !== undefined ? ob[sub] : sub;\n });\n}\n\n// export function formatPlus(str, ob = {}) {\n// return str.replace(/{\\s*([^{]+?)\\s*}/g, function (match, subwithstuff) {\n// const subs = subwithstuff.split(/\\|/);\n// console.log(subs);\n// return subs.reduce((acc, cur) => {\n// if (ob[cur] === undefined) return acc;\n// return ob[cur];\n// }, subs[0]);\n// // if (ob[sub] === undefined) return sub;\n// // if (!directives) return ob[sub] !== undefined ? ob[sub] : sub;\n// // if (\n// // directives.startsWith(\"+\") &&\n// // !Number.isNaN(ob[sub]) &&\n// // !Number.isNaN(Number(directives.slice(1)))\n// // )\n// // return Number(ob[sub]) + Number(directives.slice(1));\n// // if (\n// // directives.startsWith(\"-\") &&\n// // !Number.isNaN(ob[sub]) &&\n// // !Number.isNaN(Number(directives.slice(1)))\n// // )\n// // return Number(ob[sub]) + Number(directives.slice(1));\n// // const [sub, directives] = subwithstuff.split(/\\|/);\n// // if (ob[sub] === undefined) return sub;\n// // if (!directives) return ob[sub] !== undefined ? ob[sub] : sub;\n// // if (\n// // directives.startsWith(\"+\") &&\n// // !Number.isNaN(ob[sub]) &&\n// // !Number.isNaN(Number(directives.slice(1)))\n// // )\n// // return Number(ob[sub]) + Number(directives.slice(1));\n// // if (\n// // directives.startsWith(\"-\") &&\n// // !Number.isNaN(ob[sub]) &&\n// // !Number.isNaN(Number(directives.slice(1)))\n// // )\n// // return Number(ob[sub]) + Number(directives.slice(1));\n// return ob[sub];\n// });\n// }\n\nexport const formatPlus = format;\n\n// (str, ob = {}) {\n// return str.replace(/{\\s*([^{]+?)\\s*}/g, function (match, subwithstuff) {\n// const subs = subwithstuff.split(/\\|/);\n// console.log(subs);\n// return subs.reduceRight((acc, cur) => {\n// if (ob[cur] === undefined) return acc;\n// return ob[cur];\n// }, subs[0]);\n// // if (ob[sub] === undefined) return sub;\n// // if (!directives) return ob[sub] !== undefined ? ob[sub] : sub;\n// // if (\n// // directives.startsWith(\"+\") &&\n// // !Number.isNaN(ob[sub]) &&\n// // !Number.isNaN(Number(directives.slice(1)))\n// // )\n// // return Number(ob[sub]) + Number(directives.slice(1));\n// // if (\n// // directives.startsWith(\"-\") &&\n// // !Number.isNaN(ob[sub]) &&\n// // !Number.isNaN(Number(directives.slice(1)))\n// // )\n// // return Number(ob[sub]) + Number(directives.slice(1));\n// // const [sub, directives] = subwithstuff.split(/\\|/);\n// // if (ob[sub] === undefined) return sub;\n// // if (!directives) return ob[sub] !== undefined ? ob[sub] : sub;\n// // if (\n// // directives.startsWith(\"+\") &&\n// // !Number.isNaN(ob[sub]) &&\n// // !Number.isNaN(Number(directives.slice(1)))\n// // )\n// // return Number(ob[sub]) + Number(directives.slice(1));\n// // if (\n// // directives.startsWith(\"-\") &&\n// // !Number.isNaN(ob[sub]) &&\n// // !Number.isNaN(Number(directives.slice(1)))\n// // )\n// // return Number(ob[sub]) + Number(directives.slice(1));\n// return ob[sub];\n// });\n// }\n", "import { positionalFormat } from \"./text-utils.js\";\nimport { _ } from \"./gettext.js\";\n\nconst CODES = {\n cException: 1,\n cHTMLFormLoadCaseNotFound: 2,\n cHTMLMenuFileNotFound: 3,\n cWebModelIDDifferent: 4,\n cWebPleaseLogin: 5,\n cGetFileNotAllowed: 6,\n cGetDocumentNotFound: 7,\n cUMWrongUserNamePassword: 8,\n cWebSessionTimeOut: 9,\n cWebNoModelID: 10,\n cWebIllegalAccess: 11,\n cWebModelNotFound: 12,\n cWebCaseIsRunning: 13,\n cEngineLoadCaseFailed: 14, // Was: 3\n cEngineUpgrading: 15,\n cEngineNoInterfacesToShow: 16,\n cEngineLoadCaseFailedNotFound: 17,\n cEngineLoadCaseFailedWrongType: 18,\n cEngineLoadCaseFailedWrongData: 19,\n cWebOpenIsCalledWithUniqueID: 20,\n cTechGraphVizNotInstalled: 21,\n cGraphVizSessionNotFound: 22,\n cUMUserNotFound: 23,\n cUMModelNotFound: 24,\n cUMCaseNotFound: 25,\n cWebAdminNotAllowed: 26,\n cEngineGotoNodeFailed: 27,\n cPreviewNoCaseFound: 28,\n cTechUploadedFileToLarge: 29,\n cWebSaveCaseNotAllowed: 30,\n cWebSaveCaseFailed: 31,\n cInvalidUpload: 53\n};\n\nconst CODESREV = Object.fromEntries(\n Object.entries(CODES).map(([key, value]) => [value, key])\n);\n\n// Translate error - put translation in message property, return\n// error.\nfunction translate(_error) {\n const error = Object.assign({}, _error);\n // New API\n switch (error.code) {\n case CODES.cException:\n error.message = _(\n \"Something went wrong; see the server log for more information.\"\n );\n break;\n case CODES.cWebSessionTimeOut:\n error.message = _(\"Session has timed out. Please log in again.\");\n break;\n case CODES.cEngineLoadCaseFailed:\n switch (error.subcode) {\n case 1004:\n error.message = positionalFormat(\n _('You have no tickets left for model \"{0}\"'),\n error.summary\n .substring(56, error.summary.length - 1)\n .replace(/_/g, \" \")\n );\n break;\n default:\n error.message = error.summary; // Won't translate for now, may be st. like \"Loading case failed (xxx.mdl)\"\n }\n break;\n case CODES.cEngineLoadCaseFailedWrongData:\n error.message = _(\"Error loading session (wrong data)\");\n break;\n default:\n switch (error.subcode) {\n case 1002:\n error.message = _(\n \"We are currently updating. Please try again later.\"\n );\n break;\n case 1009:\n case 1025:\n error.message = positionalFormat(\n _('Infinite loop detected in {0}\"'),\n // Might be embedded though (in 1 or in 14...)\n error.summary.slice(18, error.summary.indexOf(\", infinite\"))\n );\n break;\n case 1010:\n error.message = _(\n \"Interface has failed (probably a failing SOAP or database connection)\"\n );\n break;\n default:\n error.message = _(CODESREV[error.code], _(error.summary));\n }\n }\n return error;\n}\n\nexport { CODES, translate };\n", "/* global URLSearchParams FormData */\n\nimport { mapConcat, either, when } from \"./functional.js\";\n\nconst ATTR_SNAME = \"data-server-name\";\nconst ATTR_SVALUE = \"data-server-value\";\nconst CONTAINER_SELECTOR = \"#bb-q .group.selected\";\n\nconst INPUT_SELECTOR = mapConcat(\n [\"input\", \"textarea\", \"select\"],\n function (c) {\n return c + \"[name]:not([disabled])\";\n },\n \", \"\n);\n\nconst inputsOf = container => container.querySelectorAll(INPUT_SELECTOR);\n\nconst isEmptyRadioValue = val => val === null;\nconst isEmptyCheckboxValue = val => val === false;\nconst isCheckedCheckboxValue = val => val === true;\n\nfunction collectWithin({\n params = null, // Object with an .append method, taking two params\n flavor = URLSearchParams, // Constructor for an object with an .append method, taking two params, used when params is not provided\n container = document.querySelector(CONTAINER_SELECTOR),\n omitFn = isEmptyCheckboxValue,\n changeFn = when(isCheckedCheckboxValue, () => \"on\"),\n collector = inputsOf\n} = {}) {\n return _collectAll(\n collector(container),\n params || new flavor(),\n omitFn,\n changeFn\n );\n}\n\nfunction _collectAll(nodeList, params, omitFn, changeFn) {\n for (const node of nodeList) {\n const val = valueOf(node),\n name = node.getAttribute(ATTR_SNAME) || node.getAttribute(\"name\");\n if (!either(isEmptyRadioValue, omitFn, val)) {\n params.append(name, changeFn(val));\n }\n }\n return params;\n}\n\nfunction valueOf(node) {\n if (node.hasAttribute(ATTR_SVALUE)) return node.getAttribute(ATTR_SVALUE);\n switch (node.type) {\n case \"radio\":\n return node.checked ? node.value : null; // Do not collect unchecked radios -- stripped in collectAll.\n case \"checkbox\":\n /* Collect unchecked checkboxes as false -- goes against usual form submission,\n but we need this for Studio API (using JSON). Stripped out by collectAll() unless provided with a omitFn. */\n if (!node.checked) return false;\n return node.hasAttribute(\"value\") // NOT the property -- this would still be \"on\".\n ? node.value // A checkbox should send either its value or\n : true; // Return Boolean true instead of \"on\", to be changed by collectAll() with changeFn,\n // or leave it at true (for JSON communication for instance) */\n default:\n return String(node.value).replace(/\\r?\\n/g, \"\\r\\n\");\n }\n}\n\nconst serializeQuestions = () =>\n collectWithin({}).toString().replace(/\\r?\\n/g, \"%0D%0A\");\n\nexport { valueOf, serializeQuestions, collectWithin };\n", "/* global $ FormData URLSearchParams */\nlet _vars = {};\n\nconst SESSION_KEYS = [\"dbname\", \"sessionid\", \"uniqueid\"];\nconst NAV_KEYS = [\"screenid\", ...SESSION_KEYS];\n\nObject.freeze(SESSION_KEYS);\nObject.freeze(NAV_KEYS);\n\nfunction setValueInVars(data, key) {\n if (typeof data[key] != \"undefined\") _vars[key] = data[key];\n}\n\nexport function setVars(data) {\n setValueInVars(data, \"version\");\n setValueInVars(data, \"uniqueid\");\n setValueInVars(data, \"replyserveraddress\");\n setValueInVars(data, \"replyserverport\");\n setValueInVars(data, \"proxyredirect\");\n setValueInVars(data, \"sessionid\");\n setValueInVars(data, \"modelname\");\n setValueInVars(data, \"dbname\");\n setValueInVars(data, \"modelid\");\n setValueInVars(data, \"showdeleteinmenu\");\n setValueInVars(data, \"showdatecreated\");\n setValueInVars(data, \"showreport\");\n setValueInVars(data, \"userinfo\");\n setValueInVars(data, \"showcopycase\");\n setValueInVars(data, \"screenid\");\n var version = getVar(\"version\");\n if (typeof version === \"string\") _vars[\"version\"] = version.split(\".\");\n}\n\nexport function getVar(string, obj) {\n return $.extend({}, _vars, obj)[string];\n}\n\n/**\n * Unset either all vars, or only those present in param vars\n *\n * @param {Array} vars An array of variable keys to delete\n *\n **/\nfunction unsetVars(arr) {\n if (!arr) return (_vars = {});\n arr.forEach(function (key) {\n delete _vars[key];\n });\n return _vars;\n}\n\nfunction collect(keys, collector = new FormData(), obj) {\n function append(key) {\n const val = getVar(key, obj);\n if (val !== undefined) collector.append(key, getVar(key, obj));\n }\n if (Array.isArray(keys)) {\n keys.forEach(append);\n } else {\n append(keys);\n }\n return collector;\n}\n\nfunction querify(keys, obj) {\n const usp = collect(keys, new URLSearchParams(), obj);\n return usp.toString();\n}\n\nexport default {\n querify,\n setVars,\n getVar,\n unsetVars,\n collect,\n NAV_KEYS,\n SESSION_KEYS\n};\n", "/* global URLSearchParams */\nimport \"./polyfills/url-search-params.js\";\nimport { Mode } from \"./mode.js\";\nimport { serializeQuestions } from \"./collect-values.js\";\nimport Vars from \"./vars.js\";\n\nexport const shouldExit = () =>\n Mode.get(\"hasModel\") && Boolean(Vars.getVar(\"sessionid\"));\n\nexport const onEnd = () => {\n if (!shouldExit()) return;\n if (!navigator.sendBeacon) return;\n const data = [\n \"step=exitdelayed\",\n Vars.querify(Vars.NAV_KEYS),\n \"fmt=json\",\n serializeQuestions()\n ]\n .filter(Boolean)\n .join(\"&\");\n\n const usp = new URLSearchParams(data);\n\n navigator.sendBeacon(\"/action\", usp);\n};\n\nfunction addEndListener() {\n // Update state before navigating away, but do not logout\n if (\"onpagehide\" in window) {\n window.addEventListener(\"pagehide\", onEnd);\n } else {\n window.addEventListener(\"unload\", onEnd, false);\n }\n}\n\nexport function removeEndListener() {\n // Update state before navigating away, but do not logout\n if (\"onpagehide\" in window) {\n window.removeEventListener(\"pagehide\", onEnd);\n } else {\n window.removeEventListener(\"unload\", onEnd, false);\n }\n}\n\naddEndListener();\n", "/* global $ */\nimport \"./a11y-user-detect.js\";\nimport { _ } from \"./gettext.js\";\n\n/*** A11y BEGIN ***/\nexport const A11y = {\n log: function (message) {\n var logdiv = document.getElementById(\"a-logdiv\");\n if (logdiv) logdiv.innerHTML = \"

\" + message + \"
\";\n }\n};\n\n/**\n * Datepicker a11y enhancements\n */\nexport const observeDatepickers = (function () {\n var init = false;\n return function initDateObservance() {\n var picker, observer;\n\n if (init || !(\"MutationObserver\" in window)) {\n init = true;\n return;\n }\n\n $(document).on(\"blur\", '[data-type=\"datetimepicker\"]', function () {\n A11y.log(\"\");\n });\n\n function observation(records, instance) {\n try {\n var infocus =\n document.activeElement.className.split(\" \").indexOf(\"hasDatepicker\") >\n -1;\n } catch (e) {\n // there mayn't be an activeElement, in which case className is undefined.\n }\n if (infocus) {\n var message = [\n $(\".ui-state-hover\").text(),\n $(\".ui-datepicker-month [selected]\").text(),\n $(\".ui-datepicker-year [selected]\").text()\n ].join(\" \");\n A11y.log(message + \", \" + _(\"press enter to accept\"));\n }\n }\n\n picker = document.getElementById(\"ui-datepicker-div\");\n\n if (picker) {\n observer = new window.MutationObserver(observation);\n observer.observe(picker, { attributes: true });\n init = true;\n }\n };\n})();\n", "let escapeHTML = (function () {\n var entityMap = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\",\n \"'\": \"'\",\n \"/\": \"/\"\n };\n var re = new RegExp(\"[&<>\\\"'/]\", \"g\");\n return function escapeHTML(string) {\n return String(string).replace(re, function (s) {\n return entityMap[s];\n });\n };\n})();\n\nconst escaped = (strings, ...values) =>\n strings.reduce(\n (acc, cur, idx) =>\n acc + cur + (values.length > idx ? escapeHTML(values[idx]) : \"\"),\n \"\"\n );\n\nexport { escapeHTML, escaped };\n", "import { Mode } from \"./mode.js\";\n\n/*** NOTIFICATIONS BEGIN ***/\nlet message;\n// Notification can either be a String or an object with a message\n// property. When supplying an object, the message property will be\n// shown to the user, but the entire object will be given to\n// console.error.\nfunction notify(options = { keepalive: false, html: false }, notification) {\n if (!notification) return;\n var text = notification.message || notification,\n timeout = 5000;\n if (\n typeof console !== \"undefined\" &&\n console &&\n typeof console.error === \"function\"\n )\n console.error(notification);\n message = { notification, options };\n Mode.set(\"hasMessage\");\n if (options.html) {\n document\n .querySelectorAll(\".bb-notification\")\n .forEach(area => (area.innerHTML = text));\n } else {\n document\n .querySelectorAll(\".bb-notification\")\n .forEach(area => (area.textContent = text));\n }\n if (!options.keepalive)\n window.setTimeout(Mode.unset.bind(Mode, \"hasMessage\"), timeout);\n}\n\nexport { notify, message };\n/*** NOTIFICATIONS END ***/\n", "/*** CONFIG BEGIN ***/\n\nimport conf from \"$conf.json\";\nimport { has } from \"./functional.js\";\n\nconf.a11y = Object.assign(\n {\n captions: false,\n optionfieldsets: false,\n strictlegends: false\n },\n conf.a11y\n);\n\nfunction propFinder(ob, prefix) {\n if (prefix) ob = find(prefix);\n\n function find(prop, fallback) {\n if (ob === undefined) return fallback;\n if (prop === undefined) return fallback;\n var leafs = prop.split(\".\").filter(Boolean),\n leaf = ob;\n while (has(leafs[0], leaf)) {\n leaf = leaf[leafs.shift()];\n }\n if (leafs.length === 0) return leaf;\n return fallback;\n }\n\n return find;\n}\n\nexport { conf, propFinder };\n\n/*** CONFIG END ***/\n", "import { conf } from \"./conf\";\nexport const fromApiServer = s =>\n s.startsWith(\"http://\") || s.startsWith(\"https://\")\n ? s\n : [conf.apiserver, s].filter(Boolean).join(\"/\");\n", "/* global jQuery */\nlet $ = jQuery;\n\nimport { escapeHTML } from \"./escape.js\";\nimport { notify } from \"./notify.js\";\nimport { _ } from \"./gettext.js\";\nimport { fromApiServer } from \"./location.js\";\n\n/**\n * Keep track of ajax requests + some convenience\n *\n * Exports busy and replace to bb.ajax object for plugins to use.\n */\nvar Ajax = {\n busy: false,\n last: null,\n direction: null,\n\n defaultOptions: {\n dataType: \"json\",\n type: \"POST\",\n url: \"action\",\n cache: false,\n async: true,\n success: checkJSON,\n error: onJSONError\n },\n\n post: function (options) {\n const _options = Object.assign({}, Ajax.defaultOptions, options, {\n url: fromApiServer(options.url || Ajax.defaultOptions.url)\n });\n $(document).trigger(\"bb:prePost\", _options);\n return $.ajax(_options);\n },\n\n replace: function (obj) {\n Ajax.last && Ajax.last.abort();\n Ajax.last = Ajax.post(obj);\n return Ajax.last;\n },\n\n release: function () {\n Ajax.busy = false;\n $(\".group.selected\").prop(\"disabled\", false);\n }\n};\n\n/**\n * Convenience method, like getJSON, but with POST\n *\n * @param {String} url URL where we POST to\n * @param {Object|String} data POST data\n *\n * Use Ajax.post instead if you want to overrule any default\n * settings from Ajax.defaultOptions.\n */\n$.postJSON = function (url, data) {\n return Ajax.post({ url: url, data: data });\n};\n\n/**\n * The default JSON error handler.\n *\n * Set appropriate flags, let user now what went wrong (as good as\n * possible).\n *\n * Trigger custom 'bb:jsonError' event on document.\n *\n * @param {Object} data XMLHTTPRequest object\n * @param {String} err Error message\n */\nfunction onJSONError(data, err) {\n Ajax.release();\n $(document).trigger(\"bb:jsonError\", data, err);\n if (data.responseText === undefined) {\n if (data.statusText === \"abort\");\n else {\n notify(\n { html: false, keepalive: true },\n _(\"Error: No response from server, server probably down\")\n );\n }\n } else if ($.trim(data.responseText) === \"\") {\n notify(\n { html: false, keepalive: true },\n _(\"Error: No response from server, server probably down\")\n );\n } else {\n notify(\n { html: true, keepalive: true },\n \"Error: \" +\n escapeHTML(err) +\n \"
Response was:
\" +\n \"
\" +\n        escapeHTML(data.responseText) +\n        \"
\"\n );\n }\n}\n\n/**\n * Indicate further processing ought to be skipped when this symbol is\n * set on JSON data.\n * @example\n import { stopDispatches } from \"$json/lib/ajax\";\n $(document).on(\"bb:preHandleData\", (event, data) => {\n event.stopImmediatePropagation(); // prevent further bb:preHandleData handlers.\n data[stopDispatches] = true;\n })\n * @constant\n * @type {Symbol}\n */\nexport const stopDispatches = Symbol(\"Skip all further dispatches\");\n\n/**\n Set this symbol to a promise on ajax data, and it shall be awaited\n before the next *handleData is run.\n*/\nconst awaiting = Symbol(\"awaiting promise\");\n\n/**\n * The default AJAX success handler. Perform actions on data.\n\n *\n * If data is not a JSON object, do nothing.\n *\n * @todo Either check data against JSON API, in some way or the\n * other, or make sure this function doesn't get called in the\n * first place when we're dealing with a non-core request; as\n * checkJSON is currently bound to ALL $.ajax requests,\n * this function may also fire for non-core requests.\n *\n * @param {Object} data 'JSON object according to BB JSON API'\n * @param {String} status Status of XHR\n * @param {Object} req The XHR object retrieving the resource\n *\n * @return undefined\n */\nasync function checkJSON(data, status, req) {\n if (typeof req.responseJSON !== \"undefined\") {\n // Since subsequent events may mess with the responseJSON\n // object, give (debuggers) the option to see the raw stuff.\n // Could be solved with a service worker instead.\n $(document).trigger(\"bb:responseText\", req.responseText);\n // use bb:preHandleData to change the JSON object for later invocations\n $(document).trigger(\"bb:preHandleData\", data);\n if (data[stopDispatches]) return;\n await data[awaiting];\n // handleData has the main stuff - the core rendering\n $(document).trigger(\"bb:handleData\", data);\n if (data[stopDispatches]) return;\n await data[awaiting];\n\n // use bb:postHandleData to change the DOM after initial rendering\n $(document).trigger(\"bb:postHandleData\", data);\n if (data[stopDispatches]) return;\n await data[awaiting];\n\n // finalHandleData may not change the DOM, but set focus for instance.\n $(document).trigger(\"bb:finalHandleData\", data);\n if (data[stopDispatches]) return;\n }\n}\n\nexport { Ajax, checkJSON, awaiting };\n", "import { Mode } from \"./mode.js\";\n\nexport const setSettled = () => Mode.set(\"isSettled\");\n", "/* global $, URLSearchParams */\nimport { setSettled } from \"./settled.js\";\nimport { removeEndListener } from \"./case-exit.js\";\n\nfunction BBI(options) {\n options = options || {};\n if (options.redirect_uri) {\n /** Example response:\n *\n * {\n * \"bbis\" : \"test\",\n * \"authid\" : \"Stubby\",\n * \"redirect_uri\" : \"https:\\/\\/HOST:8078\\/login?returnurl=http%3A%2F%2Fhost%3A80%2Fbbisreturns%3Fbbis%3Dtest&state=1507301556%3AGUID&authid=Stubby\",\n * \"url\": \"http:\\/\\/HOST:80\\/bbisreturns?bbis=test\",\n * \"state\": \"1507301556:6F2146D3-E0E6-4EB2-9DE4-2F31670B80D6\"\n * }\n *\n */\n var path = window.location.pathname.split(\"/\"),\n template = path.pop() || \"inlog.html\",\n returnurl =\n window.location.origin +\n path.concat(template).join(\"/\") +\n \"?\" +\n $.param({ bbis: options.bbis }),\n server = options.redirect_uri.split(\"?\")[0]; // The identity server sans params\n this.params = Object.assign({}, options.extraparams, {\n returnurl,\n authid: options.authid,\n // Add specific HTML page to state:\n state: options.state\n });\n this.url = server + \"?\" + $.param(this.params);\n this.stage = 1;\n } else {\n this.params = $.extend($.parseQuery(), { fmt: \"json\" });\n this.stage = 2;\n }\n return this;\n}\n\nBBI.prototype.authenticate = function () {\n if (!this.stage) throw \"BBI was not properly initialized\";\n if (this.stage === 1) {\n removeEndListener();\n window.location.href = this.url;\n } else if (this.stage === 2) {\n $.postJSON(\"bbisreturns\", this.params).then(setSettled);\n }\n};\n\nexport { BBI };\n", "import { escapeHTML } from \"./escape.js\";\nimport {\n allPass,\n anyPass,\n both,\n complement,\n compose,\n either,\n F,\n has,\n ifElse,\n pipe,\n prop,\n propEq,\n type\n} from \"./functional.js\";\nexport const isOptional = allPass([\n complement(prop(\"notnull\")),\n either(\n complement(prop(\"stringmask\")),\n pipe(prop(\"stringmask\"), RegExp, re => re.test(\"\"))\n )\n]);\n\nexport const isVisible = prop(\"visible\");\n\nexport const isLabel = either(\n propEq(\"name\", \"label\"),\n propEq(\"controltype\", \"label\")\n);\n\nexport const isOption = either(\n propEq(\"controltype\", \"radio\"),\n propEq(\"controltype\", \"checkbox\")\n);\n\nexport const isLink = propEq(\"name\", \"linklabel\");\n\nexport const isTextual = either(isLabel, isLink);\n\nexport const isPicture = propEq(\"controltype\", \"picture\");\n\nexport const isQuestion = complement(either(isTextual, isPicture));\n\nexport const isReadOnly = both(\n isQuestion,\n either(\n ifElse(has(\"originalreadonly\"), prop(\"originalreadonly\"), prop(\"readonly\")),\n propEq(\"visible\", false)\n )\n);\n\nexport const isValidatable = ifElse(\n either(isReadOnly, propEq(\"visible\", false)),\n F,\n anyPass([\n has(\"minimum\"),\n has(\"maximum\"),\n both(has(\"maxlength\"), complement(propEq(\"maxlength\", 0))),\n prop(\"notnull\"),\n compose(s => s === \"string\", type, prop(\"stringmask\"))\n ])\n);\n\nexport const renderAttribs = attr =>\n Object.entries(attr).reduce(\n (acc, [key, value]) => acc + ` ${key}=\"${escapeHTML(value)}\"`,\n \"\"\n );\n\nexport const setAttribs = (elt, attr) =>\n Object.entries(attr).forEach(([key, value]) => elt.setAttribute(key, value));\n\nexport const bbmClass = stylename =>\n `bbm-${stylename.toLowerCase().replace(/[^a-z0-9]/g, \"-\")}`;\n", "import {\n assoc,\n hasPath,\n chain,\n compose,\n either,\n path,\n prop,\n toLower,\n toUpper,\n ifElse,\n juxt,\n when\n} from \"./functional.js\";\nimport { format } from \"./text-utils.js\";\nimport { _ } from \"./gettext.js\";\n\nconst fieldDesignators = {\n datetimepicker: \"field--date\",\n numedit: \"field--value\",\n radio: \"field--list\",\n checkmultilist: \"field--list\",\n customlist: \"field--list\",\n combobox: \"field--list\",\n listbox: \"field--list\",\n multilist: \"field--list\",\n any: \"field--field\"\n};\n\nconst fieldKey = compose(\n controltype => fieldDesignators[controltype] || fieldDesignators[\"any\"],\n prop(\"controltype\")\n);\n\nconst generic = compose(key => _(key), fieldKey);\n\nconst genericQuoted = compose(\n key => _(key), // Runtime!\n key => key.replace(\"field--\", \"quoted--\"),\n fieldKey\n);\nexport const quotable = compose(\n when(\n prop(\"quotable\"),\n chain(\n assoc(\"quotable--init\"),\n compose(s => s.slice(0, 1).toUpperCase() + s.slice(1), prop(\"quotable\"))\n )\n ),\n when(\n prop(\"quotable\"),\n chain(assoc(\"quotable--upper\"), compose(toUpper, prop(\"quotable\")))\n ),\n when(\n prop(\"quotable\"),\n chain(assoc(\"quotable--lower\"), compose(toLower, prop(\"quotable\")))\n ),\n chain(assoc(\"quotable\"), either(path([\"metadata\", \"quotable\"]), generic)),\n ifElse(\n hasPath([\"metadata\", \"quotable\"]),\n compose(assoc(\"<<\", _(\"<<\", \"\u00AB\")), assoc(\">>\", _(\">>\", \"\u00BB\"))),\n compose(assoc(\"<<\", \"\"), assoc(\">>\", \"\"))\n ),\n chain(\n assoc(\"quoted--init\"),\n compose(s => s.slice(0, 1).toUpperCase() + s.slice(1), prop(\"quoted\"))\n ),\n ifElse(\n hasPath([\"metadata\", \"quotable\"]),\n chain(\n assoc(\"quoted\"),\n compose(\n arr => format(...arr),\n juxt([\n genericQuoted,\n compose(quotable => ({ quotable }), path([\"metadata\", \"quotable\"]))\n ])\n )\n ),\n chain(assoc(\"quoted\"), generic)\n )\n);\n", "/* global $ */\nimport { quotable } from \"./quotable.js\";\nimport {\n apply,\n assoc,\n cond,\n compose,\n dec,\n equals,\n identity,\n lensPath,\n mergeLeft,\n match,\n over,\n path,\n pipe,\n tail,\n test,\n T\n} from \"./functional.js\";\nimport { _ } from \"./gettext.js\";\nimport { format, formatPlus } from \"./text-utils.js\";\n\n/*** DATE UTILITIES BEGIN ***/\nDate.prototype.toHoursAndMinutes = function () {\n var hours = this.getHours();\n var minutes = this.getMinutes();\n if (hours < 10) hours = \"0\" + hours;\n if (minutes < 10) minutes = \"0\" + minutes;\n return hours + \":\" + minutes;\n};\nconst dateTimeRe = /^\\/Date\\((-?\\d+)\\)\\/$/,\n pureDateRe = /^(\\d{4})-(\\d{2})-(\\d{2})$/,\n ISO8601DateTimeInZuluRe =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d{3})?)?Z$/;\n\n/*\n * Convert JSON date string to a Date object and return it.\n *\n * @{datestring}:\n *\n * An ISO-8601 datetime string in Zulu Time\n *\n * OR\n *\n * a JSON date string of the form\n *\n * \"/Date(102938293293)/\"\n *\n * where the numerical part is\n * seconds from epoch\n *\n * OR:\n *\n * a date formatted as \"yyyy-mm-dd\"\n *\n * OR:\n *\n * undefined -> undefined\n *\n */\nconst date = (...args) => new Date(...args);\n\nexport const parseDate = cond([\n [equals(0), () => undefined],\n [equals(undefined), identity],\n [equals(\"\"), identity],\n [\n test(pureDateRe),\n // Note if we were to pass pureDates to new Date as a valid\n // DateStamp, the engine will interpret it as 0:00 Zulu\n // time. Which, in this very case, is probably not what we\n // want. We want the date as in the minds of the case (min/max in\n // a calendar etc). It should be represented 'as is' to the user,\n // so 2022-02-09 may never become 2022-02-08 in users TZ, so\n // interpret it according in users TZ.\n pipe(match(pureDateRe), tail, over(lensPath([1]), dec), apply(date))\n ],\n [test(ISO8601DateTimeInZuluRe), date],\n [test(dateTimeRe), pipe(match(dateTimeRe), path([1]), parseInt, date)],\n [\n T,\n thing => {\n throw `Not a date in our book: ${thing}`;\n }\n ]\n]);\n\nexport const leadWithZeroes = string =>\n string.replace(/([^0-9]|^)([0-9]{3})([^0-9]|$)/, \"$10$2$3\");\n\n/**\n *\n * @param {Object} spec Object describing a control conforming to the BB json api.\n * @param {String} value The value to be checked\n * @returns {Boolean|Error} true when value is according to spec\n * @throws Localized error message\n */\nexport function checkDate(spec = { notnull: false }, value) {\n const UIFormat = $.datepicker._defaults.dateFormat;\n const formatDate = $.datepicker.formatDate.bind($.datepicker);\n var date, mindate, maxdate;\n if (!spec.notnull && value.trim() === \"\") {\n return true;\n }\n const metadata = spec.metadata || {};\n try {\n date = valueToDate(UIFormat, value); // $.datepicker.parseDate(UIFormat, value); // This line may throw an error.\n } catch (e) {\n //couldn't parse - throw a translatable error message\n throw formatPlus(\n metadata.errdateinvalid || _(\"Invalid date\"),\n compose(assoc(\"value\", value), quotable)(spec)\n );\n }\n if (date === null) {\n if (spec.notnull) {\n throw format(\n metadata.errrequired || _(\"Date required\"),\n compose(assoc(\"value\", value), quotable)(spec)\n );\n }\n return true;\n }\n (mindate = parseDate(spec.minimum)), (maxdate = parseDate(spec.maximum));\n if (!(mindate || maxdate)) return true; // Neither is set\n const fmindate = formatDate(UIFormat, mindate),\n fmaxdate = formatDate(UIFormat, maxdate);\n const quotableDate = compose(\n mergeLeft({\n value,\n minimum: fmindate,\n maximum: fmaxdate\n }),\n quotable\n )(spec);\n try {\n if (mindate && !maxdate && date < mindate)\n throw (\n metadata.errdatebeforemimimum ||\n _(\"A date before {minimum} is not allowed\")\n );\n else if (mindate && maxdate && (date < mindate || maxdate < date))\n throw (\n metadata.errdatenotinrange ||\n _(\"Date has to lie between {minimum} and {maximum}\")\n );\n else if (maxdate && !mindate && maxdate < date)\n throw (\n metadata.errdateaftermaximum ||\n _(\"A date after {maximum} is not allowed\")\n );\n } catch (e) {\n throw format(e, quotableDate);\n }\n return true;\n}\n\nexport const valueToDate = (format, value) => {\n let date;\n try {\n date = $.datepicker.parseDate(format, value);\n } catch (e) {\n const yyyycleanformat = format.replace(/[^mdy]/g, \"\").replace(\"yy\", \"yyyy\"),\n clean = value.replace(/[^0-9]/g, \"\");\n date = new Date();\n const yearindex = yyyycleanformat.indexOf(\"yyyy\");\n // If year was less than 4 digits, and not at end, adjust indices of other fields.\n const adjustment = yearindex === 0 ? clean.length - 8 : 0;\n let year = Number(clean.substr(yearindex, 4 + adjustment));\n if (year <= 99) {\n const cutoffyear = Number.isInteger(\n $.datepicker._defaults.shortYearCutoff\n )\n ? $.datepicker._defaults.shortYearCutoff\n : (date.getYear() % 100) +\n Number($.datepicker._defaults.shortYearCutoff);\n // Note: this will become odd if current year approaches end of\n // century. Let's say we live in 2099. User enters 98 -> fine.\n // Is below 109. User enters 02 => not fine. Still below 109.\n // But jQuery UI should also fix this. And it's still a long time.\n const century = (date.getFullYear() / 100) >> 0;\n if (year <= cutoffyear) {\n year += century * 100;\n } else {\n year += (century - 1) * 100;\n }\n }\n const month = Math.max(\n 0,\n Number(clean.substr(yyyycleanformat.indexOf(\"mm\") + adjustment, 2)) - 1\n );\n const dom = Number(\n clean.substr(yyyycleanformat.indexOf(\"dd\") + adjustment, 2)\n );\n date.setFullYear(year);\n date.setMonth(month);\n date.setDate(dom);\n if (\n date.getFullYear() !== year ||\n date.getMonth() !== month ||\n date.getDate() !== dom\n ) {\n throw \"invalid date\";\n }\n }\n return date;\n};\n\nexport const onChangeDate = ev => {\n let date;\n try {\n date = valueToDate($.datepicker._defaults.dateFormat, ev.target.value);\n } catch (e) {\n // ignore\n } finally {\n if (date) {\n ev.target.value = leadWithZeroes(\n $.datepicker.formatDate($.datepicker._defaults.dateFormat, date)\n );\n }\n }\n};\n\nexport const humanDate = (function () {\n var now = new Date();\n var hour0 = now.setHours(0, 0, 0, 0);\n var dayinms = 1000 * 60 * 60 * 24;\n var hour24 = hour0 + dayinms;\n var thisyear = now.getYear();\n var daysofweek = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"].map(\n function (day) {\n return _(day);\n }\n );\n var monthsofyear = [\n \"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"May\",\n \"June\",\n \"July\",\n \"Aug\",\n \"Sep\",\n \"Oct\",\n \"Nov\",\n \"Dec\"\n ].map(function (month) {\n return _(month);\n });\n function isToday(ms) {\n return ms > hour0 && ms < hour24;\n }\n function isYesterday(ms) {\n return hour0 > ms && ms > hour0 - dayinms;\n }\n function isLastWeek(ms) {\n return ms > hour0 - dayinms * 6;\n }\n function isThisYear(date) {\n return thisyear == date.getYear();\n }\n function humanDate(date) {\n if (!(date instanceof Date)) throw \"Expects a Date object\";\n var ms = date.valueOf();\n var hm = \"\";\n hm = date.toHoursAndMinutes();\n if (isToday(ms)) {\n return hm;\n }\n if (isYesterday(ms)) {\n return _(\"Yesterday\") + \", \" + hm;\n }\n if (isLastWeek(ms)) {\n return daysofweek[date.getDay()] + \" \" + hm;\n }\n return (\n date.getDate() +\n \" \" +\n monthsofyear[date.getMonth()] +\n (isThisYear(date) ? \"\" : \" \" + date.getFullYear()) +\n \", \" +\n hm\n );\n }\n return humanDate;\n})();\n", "import { compose, either, isNil, not, path } from \"./functional.js\";\n\n/* editPolicy may be \"return\", \"stay\", or undefined, meaning off */\nexport const editPolicy = path([\"arbitrary\", \"core\", \"editPolicy\"]);\n\nexport const canEditEarlier = compose(not, isNil, editPolicy);\n\nconst isLabelValueDynamic = compose(\n value => value === true,\n path([\"arbitrary\", \"core\", \"isLabelValueDynamic\"])\n);\n\nconst preferUpdate = compose(\n value => value === true,\n path([\"arbitrary\", \"core\", \"preferUpdate\"])\n);\n\nexport const mustUpdate = either(preferUpdate, canEditEarlier);\n\nexport const updateLabels = either(mustUpdate, isLabelValueDynamic);\n", "const _Widgets = {};\n\nexport function registerWidget(options) {\n _Widgets[options.name] = options;\n}\nexport function getWidget(name) {\n return _Widgets[name];\n}\n", "/* global $ */\n\nimport { parseDate } from \"./dates\";\nimport { isReadOnly, isValidatable } from \"./control-helpers\";\nimport { updateLabels } from \"./feature-queries.js\";\nimport { conf } from \"./conf.js\";\nimport { getWidget } from \"./form-widgets.js\";\nimport { anyPass, has, prop } from \"./functional.js\";\nconst Dynprops = {};\n\n// Update the control element\nDynprops.update = function ($widget, control, Updates, requestor) {\n if (!$widget.get(0)) return;\n const oldval = $widget.val();\n\n const updates = Object.keys(Updates);\n const definition = getWidget(control.controltype);\n $widget.removeData([\"validated\"]);\n\n /** isForNotNull **/\n if (has(\"isForNotNull\", Updates)) {\n $widget.toggleClass(\"bb-for-required\", Boolean(control.isForNotNull));\n $widget.toggleClass(\"bb-for-optional\", !control.isForNotNull);\n }\n\n /** Placeholder **/\n if (has(\"placeholder\", Updates) > -1) {\n $widget.attr(\"placeholder\", control.placeholder);\n }\n\n /** Visible **/\n if (has(\"visible\", Updates)) {\n if (control.identifier === \"gformulier.gegevens.geschil_partner\")\n $widget.attr(\"aria-hidden\", !control.visible);\n $widget.attr(\"data-visible\", control.visible);\n\n if (control.visible) {\n window.setTimeout(function () {\n $widget.removeAttr(\"hidden\");\n }, 80);\n } else {\n window.setTimeout(function () {\n $widget.attr(\"hidden\", !control.visible);\n }, 80);\n }\n }\n\n /** Value **/\n if (has(\"value\", Updates)) {\n if (updateLabels(conf)) {\n /**\n @done: linklabel, listlabel, checkmultilist, memo, combobox, radio,\n checkbox, numedit, datetimepicker, edit, grid, multilist(?), listbox(?)\n @todo: freebox.\n\n NOTE: A widget currently can change itself *only* if\n they are registered with allowUpdatingSelf : true\n\n Widgets within a grid can update other widgets in a grid.\n */\n if (definition.setValue) {\n definition.setValue($widget.get(0), control.value, requestor, Updates);\n }\n }\n }\n\n /** Readonly **/\n if (\n anyPass([has(\"readonly\"), has(\"originalreadonly\"), has(\"visible\")], Updates)\n ) {\n const readonly = isReadOnly(control);\n if (typeof definition.onreadonly === \"function\") {\n definition.onreadonly($widget.get(0), readonly);\n } else {\n $widget.prop(\"disabled\", readonly);\n }\n }\n\n /** Minimum **/\n if (has(\"minimum\", Updates)) {\n $widget.attr(\"min\", control.minimum);\n if (control.controltype === \"datetimepicker\") {\n if (control.minimum) {\n $widget.datepicker(\"option\", \"minDate\", parseDate(control.minimum));\n }\n }\n }\n\n /** Maximum **/\n if (has(\"maximum\", Updates)) {\n $widget.attr(\"max\", control.maximum);\n if (control.controltype === \"datetimepicker\") {\n if (control.maximum) {\n $widget.datepicker(\"option\", \"maxDate\", parseDate(control.maximum));\n }\n }\n }\n\n /** Maxlength **/\n if (has(\"maxlength\", Updates)) {\n if (control.maxlength === 0) $widget.removeAttr(\"maxlength\");\n else $widget.attr(\"maxlength\", control.maxlength);\n }\n\n /** Let user know something changed perhaps against their intent. **/\n if (oldval !== $widget.val()) {\n $widget.addClass(\"bb-programmatically-changed\");\n $widget.trigger(\"change\", { programmatically: true });\n self.setTimeout(function () {\n $widget.removeClass(\"bb-programmatically-changed\");\n }, 1000);\n }\n\n /** Notnull **/\n if (has(\"notnull\", Updates)) {\n if (typeof definition.onrequired === \"function\") {\n definition.onrequired($widget.get(0), control.notnull);\n } else {\n $widget.attr(\"aria-required\", control.notnull);\n }\n if (control.notnull) {\n $widget.addClass(\"notnull\");\n } else {\n $widget.removeClass(\"notnull\");\n }\n }\n\n if (isValidatable(control)) {\n $widget.attr(\"aria-errormessage\", `${control.id}--error`);\n $widget.addClass(\"validatable\");\n } else {\n $widget.removeAttr(\"aria-errormessage\");\n $widget.removeClass(\"validatable\");\n }\n\n if (updates.length > 0) {\n const event = new CustomEvent(\"bb:updatedControl\", {\n detail: { control, Updates },\n bubbles: true\n });\n $widget.get(0).dispatchEvent(event);\n $(document).trigger(\"bb:updated\", [$widget, control, updates]);\n }\n};\n\n$.fn.extend({\n updateControl: function (controls, requestor) {\n return this.each(function () {\n const $this = $(this),\n control = $this.data(\"control\");\n if (\n this === requestor &&\n !prop(\"allowUpdatingSelf\", getWidget(control.controltype))\n ) {\n // This was the one requesting an update\n return this;\n }\n if (!control) throw (\"No updateControl defined for\", $this);\n const id = control.id,\n update = controls.find(function (c) {\n return c.id === id;\n }),\n // updates = [],\n Updates = {},\n props = [\n \"maxlength\",\n \"isForNotNull\",\n \"minimum\",\n \"maximum\",\n \"notnull\",\n \"readonly\",\n \"originalreadonly\",\n \"placeholder\",\n \"precision\",\n \"stringmask\",\n \"errortext\",\n \"visible\",\n \"value\",\n \"columns\",\n \"text\"\n ];\n // Caron-syntax used in label, therefore no (text) interface\n // returned -- should not mix and match dynprops with empty\n // labels! Do not allow this to error on the user though!\n\n // Does also handle (cause to ignore) labels within a grid!\n if (typeof update === \"undefined\") {\n return this;\n // update = $.extend({}, control, {visible: false});\n }\n for (var i in props) {\n if (control[props[i]] !== update[props[i]]) {\n Updates[props[i]] = { from: control[props[i]], to: update[props[i]] };\n control[props[i]] = update[props[i]];\n // updates.push(props[i]);\n }\n }\n Dynprops.update($this, control, Updates, requestor);\n return this;\n });\n }\n});\n\nexport { Dynprops };\n", "const Hooks = new Map();\n\nexport const registerHook = key => hook => {\n if (typeof hook !== \"function\") throw \"Can only add a function as a hook\";\n Hooks.set(key, hook);\n};\n\nexport const runHook =\n key =>\n (...args) => {\n if (Hooks.has(key)) Hooks.get(key)(...args);\n };\n", "/* global $ */\nimport { bbmClass, isReadOnly, renderAttribs } from \"./control-helpers\";\nimport { Dynprops } from \"./dynprops\";\nimport { escaped, escapeHTML } from \"./escape.js\";\nimport { conf, propFinder } from \"./conf\";\nimport { getWidget } from \"./form-widgets.js\";\nimport {\n assoc,\n both,\n compose,\n complement,\n has,\n hasPath,\n isNil,\n not,\n prop\n} from \"./functional.js\";\nimport { runHook } from \"./hooks.js\";\nimport { Mode } from \"./mode.js\";\n\nconst arbitraryCoreProp = propFinder(conf, \"arbitrary.core\");\n\n/**\n * Create a control widget, then insert it into the DOM\n *\n * @param {Object} control A control object as defined in the JSON API. The one to render + add.\n * @param {Object} group The group object to which this control belongs.\n * @param {Element} wGroup Element whereto this control should be added. *NOTE* that this need not be a .bb-group\n *\n * @return undefined\n *\n * @todo Simplify parameter list.\n */\nfunction wControl(control, group, wGroup) {\n control._group = group;\n let attribs = {};\n let widget;\n const enabled = group.current || complement(isReadOnly)(control);\n // Has been rendered\n if (control.$elt) {\n $(wGroup).append(control.$elt);\n return control.$elt;\n }\n if (compose(has(\"fixup\"), getWidget)(control.controltype))\n compose(fn => fn(control), prop(\"fixup\"), getWidget)(control.controltype);\n\n if (control.datatype) attribs[\"data-datatype\"] = control.datatype;\n\n if (control.meta)\n for (let d in control.meta) {\n if (both(has(d), compose(not, isNil, prop(d)))(control.meta))\n attribs[\"data-\" + d] = escape(control.meta[d]);\n }\n if (control.metadata) {\n attribs[\"data-metadata-keys\"] = Object.keys(control.metadata)\n .map(s => s.replace(/\\s/g, \"-\"))\n .join(\" \");\n }\n if (control.aria)\n for (let a in control.aria) {\n if (has(a, control.aria)) attribs[\"aria-\" + a] = control.aria[a];\n }\n\n if (control.name) {\n attribs[\"name\"] = control.name;\n }\n\n const wdef = getWidget(control.controltype);\n if (!wdef) {\n console.warn(`No widget definition for ${control.controltype}`);\n return null;\n }\n const tagName = wdef.tagName;\n attribs = wdef.attribs(attribs, control, enabled);\n\n attribs[\"data-type\"] = control.controltype;\n if (tagName) {\n widget = $(\"<\" + tagName + \" \" + renderAttribs(attribs) + \"/>\");\n } else {\n widget = $(wdef.render(control, group, attribs));\n if (!widget) return null;\n }\n\n if (control.className) {\n widget.addClass(control.className);\n }\n control.$elt = widget;\n control._elt = widget.get(0);\n\n if (wdef && wdef.tagName) {\n /**\n Okay, some (older) definitions have a tagName definition ->\n from which a quite empty skeleton widget is created.\n\n Afterwards, they fill that very widget with a render function\n of a different signature than usual:\n\n Instead of (control (plain object), group (plain object), attribs (array)), they get\n (control (plain object), widget (jQuery collection), group (plain object))).\n\n */\n wdef.render(control, widget, group);\n }\n\n // attach an id whenever meaningful:\n // if (control.id && /\\d+$/.test(control.id))\n if (control.id) {\n // id used not to be safe, but now we prepend the groupid, making it safe.\n widget.attr(\"id\", control.id);\n }\n if (control._originalid) {\n // Use data-id for stuff refering to the interface, no matter in which group it is, such as informationsources.\n widget.attr(\"data-id\", control._originalid);\n }\n\n if (hasPath([\"metadata\", \"autocomplete\"], control)) {\n widget\n .attr(\"data-server-name\", control.name)\n .attr(\"name\", control.metadata.autocomplete)\n .attr(\"autocomplete\", control.metadata.autocomplete);\n }\n\n $(wGroup).append(widget);\n\n /* Insert a space between elements so that elements are reasonably\n * well-placed when CSS is disabled.\n */\n $(wGroup).append(\" \");\n\n // Tooltips:\n if (control.hint) {\n if (enabled) Mode.set(\"hasHints\");\n runHook(\"hinter\")(widget, assoc(\"enabled\", enabled, control));\n }\n widget.data(\"control\", control);\n\n /**\n * Dynamic properties\n */\n var dynprops = [\n \"maxlength\",\n \"minimum\",\n \"maximum\",\n \"notnull\",\n \"isForNotNull\",\n \"readonly\",\n \"precision\",\n \"stringmask\",\n \"errortext\",\n \"placeholder\"\n ],\n dynpropsforus = {};\n\n for (var ii in dynprops) {\n if (has(dynprops[ii], control))\n dynpropsforus[dynprops[ii]] = { to: control[dynprops[ii]] }; // .push(dynprops[ii]);\n }\n\n if (has(\"visible\", control) && control.visible === false) {\n dynpropsforus[\"visible\"] = { to: false }; // .push(dynprops[ii]);\n }\n // dynpropsforus.push(\"visible\");\n\n widget.data(\"anchor\", widget);\n\n if (wdef && wdef.afterRender) {\n wdef.afterRender(widget, control);\n }\n\n if (shouldWrap(control)) {\n wrapInlineInput(widget);\n }\n\n /* Allow class-based styling */\n if (control[\"font-class\"]) {\n widget.addClass(bbmClass(control[\"font-class\"]));\n }\n\n /**\n * Two things:\n * - Put control tags in data-tags of Element.\n * - Make TAG known to CSS as bb-tagged-TAG.\n */\n if (control[\"tags\"] instanceof Array) {\n $(widget).data(\"tags\", control[\"tags\"]);\n $.each(control[\"tags\"], function (i, tag) {\n widget.addClass(\"bb-tagged-\" + tag);\n });\n }\n\n Dynprops.update(widget, control, dynpropsforus);\n\n return widget;\n}\n\nfunction shouldWrap(control) {\n return (\n control.prelabel ||\n control.postlabel ||\n (arbitraryCoreProp(\"wrapAllSingleLiners\") === true &&\n compose(prop(\"couldWrap\"), getWidget)(control.controltype)) ||\n (control.placeholder &&\n arbitraryCoreProp(\"accessiblePlaceholders\") === true &&\n compose(prop(\"couldWrap\"), getWidget)(control.controltype))\n );\n}\n\nfunction wrapInlineInput(widget) {\n var control = widget.data(\"control\"),\n prelabel = control.prelabel,\n postlabel = control.postlabel;\n var anchor = widget.data(\"anchor\");\n var wraptag = \"span\";\n if (anchor.get(0).nodeName === \"DIV\") wraptag = \"div\";\n anchor.wrapAll(\n \"<\" +\n wraptag +\n ' data-wraps-type=\"' +\n control.controltype +\n '\" class=\"bb-input-wrap\">\"\n );\n anchor = anchor.parent();\n widget.data(\"anchor\", anchor);\n anchor.data({\n control: control,\n type: control.controltype\n });\n if (prelabel)\n anchor.prepend(\n '' +\n escapeHTML(prelabel) +\n \"\"\n );\n if (control.placeholder && arbitraryCoreProp(\"accessiblePlaceholders\")) {\n widget\n .get(0)\n .setAttribute(\n \"aria-describedby\",\n (\n (widget.get(0).getAttribute(\"aria-describedby\") || \"\") +\n ` ${control.id}--placeholder`\n ).trim()\n );\n anchor.append(\n `${escapeHTML(control.placeholder)}`\n );\n }\n if (postlabel)\n anchor.append(\n '' +\n escapeHTML(postlabel) +\n \"\"\n );\n}\n\nconst getControl = elt => $.data(elt, \"control\");\n\nexport { getControl, wControl };\n", "export const listtypes = {\n radio: \"LIST\",\n checkmultilist: \"LIST\",\n customlist: \"LIST\",\n combobox: \"BOX\",\n listbox: \"BOX\",\n multilist: \"BOX\"\n};\n", "/* global $ */\nimport { getWidget } from \"./form-widgets.js\";\nimport {\n always,\n assoc,\n either,\n tap,\n cond,\n path,\n propEq,\n T\n} from \"./functional.js\";\nimport { _ } from \"./gettext.js\";\nimport { format, formatPlus } from \"./text-utils.js\";\nimport { listtypes } from \"./types.js\";\nimport { compose } from \"./functional.js\";\nimport { quotable } from \"./quotable.js\";\n\n// Validate actual input, return true if it's ok, throw an error otherwise.\nexport function validateInput(node) {\n const $node = $(node),\n control = $node.data(\"control\");\n let ok = true,\n re,\n errortext,\n val,\n category;\n\n if (control === undefined) {\n throw \"Not a BB widget\";\n }\n\n if (control.visible === false) {\n return true;\n }\n category = listtypes[control.controltype];\n\n val = $node.val();\n\n if (control.stringmask) {\n re = new RegExp(control.stringmask);\n if (!re.test(val))\n throw format(\n control.errortext,\n compose(assoc(\"value\", val), quotable)(control)\n );\n }\n if (control.notnull) {\n if (category === \"LIST\") {\n ok = $node.is(\":has(:checked)\");\n } else if (category === \"BOX\") {\n // There could be a faux, checked, option telling us to\n // fill in the field. That is the second check here.\n ok = val !== null && val !== \"\";\n } else if (control.controltype == \"checkbox\") {\n ok = $node.is(\":checked\");\n } else if (control.controltype === \"grid\") {\n if (control.addallowed === false) {\n const checkable = control.columns.find(\n either(\n propEq(\"controltype\", \"radiobutton\"),\n propEq(\"controltype\", \"checkbox\")\n )\n );\n if (checkable) {\n ok = $node.is(\":has(:checked)\");\n }\n } else {\n // A required grid should have at least one row.\n // But if no rows **can** be added it would be rude and confusing to complain to the end-user.\n ok = control.value.length > 0 || control.addallowed === false;\n }\n } else {\n re = /\\S/;\n ok = re.test(val);\n }\n if (!ok) {\n throw cond([\n [path([\"metadata\", \"errrequired\"]), path([\"metadata\", \"errrequired\"])],\n [\n propEq(\"controltype\", \"datetimepicker\"),\n compose(c => formatPlus(_(\"Date required\"), c), quotable)\n ],\n [\n always([\"BOX\", \"LIST\"].indexOf(category) > -1),\n compose(c => format(_(\"Choice required\"), c), quotable)\n ],\n [T, compose(c => format(_(\"Field required\"), c), quotable)]\n ])(control);\n }\n }\n if (control.maxlength && control.maxlength > 0) {\n ok = val.length <= control.maxlength;\n if (!ok) {\n throw format(\n path([\"metadata\", \"errtexttoolong\"])(control) ||\n _(\"Text length exceeds the maximum of {maxlength} characters\"),\n quotable(control)\n );\n }\n }\n if (getWidget(control.controltype).validate) {\n return getWidget(control.controltype).validate(control, val);\n }\n return true;\n}\n", "import {\n groupWith,\n map,\n filter,\n pipe,\n path,\n strictUniq,\n lensPath\n} from \"./functional.js\";\n\nconst pathToGroup = [\"metadata\", \"group\"];\nexport const pathGroup = path(pathToGroup);\nexport const lensGroup = lensPath([\"metadata\", \"group\"]);\n\nconst areOfOneQuestion = (a, b) => a.isfor === b.id || b.isfor === a.id;\n\nexport const groupInner = groupWith(areOfOneQuestion);\n\nconst InfinityIfMinus1 = num => (num + 1 || Infinity) - 1;\nconst indexOfOrInfinity = (sub, s) => InfinityIfMinus1(s.indexOf(sub));\nexport const baseGroup = s => s.substr(0, indexOfOrInfinity(\".\", s));\nexport const tailGroup = s => s.substr(indexOfOrInfinity(\".\", s) + 1);\n\nconst belongTogether = (a, b) =>\n areOfOneQuestion(a, b) ||\n (pathGroup(a) &&\n pathGroup(b) &&\n baseGroup(pathGroup(a)) === baseGroup(pathGroup(b)));\n\nexport const groupOuter = groupWith(belongTogether);\n\nexport const groupClasses = pipe(\n map(path[(\"metadata\", \"groupClasses\")]),\n filter(Boolean),\n strictUniq\n);\n\nexport const doGrouping = path([\"arbitrary\", \"core\", \"form-group\", \"on\"]);\n", "export const normalize = s => s.toLowerCase().replace(/[^a-z0-9]/g, \"-\");\n", "import { path, either, compose, prop } from \"./functional.js\";\nimport { conf } from \"./conf.js\";\n\n/**\n\nName keys follow this pattern:\n\n__\n\n is any of:\n\n- GROUPING: subgroup of questions and/or texts and/or links\n- ITEM: a question and/or text and/or link\n- QUESTION: a question (is also an item)\n- TEXT: a top level text (not a label for a question)\n- LINK: a top level link (so: not inside markdown)\n- PICTURE: a top level image (so : nto inside markdown)\n\nGROUPING ::= ITEM+\nITEM ::= QUESTION | TEXT | LINK | PICTURE\n\n is any of:\n\n- _CLASS_ : the css class to put on this type \n- _PREFIX_: a css class prefix\n- _DATA_: a data- attribute\n\nwhere can be anything.\n\nThe default values for those keys, thus the strings that willl be used\nin the generated DOM, are provided in nameDefaults. They can be\noverwritten in the `conf.json` file in the property\n`core.form-group.names` in order to retrofit older or other naming\nschemes.\n\n*/\n\nexport const /* A grouping groups items */\n GROUPING_CLASS = \"grouping-class\", // Class of grouping\n GROUPING_PREFIX_TYPE = \"grouping-prefix-type\", // prefix for -question, -text or -author\n GROUPING_DATA_NAME = \"grouping-data-name\", // data attribute conveying author provided group name\n GROUPING_DATA_LEVEL = \"grouping-data-level\", // grouping level, 1-based\n ITEM_PREFIX_AUTHORCLASS = \"item-prefix-authorclass\", // prefix for author class set with cssclasses on the metadata\n QUESTION_CLASS = \"question-class\", //: \"bb-questionlabelgroup\",\n QUESTION_PREFIX_TYPE = \"question-prefix-type\", //: \"bb-itype\",\n QUESTION_PREFIX_PROPERTY = \"question-prefix-property\", //: \"bb-itype\",\n QUESTION_DATA_LAYOUT = \"question-data-layout\", //: \"data-form-group-layout\",\n QUESTION_PREFIX_AUTHORSTYLE = \"question-prefix-authorstyle\", //: \"bb-g-\",\n QUESTION_CLASS_NOLABEL = \"question-class-nolabel\"; //: \"form-group__question--no-label\",\n\nconst nameDefaults = {\n [GROUPING_CLASS]: \"form-group\",\n [GROUPING_PREFIX_TYPE]: \"form-group-\",\n [GROUPING_DATA_NAME]: \"data-form-group-name\",\n [GROUPING_DATA_LEVEL]: \"data-form-group-level\",\n [ITEM_PREFIX_AUTHORCLASS]: \"form-group__item--author-class-\",\n [QUESTION_CLASS]: \"bb-questionlabelgroup\",\n [QUESTION_PREFIX_TYPE]: \"bb-itype\",\n [QUESTION_PREFIX_PROPERTY]: \"question-\", //: \"bb-itype\",\n [QUESTION_DATA_LAYOUT]: \"data-form-group-layout\",\n [QUESTION_PREFIX_AUTHORSTYLE]: \"bb-g-\",\n [QUESTION_CLASS_NOLABEL]: \"form-group__question--no-label\"\n};\n\n// const fg = {\n// [GROUPING_CLASS]: \"no-form-group-outer\",\n// [GROUPING_PREFIX_TYPE]: \"form-group-\",\n// [QUESTION_CLASS]: \"bb-questionlabelgroup p-form-group\",\n// [QUESTION_PREFIX_TYPE]: \"bb-itype-\",\n// [QUESTION_DATA_LAYOUT]: \"data-p-form-group-layout-type\",\n// [QUESTION_CLASS_NOLABEL]: \"p-form-group-orphaned\"\n// };\n\n// const bem_example = {\n// [GROUPING_CLASS]: \"form-group\",\n// [GROUPING_PREFIX_TYPE]: \"form-group-\",\n// [ITEM_PREFIX_AUTHORCLASS]: \"form-group__item--author-class-\",\n// [QUESTION_CLASS]: \"bb-questionlabelgroup\",\n// [QUESTION_PREFIX_TYPE]: \"form-group__question-\",\n// [QUESTION_DATA_LAYOUT]: \"data-form-group-layout\",\n// [QUESTION_PREFIX_AUTHORSTYLE]: \"form-group__question--author-style-\"\n// };\n\nconst pathToNames = path([\"arbitrary\", \"core\", \"form-group\", \"names\"]);\n\nexport const names = propArg =>\n either(compose(prop(propArg), pathToNames), _ => prop(propArg, nameDefaults))(\n conf\n );\n", "/* global $ */\nimport {\n all,\n both,\n curry,\n filter,\n has,\n compose,\n ifElse,\n head,\n path,\n prop,\n propEq,\n any,\n find,\n pathOr,\n split,\n join,\n map,\n when,\n tap,\n cond,\n not\n} from \"./functional.js\";\nimport {\n isTextual,\n isPicture,\n isQuestion,\n isVisible\n} from \"./control-helpers.js\";\nimport { groupOuter, baseGroup, tailGroup, pathGroup } from \"./groupings\";\nimport { normalize } from \"./font-classes\";\nimport { getWidget } from \"./form-widgets.js\";\nimport { conf } from \"./conf\";\nimport * as n from \"./names.js\";\nimport { names } from \"./names.js\";\n\nconst doTopLevel = pathOr(true, [\n \"arbitrary\",\n \"core\",\n \"form-group\",\n \"toplevel\"\n]);\n\nconst doLegends = pathOr(true, [\n \"arbitrary\",\n \"core\",\n \"form-group\",\n \"doLegends\"\n]);\n\nconst getLayout = type =>\n pathOr(compose(prop(\"layout\"), getWidget)(type), [\n \"arbitrary\",\n \"form-group\",\n type\n ]);\n\nconst getGroupName = compose(when(Boolean, baseGroup), pathGroup, head);\n\n// Interface Font Style\nconst questionGroupClass = compose(\n s => names(n.QUESTION_PREFIX_AUTHORSTYLE) + s,\n normalize,\n prop(\"font-class\")\n);\n\n// interface metadata: cssclasses=\nexport const extraClasses = prefix =>\n compose(\n when(\n Boolean,\n compose(\n join(\" \"),\n map(compose(s => names(prefix) + s, normalize)),\n split(\" \")\n )\n ),\n path([\"metadata\", \"cssclasses\"])\n );\n\nconst asciify = s => s.replace(/[^a-z-]/g, \"-\");\n\nconst areAllInvisible = compose(not, any(isVisible));\nconst areAllReadonly = both(\n any(both(isQuestion, isVisible)),\n compose(all(prop(\"originalreadonly\")), filter(both(isQuestion, isVisible)))\n);\n\nconst areAllNotNull = both(\n any(both(isQuestion, isVisible)),\n compose(all(prop(\"notnull\")), filter(both(isQuestion, isVisible)))\n);\n\nconst updateClassWhen = curry((className, fn, controls, elt) => {\n elt.classList.toggle(className, fn(controls));\n});\n\nconst setReadonlyFGClass = updateClassWhen(\n names(n.GROUPING_PREFIX_TYPE) + \"-readonly\",\n areAllReadonly\n);\nconst setEmptyFGClass = updateClassWhen(\n names(n.GROUPING_PREFIX_TYPE) + \"-empty\",\n areAllInvisible\n);\nconst setRequiredFGClass = updateClassWhen(\n names(n.GROUPING_PREFIX_TYPE) + \"-required\",\n areAllNotNull\n);\n\nconst setReadonlyQClass = updateClassWhen(\n names(n.QUESTION_PREFIX_PROPERTY) + \"-readonly\",\n areAllReadonly\n);\nconst setEmptyQClass = updateClassWhen(\n names(n.QUESTION_PREFIX_PROPERTY) + \"-empty\",\n areAllInvisible\n);\nconst setRequiredQClass = updateClassWhen(\n names(n.QUESTION_PREFIX_PROPERTY) + \"-required\",\n areAllNotNull\n);\n\nexport const createFormGroup = (wControl, group, level) => c => {\n let formGroup;\n const groupName = getGroupName(c);\n\n if (\n groupName ||\n (doTopLevel(conf) &&\n (doLegends(conf) || !all(propEq(\"controltype\", \"legend\"))(c)))\n ) {\n formGroup = document.createElement(\"div\");\n formGroup.className = names(n.GROUPING_CLASS);\n formGroup.setAttribute(names(n.GROUPING_DATA_LEVEL), level);\n setEmptyFGClass(c, formGroup);\n setReadonlyFGClass(c, formGroup);\n setRequiredFGClass(c, formGroup);\n formGroup.addEventListener(\"bb:updatedControl\", ({ detail }) => {\n if (has(\"visible\", detail.Updates)) {\n setEmptyFGClass(c, formGroup);\n }\n if (has(\"readonly\", detail.Updates)) {\n setReadonlyFGClass(c, formGroup);\n }\n if (has(\"notnull\", detail.Updates)) {\n setRequiredFGClass(c, formGroup);\n }\n });\n if (groupName) {\n formGroup.setAttribute(names(n.GROUPING_DATA_NAME), asciify(groupName));\n formGroup.classList.add(names(n.GROUPING_PREFIX_TYPE) + \"-author\");\n } else if (find(isQuestion, c)) {\n formGroup.classList.add(names(n.GROUPING_PREFIX_TYPE) + \"-interface\");\n } else if (compose(isPicture, head)(c)) {\n formGroup.classList.add(names(n.GROUPING_PREFIX_TYPE) + \"-picture\");\n } else if (compose(isTextual, head)(c)) {\n formGroup.classList.add(names(n.GROUPING_PREFIX_TYPE) + \"-text\");\n }\n } else {\n formGroup = document.createDocumentFragment();\n }\n\n const cWithin = compose(\n groupOuter,\n map(\n when(\n pathGroup,\n tap(control =>\n compose(\n ifElse(\n s => s === \"\",\n () => delete control.metadata.group,\n group => (control.metadata.group = group)\n ),\n tailGroup\n )(control.metadata.group)\n )\n )\n )\n )(c);\n cWithin.forEach(\n cond([\n [\n getGroupName,\n compose(\n n => formGroup.appendChild(n),\n createFormGroup(wControl, group, level + 1)\n )\n ],\n [\n any(isQuestion),\n controls => {\n const answer = find(isQuestion, controls);\n const classes = [\n names(n.QUESTION_CLASS),\n `${names(n.QUESTION_PREFIX_TYPE)}-${answer.controltype}`,\n questionGroupClass(answer),\n extraClasses(n.ITEM_PREFIX_AUTHORCLASS)(answer),\n controls.length === 1 && names(n.QUESTION_CLASS_NOLABEL)\n ].filter(Boolean);\n const qlg = document.createElement(\"div\");\n qlg.setAttribute(\n names(n.QUESTION_DATA_LAYOUT),\n answer._layout || getLayout(answer.controltype)(conf)\n );\n qlg.className = classes.join(\" \");\n setEmptyQClass(controls, qlg);\n setReadonlyQClass(controls, qlg);\n setRequiredQClass(controls, qlg);\n qlg.addEventListener(\"bb:updatedControl\", ({ detail }) => {\n if (has(\"visible\", detail.Updates)) {\n setEmptyQClass(controls, qlg);\n }\n if (has(\"readonly\", detail.Updates)) {\n setReadonlyQClass(controls, qlg);\n }\n if (has(\"notnull\", detail.Updates)) {\n setRequiredQClass(controls, qlg);\n }\n });\n controls.forEach(c => wControl(c, group, $(qlg)));\n formGroup.appendChild(qlg);\n }\n ],\n [\n () => true,\n map(c => {\n const $widget = wControl(c, group, $(formGroup));\n if ($widget)\n $widget.addClass(extraClasses(n.ITEM_PREFIX_AUTHORCLASS)(c));\n })\n ]\n ])\n );\n return formGroup;\n};\n", "/* global $ */\nimport { html, render } from \"lit\";\nimport { Maybe } from \"@cahmoraes93/maybe\";\nimport { A11y, observeDatepickers } from \"./a11y.js\";\nimport { conf, propFinder } from \"./conf.js\";\nimport { wControl, getControl } from \"./control.js\";\nimport { quotable } from \"./quotable.js\";\nimport {\n isLabel,\n isOption,\n isQuestion,\n isReadOnly,\n renderAttribs,\n setAttribs\n} from \"./control-helpers.js\";\nimport { checkDate, onChangeDate, parseDate, leadWithZeroes } from \"./dates.js\";\nimport { escapeHTML } from \"./escape.js\";\nimport { registerWidget } from \"./form-widgets.js\";\nimport {\n allPass,\n always,\n applyTo,\n both,\n compose,\n chain,\n dec,\n dissoc,\n find,\n F,\n gt,\n head,\n has,\n ifElse,\n inc,\n join,\n map,\n mergeLeft,\n path,\n propEq,\n when,\n pathEq,\n reverse,\n pipe,\n lensPath,\n lensProp,\n over,\n append,\n assoc,\n infichain,\n toLower,\n omit,\n nth,\n prop,\n propOr,\n equals,\n tap\n} from \"./functional.js\";\n\nimport { _ } from \"./gettext.js\";\nimport { fromApiServer } from \"./location.js\";\nimport { forceInRange, Numerals } from \"./numerals.js\";\nimport { format, formatPlus } from \"./text-utils.js\";\nimport { urlutils } from \"./url-utils.js\";\n\nconst arbitraryCoreProp = propFinder(conf, \"arbitrary.core\");\n\nfunction disconnectValue({ input, value, filter = x => x }) {\n input.setAttribute(\"data-server-value\", value);\n $(input).on(\"change\", function () {\n try {\n var newVal = filter(input.value, input);\n } catch (e) {\n //\n } finally {\n if (typeof newVal !== \"undefined\") {\n input.setAttribute(\"data-server-value\", newVal);\n }\n }\n });\n}\n\nconst noAttribs = always({});\n\nconst omitName = dissoc(\"name\");\nconst omitRequired = dissoc(\"aria-required\");\n\nconst emptyTag = (tagName, attribs) => {\n const elt = document.createElement(tagName);\n setAttribs(elt, attribs);\n return elt;\n};\nconst valueInside = (control, attribs, tagName) => {\n const elt = emptyTag(tagName, attribs);\n if (tagName === \"textarea\") {\n elt.value = control.value;\n } else {\n elt.innerHTML =\n control.text || escapeHTML(control.value).replace(/\\r?\\n/g, \"
\");\n }\n return elt;\n};\n\nconst checkbox = {\n name: \"checkbox\",\n render: (control, group, attribs) => {\n return emptyTag(\"input\", attribs);\n },\n attribs: (attr, control, enabled) =>\n Object.assign(\n {},\n attr,\n {\n type: \"checkbox\"\n },\n //Interface already has got a value server-side, so not\n //sending it back poses no problem.\n control.value && { checked: true }\n ),\n setValue: (input, value, requestor) => {\n input.checked = value;\n },\n layout: \"inline\"\n};\n\nregisterWidget(checkbox);\n\nconst picture = {\n name: \"picture\",\n render: (control, group, attribs) => emptyTag(\"img\", attribs),\n attribs: (attr, control, enabled) =>\n Object.assign({}, attr, {\n alt: control.alttext,\n src: fromApiServer(control.filename)\n })\n};\n\nregisterWidget(picture);\n\nexport const edit = {\n name: \"edit\",\n couldWrap: true,\n attribs: (attr, control, enabled) =>\n Object.assign({}, attr, {\n type: \"text\",\n autocomplete: \"off\",\n value: control.value\n }),\n render: (control, group, attribs) => emptyTag(\"input\", attribs),\n setValue: (input, value) => {\n input.value = value;\n },\n layout: \"aside\"\n};\n\nregisterWidget(edit);\n\nconst memo = {\n name: \"memo\",\n attribs: (attr, control, enabled) => {\n // const attribs = [\"name\", control.name];\n // if (control.width && control.height && control[\"font-size\"]) {\n // attribs.cols= parseInt(control.width / (control[\"font-size\"] * 0.75))\n // attribs.rows = parseInt(control.height / (control[\"font-size\"] * 1.5))\n // }\n // return [...attr, ...attribs];\n return attr;\n },\n render: (control, group, attribs) => {\n return valueInside(control, attribs, \"textarea\");\n },\n setValue: edit.setValue,\n layout: \"below\"\n};\n\nregisterWidget(memo);\n\nconst label = {\n name: \"label\",\n fixup: control => {\n control.value = (control.value || \"\").replace(/\\r\\n/g, \"\\n\"); // Normalize Windows-style (typewriter) newlines\n return control;\n },\n attribs: (attr, control, enabled) =>\n Object.assign(\n omitName(attr),\n enabled && control.isFor && { for: control.isFor },\n {\n class: `${\n control.isfor || has(\"colname\", control) ? \"bb-label\" : \"bb-text\"\n } bb-md-able`\n }\n ),\n render: (control, group, attribs) => {\n return valueInside(\n control,\n attribs,\n control._subtype === \"heading\"\n ? \"h\" + Math.min(6, control._level || 2)\n : control.isFor\n ? \"label\"\n : \"div\"\n );\n },\n setValue: (input, value) => {\n input.innerHTML = escapeHTML(value).replace(/\\r?\\n/g, \"
\");\n }\n};\n\nregisterWidget(label);\n\nexport const linklabel = {\n name: \"linklabel\",\n fixup: control => {\n control.value = control.value.trim();\n // Fix 'empty' or JS-links\n if (urlutils.isEmptyish(control.url) || urlutils.isJS(control.url)) {\n if (urlutils.isJS(control.url)) control.value = urlutils.JSAlertMessage;\n delete control.url;\n }\n return control;\n },\n attribs: (attr, control, enabled) => {\n let linkClassName = \"\";\n\n if (control.url) {\n attr[\"href\"] = fromApiServer(control.url);\n if (control.url.match(/mailto:/)) {\n attr[\"type\"] = \"email\";\n linkClassName = \"mail\";\n } else {\n linkClassName = \"bb-external\";\n if (control.isreport) linkClassName += \" report\";\n var mimetype = control.mimetype || urlutils.mimetype(control.url);\n if (mimetype) {\n attr[\"type\"] = mimetype.mimetype;\n linkClassName += \" \" + mimetype.ext;\n }\n }\n if (control.url[0] !== \"#\") attr[\"target\"] = \"_blank\";\n }\n linkClassName += \" bb-text\";\n attr[\"class\"] = linkClassName;\n return omitName(attr);\n },\n render: (control, group, attribs) => {\n return valueInside(control, attribs, \"a\");\n },\n setValue: (input, value) => {\n input.innerHTML = escapeHTML(value).replace(/\\r?\\n/g, \"
\");\n },\n layout: \"below\"\n};\n\nregisterWidget(linklabel);\n\nconst listlabel = {\n name: \"listlabel\",\n attribs: compose(\n omitName,\n omitRequired,\n mergeLeft({\n type: \"listlabel\",\n class: \"listlabel\"\n })\n ),\n item: item =>\n `
  • ${escapeHTML(item).replace(/\\\\n/g, \"
    \")}
  • `,\n render: (control, group, attribs) => {\n const value = control.value;\n const items = compose(join(\"\"), map(listlabel.item))(value);\n const widget = `
      \n${items}
    `;\n return $(widget);\n },\n setValue: (input, value, requestor) => {\n input.innerHTML = compose(join(\"\"), map(listlabel.item))(value);\n $.fn.showdown && $(input).find(\"li\").showdown();\n },\n layout: \"below\"\n};\n\nregisterWidget(listlabel);\n\nconst optionbox = {\n render: (control, group, attribs) => {\n const value = control.value;\n const widget = $(``);\n // Set head of drop-down list to an empty item.\n // If value[0].value is already the empty string, the server\n // has already done this for us (pre 4.7 or dataset-based\n // drop-down).\n // If one of the options has already been selected, do *not*\n // add this empty option.\n // @todo: remove this code once server release 4.7 or higher\n // runs everywhere.\n if (\n control.controltype === \"combobox\" &&\n value.length > 0 &&\n value[0].value !== \"\" &&\n !value.some(function (value) {\n return value.selected === true;\n })\n ) {\n value.unshift({ option: \"\", value: \"\" });\n }\n optionbox.setValue(widget.get(0), value);\n return widget;\n },\n setValue: (input, value) => {\n const options = [...input.querySelectorAll(\"option\")];\n const len = options.length;\n const newLen = value.length;\n const newOptions = input.append ? [] : null;\n let selectedValue = \"\";\n for (let i = 0; i < newLen; i++) {\n const option = value[i];\n const optionElt = options[i] || document.createElement(\"option\");\n optionElt.value = option.value;\n optionElt.textContent =\n value[i].value === \"\" ? _(\"Choose...\") : option.option;\n optionElt.classList.toggle(\"bb-valueless\", option.value === \"\");\n if (option.selected) {\n selectedValue = option.value;\n }\n if (i > len - 1) {\n if (newOptions) {\n newOptions.push(optionElt);\n } else {\n input.appendChild(optionElt);\n }\n }\n }\n if (newOptions.length) {\n input.append(...newOptions);\n } else if (newLen < len) {\n [...input.querySelectorAll(`option:nth-child(1n+${newLen + 1})`)].forEach(\n input => input.parentNode.removeChild(input)\n );\n }\n input.value = selectedValue;\n }\n};\n\nconst combobox = {\n name: \"combobox\",\n // fixup: control => {\n // if (control.freetext === true) {\n // control.controltype = \"edit\";\n // control.datalist = control.value.map(({ option }) => option);\n // control.placeholder = _(\"Choose or type...\");\n // let val = control.value.find(v => v.selected);\n // if (val) control.value = val.option;\n // else control.value = \"\";\n // }\n // return control;\n // },\n fixup: control => {\n if (control.freetext === true) {\n control.controltype = \"freebox\";\n\n // control.datalist = control.value.map(({ option }) => option);\n // control.placeholder = _(\"Choose or type...\");\n // let val = control.value.find(v => v.selected);\n // if (val) control.value = val.option;\n // else control.value = \"\";\n }\n return control;\n },\n couldWrap: true,\n attribs: (attr, control, enabled) =>\n Object.assign({}, attr, {\n name: control.name,\n size: 1\n }),\n render: optionbox.render,\n setValue: optionbox.setValue,\n layout: \"below\"\n};\n\nregisterWidget(combobox);\n\nconst listbox = {\n name: \"listbox\",\n attribs: (attr, control, enabled) =>\n Object.assign({}, attr, {\n name: control.name,\n size: control.value.length\n }),\n render: optionbox.render,\n setValue: optionbox.setValue,\n layout: \"below\"\n};\n\nregisterWidget(listbox);\n\nconst multilist = {\n name: \"multilist\",\n attribs: (attr, control, enabled) =>\n Object.assign({}, attr, {\n name: control.name,\n size: control.value.length,\n multiple: \"multiple\"\n }),\n render: optionbox.render,\n setValue: (input, value, requestor) => {\n const selected = value.find(option => option.selected === true);\n input.value = selected.value;\n },\n layout: \"below\"\n};\n\nregisterWidget(multilist);\n\nconst optionlist = {\n render: (control, group, attribs) => {\n const value = control.value;\n if (value.length === 0) return null;\n const widget = $(`
      `);\n for (let i = 0; i < value.length; i++) {\n let id = control.id + \"-\" + i;\n var option = $(`\n
    • \n \n
    • \n `);\n widget.append(option);\n widget.find(\"input:last\").val(value[i].value);\n }\n return widget;\n },\n onrequired: (input, required) => {\n // $(input).find(\"input\").attr(\"aria-required\", required);\n },\n onreadonly: (list, readonly) => {\n list.classList.toggle(\"bb-disabled\", readonly);\n [...list.querySelectorAll(\"input\")].forEach(input => {\n input.disabled = readonly;\n });\n }\n};\n\nconst checklist = {\n name: \"checkmultilist\",\n attribs: compose(omitRequired, assoc(\"class\", \"checklist bb-option-list\")),\n render: optionlist.render,\n onrequired: optionlist.onrequired,\n onreadonly: optionlist.onreadonly,\n allowUpdatingSelf: true,\n setValue: (input, value, requestor) => {\n const control = $(input).data(\"control\");\n value.forEach(({ selected }, index) => {\n const option = input.querySelector(`[id=\"${control.id}-${index}\"]`);\n if (!option) return;\n if (option.checked !== selected) option.checked = selected;\n $(option).trigger(\"programmatically-changed\");\n });\n },\n layout: \"below\"\n};\n\nregisterWidget(checklist);\n\nconst radiolist = {\n name: \"radio\",\n attribs: compose(omitRequired, assoc(\"class\", \"radiogroup bb-option-list\")),\n render: optionlist.render,\n allowUpdatingSelf: true,\n onrequired: optionlist.onrequired,\n onreadonly: optionlist.onreadonly,\n setValue: (input, value, requestor) => {\n const control = $(input).data(\"control\");\n const index = value.findIndex(option => option.selected === true);\n if (index === -1) {\n input.querySelectorAll(`[id|=\"${control.id}\"]`).forEach(i => {\n i.checked = false;\n i.closest(\".bb-option\").classList.remove(\"checked\");\n });\n return;\n }\n const option = input.querySelector(`[id=\"${control.id}-${index}\"]`);\n option.checked = true;\n $(option).trigger(\"programmatically-changed\");\n },\n layout: \"below\"\n};\n\nregisterWidget(radiolist);\n\nconst datepicker = {\n name: \"datetimepicker\",\n couldWrap: true,\n fixup: control => {\n control.placeholder = _(\"dateplaceholder\");\n return control;\n },\n serverToWidgetValue: value =>\n $.datepicker.formatDate(\n $.datepicker._defaults.dateFormat,\n parseDate(value)\n ),\n widgetToServerValue: input =>\n leadWithZeroes(\n $.datepicker.formatDate(\"yy-mm-dd\", $(input).datepicker(\"getDate\"))\n ),\n attribs: (attr, control, enabled) =>\n Object.assign({}, attr, {\n value: datepicker.serverToWidgetValue(control.value),\n autocomplete: \"off\",\n placeholder: _(\"dateplaceholder\", _(\"select date\")),\n type: \"text\"\n }),\n render: (control, group, attribs) => {\n return emptyTag(\"input\", attribs);\n },\n afterRender: (widget, control) => {\n if (!control.originalreadonly || control.dynamic) {\n widget.datepicker();\n observeDatepickers();\n\n control._elt.addEventListener(\"change\", onChangeDate);\n control._elt.addEventListener(\n \"keydown\",\n when(propEq(\"key\", \"Enter\"), () => {\n const ev = new InputEvent(\"change\", {\n bubbles: true,\n cancelable: true,\n view: window\n });\n control._elt.dispatchEvent(ev);\n })\n );\n\n disconnectValue({\n input: widget.get(0),\n filter: function (value, input) {\n return datepicker.widgetToServerValue(input);\n },\n value: control.value\n });\n widget.datepicker(\"widget\").hide();\n }\n },\n setValue: (input, value) => {\n input.setAttribute(\"data-server-value\", value);\n input.value = datepicker.serverToWidgetValue(value);\n },\n validate: (control, value) => {\n if (!control.notnull && (value || \"\").trim() === \"\") {\n // Side effect\n $($(control.$elt).datepicker(\"option\", \"altField\")).attr(\"value\", \"\");\n }\n return checkDate(control, value);\n },\n layout: \"aside\"\n};\n\nregisterWidget(datepicker);\n\nconst numedit = {\n name: \"numedit\",\n couldWrap: true,\n getMaxChars: control => {\n var max, min;\n if (has(\"maximum\", control))\n max = Numerals.formatter(\n control.maximum.toFixed(control.precision)\n ).length;\n if (has(\"minimum\", control))\n min = Numerals.formatter(\n control.minimum.toFixed(control.precision)\n ).length;\n if (typeof min === \"undefined\") return max;\n if (typeof max === \"undefined\") return undefined;\n return Math.max(max, min);\n },\n serverToWidgetValue: value => Numerals.formatter(value),\n // widgetToServerValue: input => input.value,\n attribs: (attr, control, enabled) => {\n const maxchars = numedit.getMaxChars(control);\n return Object.assign(\n {},\n attr,\n {\n type: \"text\",\n class: \"numedit\",\n autocomplete: \"off\",\n name: control.name, // Prevent bug (in JSON grid) (see mantis#5416)\n // value = control.value = parseFloat(control.value || 0);\n value: parseFloat(control.value || 0).toFixed(control.precision)\n },\n // maxchars -- not to be confused with maxlength, which used\n // for validation. This is just to aid layout decisions.\n maxchars && { \"data-maxchars\": maxchars }\n );\n },\n render: (control, group, attribs) => emptyTag(\"input\", attribs),\n afterRender: (widget, control) => {\n widget.data(\"anchor\", widget.spinner(control));\n },\n setValue: (input, value) => {\n const control = $.data(input, \"control\");\n input.value = numedit.serverToWidgetValue(\n parseFloat(value || 0).toFixed(control.precision)\n );\n },\n validate: function (control, value) {\n if (control.controltype !== \"numedit\")\n throw \"_validateNumber called on something not a number\";\n const metadata = control.metadata || {};\n var val;\n try {\n val = Numerals.parser(value);\n } catch (e) {\n throw new Error(\n format(\n metadata.errnuminvalid || _(\"Invalid number\"),\n compose(assoc(\"value\", value), numedit.quotable)(control)\n )\n );\n }\n control.hasMax = has(\"maximum\", control);\n control.hasMin = has(\"minimum\", control);\n try {\n if (typeof val !== \"number\")\n throw metadata.errnuminvalid || _(\"Invalid number\");\n if (control.hasMax && control.hasMin) {\n if (val < control.minimum || val > control.maximum) {\n throw (\n metadata.errnumnotinrange ||\n _(\"Value has to lie between {minimum} and {maximum}\")\n );\n }\n } else if (control.hasMax) {\n if (val > control.maximum) {\n if (control.maximum === 0)\n throw (\n metadata.errnumnotnegativeorzero ||\n _(\"Negative number or zero expected\")\n );\n else if (control.maximum === -1)\n throw metadata.errnumnotnegative || _(\"Negative number expected\");\n else\n throw (\n metadata.errnumabovemaximum ||\n _(\"Value has to lie below {maximum}\")\n );\n }\n } else if (control.hasMin) {\n if (val < control.minimum) {\n if (control.minimum === 0)\n throw (\n metadata.errnumnotpositiveorzero ||\n _(\"Positive number or zero expected\")\n );\n else if (control.minimum === 1)\n throw metadata.errnumnotpositive || _(\"Positive number expected\");\n else\n throw (\n metadata.errnumbelowminimum ||\n _(\"Value has to lie above {minimum}\")\n );\n }\n }\n } catch (e) {\n throw formatPlus(\n e,\n compose(assoc(\"value\", value), numedit.quotable)(control)\n );\n }\n\n return true;\n },\n quotable: compose(\n when(has(\"minimum\"), over(lensProp(\"minimum\"), Numerals.formatter)),\n when(has(\"maximum\"), over(lensProp(\"maximum\"), Numerals.formatter)),\n when(\n has(\"minimum\"),\n chain(assoc(\"minimum-1\"), compose(dec, prop(\"minimum\")))\n ),\n when(\n has(\"maximum\"),\n chain(assoc(\"maximum+1\"), compose(inc, prop(\"maximum\")))\n ),\n quotable\n ),\n layout: \"aside\"\n};\n\nregisterWidget(numedit);\n\nconst freebox = {\n name: \"freebox\",\n couldWrap: true,\n attribs: (attr, control, enabled) =>\n Object.assign({}, attr, {\n \"type\": \"text\",\n \"data-type\": control.controltype,\n \"list\": `${control.id}-list`,\n \"placeholder\": _(\"Choose...\"),\n \"value\": freebox._realValue(control.value)\n }),\n _realValue: compose(propOr(\"\", \"option\"), find(prop(\"selected\"))),\n setValue: function (input, value, requestor) {\n input.value = freebox._realValue(value);\n },\n render: (control, group, attribs) => emptyTag(\"input\", attribs),\n afterRender: (widget, control) => {\n control._elt.insertAdjacentHTML(\n \"afterEnd\",\n `\n${control.value\n .map(({ option }) => `\n`\n );\n },\n layout: \"aside\"\n};\n\nregisterWidget(freebox);\n\nconst _radioButtonWidget = {\n name: \"radiobutton\",\n tagName: \"input\",\n attribs: (attr, control, enabled) =>\n Object.assign(\n {},\n attr,\n { type: \"radio\", value: control.value },\n control.selected && { checked: \"checked\" }\n ),\n render: $.noop\n};\n\nregisterWidget(_radioButtonWidget);\n\nconst _rangeWidget = {\n name: \"range\",\n tagName: \"input\",\n attribs: (attr, control, enabled) =>\n Object.assign({}, attr, {\n type: \"range\",\n value: control.value\n }),\n render: $.noop,\n layout: \"aside\"\n};\n\nregisterWidget(_rangeWidget);\n\nconst _buttonWidget = {\n name: \"button\",\n attribs: (attr, control, enabled) =>\n Object.assign(\n {},\n attr,\n { type: \"submit\", value: control.value },\n control.label && { \"aria-label\": control.label }\n ),\n render: (control, group, attribs) => valueInside(control, attribs, \"button\"),\n setValue: (elt, value, requestor, Updates) => {\n if (has(\"text\", Updates)) elt.innerHTML = Updates.text.to;\n if (has(\"value\", Updates)) elt.value = Updates.value.to;\n elt.classList.toggle(\"bb-record-del\", Updates.value.to.endsWith(\"-\"));\n elt.classList.toggle(\"bb-record-add\", Updates.value.to.endsWith(\"+\"));\n }\n};\n\nregisterWidget(_buttonWidget);\n\nconst _legendWidget = {\n name: \"legend\",\n tagName: \"legend\",\n attribs: noAttribs,\n\n render: function (control, widget, group) {\n var level;\n if (!conf.a11y.strictlegends && control._subtype === \"heading\") {\n level = Math.min(6, control._level || 2);\n // Trim value and control.value itself as well.\n widget.html(\n \"' +\n escapeHTML(control.value.trim()) +\n \"\"\n );\n } else {\n widget.text(control.value);\n widget.addClass(\"bb-md-able\");\n }\n }\n};\n\nregisterWidget(_legendWidget);\n\nconst _captionWidget = {\n name: \"caption\",\n tagName: \"caption\",\n attribs: noAttribs,\n render: function (control, widget, group) {\n widget.text(control.value.trim());\n widget.addClass(\"bb-md-able\");\n }\n};\n\nregisterWidget(_captionWidget);\n\nconst _alertWidget = {\n name: \"alert\",\n tagName: \"p\",\n attribs: noAttribs,\n render: function (control, widget, group) {\n widget.text(control.value);\n // Yup, this widget exists mainly for this\n // side-effect -- setting role=\"alert\",\n // aria-live=\"assertive\" does not do the\n // trick - and forcing focus looks ugly too.\n A11y.log(control.value);\n }\n};\n\nregisterWidget(_alertWidget);\n\nexport const grid = {\n name: \"grid\",\n attribs: compose(omitRequired, omitName),\n item: item =>\n `
    • ${escapeHTML(item).replace(/\\\\n/g, \"
      \")}
    • `,\n renderable: control => {\n const copy = assoc(\n \"addPlacement\",\n !control.addallowed\n ? \"none\"\n : control.value.length === 0 ||\n arbitraryCoreProp(\"putAddRowButtonBelowGrid\")\n ? \"below\"\n : \"insert\",\n control\n );\n return pipe(\n when(\n propEq(\"addPlacement\", \"insert\"),\n compose(\n over(\n lensProp(\"columns\"),\n append({\n controltype: \"button\",\n text: `${\n (control.metadata && control.metadata.insertbuttontext) ||\n _(\"insert row\")\n }+`,\n name: \"update\",\n className: \"bb-record-add\",\n readonly: false,\n label: _(\"insert row\")\n })\n ),\n over(\n lensProp(\"value\"),\n map((row, i) =>\n append(\n {\n value:\n control.name +\n \".\" +\n ((control.offset || 0) + i + 1) +\n \".\" +\n \"+\"\n },\n row\n )\n )\n )\n )\n ),\n when(\n propEq(\"deleteallowed\", true),\n compose(\n over(\n lensProp(\"columns\"),\n append({\n controltype: \"button\",\n name: \"update\",\n className: \"bb-record-del\",\n readonly:\n !control.notnull ||\n control.value.length > 1 ||\n (control.showcolumns && control.addallowed)\n ? false\n : true,\n text: `${\n (control.metadata && control.metadata.deletebuttontext) ||\n _(\"delete row\")\n }-`\n })\n ),\n over(\n lensProp(\"value\"),\n map((row, i) =>\n append(\n {\n value:\n control.name + \".\" + ((control.offset || 0) + i) + \".\" + \"-\"\n },\n row\n )\n )\n )\n )\n ),\n infichain([\n prop(\"columns\"),\n (columns, grid) => {\n return over(\n lensProp(\"value\"),\n map((row, row_i) =>\n map((cell, cell_i) =>\n compose(\n when(\n both(prop(\"colname\"), isQuestion),\n assoc(\"aria\", { labelledby: `${control.id}-col-${cell_i}` })\n ),\n when(prop(\"colname\"), cell =>\n assoc(\"meta\", { label: cell.colname }, cell)\n ),\n cell =>\n Object.assign(\n {},\n columns[cell_i],\n {\n id:\n control.id +\n \"-\" +\n ((control.offset || 0) + row_i) +\n \"-\" +\n cell_i\n },\n cell\n ),\n assoc(\"_row_index\", (control.offset || 0) + row_i),\n assoc(\"_cell_index\", cell_i)\n )(cell)\n )(row)\n ),\n grid\n );\n }\n ]),\n over(\n lensProp(\"columns\"),\n map((col, col_i) => assoc(\"id\", `${control.id}-col-${col_i}`, col))\n ),\n over(\n lensProp(\"value\"),\n map(\n map((cell, cell_i, cells) =>\n compose(\n assoc(\"_tag\", grid.cellTag(cell, cells)),\n when(\n allPass([\n isLabel,\n pipe(prop(\"_cell_index\"), gt, applyTo(0)),\n () => isOption(cells[cell_i - 1])\n ]),\n cell => assoc(\"isFor\", cells[cell_i - 1].id, cell)\n ),\n when(\n allPass([\n isOption,\n propEq(\"_cell_index\", 0),\n () => isLabel(cells[cell_i + 1])\n ]),\n cell =>\n over(\n lensPath([\"aria\", \"labelledby\"]),\n col_id => `${cells[cell_i + 1].id} ${col_id || \"\"}`,\n cell\n )\n )\n )(cell)\n )\n )\n )\n )(copy);\n },\n cellTag: (cell, row) => {\n return cell.value === null\n ? null\n : cell._rowspan && cell._cell_index === 0 && row.length > 1\n ? \"th\"\n : \"td\";\n },\n columnheader: column => {\n const header = document.createElement(\"th\");\n header.classList.add(\"bb-md-able\");\n header.setAttribute(\"data-rowtype\", column.controltype);\n header.setAttribute(\"data-rowreadonly\", Boolean(column.readonly));\n if (has(\"colname\", column)) {\n header.innerText = column.colname;\n header.id = column.id;\n }\n return header;\n },\n colheaderids: ifElse(\n prop(\"showcolumns\"),\n compose(\n map(ifElse(propEq(\"controltype\", \"button\"), F, prop(\"id\"))),\n prop(\"columns\")\n ),\n compose(map(F), prop(\"columns\"))\n ),\n rowheaderid: (rows, i) => {\n const rows_up_to_here = rows.slice(0, i + 1);\n return compose(\n prop(\"value\"),\n map(compose(id => `${id}--cell`, prop(\"id\"), head)),\n Maybe.of,\n find(pathEq([0, \"_tag\"], \"th\")),\n reverse\n )(rows_up_to_here);\n },\n cell: cell => {\n const tag = cell._tag;\n const e_cell =\n tag === null\n ? document.createComment(\"empty cell\")\n : document.createElement(tag);\n if (tag === \"th\") {\n e_cell.id = `${cell.id}--cell`;\n }\n return e_cell;\n },\n cellSetAttributes: (e_cell, cell) => {\n if (cell._tag === null) return e_cell;\n if (cell._tag === \"th\") e_cell.setAttribute(\"scope\", \"row\");\n if (cell._rowspan > 1) e_cell.setAttribute(\"rowspan\", cell._rowspan);\n else e_cell.removeAttribute(\"rowspan\");\n if (cell.headers) e_cell.setAttribute(\"headers\", cell.headers);\n else e_cell.removeAttribute(\"headers\");\n if (typeof cell.colname !== \"undefined\")\n e_cell.setAttribute(\"data-column\", cell.colname);\n else e_cell.removeAttribute(\"data-column\");\n e_cell.classList.add(\"nth-child-\" + (cell._cell_index + 1));\n if (cell.value === \"\")\n e_cell.classList.toggle(\n \"empty\",\n cell.controltype === \"label\" && cell.value === \"\"\n ); // IE8 does not support :empty\n\n e_cell.classList.add(\"bb-celltype-\" + cell.controltype);\n return e_cell;\n },\n render: (control, group, attribs) => {\n const widget = $(`
      `);\n control = grid.renderable(control);\n if (control.value.length === 0) {\n widget.addClass(\"bb-empty\");\n }\n if (control.caption) {\n wControl(\n control.caption,\n group,\n widget //append hereto\n );\n }\n if (control.showcolumns) {\n // widget.append($(\"\".repeat(control.columns.length)));\n const thead = document.createElement(\"thead\");\n const tr = document.createElement(\"tr\");\n thead.append(tr);\n widget.append(thead);\n if (control.value.length > 0)\n tr.append(...control.columns.map(grid.columnheader));\n }\n const e_body = document.createElement(\"tbody\");\n widget.append(e_body);\n const colheaders = grid.colheaderids(control);\n control.value.forEach(function (row, i, rows) {\n // NOTE: control.offset is set by global plugin split-grid.\n // const i = idx + (control.offset || 0);\n const last_spanning_cell_id = grid.rowheaderid(rows, i);\n const e_row = document.createElement(\"tr\");\n if (row.length === 0) return;\n e_row.classList.toggle(\"bb-newscope\", row[0]._tag === \"th\");\n e_body.appendChild(e_row);\n row.forEach(function (cell, icol) {\n const rowheader = cell._tag === \"td\" ? last_spanning_cell_id : false;\n const headers = [rowheader, colheaders[icol]].filter(Boolean).join(\" \");\n const cellWithHeaders = {\n ...cell,\n headers\n };\n if (cell.value !== null) {\n const e_cell = grid.cell(cell);\n grid.cellSetAttributes(e_cell, cellWithHeaders);\n e_row.appendChild(e_cell);\n wControl(\n cell,\n control._group,\n e_cell //append hereto\n );\n } else {\n e_row.appendChild(document.createComment(\"empty cell\"));\n }\n });\n });\n\n return $(widget);\n },\n afterRender: (widget, control) => {\n const addPlacement = !control.addallowed\n ? \"none\"\n : control.value.length === 0 ||\n arbitraryCoreProp(\"putAddRowButtonBelowGrid\")\n ? \"below\"\n : \"insert\";\n if (addPlacement === \"below\") {\n const gridAddButton = ``;\n widget.get(0).insertAdjacentHTML(\"afterEnd\", gridAddButton);\n // $(widget.in.append(widget, gridAddButton);\n }\n },\n setValue: (e_grid, value, requestor, updates) => {\n // if (grid.contains(requestor))\n const control = $.data(e_grid, \"control\");\n const old = compose(\n grid.renderable,\n assoc(\"value\", updates[\"value\"].from),\n assoc(\"columns\", updates[\"columns\"].from)\n )(control);\n\n const now = grid.renderable(control);\n // Remove spurious row\n [\n ...e_grid.querySelectorAll(\n `tbody tr:nth-child(1n + ${now.value.length + 1})`\n )\n ].forEach(row => row.remove());\n // Remove spurious 'cells' (also empty cell comments)\n [...e_grid.querySelectorAll(`tbody tr`)].forEach(row => {\n let cell;\n while (((cell = row.childNodes[now.columns.length]), cell)) {\n cell.remove();\n }\n });\n\n if (\n !equals(old.columns, now.columns) ||\n (old.value.length === 0 && now.value.length !== 0) ||\n (old.value.length !== 0 && now.value.length === 0)\n ) {\n // Remove ALL column headers (re-created)\n [...e_grid.querySelectorAll(`thead tr th`)].forEach(colheader =>\n colheader.remove()\n );\n\n if (now.showcolumns && now.value.length > 0)\n now.columns // .slice(old.columns.length)\n .forEach(function (column) {\n e_grid.querySelector(\"thead tr\").append(grid.columnheader(column));\n });\n }\n\n const colheaders = grid.colheaderids(now);\n now.value.forEach((row, irow, rows) => {\n let e_row = e_grid.querySelector(`tbody tr:nth-child(${irow + 1})`);\n if (e_row === null) {\n e_row = document.createElement(\"tr\");\n e_grid.tBodies[0].append(e_row);\n }\n e_row.classList.toggle(\"bb-newscope\", row[0]._tag === \"th\");\n const last_spanning_cell_id = grid.rowheaderid(rows, irow);\n row.forEach((cell, icol) => {\n const cellInput = e_grid.querySelector(`[id=\"${cell.id}\"]`);\n const oldcell = old.value[irow] && old.value[irow][icol];\n const rowheader = cell._tag === \"td\" ? last_spanning_cell_id : false;\n const headers = [rowheader, colheaders[icol]].filter(Boolean).join(\" \");\n const cellWithHeaders = {\n ...cell,\n headers\n };\n const spot = e_row.childNodes[icol];\n if (!spot) {\n // NEW => Add at end\n const e_cell = grid.cell(cell);\n grid.cellSetAttributes(e_cell, cellWithHeaders);\n e_row.appendChild(e_cell);\n wControl(cell, control._group, e_cell);\n return;\n }\n if (\n cell.controltype !== oldcell.controltype ||\n cell._tag !== oldcell._tag\n ) {\n // REPLACE\n let e_cell;\n if (cell._tag !== oldcell._tag) {\n e_cell = grid.cell(cell);\n spot.replaceWith(e_cell);\n } else {\n // Re-use old cell\n e_cell = spot;\n if (cell._tag !== null) {\n e_cell.classList.remove(\"bb-celltype-\" + oldcell.controltype);\n e_cell.innerHTML = \"\";\n }\n }\n if (cell._tag !== null) {\n grid.cellSetAttributes(e_cell, cellWithHeaders);\n wControl(cell, control._group, e_cell);\n }\n return;\n }\n if (cell._tag === null) return;\n // UPDATE\n grid.cellSetAttributes(spot, cellWithHeaders);\n const cellControl = $.data(cellInput, \"control\");\n if (!cellControl) return;\n if (cell.value !== cellControl.value) {\n $(cellInput).updateControl(\n [\n Object.assign({}, cellControl, {\n value: cell.value,\n text: cell.text\n })\n ],\n requestor\n );\n }\n });\n });\n },\n onrequired: (grid, required) => {},\n onreadonly: (grid, readonly) => {\n grid.classList.toggle(\"bb-disabled\", readonly);\n [...grid.querySelectorAll(\"input, textarea, button\")].forEach(input => {\n input.disabled =\n readonly || compose(ifElse(Boolean, isReadOnly, F), getControl)(input);\n });\n },\n layout: \"below\"\n};\n\nregisterWidget(grid);\n\n$.fn.extend({\n /**\n * Widgetize as numedit\n */\n spinner: function (control) {\n control = control || {};\n var _interval = 250,\n interval = _interval,\n timer = null,\n me = this,\n val = Numerals.formatter(me.val()),\n $this = $(this),\n $anchor = $this;\n\n function mustAddButtons() {\n return !(arbitraryCoreProp(\"skipNumButtons\") === true);\n }\n\n function addButtons($input, control) {\n var buttontemplate =\n '
      ' +\n '
      ' +\n '
      ' +\n \"
      \";\n $input\n .wrapAll('
      ')\n .after(buttontemplate);\n $input.parents(\".bb-num\").data(\"control\", control);\n $input\n .next()\n .find(\".bb-num-down, .bb-num-up\")\n .on(\"click\", adjustOnce)\n .on(\"mousedown\", keepAdjusting)\n .on(\"mouseup mouseout\", stopAdjusting);\n\n return $input.parent();\n }\n\n function adjust(diff) {\n var parsed, val;\n try {\n parsed = Numerals.parser(me.val());\n } catch (err) {\n $this.validate(); // Let validate() handle\n // showing of errors\n }\n if (typeof parsed === \"undefined\") return;\n // A diff of 0 is just used for the sake of formatting - so do\n // not force the number to be in range.\n val = (\n diff === 0\n ? parseFloat(parsed - diff)\n : forceInRange(\n parseFloat(parsed - diff),\n control.minimum,\n control.maximum\n )\n ).toFixed(control.precision || 0);\n\n me.val(Numerals.formatter(val));\n\n //if (val == \"NaN\") val = \"\";\n $this.validate(); // Validate just for the sake\n // of getting away the error\n // message\n if (me.data(\"orgval\") !== me.val()) me.trigger(\"change\");\n $this.data(\"orgval\", $this.val());\n }\n\n $this\n .data(\"orgval\", val) // Remember the original value\n .val(val)\n .on(\"keydown\", function (e) {\n var key = e.keyCode;\n if (key === 38 || key === 40) {\n var diff = key === 38 ? -1 : 1;\n adjust(diff);\n }\n if (key === 13) {\n adjust(0);\n }\n })\n .on(\"click\", function () {\n let parsed;\n try {\n parsed = Numerals.parser(me.val());\n } catch (err) {\n //\n } finally {\n if (parsed === 0) $this.val(\"\");\n }\n })\n .on(\"blur\", function () {\n let orgval = $this.val();\n adjust(0);\n if ($this.val() !== orgval) {\n $this.addClass(\"bb-programmatically-changed\");\n window.setTimeout(function () {\n $this.removeClass(\"bb-programmatically-changed\");\n }, 1000);\n }\n // Set orgval for future changes.\n $this.data(\"orgval\", $this.val());\n });\n\n function keepAdjusting() {\n var thing = $(this);\n var diff = thing.hasClass(\"bb-num-down\") ? 1 : -1;\n timer = window.setTimeout(function () {\n adjust(diff);\n if (interval > 20) interval = interval - 10;\n thing.trigger(\"mousedown\");\n }, interval);\n }\n\n function adjustOnce() {\n var diff = $(this).hasClass(\"bb-num-down\") ? 1 : -1;\n adjust(diff);\n }\n\n function stopAdjusting() {\n window.clearTimeout(timer);\n interval = _interval;\n return false; // prevent text selection\n }\n\n if (mustAddButtons()) $anchor = addButtons($this, control);\n\n disconnectValue({\n input: $this.get(0),\n filter: Numerals.parser,\n value: control.value\n });\n $this.on(\"change\", function (_event, data) {\n if (!prop(\"programmatically\", data)) $this.validate();\n });\n return $anchor;\n }\n});\n", "import { _ } from \"./gettext\";\n\n/*** NUMBER UTILITIES BEGIN ***/\n\nexport function forceInRange(num, min, max) {\n if (typeof min == \"undefined\" && typeof max == \"undefined\") return num;\n if (typeof min == \"undefined\") return Math.min(max, num);\n if (typeof max == \"undefined\") return Math.max(min, num);\n if (min === max) return min;\n return Math.max(Math.min(max, num), min);\n}\n\nexport const Numerals = (function () {\n /**\n * Create a getter for array, consuming items, repeating the last one\n * indefinitely.\n *\n * @param {Array} arr The array to make a repeater for\n * @return {Function()} Gets next item in arr, repeating last item indefinitely\n */\n function makeLastItemRepeater(arr) {\n var _a = arr.slice();\n var _last;\n return function getIter() {\n _last = _a.shift() || _last;\n return _last;\n };\n }\n /**\n * Create a formatting function for (arabic-hindu) numerals.\n *\n * @param {String} radixPoint String (character) used as radix point.\n * @param {String} groupingChar String (character) used for grouping\n * digits before the radix point.\n * @param {Array} groupingRules (optional) Array defining\n * grouping rules. Each element in this array stands for a group,\n * tracking leftwards from the radix point. When no more elements\n * remain, the last element will be repeated indefinitely.\n *\n * Most language use [3] (the default). For Indian, use [3,2]; for Chinese (and\n * Japanese?), use [4].\n *\n * Besides these rules, the special case of formatting\n * four digits in a row without grouping and no\n * fractional part is supported, and cannot be overruled.\n *\n * @return {Function()} Formatting function.\n */\n function makeFormatter(radixPoint, groupingChar, groupingRules) {\n return function formatter(num) {\n var idx = makeLastItemRepeater(groupingRules || [3]);\n var split = num.toString().split(\".\");\n var integralPart = split[0];\n var fractionalPart = split[1];\n var neg = (integralPart[0] === \"-\" && \"-\") || \"\";\n if (neg) integralPart = integralPart.substr(1);\n var th,\n out = \"\";\n if (integralPart) {\n // The four-digit exception rule (such as in years):\n if (!fractionalPart && integralPart.length === 4) out = integralPart;\n else {\n integralPart = integralPart.split(\"\").reverse();\n while ((th = integralPart.splice(0, idx()))[0]) {\n out = th.reverse().join(\"\") + (out ? groupingChar : \"\") + out;\n }\n }\n }\n if (fractionalPart) return neg + out + radixPoint + fractionalPart;\n return neg + out;\n };\n }\n function makeParser(radixPoint, groupingChar) {\n /**\n * Match anything not a digit or negative sign\n */\n var thre = /[^0-9-]/g;\n /**\n * Match only optional leading minus digits,\n * radixPoint, groupingChar and space characters.\n */\n var testre = new RegExp(\"^s?-?[0-9 \" + radixPoint + groupingChar + \"]*$\");\n\n return function parser(s) {\n if (!testre.test(s)) throw new Error(_(\"Invalid number\"));\n var split = s.split(radixPoint);\n var integralPart = split[0].replace(thre, \"\");\n if (!/^-?[0-9]*$/.test(integralPart))\n throw new Error(_(\"Invalid number\"));\n var fractionalPart = split[1];\n if (fractionalPart) fractionalPart = fractionalPart.replace(/\\s/g, \"\");\n if (!fractionalPart) fractionalPart = \"0\";\n if (!/^[0-9]*$/.test(fractionalPart))\n throw new Error(_(\"Invalid number\"));\n // Room for errors here.\n return new Number(integralPart + \".\" + fractionalPart) + 0;\n };\n }\n\n return {\n parser: makeParser(\n _(\"__radixpoint__\", \".\"),\n _(\"__digitgroupingchar__\", \",\")\n ),\n formatter: makeFormatter(\n _(\"__radixpoint__\", \".\"),\n _(\"__digitgroupingchar__\", \",\"),\n _(\"__digitgroupingrules__\", [3])\n ),\n makeFormatter: makeFormatter,\n makeParse: makeParser,\n refresh: () => {\n // console.log(this);\n Numerals.parser = makeParser(\n _(\"__radixpoint__\", \".\"),\n _(\"__digitgroupingchar__\", \",\")\n );\n Numerals.formatter = makeFormatter(\n _(\"__radixpoint__\", \".\"),\n _(\"__digitgroupingchar__\", \",\"),\n _(\"__digitgroupingrules__\", [3])\n );\n }\n };\n})();\n/*** NUMBER UTILITIES END ***/\n", "import { fromApiServer } from \"./location.js\";\nimport Vars from \"./vars.js\";\n\nif (!window.location.origin) {\n window.location.origin =\n window.location.protocol +\n \"//\" +\n window.location.hostname +\n (window.location.port ? \":\" + window.location.port : \"\");\n}\n\n/*** URL UTILITIES BEGIN ***/\nexport const urlutils = (function () {\n var mimetypes = {\n xsl: \"text/html\",\n html: \"text/html\",\n docx: \"application/msword\",\n pdf: \"application/pdf\",\n odt: \"application/vnd.oasis.opendocument.text\",\n rtf: \"application/rtf\",\n doc: \"application/msword\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n png: \"image/png\"\n };\n function caseReport(casus) {\n return fromApiServer(\"report?\" + Vars.querify(Vars.SESSION_KEYS, casus));\n }\n function getFiles(casus) {\n return \"getfiles?\" + Vars.querify(Vars.SESSION_KEYS, casus);\n }\n function isJS(url) {\n return url.match(/javascript:/);\n }\n function isEmptyish(url) {\n return url[0] === \"?\";\n }\n var JSAlertMessage =\n \"ALERT:\\nIt looks like someone is trying to eavesdrop on you,\" +\n \" trying to evaluate JavaScript code. \" +\n \"This person may want to steal private information \" +\n \"from you or other persons. \" +\n \"For your safety and that of others, \" +\n \"please contact this website \" +\n \"to report this message.\";\n return {\n isJS,\n isEmptyish,\n JSAlertMessage,\n getFiles,\n caseReport,\n mimetype: function (url) {\n const absoluteURL = new URL(\n fromApiServer(url),\n `${location.protocol}${location.host}${location.pathname}`\n );\n const filename = absoluteURL.pathname.endsWith(\"/getfile\")\n ? new URLSearchParams(absoluteURL.search).get(\"filename\")\n : absoluteURL.pathname.split(\"/\").pop();\n if (!filename) return null;\n const ext = filename.match(/\\.([^?.]+)$/),\n mimetype = ext && mimetypes[ext[1]];\n if (!mimetype) return null;\n return {\n mimetype: mimetype,\n ext: ext[1]\n };\n }\n };\n})();\n/*** URL UTILITIES END ***/\n", "import { compose, map, filter } from \"./functional\";\n\nexport const collectAttributes = (prefix, elt) =>\n compose(\n Object.fromEntries,\n map(({ name, value }) => [name.substr(prefix.length), value]),\n filter(({ name, value }) => name.startsWith(prefix)),\n x => [...x]\n )(elt.attributes);\n", "import { escapeHTML } from \"./escape.js\";\nimport {\n choose,\n compose,\n equals,\n findIndex,\n T,\n identity,\n slice\n} from \"$json/lib/functional.js\";\n\nconst times = (string, integer) => string.repeat(integer);\n\n/*** JUMPLIST BEGIN ***/\nfunction hasselectedbelowlevel(jumplist, level) {\n if (jumplist.length == 0) return false;\n if (jumplist[0].level <= level) return false;\n if (jumplist[0].status == \"selected\") return true;\n return hasselectedbelowlevel(jumplist.slice(1), jumplist[0].level);\n}\nfunction hasselectedbelow(jumplist) {\n return hasselectedbelowlevel(jumplist.slice(1), jumplist[0].level);\n}\n\nconst ariaCurrentAttrib = jumplist =>\n jumplist.status === \"selected\" ? ` aria-current=\"step\"` : \"\";\n\nconst chapterDataAttrib = jumplist =>\n !jumplist.ischapter ? \"\" : `data-chapterstatus=${jumplist.chapterstatus}`;\n\nfunction bakeInnerList(jumplist, level = 0, containsselection) {\n if (!(jumplist instanceof Array)) {\n return (\n (jumplist.level > level\n ? times(\n `<${Jumplist.type}>
    • `,\n jumplist.level - level\n )\n : jumplist.level < level\n ? times(`
    • `, level - jumplist.level) +\n `
    • `\n : `
    • `) +\n `${escapeHTML(\n jumplist.screentitle.trim()\n )}`\n );\n }\n if (jumplist.length == 0)\n return \"
    • \" + times(``, level);\n return (\n bakeInnerList(\n jumplist[0],\n level,\n hasselectedbelow(jumplist, jumplist[0].level)\n ) + bakeInnerList(jumplist.slice(1), jumplist[0].level)\n );\n}\nexport const bakeAsListitems = jumplist => {\n let html = bakeInnerList(jumplist);\n // Odd case of indentation sans parent:\n if ([\"u\", \"o\"].includes(html.charAt(1)))\n return '
    • ' + html + \"
    • \";\n return html;\n};\nfunction bakeAsDropDown(jumplist, level = 0, containsselection) {\n // Implemented recursively so we can make the 'chapter' selected\n if (!(jumplist instanceof Array)) {\n return (\n \"\" +\n times(\" \", level * 2) +\n escapeHTML(jumplist.screentitle.trim()) +\n \"\"\n );\n }\n if (jumplist.length == 0) return \"\";\n return (\n bakeAsDropDown(\n jumplist[0],\n level,\n hasselectedbelow(jumplist, jumplist[0].level)\n ) + bakeAsDropDown(jumplist.slice(1), jumplist[0].level)\n );\n}\n\nconst findCurrentIndex = compose(\n i => (i === -1 ? Infinity : i),\n findIndex(({ status }) => status === \"future\")\n);\n\nexport var Jumplist = new (function () {\n var _jumplist = []; //Save last jumplist\n this.type = \"ul\";\n this.draw = function draw(jumplist) {\n jumplist = jumplist || _jumplist;\n if (jumplist) _jumplist = jumplist;\n $(\n `.bb-jumplist ${Jumplist.type}, .bb-jumplist li, .bb-jumplist-dropdown select`\n ).remove();\n if (jumplist.length) {\n if (\n $(\".bb-jumplist:visible, .bb-jumplist-dropdown:visible\").length === 0\n ) {\n // If we can't rely on CSS to decide the appropriate type\n // of jumplist (happens sometimes onload), draw them both\n drawAsList(jumplist);\n drawAsDropDown(jumplist);\n } else {\n // Draw our standard list:\n if ($(\".bb-jumplist\").is(\":visible\")) drawAsList(jumplist);\n // Also draw the dropdown:\n if ($(\".bb-jumplist-dropdown\").is(\":visible\")) drawAsDropDown(jumplist);\n }\n }\n };\n\n function drawAsList(jumplist) {\n const currentIndex = findCurrentIndex(jumplist);\n $(\".bb-jumplist\").map((i, l) => {\n const slicetype = l.dataset[\"slice\"];\n const itemizer = choose([\n [equals(\"before\"), slice(0, currentIndex)],\n [equals(\"after\"), slice(currentIndex, Infinity)],\n [T, identity]\n ])(slicetype);\n\n const html = bakeAsListitems(itemizer(jumplist));\n $(l).append(\n `<${Jumplist.type} aria-describedby=\"a-jumplist-title\">${html}`\n );\n });\n $(\".bb-jumplist a:last\").addClass(\"last\");\n $(\".bb-jumplist li:last-child\").addClass(\"last-child\"); // aid older browsers\n }\n function drawAsDropDown(jumplist) {\n if (jumplist.length) {\n var html = bakeAsDropDown(jumplist, 0);\n $(\".bb-jumplist-dropdown\").append(\"\");\n }\n }\n\n return this;\n})();\n", "import { getVar } from \"./vars.js\";\n\nexport const userinfo = () => getVar(\"userinfo\") || {};\n", "import { userinfo } from \"./user-info.js\";\nimport {\n compose,\n either,\n includes,\n prop,\n strictDifference\n} from \"./functional.js\";\n\nexport const PERM_ACCESSALLMODELS = \"accessallmodels\",\n // Allow to access all models\n PERM_ALLOWACCESSCASES = \"allowaccesscases\",\n // Allow to access to all the cases on the server\n PERM_ALLOWACCESSCASESFROMDOMAIN = \"allowaccesscasesfromdomain\",\n // Allow to access all the cases in the same domain on the server\n PERM_ALLOWALLCASEOVERVIEWDOMAIN = \"allowallcaseoverviewdomain\",\n // Allow to see all the cases in same domain on the server\n PERM_ALLOWALLCASESOVERVIEW = \"allowallcasesoverview\",\n // Allow to see all the cases made on the server\n PERM_ALLOWCASEOVERVIEW = \"allowcaseoverview\",\n // Allow to see the cases made by the user on the server\n PERM_ALLOWDOWNLOADCASE = \"allowdownloadcase\",\n // Allow user to download a case from the server\n PERM_ALLOWIPLOGTOUSER = \"allowiplogtouser\",\n // Allow the IP log to be send to the user\n PERM_ALLOWLOGTOUSER = \"allowlogtouser\",\n // Allow the WHOLE log of the server to be send to the user\n\n PERM_ALLOWMISALL = \"allowmisall\",\n // Allow all the MIS data to be shown\n PERM_ALLOWMISDOCUMENTS = \"allowmisdocuments\",\n // Allow the documents of the case to be opened\n PERM_ALLOWMISDOMAIN = \"allowmisdomain\",\n // Allow the MIS data within the same domain to be shown\n PERM_ALLOWMISOWNCASES = \"allowmisowncases\",\n // Allow the MIS data of the own cases to be shown\n\n PERM_ALLOWSAVECASE = \"allowsavecase\",\n // Allow to save a case on the server\n PERM_ALLOWSESSIONLOGTOUSER = \"allowsessionlogtouser\",\n // Allow the log concerning a case to be send to the user\n\n PERM_ALLOWSTARTCASES = \"allowstartcases\",\n // Allow to create a new case on the server\n PERM_PUBLISHMODEL = \"publishmodel\",\n // Allow to publish models to the server\n PERM_SAASCLIENTLOGICWRITABLE = \"saasclientlogicwritable\",\n // Allow users to change texts and logic in SAAS\tNeeds either updatemodels or updateownmodel to have effect\n PERM_SAASCLIENTWRITABLE = \"saasclientwritable\",\n // Allow users to change texts of the model in SAAS\tNeeds either updatemodels or updateownmodel to have effect\n PERM_SAASMANAGEPUBLISHINGSERVERS = \"saasmanagepublishingservers\",\n // Allow management of the publishing servers in server\n PERM_UPDATEDOMAINS = \"updatedomains\",\n // Allow to update or delete all the domains on the server (needs update users and models)\n PERM_UPDATEMODELS = \"updatemodels\",\n // Allow to update or delete all the models on the server\n PERM_UPDATEOWNMODEL = \"updateownmodel\",\n // Allow update or delete the models owned by user\n PERM_UPDATEOWNUSER = \"updateownuser\",\n // Allow to update the own user on the server, need this for webadmin access\n PERM_UPDATEROLES = \"updateroles\",\n // Allow to update or delete all the roles on the server\n PERM_UPDATESETTINGS = \"updatesettings\",\n // Allow to update the settings of the server\n PERM_UPDATEUSERS = \"updateusers\",\n // Allow to update or delete all the users on the server\n PERM_GETDATASOURCELIST = \"getdatasourcelist\",\n // Allow retrieving a sparse list of datasources\n PERM_MANAGEDATASOURCES = \"managedatasources\";\n// Allow retrieving, posting, updating, and deleting datasource specs and file\n\n// 4.12 equivalents\nconst oldperms = {\n guest: [PERM_ALLOWSTARTCASES],\n user: [\n PERM_PUBLISHMODEL,\n PERM_UPDATEOWNMODEL,\n PERM_UPDATEOWNUSER,\n PERM_ALLOWCASEOVERVIEW,\n PERM_ALLOWSTARTCASES,\n PERM_ALLOWSAVECASE,\n PERM_ALLOWMISOWNCASES // ,\n // PERM_SAASCLIENTWRITABLE,\n // PERM_SAASCLIENTLOGICWRITABLE\n ],\n administrator: [\n PERM_PUBLISHMODEL,\n PERM_ACCESSALLMODELS,\n PERM_UPDATEOWNMODEL,\n PERM_UPDATEDOMAINS,\n PERM_UPDATESETTINGS,\n PERM_UPDATEMODELS,\n PERM_UPDATEUSERS,\n // PERM_UPDATEROLES,\n PERM_UPDATEOWNUSER,\n PERM_ALLOWCASEOVERVIEW,\n PERM_ALLOWACCESSCASESFROMDOMAIN,\n PERM_ALLOWACCESSCASES,\n PERM_ALLOWSTARTCASES,\n PERM_ALLOWSAVECASE,\n PERM_ALLOWMISOWNCASES,\n PERM_ALLOWMISDOCUMENTS,\n // PERM_SAASCLIENTWRITABLE,\n // PERM_SAASCLIENTLOGICWRITABLE,\n // PERM_SAASMANAGEPUBLISHINGSERVERS,\n // PERM_SAASCLIENTWRITABLE,\n PERM_ALLOWDOWNLOADCASE // ,\n // PERM_MANAGEDATASOURCES\n ],\n viewer: [PERM_ALLOWMISDOMAIN],\n manager: [\n PERM_UPDATEOWNUSER,\n PERM_ALLOWCASEOVERVIEW,\n PERM_ALLOWACCESSCASESFROMDOMAIN,\n PERM_ALLOWACCESSCASES,\n PERM_ALLOWSAVECASE,\n PERM_ALLOWMISOWNCASES // ,\n // PERM_SAASCLIENTWRITABLE\n ],\n vieweradmin: [PERM_ALLOWMISALL, PERM_ALLOWMISDOMAIN, PERM_ALLOWMISDOCUMENTS],\n any: []\n};\n\nexport const permissions = () =>\n compose(\n either(\n prop(\"permissions\"),\n compose(role => oldperms[role] || oldperms[\"any\"], prop(\"role\"))\n ),\n userinfo\n )(null);\n\nexport const hasPermission = perm =>\n perm instanceof Array\n ? strictDifference(perm, permissions()).length === 0\n : includes(perm, permissions());\n\nexport const webadminMakesSense = permissions =>\n permissions.some(perm => perm.startsWith(\"update\"));\n", "/**\n * https://github.com/flesler/jquery.scrollTo\n * Copyright (c) 2007-2013 Ariel Flesler - afleslergmailcom | http://flesler.blogspot.com\n * Dual licensed under MIT and GPL.\n * @author Ariel Flesler\n * @version 1.4.6\n */\n(function ($) {\n var h = ($.scrollTo = function (a, b, c) {\n $(window).scrollTo(a, b, c);\n });\n h.defaults = {\n axis: \"xy\",\n duration: parseFloat($.fn.jquery) >= 1.3 ? 0 : 1,\n limit: true\n };\n h.window = function (a) {\n return $(window)._scrollable();\n };\n $.fn._scrollable = function () {\n return this.map(function () {\n var a = this,\n isWin =\n !a.nodeName ||\n $.inArray(a.nodeName.toLowerCase(), [\n \"iframe\",\n \"#document\",\n \"html\",\n \"body\"\n ]) != -1;\n if (!isWin) return a;\n var b = (a.contentWindow || a).document || a.ownerDocument || a;\n return /webkit/i.test(navigator.userAgent) || b.compatMode == \"BackCompat\"\n ? b.body\n : b.documentElement;\n });\n };\n $.fn.scrollTo = function (e, f, g) {\n if (typeof f == \"object\") {\n g = f;\n f = 0;\n }\n if (typeof g == \"function\") g = { onAfter: g };\n if (e == \"max\") e = 9e9;\n g = $.extend({}, h.defaults, g);\n f = f || g.duration;\n g.queue = g.queue && g.axis.length > 1;\n if (g.queue) f /= 2;\n g.offset = both(g.offset);\n g.over = both(g.over);\n return this._scrollable()\n .each(function () {\n if (e == null) return;\n var d = this,\n $elem = $(d),\n targ = e,\n toff,\n attr = {},\n win = $elem.is(\"html,body\");\n switch (typeof targ) {\n case \"number\":\n case \"string\":\n if (/^([+-]=?)?\\d+(\\.\\d+)?(px|%)?$/.test(targ)) {\n targ = both(targ);\n break;\n }\n targ = $(targ, this);\n if (!targ.length) return;\n case \"object\":\n if (targ.is || targ.style) toff = (targ = $(targ)).offset();\n }\n $.each(g.axis.split(\"\"), function (i, a) {\n var b = a == \"x\" ? \"Left\" : \"Top\",\n pos = b.toLowerCase(),\n key = \"scroll\" + b,\n old = d[key],\n max = h.max(d, a);\n if (toff) {\n attr[key] = toff[pos] + (win ? 0 : old - $elem.offset()[pos]);\n if (g.margin) {\n attr[key] -= parseInt(targ.css(\"margin\" + b)) || 0;\n attr[key] -= parseInt(targ.css(\"border\" + b + \"Width\")) || 0;\n }\n attr[key] += g.offset[pos] || 0;\n if (g.over[pos])\n attr[key] += targ[a == \"x\" ? \"width\" : \"height\"]() * g.over[pos];\n } else {\n var c = targ[pos];\n attr[key] =\n c.slice && c.slice(-1) == \"%\" ? (parseFloat(c) / 100) * max : c;\n }\n if (g.limit && /^\\d+$/.test(attr[key]))\n attr[key] = attr[key] <= 0 ? 0 : Math.min(attr[key], max);\n if (!i && g.queue) {\n if (old != attr[key]) animate(g.onAfterFirst);\n delete attr[key];\n }\n });\n animate(g.onAfter);\n function animate(a) {\n $elem.animate(\n attr,\n f,\n g.easing,\n a &&\n function () {\n a.call(this, targ, g);\n }\n );\n }\n })\n .end();\n };\n h.max = function (a, b) {\n var c = b == \"x\" ? \"Width\" : \"Height\",\n scroll = \"scroll\" + c;\n if (!$(a).is(\"html,body\")) return a[scroll] - $(a)[c.toLowerCase()]();\n var d = \"client\" + c,\n html = a.ownerDocument.documentElement,\n body = a.ownerDocument.body;\n return Math.max(html[scroll], body[scroll]) - Math.min(html[d], body[d]);\n };\n function both(a) {\n return typeof a == \"object\" ? a : { top: a, left: a };\n }\n})(jQuery);\n", "/* global $, URLSearchParams */\n\nif (\"bb\" in window) {\n throw \"bb was already loaded\";\n}\nimport \"./lib/polyfills/url-search-params.js\";\nimport * as Errors from \"./lib/errors.js\";\nimport { token } from \"./lib/tokens.js\";\nimport { shouldExit } from \"./lib/case-exit.js\";\nimport { A11y } from \"./lib/a11y\";\nimport { Ajax, checkJSON } from \"./lib/ajax.js\";\nimport { BBI } from \"./lib/bbi.js\";\nimport { collectWithin, serializeQuestions } from \"./lib/collect-values.js\";\nimport { conf, propFinder } from \"./lib/conf\";\nimport { wControl, getControl } from \"./lib/control.js\";\nimport { validateInput } from \"./lib/control-validation.js\";\nimport { parseDate, humanDate } from \"./lib/dates\";\nimport { escapeHTML } from \"./lib/escape.js\";\nimport {\n editPolicy,\n mustUpdate,\n canEditEarlier\n} from \"./lib/feature-queries.js\";\nimport { createFormGroup } from \"./lib/form-groups.js\";\nimport \"./lib/form-widgets-definitions.js\";\nimport { setSettled } from \"./lib/settled.js\";\nimport { collectAttributes } from \"./lib/utils\";\nimport {\n any,\n both,\n complement,\n compose,\n either,\n find,\n has,\n ifElse,\n includes,\n map,\n path,\n pathEq,\n prop,\n propEq,\n propOr,\n tap,\n when\n} from \"./lib/functional\";\nimport { doGrouping, groupOuter } from \"./lib/groupings\";\nimport { Jumplist } from \"./lib/jumplist\";\nimport { fromApiServer } from \"./lib/location.js\";\nimport { Mode } from \"./lib/mode.js\";\nimport { Numerals } from \"./lib/numerals.js\";\nimport { notify } from \"./lib/notify.js\";\nimport { permissions, webadminMakesSense } from \"./lib/permissions.js\";\nimport { _ } from \"./lib/gettext.js\";\nimport { positionalFormat } from \"./lib/text-utils\";\nimport { urlutils } from \"./lib/url-utils.js\";\nimport Vars from \"./lib/vars.js\";\nimport \"./lib/$.scrollTo.js\";\n\n$(\"html\").removeClass(\"no-js\");\n\nconst arbitraryCoreProp = propFinder(conf, \"arbitrary.core\");\n/**\n * Copyright (c) 2010 Conrad Irwin MIT license.\n * Based loosely on original: Copyright (c) 2008 mkmanning MIT license.\n *\n * Parses CGI query strings into javascript objects.\n *\n * See the README for details.\n **/\n$.parseQuery = function (options) {\n var config = { query: window.location.search || \"\" },\n params = {};\n\n if (typeof options === \"string\") {\n options = { query: options };\n }\n $.extend(config, $.parseQuery, options);\n config.query = config.query.replace(/^\\?/, \"\");\n\n $.each(config.query.split(config.separator), function (i, param) {\n var pair = param.split(\"=\"),\n key = config.decode(pair.shift(), null).toString(),\n value = config.decode(pair.length ? pair.join(\"=\") : null, key);\n\n if (\n config.array_keys.test\n ? config.array_keys.test(key)\n : config.array_keys(key)\n ) {\n params[key] = params[key] || [];\n params[key].push(value);\n } else {\n params[key] = value;\n }\n });\n delete params[\"\"];\n return params;\n};\n$.parseQuery.decode = $.parseQuery.default_decode = function (string) {\n return decodeURIComponent((string || \"\").replace(/\\+/g, \" \"));\n};\n$.parseQuery.array_keys = function () {\n return false;\n};\n$.parseQuery.separator = \"&\";\n\n// thanks http://web.enavu.com/daily-tip/maxlength-for-textarea-with-jquery/\n$(document).on(\"keyup\", \"textarea[maxlength]\", function () {\n var $this = $(this);\n //get the limit from maxlength attribute\n var limit = parseInt($this.prop(\"maxlength\"));\n //get the current text inside the textarea\n var text = $this.val();\n //count the number of characters in the text\n var chars = text.length;\n\n //check if there are more characters then allowed\n if (chars > limit) {\n //and if there are use substr to get the text before the limit\n var new_text = text.substr(0, limit);\n\n //and change the current text with the new text\n $this.val(new_text);\n $this.addClass(\"bb-programmatically-changed\");\n window.setTimeout(function () {\n $this.removeClass(\"bb-programmatically-changed\");\n }, 1000);\n }\n});\n\nlet bb = { Mode, conf };\n\n/*** TEXT UTILITIES BEGIN ***/\n\n/******* compareVersions ******/\nfunction compareVersions(a, b) {\n var i, l, d;\n\n a = a.toLowerCase().split(/(\\d+)/);\n b = b.toLowerCase().split(/(\\d+)/);\n l = Math.min(a.length, b.length);\n\n for (i = 0; i < l; i++) {\n d = a[i] - b[i];\n if (isNaN(d)) {\n if (a[i] === b[i]) d = 0;\n else if (a[i] < b[i]) {\n d = -1;\n } else d = 1;\n }\n if (d !== 0) return d;\n }\n\n return a.length - b.length;\n}\n\nfunction compareVersionsOn(prop, a, b) {\n return compareVersions(String(a[prop]), String(b[prop]));\n}\n/*** TEXT UTILITIES END ***/\n\n/*** DATEPICKER BEGIN ***/\n\n// Defaults jQuery datepicker BEGIN\n$(function () {\n $.datepicker.setDefaults(\n $.extend(\n true,\n $.datepicker._defaults,\n {\n showAnim: \"\",\n changeYear: true,\n changeMonth: true,\n yearRange: \"c-150:c+150\"\n }, // RFC\n arbitraryCoreProp(\"datepicker.defaults\") || {},\n { altFormat: \"yy-mm-dd\" }\n )\n );\n});\n// Defaults jQuery datepicker END\n\n/*** DATEPICKER END ***/\n\n/*** MISC jQUERY UTILITIES BEGIN ***/\n\n// thanks http://jqueryfordesigners.com/video.php?f=queue.flv\n$.fn.pause = function (n) {\n return this.queue(function () {\n var el = this;\n window.setTimeout(function () {\n return $(el).dequeue();\n }, n);\n });\n};\n\n$.fn.sort = function () {\n return this.pushStack($.makeArray([].sort.apply(this, arguments)));\n};\n\n$.fn.extend({\n insertAtCaret: function (myValue) {\n return this.each(function () {\n if (document.selection) {\n //For browsers like Internet Explorer\n this.focus();\n var sel = document.selection.createRange();\n sel.text = myValue;\n this.focus();\n } else if (this.selectionStart || this.selectionStart == \"0\") {\n //For browsers like Firefox and Webkit based\n var startPos = this.selectionStart;\n var endPos = this.selectionEnd;\n var scrollTop = this.scrollTop;\n this.value =\n this.value.substring(0, startPos) +\n myValue +\n this.value.substring(endPos, this.value.length);\n this.focus();\n this.selectionStart = startPos + myValue.length;\n this.selectionEnd = startPos + myValue.length;\n this.scrollTop = scrollTop;\n } else {\n this.value += myValue;\n this.focus();\n }\n return this;\n });\n },\n selectAllText: function () {\n var el = this.get(0);\n if (el) {\n if (typeof el.selectionStart === \"number\") {\n (el.selectionStart = 0), (el.selectionEnd = el.value.length);\n } else if (typeof el.createTextRange !== \"undefined\") {\n el.focus();\n var range = el.createTextRange();\n range.select();\n }\n }\n return this;\n }\n});\n\n/** Add resizeEnd event.\n *\n * Thanks Carlos Martinez on\n * http://stackoverflow.com/questions/2854407/\n * javascript-jquery-window-resize-how-to-fire-after-the-resize-is-completed\n *\n * I did put this in a closure so as not to pollute the global\n * namespace.\n */\n(function () {\n var _to = null,\n _delay = 500;\n $(window).on(\"resize\", function () {\n if (_to) window.clearTimeout(_to);\n _to = window.setTimeout(function () {\n $(this).trigger(\"resizeEnd\");\n }, _delay);\n });\n})();\n/*** MISC jQUERY UTILITIES END ***/\n\n/*** KEYMAP BEGIN ***/\nvar KEYS = {\n BACKSPACE: 8,\n TAB: 9,\n ENTER: 13,\n SPACE: 32,\n ESC: 27,\n UP: 38,\n DOWN: 40,\n KP_RADIX: 110\n};\n\n// Navigation\nvar maps = {\n questions: function (ev) {\n if (!Mode.get(\"hasModel\")) return undefined;\n if (ev.originalEvent.target && ev.originalEvent.target.tagName === \"TR\") {\n if (!gridKeys(ev)) return false;\n }\n var $target = $(ev.target);\n switch (ev.keyCode) {\n case KEYS.ENTER:\n if ($target.hasClass(\"bb-prior\")) {\n step(\"prior\");\n return false;\n }\n if ($target.hasClass(\"bb-skip\")) {\n step(\"skip\");\n return false;\n }\n if (!Mode.get(\"hasNoNext\")) {\n if (\n ev.shiftKey ||\n $target.hasClass(\"bb-next\") ||\n $target.is('input[type=\"text\"]') ||\n $target.is('input[type=\"radio\"]') ||\n $target.is('input[type=\"checkbox\"]') ||\n $target.is('input[type=\"checkbox\"]') ||\n $target.is('select[data-type=\"listbox\"]') ||\n $target.is(\"fieldset\")\n ) {\n step(\"next\");\n return false;\n }\n if (ev.target.tagName === \"TEXTAREA\") {\n ev.stopImmediatePropagation();\n break;\n }\n }\n if (ev.target.tagName === \"A\") {\n if (ev.target.href.substr(-1) !== \"#\")\n // A true link\n break;\n }\n break;\n case KEYS.SPACE:\n if ($target.is('[role=\"button\"]')) {\n $target.trigger(\"click\");\n return false;\n }\n break;\n case KEYS.BACKSPACE:\n return dispatchBackspace(ev);\n // Escape from modal window\n case KEYS.ESC:\n $(\".closable\").hide();\n break;\n case KEYS.KP_RADIX:\n if ($target.data(\"type\") === \"numedit\") {\n $target.insertAtCaret(_(\"__radixpoint__\", \".\"));\n return false;\n }\n }\n return undefined;\n }\n};\n\nfunction gridKeys(ev) {\n var target = ev.originalEvent.target,\n $target = $(target);\n switch (ev.keyCode) {\n case KEYS.UP:\n $(ev.target).prev().trigger(\"focus\");\n return false;\n case KEYS.DOWN:\n case KEYS.TAB:\n if ($target.find(\":input, a\").length !== 1) {\n return true;\n }\n if (\n $target.find(\n \"a, :input\" + ':not([type=\"checkbox\"])' + ':not([type=\"radio\"])'\n ).length\n ) {\n return true;\n }\n if (ev.shiftKey) $target.prev().trigger(\"focus\");\n else $target.next().trigger(\"focus\");\n return false;\n case KEYS.SPACE:\n var $inputs = $target.find(\n 'input[type=\"checkbox\"], ' + 'input[type=\"radio\"]'\n ),\n $input = $inputs.filter(\":nth(0)\");\n if ($inputs.length > 2) return true;\n else $input.prop(\"checked\", !$input.is(\":checked\"));\n return false;\n }\n return true;\n}\n\nfunction aintTheEnterKey(ev) {\n return ev.type === \"keydown\" && ev.keyCode !== KEYS.ENTER;\n}\n\nfunction dispatchBackspace(ev) {\n if (!ev.shiftKey) return true;\n if (Mode.get(\"hasNoPrior\")) return false;\n step(\"prior\");\n ev.preventDefault();\n ev.stopImmediatePropagation();\n return false;\n}\n\n$(document).on(\"keydown\", maps.questions);\n\n$(document).on(\"keydown\", \".bb-btn\", function (ev) {\n if (ev.keyCode === 13) {\n // Dispatch to click handler on ENTER.\n $(this).trigger(\"click\");\n return false;\n }\n return true;\n});\n/*** KEYMAP END ***/\n\n/*** ROLES BEGIN ***/\n\nfunction setRole() {\n var userinfo = Vars.getVar(\"userinfo\") || {};\n\n Mode.toggle(\"isAdmin\", userinfo.role === \"administrator\");\n Mode.toggle(\"isUser\", userinfo.role === \"user\");\n Mode.toggle(\"isViewer\", userinfo.role === \"viewer\");\n Mode.toggle(\"isVieweradmin\", userinfo.role === \"vieweradmin\");\n Mode.toggle(\"isGuest\", userinfo.role === \"guest\");\n Mode.toggle(\"isAnonymous\", userinfo.fullname === \"anonymous\");\n const perms = permissions();\n perms.forEach(p => {\n Mode.toggle(p, true, false);\n });\n Mode.toggle(\"webadminMakesSense\", webadminMakesSense(perms), false);\n}\n\n/*** ROLES END ***/\n\n/*** INITIALIZATION BEGIN ***/\n\n$(function () {\n $(\"body\").attr(\"data-modus\", \"none\");\n\n document.addEventListener(\"submit\", function (ev) {\n var action = ev.target.getAttribute(\"action\");\n if (!action) {\n ev.preventDefault();\n return false;\n }\n return undefined;\n });\n\n $(document).on(\"submit\", \"form#bb-login\", function () {\n // Serialize form as array\n var params = $(this).serializeArray(),\n action = this.getAttribute(\"action\");\n // Trim values and set the desired format\n $.each(params, function (_, val) {\n if (val.name === \"fmt\") val.value = \"json\";\n else val.value = (val.value || \"\").trim();\n });\n $.postJSON(\n action,\n [$.param(params), window.location.search.substring(1)].join(\"&\")\n );\n return false;\n });\n\n var formfocus = window.setTimeout(function () {\n $(\"form#bb-login input[name=username]\").trigger(\"focus\");\n }, 0);\n\n bb.Router = function router(params) {\n if (\n (typeof params.username !== \"undefined\" &&\n typeof params.password !== \"undefined\") ||\n params.uniqueid ||\n params.modelid ||\n params.modelname ||\n params.dbname ||\n params.state ||\n params.request ||\n params.bsid\n ) {\n Mode.set(\"isDeepLinked\");\n hideLogin();\n if (params.bsid) new BBI().authenticate();\n else if (!bb.autologinrewritten) {\n var action;\n if (\n typeof params.username !== \"undefined\" &&\n typeof params.password !== \"undefined\"\n )\n action = \"login\";\n if (params.uniqueid) action = \"menu\";\n // Studio deeplink\n if (typeof params.uniqueid === \"undefined\" && params.modelid)\n action = \"open\";\n if (params.uniqueid && (params.modelid || params.dbname))\n action = \"action\";\n if (params.modelname) action = \"open\";\n if (params.request) {\n action = params.request;\n delete params.request;\n }\n $.postJSON(action, $.param(params) + \"&fmt=json\").then(setSettled);\n }\n window.clearTimeout(formfocus);\n }\n };\n\n if (window.location.search.length > 1) {\n bb.Router($.parseQuery());\n } else setSettled();\n\n $(document).on(\"bb:renderQuestions\", renderGroups);\n});\n\n/**\n * Set the effect to be used when re-showing login form.\n *\n * @param {String} effect One of 'show', 'fadeIn' or 'slideDown'\n */\nfunction safeResetEffect(effect = \"slideDown\") {\n if (typeof effect !== \"string\") {\n console.warn(\"Argument effect should be a string\");\n return \"slideDown\";\n }\n if (!/^(show|fadeIn|slideDown)$/.test(effect)) {\n console.warn(\"Invalid effect: \" + effect);\n return \"slideDown\";\n }\n return effect;\n}\n\nresetLogin.effect = safeResetEffect(\n arbitraryCoreProp(\"loginResetEffect\", \"slideDown\")\n);\n\nfunction resetLogin() {\n $(\"#bb-login\")[resetLogin.effect]();\n}\n\n/*** INITIALIZATION END ***/\n/*** JUMPLIST BEGIN ***/\n$(document).on(\"change\", \".bb-jumplist-dropdown select\", function () {\n bb.gotonode($(this).val());\n});\n\n$(document).on(\"click\", \"[data-groupid]\", function () {\n var $this = $(this),\n groupid = $this.attr(\"data-groupid\");\n bb.gotonode(groupid);\n});\n\n/*** JUMPLIST END ***/\n\n/*** CASES BEGIN ***/\n$.fn.deleteme = function () {\n if (\n confirm(\n _(\"Delete\") + \" \" + (this.length == 1 ? _(\"case\") : _(\"cases\")) + \"?\"\n )\n ) {\n return this.each(function () {\n var me = $(this);\n if (me.hasClass(\"bb-case\")) {\n var casus = {\n dbname: me.data(\"dbname\"),\n sessionid: me.data(\"sessionid\")\n };\n deleteCase(casus.dbname, casus.sessionid, Vars.getVar(\"uniqueid\"));\n if (isCaseCurrent(casus)) {\n $(\"#bb-q\").empty();\n Mode.unset(\"hasModel\");\n }\n }\n });\n }\n return this;\n};\n\nvar Cases = (function () {\n var _cases = [];\n var _unfilteredcases = [];\n var _MAX = 10;\n var _idx = 0;\n var _filtertext = _(\"filter cases by name\");\n\n function update(cases) {\n _unfilteredcases = cases || [];\n _cases = cases || [];\n if (cases && cases.length > 0) {\n cases.sort(function (a, b) {\n return a.dateenter > b.dateenter ? -1 : 1;\n });\n var $controls = $(\"#bb-cases-controls\");\n if ($controls.is(\":empty\")) {\n $controls.html(\n ' ' +\n ' ' +\n ' 1-10' +\n ' ' +\n ' ' +\n ''\n );\n $controls.attr(\"data-unbound\", true);\n }\n if ($controls.attr(\"data-unbound\")) {\n $controls.removeAttr(\"data-unbound\");\n $(\"#bb-cases-prev\").click(prevSlice);\n $(\"#bb-cases-next\").click(nextSlice);\n $(\"#bb-cases-first\").click(showSlice.bind(null, 0));\n $(\"#bb-cases-last\").click(\n showSlice.bind(null, Math.floor((_cases.length - 1) / _MAX))\n );\n\n $(\"#bb-cases-filter\", $controls).keyup(function (ev) {\n if (ev.keyCode === KEYS.TAB) return true;\n var $this = $(this),\n val = ($this.val() || \"\").trim();\n if (val != \"\") {\n var re = new RegExp(val, \"i\");\n _cases = _unfilteredcases.filter(function (e) {\n return re.test(e.name);\n });\n } else _cases = _unfilteredcases;\n showSlice(0);\n return false;\n });\n }\n showSlice(0);\n } else {\n empty();\n }\n }\n function showSlice(idx) {\n _idx = idx;\n var caselen = _cases.length;\n\n $(\"#bb-cases .bb-case\").remove();\n\n $(_cases.slice(_idx * _MAX, (_idx + 1) * _MAX)).each(function (i) {\n wCasus(_cases[i + _idx * _MAX]).appendTo(\"#bb-cases-table\");\n });\n if (_cases.length) {\n $(\n '' +\n '\" +\n \"\" +\n \"\" +\n (bb.Plugins.newname\n ? '' +\n '' +\n '' +\n \"\" +\n \"\"\n : \"\") +\n \"\"\n ).prependTo(\"#bb-cases-table\");\n\n // Some browsers do leave thead and tbody in place, even when\n // $().empty-ing the table, so:\n $(\"#bb-cases-table thead~thead\").remove();\n }\n\n $(\"#bb-cases-currentslice\")\n .text(\n _idx * _MAX +\n 1 +\n \"-\" +\n Math.min(caselen, (_idx + 1) * _MAX) +\n \"/\" +\n caselen\n )\n .attr(\n \"aria-label\",\n positionalFormat(\n _(\"results {0} to {1} from {2}\"),\n _idx * _MAX + 1,\n Math.min(caselen, (_idx + 1) * _MAX),\n caselen\n )\n );\n\n $(\"#bb-cases-prev, #bb-cases-first\").prop(\"disabled\", _idx == 0);\n var hasNoNext = _idx == Math.floor((caselen - 1) / _MAX);\n $(\"#bb-cases-next, #bb-cases-last\").prop(\"disabled\", hasNoNext);\n\n $(\"#bb-cases\").trigger(\"bb:rendered\");\n }\n function nextSlice() {\n var divident = Math.floor(_cases.length / _MAX);\n showSlice(Math.min(_idx + 1, divident));\n }\n function prevSlice() {\n showSlice(Math.max(_idx - 1, 0));\n }\n function empty() {\n $(\"#bb-cases-table\").empty();\n }\n return {\n empty: empty,\n update: update\n };\n})();\n\nfunction howManyColumns() {\n var base = 2;\n return (\n $.grep([\"showreport\", \"showdeleteinmenu\", \"showcopycase\"], Vars.getVar)\n .length + base\n );\n}\n\nfunction wCasus(casus) {\n var cas = $.extend(\n {},\n casus,\n // Turn into JavaScript dates, and normalize as good as we can:\n {\n dateenter: casus.dateenter && parseDate(casus.dateenter),\n datecreate:\n Vars.getVar(\"showdatecreated\") &&\n casus.datecreate &&\n parseDate(casus.datecreate)\n },\n {\n showcopycase: Vars.getVar(\"showcopycase\"),\n showdeleteinmenu: Vars.getVar(\"showdeleteinmenu\")\n }\n );\n if (Vars.getVar(\"showreport\")) cas.reporturl = urlutils.caseReport(casus);\n // Turn into JavaScript dates, and normalize as good as we can:\n if (cas.datecreate) cas.firstrun = humanDate(cas.datecreate);\n if (cas.dateenter) cas.lastaccess = humanDate(cas.dateenter);\n var html = bb.createCaseItem(cas);\n\n var $case = $(html);\n\n $case.find(\".bb-case-name\").bind(\"click keydown\", function (ev) {\n if (aintTheEnterKey(ev)) return;\n Ajax.replace({\n url: \"action\",\n data: {\n dbname: casus.dbname,\n sessionid: casus.sessionid,\n uniqueid: Vars.getVar(\"uniqueid\"),\n fmt: \"json\"\n }\n });\n });\n $case.find(\".bb-case-copy\").bind(\"click keydown\", function (ev) {\n if (aintTheEnterKey(ev)) return;\n Ajax.replace({\n url: \"action\",\n data: {\n dbname: casus.dbname,\n templateindex: casus.sessionid,\n uniqueid: Vars.getVar(\"uniqueid\"),\n fmt: \"json\"\n }\n });\n });\n $case.data(\"sessionid\", casus.sessionid);\n $case.data(\"dbname\", casus.dbname);\n return $case;\n}\n\nbb.createCaseItem =\n bb.createCaseItem ||\n function (casus) {\n var dateTitle,\n dateSpan = \"\",\n copySpan = \"\",\n reportSpan = \"\",\n deleteSpan = \"\",\n classes = [\"bb-case\"];\n dateTitle = _(\"Last opened\") + \": \" + casus.lastaccess;\n if (Vars.getVar(\"showdatecreated\")) {\n dateTitle += \", \" + _(\"created\") + \": \" + casus.firstrun;\n }\n dateSpan =\n '' +\n casus.lastaccess +\n \"\";\n if (Vars.getVar(\"showreport\")) {\n reportSpan =\n '' +\n '' +\n ' ' +\n _(\"report\") +\n \"\";\n }\n if (Vars.getVar(\"showdeleteinmenu\")) {\n deleteSpan =\n \"\" +\n '\" +\n \"\";\n }\n\n if (Vars.getVar(\"showcopycase\")) {\n copySpan =\n \"\" +\n '\" +\n \"\";\n }\n\n if (isCaseCurrent(casus)) {\n classes.push(\"current\");\n }\n\n return (\n '' +\n \"\" +\n '\" +\n dateSpan +\n reportSpan +\n deleteSpan +\n copySpan +\n \"\"\n );\n };\n\nfunction isCaseCurrent(casus) {\n return (\n casus.sessionid == Vars.getVar(\"sessionid\") &&\n casus.dbname == Vars.getVar(\"dbname\")\n );\n}\n\nfunction deleteCase(dbname, sessionid, uniqueid) {\n // Ajax.last && Ajax.last.abort();\n // todo: voeg nieuwe waarden toe aan object.\n Ajax.post({\n url: \"delete\",\n data: {\n dbname,\n sessionid,\n uniqueid,\n fmt: \"json\"\n }\n });\n}\n\n$(document).on(\"click keydown\", \".bb-case-delete\", function (ev) {\n if (ev.type === \"keydown\" && ev.keyCode !== KEYS.ENTER) return;\n $(this).parents(\".bb-case\").deleteme();\n});\n\nfunction newcase(dbname, newname, params = {}) {\n const data = Object.assign(\n {},\n Object(params) === params && params,\n {\n dbname: dbname,\n uniqueid: Vars.getVar(\"uniqueid\"),\n step: \"open\",\n fmt: \"json\"\n },\n newname && { newname }\n );\n if (Vars.getVar(\"sessionid\"))\n step(\"exit\", function (jsondata) {\n Ajax.busy = false;\n if (jsondata.status === \"Ready\") {\n Ajax.replace({ data: data });\n }\n });\n else {\n Ajax.replace({ data: data });\n }\n}\n\n$(document).on(\"click keydown\", \".bb-newname\", function (ev) {\n if (ev.type === \"click\" || aintTheEnterKey(ev)) ev.stopPropagation();\n return true;\n});\n\n$(document).on(\"click keydown\", \".bb-newcase\", function (ev) {\n if (aintTheEnterKey(ev)) return true;\n const $this = $(this),\n dbname =\n this.getAttribute(\"data-bb:dbname\") ||\n $this.parents(\".bb-model\").attr(\"data-bb:dbname\"),\n newname = $this.find(\".bb-newname\").val(),\n params = collectAttributes(\"data-bb:params-\", this);\n newcase(dbname, newname, params);\n return false;\n});\n\n/*** CASES END ***/\n\n/*** MODELS BEGIN ***/\nvar Models = {\n selector: \"#bb-models\",\n modelitem: function (model) {\n model.uniqueid = Vars.getVar(\"uniqueid\");\n return (\n (bb.createModelItem && bb.createModelItem(model)) ||\n (function (model) {\n var dbname = model.dbname;\n return (\n '' +\n \"\" +\n '\" +\n \"\" +\n '\" +\n \"\"\n );\n })(model)\n );\n },\n // Enhance Model with extra computed properties:\n enhanceModel: function (model) {\n model._selectedclass = model.selected ? \"selected\" : \"\";\n model._nicename = model.modelname.replace(/_/g, \" \");\n if (model.lastupdate) {\n model._date = parseDate(model.lastupdate);\n model._humandate = humanDate(model._date);\n }\n if (model.modelinfo) {\n model._liner_notes = model.modelinfo.split(/(?:\\r?\\n|\\\\r\\\\n|\\\\n)/);\n }\n if (model.authorinfo) {\n model._author_notes = model.authorinfo.split(/(?:\\r?\\n|\\\\r\\\\n|\\\\n)/);\n }\n return model;\n },\n update: function (data) {\n var models = data.models;\n models.sort(compareVersionsOn.bind(null, \"modelname\"));\n\n var explicit = models.filter(function (m) {\n return typeof m[\"order\"] === \"number\";\n });\n if (explicit[0]) {\n explicit.sort(function (a, b) {\n return (\n a[\"order\"] - b[\"order\"] ||\n compareVersions(String(a[\"order\"]), String(b[\"order\"]))\n );\n });\n models = models.filter(function (m) {\n // absent (undefined) or the empty string\n return typeof m[\"order\"] !== \"number\";\n });\n models = explicit.concat(models);\n }\n\n this.empty();\n var self = this;\n $(this.selector).append(\n $.map(models, function (model) {\n return self.modelitem(self.enhanceModel(model));\n })\n );\n },\n empty: function () {\n $(this.selector).empty();\n }\n};\n\n$(document).on(\"click keydown\", \".bb-model-cases\", function (ev) {\n if (aintTheEnterKey(ev)) return;\n var $this = $(this),\n dbname =\n this.getAttribute(\"data-bb:dbname\") ||\n $this.parents(\".bb-model\").attr(\"data-bb:dbname\");\n Ajax.replace({\n url: \"menu\",\n data: {\n dbname: dbname,\n uniqueid: Vars.getVar(\"uniqueid\"),\n fmt: \"json\"\n },\n dataType: \"json\"\n });\n});\n/*** MODELS END ***/\n\n/*** NAVIGATION, REQUESTS BEGIN ***/\n\n/**\n * Request 'action'\n *\n * @param {String} direction One of 'prior', 'next', 'exit', 'runtonode', 'gotonode', 'update' or 'updatemis'\n * @param {Function} cb Callback function to run on succes, defaults to checkJSON()\n * @param {Object} options Object, with possible keys: 'fullnodename' : 'graph.node',\n * 'groupid' : 'groupid-iteration',\n * 'sync' : Boolean\n */\nfunction step(direction, cb, options = {}) {\n Validation.reset();\n if (Ajax.busy) return;\n\n Ajax.last && Ajax.last.abort();\n Ajax.direction = direction;\n Ajax.row = Ajax.direction === \"update\" && options && options.update;\n\n try {\n if (\n [\"next\", \"skip\"].includes(direction) &&\n $(\"#bb-q .group:not([disabled]) .validatable:visible\")\n .validate({ silent: false, justhide: false, requestUpdate: false })\n .filter(\"[aria-invalid=true]\").length > 0\n )\n throw new Error(\"There are errors, please double check your answers.\");\n\n const container = either(prop(\"groupElt\"), () =>\n document.querySelector(\".group.selected\")\n )(options);\n const screenid = Vars.getVar(\"screenid\");\n const groupid = $.data(container).groupid;\n Ajax.groupid = groupid;\n\n // todo: voeg nieuwe waarden toe aan object.\n if (!(direction === \"prior\" && Mode.get(\"hasNoPrior\"))) {\n const ajaxOptions = {\n async: true && (!options || !options.sync), //See noted render() as a reason for this.\n data: [\n \"step=\" + direction,\n direction === \"update\" && options && options.update\n ? \"update=\" + encodeURIComponent(options.update)\n : \"\",\n direction === \"runtonode\"\n ? \"fullnodename=\" + options.fullnodename\n : \"\",\n direction === \"gotonode\" ? \"groupid=\" + options.groupid : \"\",\n Vars.querify(Vars.SESSION_KEYS),\n \"screenid=\" + groupid,\n \"fmt=json\",\n collectWithin({\n container,\n params: new URLSearchParams(options.extraparams)\n })\n .toString()\n .replace(/\\r?\\n/g, \"%0D%0A\")\n ]\n .filter(Boolean)\n .join(\"&\"),\n success: function (data, status, req) {\n data._direction = direction;\n data._passed = options && options.pass;\n data._isUpdate = propEq(\"isUpdate\", true, options);\n // if (direction === \"update\" && groupid !== screenid && editPolicy(conf) === \"stay\") {\n // container.classList.remove(\"unselected\");\n // container.classList.add(\"selected\");\n\n // // Do not render, just update\n // Ajax.release();\n // Vars.setVars(data);\n // updateDynProps(data);\n // } else\n\n if (groupid !== screenid && editPolicy(conf) === \"return\") {\n // Do not render, we're going back again. This would be\n // nice, but we do need some values to be rerendered -\n // warranting redraw of nodes after the edited one.\n\n Ajax.release();\n Vars.setVars(data);\n } else if (options && options.cbIsAdditional) {\n options.cbIsAdditional === \"before\" && cb && cb(data, status, req);\n checkJSON(data, status, req);\n options.cbIsAdditional !== \"before\" && cb && cb(data, status, req);\n } else {\n (cb || checkJSON)(data, status, req);\n }\n if (\n Ajax.row &&\n groupid === screenid &&\n compose(\n when(Boolean, any(propEq(\"dynamic\", true))),\n prop(\"groups\")\n )(data)\n ) {\n console.info(\n \"Requesting an extra update for dynprops. Should be handled by server instead\"\n );\n window.setTimeout(bb.update, 0);\n }\n }\n };\n\n if (\n screenid !== undefined &&\n direction !== \"update\" &&\n groupid !== screenid\n ) {\n console.warn(\n `groupid ${groupid} is not the current screenid ${screenid}, but no update was requested`\n );\n }\n if (direction === \"update\" && groupid !== screenid) {\n // Hold your breath, first go back, so as to put server pointer at the right node.\n bb.gotonode(\n // Will get the .selected\n groupid,\n data => {\n Ajax.release();\n Vars.setVars(data); // Sets screenid\n Ajax.direction = direction;\n // Is always \"update\", actually;\n Ajax.row = direction === \"update\" && options && options.update;\n Ajax.groupid = groupid;\n const req = Ajax.post(ajaxOptions); // Gets the original callback, if any.\n if (editPolicy(conf) === \"return\")\n req.then(data => {\n Ajax.release();\n Vars.setVars(data);\n\n bb.gotonode(\n screenid,\n () => {\n // The gotonode invocation just overwrote the direction and row.\n Ajax.direction = direction;\n Ajax.row =\n direction === \"update\" && options && options.update;\n if (!Ajax.row) cb && cb();\n },\n {\n cbIsAdditional: \"before\",\n groupElt: container,\n isUpdate: true\n }\n );\n });\n },\n { sync: false, cbIsAdditional: false }\n );\n } else {\n Ajax.post(ajaxOptions);\n }\n }\n } catch (e) {\n $(document).trigger(\"bb:userError\", e.message);\n A11y.log(_(e.message));\n }\n}\n\nlet lastUpdateRequest;\n\nfunction requestDynProps(input) {\n if (Ajax.busy) return;\n\n var thisUpdateRequest;\n\n Ajax.last && Ajax.last.abort();\n Ajax.direction = \"update\";\n // Ajax.row = Ajax.direction === 'update' && options && options.update;\n\n const ajaxOptions = {\n async: true,\n data: [\n \"step=update\",\n Vars.querify(Vars.NAV_KEYS),\n \"fmt=json\",\n serializeQuestions()\n ]\n .filter(Boolean)\n .join(\"&\"),\n success: (...args) => {\n if (thisUpdateRequest === lastUpdateRequest) {\n $(document).trigger(\"bb:preHandleData\", ...args);\n updateDynProps(args[0], input);\n }\n }\n };\n lastUpdateRequest = thisUpdateRequest = Ajax.post(ajaxOptions);\n}\n\n// bb:prePost handler always goes off on bb.ajax.post.\n$(document).on(\"bb:prePost\", function (event, options) {\n if (includes(options.url, [\"action\", \"open\", \"bbisreturns\"]))\n if (!includes(Ajax.direction, [\"update\", \"updatemis\"]))\n $(document).trigger(\"bb:preStep\", options);\n});\n\n// bb:preStep handler goes off after user-initiated, possibly\n// expensive, actions.\n$(document).on(\"bb:preStep\", function () {\n Ajax.busy = true;\n // Hide lingering calendars\n $(\".group.selected .hasDatepicker\").datepicker(\"hide\");\n A11y.log(\"\");\n});\n\n// Save\n$(document).on(\"click\", \".bb-save\", function () {\n step(\"save\", null);\n});\n\n// Update\n$(document).on(\"click\", \"[name=update]\", function (ev) {\n step(\"update\", null, {\n update: $(this).val(),\n groupElt: ev.target.closest(\".group\")\n });\n});\n\n// Prior\n$(document).on(\"click\", \".bb-prior\", function () {\n step(\"prior\");\n});\n\n// Next\n$(document).on(\"click\", \".bb-next\", function (ev) {\n bb.next();\n ev.preventDefault();\n ev.stopImmediatePropagation();\n return false;\n});\n\n// Skip\n$(document).on(\"click\", \".bb-skip\", function (ev) {\n bb.skip();\n ev.preventDefault();\n ev.stopImmediatePropagation();\n return false;\n});\n\n$(document).on(\"keydown\", \".group a\", function (ev) {\n if (\n ev.shiftKey &&\n ev.keyCode === KEYS.ENTER &&\n ev.target.href.substr(-1) !== \"#\"\n ) {\n // true link BUT SHIFT + ENTER\n bb.next();\n ev.preventDefault();\n ev.stopImmediatePropagation();\n return false;\n }\n return true;\n});\n\n// Close\n$(document).on(\"click\", \".bb-close\", function () {\n logout();\n self.close();\n $(\"body\").html(_(\"You may now safely close this window\"));\n});\n\n// Restart\n$(document).on(\"click\", \".bb-restart\", function (event) {\n if (\n \"noconfirm\" in event.currentTarget.dataset ||\n confirm(_(\"Are you sure? This will reset all values.\"))\n )\n bb.restart();\n return false;\n});\n\n/**\n * Log out\n *\n * @param {Boolean} ev Either a jQuery event or not\n * @param {Function} cb Callback function to be run after logout.\n * Supercedes default action on Ajax request. @see Ajax.post.\n */\n\nconst timedOutResponse = () => ({\n error: {\n code: 9 //Errors.CODES.cWebSessionTimeOut\n }\n});\n\nfunction logout(ev, cb) {\n if (Vars.getVar(\"uniqueid\")) {\n exit(function () {\n const options = {\n url: \"logout\",\n data: \"fmt=json&\" + Vars.querify(\"uniqueid\"),\n async: false\n };\n // When called directly, which\n if (cb instanceof Function) {\n options.success = options.error = cb;\n }\n Ajax.post(options);\n });\n } else {\n console && console.info && console.info(\"Fake logging out, ID is missing\");\n const mockResponse = timedOutResponse();\n ((cb instanceof Function && cb) || checkJSON)(mockResponse, 200, {\n responseJSON: mockResponse,\n responseText: JSON.stringify(mockResponse)\n });\n }\n return false;\n}\n\n$(document).on(\"click\", \".bb-logout\", logout);\n$(document).on(\"keydown\", \".bb-logout\", function (ev) {\n if (ev.keyCode !== KEYS.ENTER && ev.keyCode !== KEYS.SPACE) return true;\n logout(ev);\n return false;\n});\n\n/** Exit\n *\n * Exit the current case;\n * @param {Function} fun Function to execute after having exited.\n * If exiting isn't necessary, still execute fun.\n */\nfunction exit(fun, sync = true) {\n if (typeof fun !== \"function\")\n // Could be an event object on .bb-stop\n fun = undefined;\n if (shouldExit()) {\n step(\"exit\", fun, { sync });\n } else fun && fun();\n}\n\n$(document).on(\"click\", \".bb-stop\", exit);\n\n// Request 'getuserinfo'\nfunction getUserInfo() {\n $.postJSON(\"getuserinfo\", Vars.querify(\"uniqueid\") + \"&fmt=json\");\n}\n\n/*** NAVIGATION, REQUESTS END ***/\n\n/*** MENU BEGIN ***/\n\nfunction setupMenu() {\n $(\".bb-settings\").attr({ target: \"blank\" });\n}\n\n// Open WebAdmin (in new page)\nfunction openSettings() {\n var href = fromApiServer(\"webadmin\" + \"?\" + Vars.querify(\"uniqueid\"));\n window.open(href);\n return false;\n}\n\n$(document).on(\"click\", \".bb-settings\", openSettings);\n$(document).on(\"keydown\", \".bb-settings\", function (ev) {\n if (ev.keyCode !== KEYS.ENTER && ev.keyCode !== KEYS.SPACE) return true;\n openSettings(ev);\n return false;\n});\n\n/** menu\n *\n * Open menu (model overview)\n * @param {String|Object|undefined} creds Optional credentials,\n * defaults to fmt:json and uniqueid\n */\nfunction menu(creds) {\n return $.postJSON(\n \"menu\",\n creds || {\n fmt: \"json\",\n uniqueid: Vars.getVar(\"uniqueid\")\n }\n );\n}\n\n/** exitthenmenu\n *\n * Exit a case, then open a menu\n * @param {Event} ev Optional event whose propagation will be stopped\n */\nfunction exitthenmenu(ev) {\n exit(function () {\n menu();\n });\n ev && ev.stopPropagation && ev.stopPropagation();\n}\n\n$(document).on(\"click\", \".bb-openmodels\", exitthenmenu);\n$(document).on(\"keydown\", \".bb-openmodels\", function (ev) {\n if (ev.keyCode !== KEYS.ENTER) return;\n exitthenmenu(ev);\n});\n\n/*** MENU END ***/\n\n/*** MISC UI BEGIN ***/\n\nfunction hideLogin() {\n $(\"form#bb-login\").hide();\n}\n\n/**\n * Simple class toggling to implement collapsing/expanding widgets.\n *\n * Needs CSS styling and / or Event handler registered on custom\n * jQuery 'bb:collapsing' Event.\n */\n$(document).on(\"click keydown\", \".bb-collapsable .bb-collapser\", function (ev) {\n if (aintTheEnterKey(ev) || ev.shiftKey) return true;\n $(this)\n .closest(\".bb-collapsable\")\n .toggleClass(\"bb-collapsed\")\n .trigger(\"bb:collapsing\");\n return false;\n});\n\n/*** MISC UI END ***/\n\n/*** DATA HANDLERS BEGIN ***/\n\n/**\n * Default handlers for JSON object.\n *\n * Order in which these handlers are executed are:\n *\n * bb:preHandleData\n * bb:handleData\n * bb:postHandleData\n * bb:finalHandleData\n */\n\n$(document).on(\"bb:preHandleData\", function (event, data) {\n if (data && data.groups) {\n data.groups.forEach(function (group) {\n const groupid = group.groupid;\n group.controls.forEach(function (control) {\n control._originalid = control.id;\n control.id = groupid + \"-\" + control.id;\n if (control.isfor) {\n control._originalisfor = control.isfor;\n control.isfor = groupid + \"-\" + control.isfor;\n }\n if (control.controltype === \"label\") {\n control.value = control.value.trim();\n if (control.isfor && control.value)\n control.value = control.value + \" \";\n }\n if (\n control.controltype === \"memo\" &&\n control.maxlength > 0 &&\n !control.placeholder\n ) {\n control.placeholder = positionalFormat(\n _(\"Maximum allowed characters: {0}\"),\n control.maxlength\n );\n }\n });\n });\n }\n});\n/**\n * Default handler for JSON object.\n *\n * Sets mode, variables, calls functions to update UI.\n *\n */\nfunction onHandleData(event, data) {\n // Save previous modus - it will be the next modus if unset.\n var modus = $(\"body\").attr(\"data-modus\"); // Either 'model', 'menu', or 'none'\n\n Mode.unset(\"hasMessage\");\n if (typeof data == \"undefined\") return;\n if (typeof document.selection != \"undefined\")\n try {\n document.selection.removeAllRanges();\n } catch (e) {\n // tryCatch was there for IE's sake. probably because we were\n // using Selection.empty()\n }\n\n // Fix error objects - they are a mess\n if (data.error) {\n data.error = Errors.translate(data.error);\n // Do not throw the error just yet - we may need it to\n // get in the right mode\n }\n\n Vars.setVars(data);\n\n if (data.userinfo) {\n Mode.set(\"isLoggedIn\");\n setRole();\n setupMenu();\n return;\n }\n\n if (\n data.error &&\n ([\n Errors.CODES.cWebPleaseLogin,\n Errors.CODES.cUMWrongUserNamePassword,\n Errors.CODES.cWebSessionTimeOut\n ].indexOf(data.error.code) > -1 ||\n data.error.code === \"UNAUTHORIZED\")\n ) {\n // Do nothing\n } else if (has(\"bbis\", data)) {\n // Authenticate through BBI\n new BBI(data).authenticate();\n return;\n } else if (Vars.getVar(\"uniqueid\")) {\n // We are apparently logged in\n hideLogin();\n if (!Vars.getVar(\"userinfo\")) {\n // Get user information\n getUserInfo();\n }\n }\n\n // \"DrawScreen: end\"\n /* Only set modus if this is possibly mode-changing data (e.g.\n * DON'T even go here when data.userinfo is true).\n */\n if (data.status || data.groups || data.cases || data.models || data.error) {\n if (data.groups) modus = \"model\";\n else if (\n data.models ||\n data.cases ||\n (data.status && data.status == \"Ready\")\n ) {\n modus = \"menu\";\n } else if (data.status && data.status == \"logout successful\") {\n modus = \"none\";\n } else if (data.error && data.error.code === Errors.CODES.cWebPleaseLogin) {\n modus = \"none\";\n } else if (\n data.error &&\n data.error.code === Errors.CODES.cUMWrongUserNamePassword\n ) {\n modus = \"none\";\n } else if (\n data.error &&\n data.error.code === Errors.CODES.cWebSessionTimeOut\n ) {\n modus = \"none\";\n } else if (data.error && data.error.code === \"READY\") {\n modus = \"menu\";\n }\n $(\"body\").attr(\"data-modus\", modus);\n // Set current modus\n\n // Clean up state vars that were left over\n if (modus === \"menu\") {\n Vars.unsetVars([\"sessionid\", \"screenid\"]); // Session specific data\n }\n if (modus === \"none\") {\n const perms = permissions();\n Vars.unsetVars();\n perms.forEach(p => {\n Mode.toggle(p, false, false);\n });\n }\n\n // Will need to be seen with every control\n Mode.unset(\"hasHints\");\n\n if (!data.error)\n Mode.toggle(\"hasNoModelsShown\", modus !== \"menu\")\n\n .toggle(\"hasModel\", modus === \"model\")\n\n .toggle(\"hasMenu\", modus === \"menu\")\n\n .toggle(\n \"hasModels\",\n modus === \"menu\" && !!data.models && !!data.models.length\n )\n\n .toggle(\n \"hasCases\",\n modus === \"menu\" && !!data.cases && !!data.cases.length\n )\n\n .toggle(\n \"hasJumplist\",\n modus === \"model\" && !!data.jumplist && !!data.jumplist.length\n )\n\n .toggle(\n \"hasInformationsources\",\n modus === \"model\" &&\n data.informationsources &&\n !!data.informationsources.length\n )\n\n .toggle(\"hasNoPrior\", modus === \"model\" && !data.hasprevious)\n\n .toggle(\"hasNoNext\", modus === \"model\" && !data.hasnext);\n\n Mode.toggle(\"isLoggedIn\", modus !== \"none\");\n\n if (modus === \"none\") {\n Mode.unset(\"isDeepLinked\");\n setRole(); // Sets Mode\n }\n if (modus !== \"model\") {\n Mode.unset(\"isValidated\");\n }\n }\n\n if (\n data.error &&\n !includes(data.error.code, propOr([], \"ignoredErrorCodes\", conf))\n ) {\n notify(\n {\n keepalive: path([\"arbitrary\", \"core\", \"notify\", \"keepalive\"], conf),\n html: false\n },\n data.error\n );\n }\n\n // View updates\n if (data.modeldescription) {\n $(\".bb-modelname\")\n .text(data.modeldescription.replace(/_/g, \" \"))\n .attr(\"lang\", data.modellanguage);\n } else if (modus !== \"model\") {\n $(\".bb-modelname\").text(\"\");\n }\n\n if (modus !== \"model\") {\n $(\"#bb-q\").empty();\n }\n\n if (modus !== \"menu\") {\n Cases.empty();\n Models.empty();\n }\n\n if (modus === \"none\") {\n resetLogin();\n }\n\n if (modus === \"none\") {\n Mode.unset(\"hasModel\")\n .unset(\"hasNoModelsShown\")\n .unset(\"hasMenu\")\n .unset(\"hasModels\")\n .unset(\"hasCases\")\n .unset(\"hasJumplist\")\n .unset(\"hasInformationsources\")\n .unset(\"hasNoPrior\")\n .unset(\"hasNoNext\");\n }\n\n if (modus === \"menu\") {\n if (data.models && !!data.models.length) {\n Models.update(data);\n }\n if (data.cases && !!data.cases.length) {\n Cases.update(data.cases);\n }\n }\n\n if (modus === \"model\") {\n if (data.groups) {\n Validation.reset();\n $(document).trigger(\"bb:renderQuestions\", data);\n }\n Validation.setMode(); // Sets Mode\n\n $(\".bb-openattachments\").attr(\"href\", urlutils.getFiles());\n\n // if (data.informationsources){\n // runHook(\"informationsources\")(data.informationsources);\n // }\n if (data.jumplist) {\n Jumplist.type = arbitraryCoreProp(\"jumplist.type\") || \"ul\";\n Jumplist.draw(data.jumplist);\n }\n }\n}\n\n$(document).on(\"bb:handleData\", onHandleData);\n\n/**\n * Default final handler for JSON object.\n *\n * Runs after any DOM updates. Should only be used for focusing or non-UI stuff.\n *\n * Do not override (unless you know exactly what you are doing) --\n * just augment it if need be.\n *\n */\n$(document).on(\"bb:finalHandleData\", function () {\n bb.ajax.release();\n});\n\nlet returnfocusto, returnSelection;\n\nconst $document = $(document);\n\n$document.on(\"focus\", \":input\", ev => {\n const activeElement = ev.target;\n returnfocusto = activeElement.getAttribute(\"id\");\n if (activeElement.value)\n returnSelection = {\n selectionStart: 0,\n selectionEnd: activeElement.value.length,\n selectionDirection: \"forward\"\n };\n});\n\n$document.on(\"keydown\", \":input\", ev => {\n const activeElement = ev.target;\n const { selectionStart, selectionEnd, selectionDirection } = activeElement;\n returnSelection = { selectionStart, selectionEnd, selectionDirection };\n});\n\nfunction returnfocus() {\n try {\n let elt = document.querySelector(`[id=\"${returnfocusto}\"]`);\n if (elt) {\n elt.focus();\n if (elt.classList.contains(\"hasDatepicker\")) {\n $(elt).datepicker(\"widget\").hide();\n }\n let { selectionStart, selectionEnd, selectionDirection } =\n returnSelection;\n elt.setSelectionRange(selectionStart, selectionEnd, selectionDirection);\n }\n } catch (e) {\n // Checkbox throw an error that some object is not or no\n // longer usable. But how may we check?\n\n // Number inputs and such\n e.select && e.select();\n return true;\n }\n return false;\n}\n\nfunction focusHandler(event, data) {\n if (data.groups) {\n window.setTimeout(function () {\n const [grid, row] = (Ajax.row || \"\").split(\".\");\n var $input,\n focusstring = \":input:visible:enabled:not([readonly]):last\";\n if (row) {\n if (row === \"+\") {\n // Addbutton for entire grid\n $input = $(`.group [name=\"update\"][value=\"${grid}.+\"]`);\n } else {\n $input = $(\n '.group [name=\"' +\n grid +\n '\"] tbody tr:nth(' +\n row +\n \") \" +\n focusstring\n );\n // Might've been the last row - then focus the butlast one\n if (!$input.length)\n $input = $(\n '.group [name=\"' +\n grid +\n '\"] tbody tr:nth(' +\n (parseInt(row) - 1) +\n \") \" +\n focusstring\n );\n // Empty table? Focus addbutton\n if (!$input.length)\n $input = $(`.group [name=\"update\"][value=\"${grid}.+\"]`);\n }\n if ($input.length) {\n $input.trigger(\"focus\");\n }\n } else {\n // focus was lost\n if (\n both(\n complement(propEq(\"_isUpdate\", true)),\n complement(propEq(\"_direction\", \"update\"))\n )(data) ||\n (Mode.get(\"a-keyboard-user\") &&\n document.activeElement === document.body &&\n !returnfocus())\n ) {\n $(\".group.selected\").trigger(\"focus\");\n const e_group = document.querySelector(\".group.selected\");\n if (e_group === null) return;\n e_group.focus();\n if (doScrollToSelected(conf)) {\n if (e_group.previousElementSibling) {\n e_group.scrollIntoView({\n behavior: window.matchMedia(\"(prefers-reduced-motion: reduce)\")\n .matches\n ? \"auto\"\n : \"smooth\"\n });\n }\n }\n }\n }\n }, 0);\n return;\n }\n if (data.models && (!data.cases || !data.cases.length)) {\n $(\".bb-model-name:first\").trigger(\"focus\");\n $(\".bb-model.selected .bb-model-name:first\").trigger(\"focus\");\n return;\n }\n if (data.cases) {\n $(\"#bb-cases tbody .bb-case .bb-case-name:first\").trigger(\"focus\");\n return;\n }\n $(\"form#bb-login input[name=username]\").trigger(\"focus\");\n}\n\nfunction setupFocusHandler(event, data) {\n if (data.uniqueid) {\n $(document).on(\"bb:finalHandleData\", focusHandler);\n $(document).off(\"bb:finalHandleData\", setupFocusHandler);\n }\n}\n\n$(document).on(\"bb:finalHandleData\", setupFocusHandler);\n\nfunction updateDynProps(fulldata, input) {\n var data = {\n groups: fulldata.groups\n };\n $(document).trigger(\"bb:willUpdate\", fulldata);\n if (data && data.groups) {\n var group = data.groups.filter(function (group) {\n return group.current;\n })[0];\n let controls = sortControls(group.controls.slice(0), []);\n $(\n '.group [data-datatype^=\"datades:\"], .group [data-type=\"label\"]'\n ).updateControl(controls, input);\n Validation.setMode();\n }\n $(document).trigger(\"bb:hasUpdated\", fulldata);\n}\n\n$(document).on(\"bb:updated\", function (event, $widget, control, updates) {\n if (updates.indexOf(\"visible\") > -1 && control.identifier) {\n var $parent = $widget.parents(\".bb-questionlabelgroup\");\n if (control.visible) {\n $parent.attr(\"data-visible\", control.visible);\n window.setTimeout(function () {\n $parent.removeAttr(\"hidden\").attr(\"data-visible\", control.visible);\n }, 80);\n } else {\n $parent.attr(\"data-visible\", control.visible);\n window.setTimeout(function () {\n $parent.attr(\"hidden\", true);\n }, 80);\n }\n }\n});\n\n/*** DATA HANDLERS END ***/\n\n/*** VALIDATION BEGIN ***/\n\n/**\n * @Class Validation object.\n *\n */\nvar Validation = {\n /**\n * @member @private {Array} Stack of to-be-validated elemenents\n */\n _stack: [],\n /**\n * @member {Function}\n * @return undefined\n */\n reset: function () {\n this._stack = [];\n },\n /**\n * @member {Function}\n * @return {Element} Next Element eligible for validation\n */\n next: function () {\n return this._stack.pop();\n },\n /**\n * @member {Function}\n * @param {Element} el Element we want to be validated in due time\n */\n add: function (el) {\n this._stack.push(el);\n }\n};\n\n/**\n * Are all inputs valid?\n * @return {Boolean} Whether all inputs pass the test\n */\nValidation.allValid = function () {\n return (\n $.grep(\n $(\n '.group:not([disabled]) .validatable, .group:not([disabled]) [data-datatype^=\"datades:\"]'\n )\n .validate({ silent: true })\n .map(function () {\n return $(this).data(\"validated\");\n }),\n function (val) {\n return val === false;\n }\n ).length === 0\n );\n};\n\n/**\n * Update isValidated Mode\n * @return undefined\n */\nValidation.setMode = function () {\n Mode.toggle(\"isValidated\", Validation.allValid());\n};\n\n/**\n * Live Validation instructions\n */\n$(document).on(\"keyup change\", \"body.hasModel\", Validation.setMode);\n\n// Push the input just left onto the validation stack\n$(document).on(\"focusout\", \"#bb-q .group .validatable\", function () {\n var me = $(this);\n Validation.add(me[0]);\n});\n\n$.fn.extend({\n geterrorelt: function () {\n var $this = $(this);\n return $this.data(\"$error\") || $();\n },\n showValidation: function (options, ok, error) {\n var $this = $(this),\n node = $this.get(0);\n\n var errortext;\n if (error instanceof Error) errortext = error.message;\n else errortext = error;\n\n if (!document.body.contains(node)) {\n // console.log('Trying to validate unconnected', this)\n return;\n }\n $this.data(\"validated\", ok);\n\n if (!ok) {\n var $error = $this.geterrorelt(),\n $anchor = $this.is(\"input[type=checkbox]\")\n ? $this.next()\n : $this.data(\"anchor\");\n\n $this.attr(\"aria-invalid\", true);\n\n if ($error.length === 0) {\n if (!options.silent && !options.justhide) {\n $error = $(\n ``\n );\n $this.data(\"$error\", $error);\n }\n }\n // If there was already an error element, and the input is\n // still invalid but (reason and therefore) the errortext\n // has changed, change the error text shown to the user.\n if ($error.length > 0) {\n if ($error.data(\"lasterrortext\") !== errortext) {\n $error.data(\"lasterrortext\", errortext);\n $error.text(errortext);\n }\n }\n if (!options.silent && !options.justhide) {\n $this.addClass(\"error invalid\");\n // (re-)attach $error.\n $anchor.after($error);\n // This may be necessary:\n $(\"#bb-wrapmodel\").scrollTo($error);\n // Allow complicated widgets to fix stuff afterwards\n $this.trigger(\"bb:errorOn\", [errortext, $anchor, $error]);\n }\n } else {\n $this.attr(\"aria-invalid\", false);\n $this.geterrorelt().remove();\n $this.removeClass(\"error invalid\");\n $this.addClass(\"validated\");\n // Allow complicated widgets to fix stuff afterwards\n $this.trigger(\"bb:errorOff\");\n\n if (!options.silent && options.requestUpdate) {\n if (Mode.get(\"hasDynamicInterfaces\")) {\n requestDynProps(node);\n }\n }\n }\n },\n // Validate input\n // OPTIONS: silent, justhide\n validate: function (options) {\n if (!options) {\n options = {};\n }\n if (options.silent === undefined) {\n options.silent = false;\n }\n if (options.justhide === undefined) {\n options.justhide = false;\n }\n // requestUpdate needs to be false whenever validation is done\n // upon node navigation (next, skip), in order to avoid useless\n // server requests. Also, on validating for just showing errors\n // on tabbing away, we want not to request an update - that is\n // already taken care of by the onChange event\n if (options.requestUpdate === undefined) {\n options.requestUpdate = true;\n }\n\n // Argument noui says: do not update the ui (i.e. do not show nor hide any errors).\n return $(this).each(function () {\n var $this = $(this),\n ok = true,\n errortext;\n\n try {\n // Let actual validation be performed by other method.\n ok = validateInput($this);\n } catch (err) {\n ok = false;\n errortext = err;\n }\n\n return $this.showValidation(options, ok, errortext);\n });\n }\n});\n\n// Check when tabbing / clicking to new input - we want to show\n// validation while tabbing through, but not tabbing. onChange we want\n// to hide validation errors, but not show them immediately.\n$(document).on(\"focusin\", \":input\", function () {\n let validatable;\n while ((validatable = Validation.next())) {\n validatable = $(validatable);\n if ($(this).is(\":radio\")) {\n //Only validate when really outside of the radiogroup\n if (!$(this).parent(\".radiogroup\").has(validatable))\n validatable.validate({ requestUpdate: false });\n } else {\n if (validatable.get(0) != $(this).get(0))\n validatable.validate({ requestUpdate: false });\n }\n }\n});\n\n$(document).on(\n \"change\",\n \"#bb-q .group.selected :input:not(button)\",\n function () {\n var $this = $(this),\n options = { silent: false, justhide: true };\n if ($this.is(\":radio\")) {\n // validating radio???\n $this.parents(\".radiogroup\").validate(options);\n } else {\n $this.validate(options);\n }\n }\n);\n\n// Always check checkboxes onchange\n$(document).on(\"change\", \"#bb-q .group :checkbox\", function () {\n $(this).parents(\".checklist\").validate();\n});\n\nfunction debounce(func, wait, immediate) {\n var timeout;\n return function () {\n var context = this,\n args = arguments;\n var later = function () {\n timeout = null;\n if (!immediate) func.apply(context, args);\n };\n var callNow = immediate && !timeout;\n window.clearTimeout(timeout);\n timeout = window.setTimeout(later, wait);\n if (callNow) func.apply(context, args);\n };\n}\n\nconst eltControltype = compose(prop(\"controltype\"), getControl);\n\nconst doChangeOnKeyDown = elt => {\n const setting = path([\"arbitrary\", \"core\", \"update-on-typing\"])(conf);\n return (\n setting === \"always\" ||\n (setting instanceof Array && includes(eltControltype(elt), setting))\n );\n};\n\nfunction keyDown() {\n if (doChangeOnKeyDown(this)) $(this).data(\"valBefore\", $(this).val());\n}\n\n$(document).on(\n \"keydown\",\n \"#bb-q .group.selected :input:not(button)\",\n debounce(keyDown, 32, true)\n);\n\n$(document).on(\n \"keyup\",\n \"#bb-q .group.selected :input:not(button)\",\n function () {\n if (doChangeOnKeyDown(this)) {\n var $this = $(this),\n before = $this.data(\"valBefore\"),\n val = $this.val();\n if (before !== undefined && before !== val) {\n $this.trigger(\"change\");\n $this.removeData(\"valBefore\");\n }\n }\n }\n);\n/*** VALIDATION END ***/\n\n/*** HINTS, TOOLTIPS BEGIN ***/\n// Move to plugin core:tooltips\n/*** HINTS, TOOLTIPS END ***/\n\n/*** RENDERING 'ENGINE' BEGIN ***/\nconst doScrollToSelected = compose(\n val => val !== false,\n path([\"arbitrary\", \"core\", \"scrollToSelectedGroup\"])\n);\nconst setDynamicMode = tap(\n group =>\n group.current && Mode.toggle(\"hasDynamicInterfaces\", Boolean(group.dynamic))\n);\n\n/**\n * Render questions / labels (i.o.w. the main interaction\n * interface) This function is only called when there are actually\n * screens in need of rendering. Therefore, it need not check the JSON\n * object\n *\n * @param ev {Event} The event that triggered this function\n * @param data {Object} 'JSON'-object conforming to BB JSON API.\n */\nfunction renderGroups(ev, data) {\n // Save previous id\n var previd = $(\"#bb-q\" + \" .group.selected\").data(\"groupid\"),\n groups = data.groups,\n $bbq = $(\"#bb-q\");\n\n // Begin -- Only update what is new or was .selected before! There\n // is a problem with $.ajax calls when fast-clicking => therefore\n // step has {async: false}\n //\n // FIXME: when user press next, while\n // there is no next, a node too many is inserted. This can be\n // fixed now the server passes along the node id of a group.\n\n groups.forEach(setGroupTitle);\n if (![\"open\", \"exit\"].includes(Ajax.direction) && mustUpdate(conf)) {\n // Prepare DOM -- remove unneeded or to be re-rendered .groups\n for (let group of document.querySelectorAll(\".group\")) {\n if (complement(any(propEq(\"groupid\", group.dataset[\"gid\"])))(groups)) {\n // Remove a group if not in response\n group.parentNode.removeChild(group);\n } else if (Ajax.row && group.dataset[\"gid\"] === Ajax.groupid) {\n // When adding/deleting rows, safe the space where the group\n // was (entire group will be re-rendered)\n const gob = find(propEq(\"groupid\", group.dataset[\"gid\"]))(groups);\n const tempNode = document.createComment(\"group\");\n group.parentNode.replaceChild(tempNode, group);\n gob._tempNode = tempNode;\n }\n }\n compose(\n map(\n compose(\n ifElse(\n ({ groupid }) =>\n document.querySelector(`.group[data-gid=\"${groupid}\"]`),\n group => {\n updateDynProps({\n groups: [{ current: true, controls: group.controls }]\n });\n const elt = document.querySelector(\n `.group[data-gid=\"${group.groupid}\"]`\n );\n setSelectedStateAttributes(elt, group);\n },\n renderGroup\n ),\n setDynamicMode\n )\n ),\n sortGroups\n )(groups);\n } else {\n // Always remove .selected:\n $(\".group.selected\", $bbq).remove();\n if (Ajax.direction == \"next\" && groups.length > 1) {\n // Re-render only previous group and current group\n groups = groups.filter(function (group) {\n return group.current || group.groupid === previd;\n });\n } else if (\n Ajax.direction == \"prior\" &&\n $(\"#bb-q .group\").length > 0 &&\n groups.length > 1\n ) {\n // Re-render only current group\n groups = groups.filter(function (group) {\n return group.current;\n });\n } else $bbq.empty();\n // End -- Only update what is new!\n\n $bbq.hide();\n compose(map(compose(renderGroup, setDynamicMode)), sortGroups)(groups);\n }\n $bbq.attr(\"lang\", data.modellanguage).show();\n\n // Old questionlabelgroup plugin:\n if (!doGrouping(conf)) {\n (bb.questionlabelgroup || questionlabelgroup)();\n\n $('.bb-questionlabelgroup:has([data-datatype][data-visible=\"false\"])').attr(\n {\n \"data-visible\": false,\n \"hidden\": true\n }\n );\n }\n}\n\nfunction sortGroups(groups) {\n // Fix insertion order\n return groups.sort(function (a, b) {\n return a.order - b.order;\n });\n}\n\nfunction sortControls(a, b) {\n if (!a[0]) return b.reverse();\n var ac = a.shift(),\n bc = b[0];\n if (\n bc &&\n ac.controltype === \"label\" &&\n !ac.datatype && // Label with a datatype is a text interface\n bc._sorted === undefined &&\n bc.controltype !== \"label\" &&\n (bc.controltype !== \"linklabel\" || bc.isreport) &&\n bc.controltype !== \"checkbox\"\n ) {\n // Reverse input with label\n b.shift();\n bc._sorted = true; // Instruct next recursion not to touch the control\n if (has(\"notnull\", bc)) ac.isForNotNull = bc.notnull;\n if (has(\"readonly\", bc)) ac.readonly = bc.readonly;\n ac.dynamic = bc.dynamic = /^datades:/.test(bc.datatype);\n ac.metadata = Object.assign({}, bc.metadata, ac.metadata);\n bc.meta = bc.meta || {}; // Associate input with label\n bc.meta.label = (ac.value || \"\").trim();\n bc.aria = bc.aria || {}; // Associate input with label\n if (bc.notnull) bc.aria.required = true;\n if (ac.notnull) ac.aria.required = true;\n // Associate input (group) with label.\n if (\n [\"radio\", \"checkmultilist\", \"listbox\", \"multilist\"].includes(\n bc.controltype\n )\n ) {\n if (bb.conf.a11y.optionfieldsets) {\n ac.controltype = \"legend\";\n ac.className = \"bb-label\";\n } else {\n bc.aria.labelledby = ac.id;\n }\n } else if (bc.controltype === \"grid\") {\n if (bb.conf.a11y.captions) {\n ac.controltype = \"caption\";\n bc.caption = ac;\n } else {\n bc.aria.labelledby = ac.id;\n }\n } else {\n ac.isFor = bc.id;\n }\n return sortControls(a, [bc, ac].concat(b));\n } else {\n if (\n bc &&\n ac.controltype === \"label\" &&\n !ac.datatype && // Label with a datatype is a text interface\n bc.controltype === \"checkbox\"\n ) {\n ac.isFor = bc.id; // Associate label with checkbox (that comes before)\n if (has(\"notnull\", bc)) ac.isForNotNull = bc.notnull;\n if (has(\"readonly\", bc)) ac.readonly = bc.readonly;\n ac.dynamic = /^datades:/.test(bc.datatype);\n ac.metadata = Object.assign({}, bc.metadata, ac.metadata);\n bc.meta = bc.meta || {}; // Associate input with label\n bc.meta.label = (ac.value || \"\").trim();\n bc.aria = bc.aria || {};\n if (bc.notnull) bc.aria.required = true;\n if (ac.notnull) ac.aria.required = true;\n }\n return sortControls(a, [ac].concat(b));\n }\n}\n\nfunction setGroupTitle(group) {\n var controls = group.controls;\n // It's a title, if:\n // there are two 1st is label Not a 'text' interface 1st doesnt control any\n if (\n controls[1] &&\n controls[0].controltype === \"label\" &&\n !controls[0].datatype &&\n !controls[0].isfor\n ) {\n controls[0].controltype = \"legend\";\n group.screentitle = controls[0].value;\n }\n}\n\nconst setSelectedStateAttributes = (elt, group) => {\n elt.classList.toggle(\"selected\", group.current);\n elt.classList.toggle(\"unselected\", !group.current);\n if (group.current || canEditEarlier(conf)) {\n elt.removeAttribute(\"aria-hidden\");\n elt.removeAttribute(\"disabled\");\n } else {\n elt.setAttribute(\"aria-hidden\", true);\n elt.setAttribute(\"disabled\", \"disabled\");\n }\n};\n\nconst hasStatusRole = pathEq([\"metadata\", \"role\"], \"status\");\n\nfunction renderGroup(group) {\n var controls = group.controls,\n wGroup = $(\n '
      \"\n );\n\n // If this has a dupe, first remove the old one:\n $(\".group\").each(function () {\n if ($(this).data(\"groupid\") === group.groupid) $(this).remove();\n });\n\n const elt = wGroup.get(0);\n elt.dataset[\"gid\"] = group[\"groupid\"];\n wGroup.data(\"groupid\", group[\"groupid\"]);\n\n controls = sortControls(controls.slice(0), []);\n\n if (doGrouping(conf)) controls = groupOuter(controls);\n\n $(controls).each(function (i, c) {\n if (doGrouping(conf)) {\n elt.appendChild(createFormGroup(wControl, group, 1)(c));\n } else wControl(c, group, elt);\n });\n\n elt.classList.add(\"bb-screenmode-\" + group.screenmode);\n elt.setAttribute(\"data-node\", group.name);\n if (!bb.getVar(\"wrongOrder\")) elt.setAttribute(\"data-bb:order\", group.order);\n\n setSelectedStateAttributes(elt, group);\n\n if (group._tempNode) {\n group._tempNode.parentNode.replaceChild(elt, group._tempNode);\n delete group._tempNode;\n } else {\n if (group.screenmode == \"addtop\") $(\"#bb-q\").prepend(elt);\n else $(\"#bb-q\").append(elt);\n }\n}\n\n/**\n * Wrap questions + accompanying labels in a single group\n *\n * This function may be overriden by assigning a function to bb.questionlabelgroup\n * @see Plugin questionlabelgroup-ng\n *\n * @return undefined\n */\nfunction questionlabelgroup() {\n $(\".group:not(:has(.bb-questionlabelgroup))>.bb-label\").each(function () {\n var $this = $(this);\n var input = $this.next(\n \":not(label):not(a):not([type=checkbox]):not(img):not(.clearfix)\"\n );\n var itype = input.data(\"type\");\n var questionandlabel = $this.add(input);\n\n if (questionandlabel.length > 1)\n questionandlabel.wrapAll(\n '
      '\n );\n else {\n questionandlabel = $this.prev(\"[type=checkbox]\").add(this);\n if (questionandlabel.length > 1)\n questionandlabel.wrapAll(\n '
      '\n );\n }\n questionandlabel\n .parent(\".bb-questionlabelgroup\")\n .append('
      ');\n $.each(\n questionandlabel.parent(\".bb-questionlabelgroup\").find(\"[data-type]\"),\n function () {\n var $this = $(this);\n if ($this.attr(\"class\")) {\n var classname = $this.attr(\"class\").match(/\\bbbm-[a-z0-9-]+\\b/);\n if (classname) {\n classname = classname[0].replace(/\\bbbm-/, \"bb-g-\");\n $this.parents(\".bb-questionlabelgroup\").addClass(classname);\n }\n }\n }\n );\n });\n}\n\n/*** RENDERING 'ENGINE' END ***/\n\n/*** 'COMPLEX' WIDGET BEHAVIOUR BEGIN ***/\n\n/**\n * Radiogroup and checklist enhancements\n */\n\n$(document)\n .on(\"change programmatically-changed\", \".bb-option\", function (ev) {\n var $this = $(this);\n $this.toggleClass(\"checked\", ev.target.checked);\n if (ev.target.type === \"radio\" && ev.target.checked) {\n $this.siblings().removeClass(\"checked\");\n }\n })\n .on(\"focus\", \".bb-option\", function (ev) {\n $(this).addClass(\"focus\");\n if (ev.target.type === \"radio\") {\n ev.preventDefault();\n ev.stopImmediatePropagation();\n return false;\n }\n return true;\n })\n .on(\"blur\", \".bb-option\", function () {\n $(this).removeClass(\"focus\");\n })\n .on(\n \"keydown\",\n \".radiogroup .bb-option\",\n // Fix the odd default behaviour of selecting upon focus\n function (ev) {\n var $other,\n chars = [37, 38, 39, 40],\n // left, up, right, down\n idx = chars.indexOf(ev.keyCode);\n if (idx === -1) return true;\n\n $other =\n idx < 2 // 'prev' chars\n ? $(this).prev().find('input[type=\"radio\"]')\n : $(this).next().find('input[type=\"radio\"]');\n\n // At beginning or end... go around (Edge selects otherwise...).\n if (!$other.length) {\n $other =\n idx < 2 // 'prev' chars\n ? $(this).siblings().last().find('input[type=\"radio\"]')\n : $(this).siblings().first().find('input[type=\"radio\"]');\n }\n if ($other.length) {\n $other.trigger(\"focus\");\n ev.preventDefault();\n ev.stopImmediatePropagation();\n return false;\n }\n return true;\n }\n );\n\n/*** 'COMPLEX' WIDGET BEHAVIOUR END ***/\n\n/*** LINKS BEGIN ***/\n\n/**\n * Original code moved to plugin rewrite-links\n *\n */\n\n/*** LINKS END ***/\n\n/*** TOKENCHANNEL BEGIN ***/\n\n$(document).on(\"bb:preHandleData\", (_, data) => {\n if (has(\"uniqueid\", data)) {\n token.setToken(prop(\"uniqueid\", data));\n }\n});\n\n$(document).on(\"bb:preHandleData\", (_, data) => {\n // document.body.dispatchEvent(new customEvent(\"bb:storeToken\", { bubbles: true, })\n if (has(\"uniqueid\", data)) {\n token.setToken(prop(\"uniqueid\", data));\n }\n});\n\n$(document).on(\"bb:mode:isLoggedIn\", (_event, bool) => {\n if (!bool) {\n token\n .getHash()\n .then(tokenHash => token.postMessage({ tokenHash, type: \"loggedOut\" }));\n }\n});\n\ntoken.addEventListener(\"message\", message => {\n token.getHash().then(hash => {\n if (message.data.tokenHash === hash) {\n if (message.data.type === \"loggedOut\") window.close() || logout();\n }\n });\n});\n\n/*** TOKENCHANNEL END ***/\n\n/*** EXPORTS BEGIN ***/\n\nbb.escapeHTML = escapeHTML;\nbb.exit = exit;\nbb.deleteCase = deleteCase;\nbb.logout = logout;\nbb.menu = menu;\n\nbb.authenticate = token => Vars.setVars({ uniqueid: token });\nbb.newcase = newcase;\nbb.step = step;\nbb.restart = function restart() {\n newcase(Vars.getVar(\"dbname\"));\n};\nbb.rewind = function rewind(cb, options) {\n step(\"rewind\", cb, options);\n};\nbb.update = function update(cb, options) {\n step(\"update\", cb, options);\n};\nbb.updatemis = function updatemis(options) {\n step(\"updatemis\", $.noop, options);\n};\nbb.next = function next(cb, options) {\n step(\"next\", cb, options);\n};\nbb.prior = function prior(cb, options) {\n step(\"prior\", cb, options);\n};\nbb.skip = function skip(cb, options) {\n step(\"skip\", cb, options);\n};\nbb.gotonode = function gotonode(groupid, cb, options = null) {\n step(\"gotonode\", cb, Object.assign({}, { groupid }, options));\n};\nbb.runtonode = function runtonode(nodename, cb) {\n step(\"runtonode\", cb, { fullnodename: nodename });\n};\nbb.getVar = Vars.getVar;\nbb.notify = notify.bind(null, {});\nbb.ajax = {\n replace: Ajax.replace,\n busy: function () {\n return Ajax.busy;\n },\n release: Ajax.release,\n post: Ajax.post,\n direction: function () {\n return Ajax.direction;\n }\n};\nbb.URL = urlutils;\nbb.Numerals = Numerals;\nbb.Plugins = bb.Plugins || {};\nbb.Validation = Validation;\nbb.positionalFormat = positionalFormat;\nbb.humanDate = humanDate;\nbb.propFinder = propFinder;\nbb.requestDynProps = requestDynProps;\n// Window-export some stuff used in bookmarklets.\nwindow.bb = {\n restart: bb.restart,\n getVar: bb.getVar,\n requestDynProps: bb.requestDynProps,\n Mode,\n menu\n};\n\n/*** EXPORTS END ***/\n\nexport { bb, _, _ as gt };\n", "/* reset:\n *\n * Stub to include css reset\n *\n * Author: Niels Giesen\n * Copyright 2016 Berkeley Bridge\n *\n */\n(function ($, win, doc) {\n $(function () {});\n})(jQuery, window, document);\n", "/* a11y-describedby:\n *\n * - Describe group with all its standard remarks\n * - Describe input by any non-standard remark labels directly\n * preceding it\n *\n * Author: Niels Giesen\n * Copyright 2016 Berkeley Bridge\n *\n */\nimport { tap, when, compose, prop, path, find } from \"$json/lib/functional\";\n\n$(document).on(\"bb:preHandleData\", function (event, data) {\n if (data && data.groups) {\n $.each(data.groups, function (_, group) {\n var remarks = [],\n pretexts = [];\n $.each(group.controls, function (idx, control) {\n if (control[\"font-class\"].toLowerCase() === \"standard remark\") {\n remarks.push(control.id);\n } else if (control.datatype && control.controltype === \"label\") {\n pretexts.push(control.id);\n }\n const explicitId = path([\"metadata\", \"describedby\"], control);\n if (explicitId) {\n compose(\n when(\n Boolean,\n compose(id => pretexts.push(id), prop(\"id\"))\n ),\n find(c => c.identifier && c.identifier.endsWith(`.${explicitId}`)),\n prop(\"controls\")\n )(group);\n }\n if (control.datatype && control.controltype !== \"label\") {\n maybeSetDescription(control, pretexts);\n pretexts = [];\n }\n });\n maybeSetDescription(group, remarks);\n });\n }\n});\n\nfunction maybeSetDescription(thing, description_ids) {\n if (description_ids.length) {\n thing.aria = thing.aria || {};\n thing.aria.describedby = description_ids.join(\" \");\n }\n}\n", "/* asterisk:\n *\n * Add asterisk to labels for required fields\n *\n * Author: Niels Giesen\n * Copyright 2015 Berkeley Bridge\n *\n */\n(function ($, win, doc) {\n function appendAsterisk(child) {\n if (child.nodeType === 3 /* Node.TEXT_NODE */) {\n var val = child.nodeValue,\n space = \"\",\n words = val.split(\" \"),\n lastword = words.pop();\n // json.js adds a space for visual purposes\n if (lastword === \"\") {\n space = \" \";\n lastword = words.pop();\n }\n child.nodeValue = words.join(\" \");\n child.parentNode.insertAdjacentHTML(\n \"beforeEnd\",\n ' ' +\n lastword +\n ` *` +\n \"\" +\n space\n );\n } else if (child.nodeType === 1 /* Node.ELEMENT_NODE */) {\n if (child.lastChild) appendAsterisk(child.lastChild);\n }\n }\n\n $(doc).on(\"bb:updated\", function (event, $widget, control, updates) {\n if (updates.indexOf(\"isForNotNull\") > -1) {\n if (control.isForNotNull) {\n appendAsterisk($widget.get(0).lastChild);\n } else {\n const $stick = $widget.find(\".bb-p-asterisk-stick\");\n if (!$stick.get(0)) return;\n $stick.find(\"sup\").remove();\n const textnode = $stick.get(0).childNodes[0];\n if (textnode) $(textnode).unwrap();\n }\n }\n });\n})(jQuery, window, document);\n", "/* bb-xarea:\n *\n * Dynamically grow textareas.\n *\n * Depends on: jquery.xarea.js\n *\n * Copyright 2013 Berkeley Bridge\n *\n */\n\n(function ($) {\n var first = true;\n\n function xarea(event, data, status, req) {\n if (\n typeof data != \"undefined\" &&\n data &&\n data.groups &&\n data.groups.length > 0\n )\n $(\".group textarea\")\n .filter(function () {\n return !$(this).data(\"xarea\");\n })\n .data(\"xarea\", true)\n .on(\"bb:errorOn\", function (ev, text, anchor) {\n var parent = $(this).parents(\".xarea\");\n var errordiv = parent.find(\".errortext\");\n parent.next(\".errortext\").remove();\n errordiv.insertAfter(parent);\n })\n .on(\"bb:errorOff\", function (ev) {\n var parent = $(this).parents(\".xarea\");\n parent.next(\".errortext\").remove();\n })\n .xarea()\n .each(function () {\n this.parentNode.className = \"xarea\";\n });\n }\n\n $(document)\n .on(\"change keydown keyup\", \".group textarea\", function () {\n window.setTimeout(function () {\n $(document).trigger(\"bb:resized\");\n }, 150);\n })\n .on(\"focus\", \".xarea\", function (ev) {\n $(this).addClass(\"focus\");\n return true;\n })\n .on(\"blur\", \".xarea\", function (ev) {\n $(this).removeClass(\"focus\");\n });\n\n $(document).on(\"bb:updated\", function (event, $widget, control, updates) {\n if (\n updates.includes(\"visible\") &&\n control.controltype === \"memo\" &&\n control.visible\n ) {\n $widget.trigger(\"bb:reclone\");\n }\n });\n\n $(document).on(\"bb:postHandleData\", function (event, data, status, req) {\n if (first) {\n window.setTimeout(function () {\n xarea(event, data, status, req);\n }, 150);\n first = false;\n } else {\n xarea(event, data, status, req);\n }\n });\n})(jQuery);\n", "import { bb } from \"$json\";\n/* detect-iframe:\n *\n * detect iframe\n *\n * Author: Niels Giesen\n * Copyright 2017 Berkeley Bridge\n *\n */\n(function ($, win, doc) {\n $(function () {\n if (top === self) {\n bb.Mode.set(\"isStandalone\");\n } else {\n bb.Mode.set(\"isIframed\");\n }\n });\n})(jQuery, window, document);\n", "// nb. This is for IE10 and lower _only_.\nvar supportCustomEvent = window.CustomEvent;\nif (!supportCustomEvent || typeof supportCustomEvent === 'object') {\n supportCustomEvent = function CustomEvent(event, x) {\n x = x || {};\n var ev = document.createEvent('CustomEvent');\n ev.initCustomEvent(event, !!x.bubbles, !!x.cancelable, x.detail || null);\n return ev;\n };\n supportCustomEvent.prototype = window.Event.prototype;\n}\n\n/**\n * @param {Element} el to check for stacking context\n * @return {boolean} whether this el or its parents creates a stacking context\n */\nfunction createsStackingContext(el) {\n while (el && el !== document.body) {\n var s = window.getComputedStyle(el);\n var invalid = function(k, ok) {\n return !(s[k] === undefined || s[k] === ok);\n };\n \n if (s.opacity < 1 ||\n invalid('zIndex', 'auto') ||\n invalid('transform', 'none') ||\n invalid('mixBlendMode', 'normal') ||\n invalid('filter', 'none') ||\n invalid('perspective', 'none') ||\n s['isolation'] === 'isolate' ||\n s.position === 'fixed' ||\n s.webkitOverflowScrolling === 'touch') {\n return true;\n }\n el = el.parentElement;\n }\n return false;\n}\n\n/**\n * Finds the nearest from the passed element.\n *\n * @param {Element} el to search from\n * @return {HTMLDialogElement} dialog found\n */\nfunction findNearestDialog(el) {\n while (el) {\n if (el.localName === 'dialog') {\n return /** @type {HTMLDialogElement} */ (el);\n }\n el = el.parentElement;\n }\n return null;\n}\n\n/**\n * Blur the specified element, as long as it's not the HTML body element.\n * This works around an IE9/10 bug - blurring the body causes Windows to\n * blur the whole application.\n *\n * @param {Element} el to blur\n */\nfunction safeBlur(el) {\n if (el && el.blur && el !== document.body) {\n el.blur();\n }\n}\n\n/**\n * @param {!NodeList} nodeList to search\n * @param {Node} node to find\n * @return {boolean} whether node is inside nodeList\n */\nfunction inNodeList(nodeList, node) {\n for (var i = 0; i < nodeList.length; ++i) {\n if (nodeList[i] === node) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * @param {HTMLFormElement} el to check\n * @return {boolean} whether this form has method=\"dialog\"\n */\nfunction isFormMethodDialog(el) {\n if (!el || !el.hasAttribute('method')) {\n return false;\n }\n return el.getAttribute('method').toLowerCase() === 'dialog';\n}\n\n/**\n * @param {!HTMLDialogElement} dialog to upgrade\n * @constructor\n */\nfunction dialogPolyfillInfo(dialog) {\n this.dialog_ = dialog;\n this.replacedStyleTop_ = false;\n this.openAsModal_ = false;\n\n // Set a11y role. Browsers that support dialog implicitly know this already.\n if (!dialog.hasAttribute('role')) {\n dialog.setAttribute('role', 'dialog');\n }\n\n dialog.show = this.show.bind(this);\n dialog.showModal = this.showModal.bind(this);\n dialog.close = this.close.bind(this);\n\n if (!('returnValue' in dialog)) {\n dialog.returnValue = '';\n }\n\n if ('MutationObserver' in window) {\n var mo = new MutationObserver(this.maybeHideModal.bind(this));\n mo.observe(dialog, {attributes: true, attributeFilter: ['open']});\n } else {\n // IE10 and below support. Note that DOMNodeRemoved etc fire _before_ removal. They also\n // seem to fire even if the element was removed as part of a parent removal. Use the removed\n // events to force downgrade (useful if removed/immediately added).\n var removed = false;\n var cb = function() {\n removed ? this.downgradeModal() : this.maybeHideModal();\n removed = false;\n }.bind(this);\n var timeout;\n var delayModel = function(ev) {\n if (ev.target !== dialog) { return; } // not for a child element\n var cand = 'DOMNodeRemoved';\n removed |= (ev.type.substr(0, cand.length) === cand);\n window.clearTimeout(timeout);\n timeout = window.setTimeout(cb, 0);\n };\n ['DOMAttrModified', 'DOMNodeRemoved', 'DOMNodeRemovedFromDocument'].forEach(function(name) {\n dialog.addEventListener(name, delayModel);\n });\n }\n // Note that the DOM is observed inside DialogManager while any dialog\n // is being displayed as a modal, to catch modal removal from the DOM.\n\n Object.defineProperty(dialog, 'open', {\n set: this.setOpen.bind(this),\n get: dialog.hasAttribute.bind(dialog, 'open')\n });\n\n this.backdrop_ = document.createElement('div');\n this.backdrop_.className = 'backdrop';\n this.backdrop_.addEventListener('click', this.backdropClick_.bind(this));\n}\n\ndialogPolyfillInfo.prototype = {\n\n get dialog() {\n return this.dialog_;\n },\n\n /**\n * Maybe remove this dialog from the modal top layer. This is called when\n * a modal dialog may no longer be tenable, e.g., when the dialog is no\n * longer open or is no longer part of the DOM.\n */\n maybeHideModal: function() {\n if (this.dialog_.hasAttribute('open') && document.body.contains(this.dialog_)) { return; }\n this.downgradeModal();\n },\n\n /**\n * Remove this dialog from the modal top layer, leaving it as a non-modal.\n */\n downgradeModal: function() {\n if (!this.openAsModal_) { return; }\n this.openAsModal_ = false;\n this.dialog_.style.zIndex = '';\n\n // This won't match the native exactly because if the user set top on a centered\n // polyfill dialog, that top gets thrown away when the dialog is closed. Not sure it's\n // possible to polyfill this perfectly.\n if (this.replacedStyleTop_) {\n this.dialog_.style.top = '';\n this.replacedStyleTop_ = false;\n }\n\n // Clear the backdrop and remove from the manager.\n this.backdrop_.parentNode && this.backdrop_.parentNode.removeChild(this.backdrop_);\n dialogPolyfill.dm.removeDialog(this);\n },\n\n /**\n * @param {boolean} value whether to open or close this dialog\n */\n setOpen: function(value) {\n if (value) {\n this.dialog_.hasAttribute('open') || this.dialog_.setAttribute('open', '');\n } else {\n this.dialog_.removeAttribute('open');\n this.maybeHideModal(); // nb. redundant with MutationObserver\n }\n },\n\n /**\n * Handles clicks on the fake .backdrop element, redirecting them as if\n * they were on the dialog itself.\n *\n * @param {!Event} e to redirect\n */\n backdropClick_: function(e) {\n if (!this.dialog_.hasAttribute('tabindex')) {\n // Clicking on the backdrop should move the implicit cursor, even if dialog cannot be\n // focused. Create a fake thing to focus on. If the backdrop was _before_ the dialog, this\n // would not be needed - clicks would move the implicit cursor there.\n var fake = document.createElement('div');\n this.dialog_.insertBefore(fake, this.dialog_.firstChild);\n fake.tabIndex = -1;\n fake.focus();\n this.dialog_.removeChild(fake);\n } else {\n this.dialog_.focus();\n }\n\n var redirectedEvent = document.createEvent('MouseEvents');\n redirectedEvent.initMouseEvent(e.type, e.bubbles, e.cancelable, window,\n e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey,\n e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);\n this.dialog_.dispatchEvent(redirectedEvent);\n e.stopPropagation();\n },\n\n /**\n * Focuses on the first focusable element within the dialog. This will always blur the current\n * focus, even if nothing within the dialog is found.\n */\n focus_: function() {\n // Find element with `autofocus` attribute, or fall back to the first form/tabindex control.\n var target = this.dialog_.querySelector('[autofocus]:not([disabled])');\n if (!target && this.dialog_.tabIndex >= 0) {\n target = this.dialog_;\n }\n if (!target) {\n // Note that this is 'any focusable area'. This list is probably not exhaustive, but the\n // alternative involves stepping through and trying to focus everything.\n var opts = ['button', 'input', 'keygen', 'select', 'textarea'];\n var query = opts.map(function(el) {\n return el + ':not([disabled])';\n });\n // TODO(samthor): tabindex values that are not numeric are not focusable.\n query.push('[tabindex]:not([disabled]):not([tabindex=\"\"])'); // tabindex != \"\", not disabled\n target = this.dialog_.querySelector(query.join(', '));\n }\n safeBlur(document.activeElement);\n target && target.focus();\n },\n\n /**\n * Sets the zIndex for the backdrop and dialog.\n *\n * @param {number} dialogZ\n * @param {number} backdropZ\n */\n updateZIndex: function(dialogZ, backdropZ) {\n if (dialogZ < backdropZ) {\n throw new Error('dialogZ should never be < backdropZ');\n }\n this.dialog_.style.zIndex = dialogZ;\n this.backdrop_.style.zIndex = backdropZ;\n },\n\n /**\n * Shows the dialog. If the dialog is already open, this does nothing.\n */\n show: function() {\n if (!this.dialog_.open) {\n this.setOpen(true);\n this.focus_();\n }\n },\n\n /**\n * Show this dialog modally.\n */\n showModal: function() {\n if (this.dialog_.hasAttribute('open')) {\n throw new Error('Failed to execute \\'showModal\\' on dialog: The element is already open, and therefore cannot be opened modally.');\n }\n if (!document.body.contains(this.dialog_)) {\n throw new Error('Failed to execute \\'showModal\\' on dialog: The element is not in a Document.');\n }\n if (!dialogPolyfill.dm.pushDialog(this)) {\n throw new Error('Failed to execute \\'showModal\\' on dialog: There are too many open modal dialogs.');\n }\n\n if (createsStackingContext(this.dialog_.parentElement)) {\n console.warn('A dialog is being shown inside a stacking context. ' +\n 'This may cause it to be unusable. For more information, see this link: ' +\n 'https://github.com/GoogleChrome/dialog-polyfill/#stacking-context');\n }\n\n this.setOpen(true);\n this.openAsModal_ = true;\n\n // Optionally center vertically, relative to the current viewport.\n if (dialogPolyfill.needsCentering(this.dialog_)) {\n dialogPolyfill.reposition(this.dialog_);\n this.replacedStyleTop_ = true;\n } else {\n this.replacedStyleTop_ = false;\n }\n\n // Insert backdrop.\n this.dialog_.parentNode.insertBefore(this.backdrop_, this.dialog_.nextSibling);\n\n // Focus on whatever inside the dialog.\n this.focus_();\n },\n\n /**\n * Closes this HTMLDialogElement. This is optional vs clearing the open\n * attribute, however this fires a 'close' event.\n *\n * @param {string=} opt_returnValue to use as the returnValue\n */\n close: function(opt_returnValue) {\n if (!this.dialog_.hasAttribute('open')) {\n throw new Error('Failed to execute \\'close\\' on dialog: The element does not have an \\'open\\' attribute, and therefore cannot be closed.');\n }\n this.setOpen(false);\n\n // Leave returnValue untouched in case it was set directly on the element\n if (opt_returnValue !== undefined) {\n this.dialog_.returnValue = opt_returnValue;\n }\n\n // Triggering \"close\" event for any attached listeners on the .\n var closeEvent = new supportCustomEvent('close', {\n bubbles: false,\n cancelable: false\n });\n this.dialog_.dispatchEvent(closeEvent);\n }\n\n};\n\nvar dialogPolyfill = {};\n\ndialogPolyfill.reposition = function(element) {\n var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;\n var topValue = scrollTop + (window.innerHeight - element.offsetHeight) / 2;\n element.style.top = Math.max(scrollTop, topValue) + 'px';\n};\n\ndialogPolyfill.isInlinePositionSetByStylesheet = function(element) {\n for (var i = 0; i < document.styleSheets.length; ++i) {\n var styleSheet = document.styleSheets[i];\n var cssRules = null;\n // Some browsers throw on cssRules.\n try {\n cssRules = styleSheet.cssRules;\n } catch (e) {}\n if (!cssRules) { continue; }\n for (var j = 0; j < cssRules.length; ++j) {\n var rule = cssRules[j];\n var selectedNodes = null;\n // Ignore errors on invalid selector texts.\n try {\n selectedNodes = document.querySelectorAll(rule.selectorText);\n } catch(e) {}\n if (!selectedNodes || !inNodeList(selectedNodes, element)) {\n continue;\n }\n var cssTop = rule.style.getPropertyValue('top');\n var cssBottom = rule.style.getPropertyValue('bottom');\n if ((cssTop && cssTop !== 'auto') || (cssBottom && cssBottom !== 'auto')) {\n return true;\n }\n }\n }\n return false;\n};\n\ndialogPolyfill.needsCentering = function(dialog) {\n var computedStyle = window.getComputedStyle(dialog);\n if (computedStyle.position !== 'absolute') {\n return false;\n }\n\n // We must determine whether the top/bottom specified value is non-auto. In\n // WebKit/Blink, checking computedStyle.top == 'auto' is sufficient, but\n // Firefox returns the used value. So we do this crazy thing instead: check\n // the inline style and then go through CSS rules.\n if ((dialog.style.top !== 'auto' && dialog.style.top !== '') ||\n (dialog.style.bottom !== 'auto' && dialog.style.bottom !== '')) {\n return false;\n }\n return !dialogPolyfill.isInlinePositionSetByStylesheet(dialog);\n};\n\n/**\n * @param {!Element} element to force upgrade\n */\ndialogPolyfill.forceRegisterDialog = function(element) {\n if (window.HTMLDialogElement || element.showModal) {\n console.warn('This browser already supports , the polyfill ' +\n 'may not work correctly', element);\n }\n if (element.localName !== 'dialog') {\n throw new Error('Failed to register dialog: The element is not a dialog.');\n }\n new dialogPolyfillInfo(/** @type {!HTMLDialogElement} */ (element));\n};\n\n/**\n * @param {!Element} element to upgrade, if necessary\n */\ndialogPolyfill.registerDialog = function(element) {\n if (!element.showModal) {\n dialogPolyfill.forceRegisterDialog(element);\n }\n};\n\n/**\n * @constructor\n */\ndialogPolyfill.DialogManager = function() {\n /** @type {!Array} */\n this.pendingDialogStack = [];\n\n var checkDOM = this.checkDOM_.bind(this);\n\n // The overlay is used to simulate how a modal dialog blocks the document.\n // The blocking dialog is positioned on top of the overlay, and the rest of\n // the dialogs on the pending dialog stack are positioned below it. In the\n // actual implementation, the modal dialog stacking is controlled by the\n // top layer, where z-index has no effect.\n this.overlay = document.createElement('div');\n this.overlay.className = '_dialog_overlay';\n this.overlay.addEventListener('click', function(e) {\n this.forwardTab_ = undefined;\n e.stopPropagation();\n checkDOM([]); // sanity-check DOM\n }.bind(this));\n\n this.handleKey_ = this.handleKey_.bind(this);\n this.handleFocus_ = this.handleFocus_.bind(this);\n\n this.zIndexLow_ = 100000;\n this.zIndexHigh_ = 100000 + 150;\n\n this.forwardTab_ = undefined;\n\n if ('MutationObserver' in window) {\n this.mo_ = new MutationObserver(function(records) {\n var removed = [];\n records.forEach(function(rec) {\n for (var i = 0, c; c = rec.removedNodes[i]; ++i) {\n if (!(c instanceof Element)) {\n continue;\n } else if (c.localName === 'dialog') {\n removed.push(c);\n }\n removed = removed.concat(c.querySelectorAll('dialog'));\n }\n });\n removed.length && checkDOM(removed);\n });\n }\n};\n\n/**\n * Called on the first modal dialog being shown. Adds the overlay and related\n * handlers.\n */\ndialogPolyfill.DialogManager.prototype.blockDocument = function() {\n document.documentElement.addEventListener('focus', this.handleFocus_, true);\n document.addEventListener('keydown', this.handleKey_);\n this.mo_ && this.mo_.observe(document, {childList: true, subtree: true});\n};\n\n/**\n * Called on the first modal dialog being removed, i.e., when no more modal\n * dialogs are visible.\n */\ndialogPolyfill.DialogManager.prototype.unblockDocument = function() {\n document.documentElement.removeEventListener('focus', this.handleFocus_, true);\n document.removeEventListener('keydown', this.handleKey_);\n this.mo_ && this.mo_.disconnect();\n};\n\n/**\n * Updates the stacking of all known dialogs.\n */\ndialogPolyfill.DialogManager.prototype.updateStacking = function() {\n var zIndex = this.zIndexHigh_;\n\n for (var i = 0, dpi; dpi = this.pendingDialogStack[i]; ++i) {\n dpi.updateZIndex(--zIndex, --zIndex);\n if (i === 0) {\n this.overlay.style.zIndex = --zIndex;\n }\n }\n\n // Make the overlay a sibling of the dialog itself.\n var last = this.pendingDialogStack[0];\n if (last) {\n var p = last.dialog.parentNode || document.body;\n p.appendChild(this.overlay);\n } else if (this.overlay.parentNode) {\n this.overlay.parentNode.removeChild(this.overlay);\n }\n};\n\n/**\n * @param {Element} candidate to check if contained or is the top-most modal dialog\n * @return {boolean} whether candidate is contained in top dialog\n */\ndialogPolyfill.DialogManager.prototype.containedByTopDialog_ = function(candidate) {\n while (candidate = findNearestDialog(candidate)) {\n for (var i = 0, dpi; dpi = this.pendingDialogStack[i]; ++i) {\n if (dpi.dialog === candidate) {\n return i === 0; // only valid if top-most\n }\n }\n candidate = candidate.parentElement;\n }\n return false;\n};\n\ndialogPolyfill.DialogManager.prototype.handleFocus_ = function(event) {\n if (this.containedByTopDialog_(event.target)) { return; }\n\n if (document.activeElement === document.documentElement) { return; }\n\n event.preventDefault();\n event.stopPropagation();\n safeBlur(/** @type {Element} */ (event.target));\n\n if (this.forwardTab_ === undefined) { return; } // move focus only from a tab key\n\n var dpi = this.pendingDialogStack[0];\n var dialog = dpi.dialog;\n var position = dialog.compareDocumentPosition(event.target);\n if (position & Node.DOCUMENT_POSITION_PRECEDING) {\n if (this.forwardTab_) {\n // forward\n dpi.focus_();\n } else if (event.target !== document.documentElement) {\n // backwards if we're not already focused on \n document.documentElement.focus();\n }\n }\n\n return false;\n};\n\ndialogPolyfill.DialogManager.prototype.handleKey_ = function(event) {\n this.forwardTab_ = undefined;\n if (event.keyCode === 27) {\n event.preventDefault();\n event.stopPropagation();\n var cancelEvent = new supportCustomEvent('cancel', {\n bubbles: false,\n cancelable: true\n });\n var dpi = this.pendingDialogStack[0];\n if (dpi && dpi.dialog.dispatchEvent(cancelEvent)) {\n dpi.dialog.close();\n }\n } else if (event.keyCode === 9) {\n this.forwardTab_ = !event.shiftKey;\n }\n};\n\n/**\n * Finds and downgrades any known modal dialogs that are no longer displayed. Dialogs that are\n * removed and immediately readded don't stay modal, they become normal.\n *\n * @param {!Array} removed that have definitely been removed\n */\ndialogPolyfill.DialogManager.prototype.checkDOM_ = function(removed) {\n // This operates on a clone because it may cause it to change. Each change also calls\n // updateStacking, which only actually needs to happen once. But who removes many modal dialogs\n // at a time?!\n var clone = this.pendingDialogStack.slice();\n clone.forEach(function(dpi) {\n if (removed.indexOf(dpi.dialog) !== -1) {\n dpi.downgradeModal();\n } else {\n dpi.maybeHideModal();\n }\n });\n};\n\n/**\n * @param {!dialogPolyfillInfo} dpi\n * @return {boolean} whether the dialog was allowed\n */\ndialogPolyfill.DialogManager.prototype.pushDialog = function(dpi) {\n var allowed = (this.zIndexHigh_ - this.zIndexLow_) / 2 - 1;\n if (this.pendingDialogStack.length >= allowed) {\n return false;\n }\n if (this.pendingDialogStack.unshift(dpi) === 1) {\n this.blockDocument();\n }\n this.updateStacking();\n return true;\n};\n\n/**\n * @param {!dialogPolyfillInfo} dpi\n */\ndialogPolyfill.DialogManager.prototype.removeDialog = function(dpi) {\n var index = this.pendingDialogStack.indexOf(dpi);\n if (index === -1) { return; }\n\n this.pendingDialogStack.splice(index, 1);\n if (this.pendingDialogStack.length === 0) {\n this.unblockDocument();\n }\n this.updateStacking();\n};\n\ndialogPolyfill.dm = new dialogPolyfill.DialogManager();\ndialogPolyfill.formSubmitter = null;\ndialogPolyfill.useValue = null;\n\n/**\n * Installs global handlers, such as click listers and native method overrides. These are needed\n * even if a no dialog is registered, as they deal with
      .\n */\nif (window.HTMLDialogElement === undefined) {\n\n /**\n * If HTMLFormElement translates method=\"DIALOG\" into 'get', then replace the descriptor with\n * one that returns the correct value.\n */\n var testForm = document.createElement('form');\n testForm.setAttribute('method', 'dialog');\n if (testForm.method !== 'dialog') {\n var methodDescriptor = Object.getOwnPropertyDescriptor(HTMLFormElement.prototype, 'method');\n if (methodDescriptor) {\n // nb. Some older iOS and older PhantomJS fail to return the descriptor. Don't do anything\n // and don't bother to update the element.\n var realGet = methodDescriptor.get;\n methodDescriptor.get = function() {\n if (isFormMethodDialog(this)) {\n return 'dialog';\n }\n return realGet.call(this);\n };\n var realSet = methodDescriptor.set;\n methodDescriptor.set = function(v) {\n if (typeof v === 'string' && v.toLowerCase() === 'dialog') {\n return this.setAttribute('method', v);\n }\n return realSet.call(this, v);\n };\n Object.defineProperty(HTMLFormElement.prototype, 'method', methodDescriptor);\n }\n }\n\n /**\n * Global 'click' handler, to capture the or