\" + times(`${Jumplist.type}>`, 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 );\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}${Jumplist.type}>`\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","/* global $ */\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 return html;\n }\n\n $(doc).on(\"bb:finalHandleData\", (_e, data) => {\n if (data && data.groups && data.groups.length) {\n const props = getmetadata(data).props;\n if (props.has(\"p-actielijst-show\")) {\n bb.Mode.set(\"hasActielijst\");\n // Break into the auto-scroll if needed:\n if (doc.querySelector(\".bbm-deel-2\")) {\n scrollconfig.props = { selector: \".bbm-deel-2\" };\n } else {\n scrollconfig.props = \"default\";\n }\n // Store the chapterID for the jump back button\n let saved = state.has(\"p-chapters-helper\")\n ? state.get(\"p-chapters-helper\")\n : {};\n saved.actielijstID = getCurrentChapterID(data.groups);\n state.set(\"p-chapters-helper\", saved);\n\n // Grab some values for continue later link in agenda:\n const location = bb.propFinder(bb.conf)(\n \"arbitrary.savecase-email-link-popup.location\",\n window.location.href\n );\n const sessionid = data.sessionid;\n continueLink = encodeURIComponent(\n `${location}?modelid=${data.dbname}&sessionid=${sessionid}`\n );\n try {\n // Move some things arround in the DOM to support the design.\n let fieldset = doc.querySelector(\"#bb-q fieldset\");\n let legend = fieldset.querySelector(\"legend\");\n let text = fieldset.querySelector(\".bb-text\");\n let toggler = fieldset.querySelector(\n '[data-metadata-keys=\"expanderToggle\"]'\n );\n let togglerText = fieldset.querySelector(\n '[data-metadata-keys=\"expanderText\"]'\n );\n let download = fieldset.querySelector('a[type=\"application/pdf\"]');\n let newContainer = doc.createElement(\"div\");\n newContainer.className = \"p-actielijst-head\";\n newContainer.innerHTML = `\n
\n `;\n fieldset.removeChild(legend);\n fieldset.removeChild(text);\n fieldset.removeChild(toggler);\n fieldset.removeChild(togglerText);\n fieldset.removeChild(download);\n fieldset.prepend(newContainer);\n let clonebtns = doc.querySelector(\".btns\").cloneNode(true);\n clonebtns.classList.add(\"final\");\n clonebtns.querySelector('a[type=\"application/pdf\"]').id = \"\";\n fieldset.append(clonebtns);\n doc.querySelectorAll(\"select.href-selector\").forEach(select => {\n select.addEventListener(\"change\", createHref);\n });\n doc\n .querySelectorAll(\".btns:not(.final) .p-actielijst--agenda-header\")\n .forEach(agenda => {\n agenda.addEventListener(\"click\", _e => {\n bb.Mode.toggle(\"showAgendaAdd\");\n });\n });\n } catch (err) {\n win.console && win.console.warn(err);\n }\n try {\n // let originalGrid = doc.querySelector(\"table.bbm-actielijst\");\n // originalGrid.querySelectorAll(\"tr\").forEach(row => {\n // row.replaceWith(newRow(row));\n // });\n let originalGrid = doc.querySelectorAll(\"table.bbm-actielijst\");\n originalGrid.forEach(grid => {\n grid.querySelectorAll(\"tr\").forEach(row => {\n row.replaceWith(newRow(row));\n });\n });\n } catch (err) {\n win.console && win.console.warn(err);\n }\n // Add some mis recording for clicks on add to agenda...\n let recorder = doc.querySelector(\n 'input[data-metadata-keys^=\"p-mis-click-count-agenda-field\"]'\n );\n\n if (recorder) {\n recorder.closest(\".bb-questionlabelgroup\").style.display = \"none\";\n doc\n .querySelectorAll(\".p-actielijst--agenda-content a.agenda\")\n .forEach(btn => {\n btn.addEventListener(\"click\", _e => {\n try {\n recorder.value = \"true\";\n bb.updatemis();\n } catch (err) {\n window.console && window.console.warn(err);\n }\n });\n });\n }\n\n // In case this is \"deel 2\", scroll the user to the start of that chapter.\n // if (\n // doc.querySelector(\"body\").dataset[\"node\"] ===\n // \"gresultaat.resultaat\"\n // ) {\n // console.log(\"yes\");\n // let title = doc.querySelector('.bbm-foo');\n // // title.scrollIntoView({ behavior: \"smooth\", block: \"start\" })\n // }\n } else {\n bb.Mode.unset(\"hasActielijst\");\n }\n }\n });\n})(window, document, jQuery);\n","/*\n A small plugin to annoy people into returning\n to a tab which lost focus.\n\n Author: Tim Bauwens 2023\n*/\n\nimport { bb } from \"$json\";\n\n(doc => {\n const change = e => {\n let title = e.type === \"blur\" ? newTitle : originalTitle;\n doc.querySelector(\"head title\").innerText = title;\n };\n const props = bb.propFinder(bb.conf.template, \"change-title-on-tab-blur\");\n const newTitle = props(\"new-title\", \"Come back!\");\n\n const originalTitle = props(\n \"original-title\",\n doc.querySelector(\"head title\").innerText\n );\n\n try {\n window.addEventListener(\"blur\", change);\n window.addEventListener(\"focus\", change);\n } catch (err) {\n window.console && window.console.error(err);\n }\n})(document);\n","/*\n chapter-helper.js\n\n A local helper to set display props\n for chapter items.\n\n Author: Tim Bauwens\n Copyright: xxllnc 2022\n*/\n\nimport { getCurrentChapterID } from \"$json/lib/getcurrentchapterid\";\nimport { getmetadata } from \"$json/lib/getmetadata\";\nimport { state } from \"$json/lib/store\";\nimport { has } from \"$json/lib/functional\";\nimport { CONFIG as scrollconfig } from \"../../../../plugins/auto-scroll/auto-scroll\";\n\n((_win, doc, $) => {\n var lastKnownScrollPos = 0;\n\n const applystate = () => {\n if (state.has(\"p-chapters-helper\")) {\n let saved = state.get(\"p-chapters-helper\");\n let toshow = saved.toshow || [];\n bb.Mode.toggle(\"hasSpecialChapters\", Boolean(toshow.length));\n let currentChapter = saved.currentChapter || \"\";\n let jl = doc.querySelector(\".bb-jumplist ul\");\n if (jl !== null) {\n jl.querySelectorAll(\"li\").forEach(chapter => {\n let title = chapter\n .querySelector(\"button > span\")\n .innerText.replace(/\\s/g, \"\");\n\n let bgpath = has(\"finalScore\")(\n chapter.querySelector(\"button[data-groupid]\").dataset\n )\n ? `url('../../rijks-cyberscan/plugins/chapters-helper/live/chapter_icons/${title}Actief.svg?v=20230117')`\n : `url('../../rijks-cyberscan/plugins/chapters-helper/live/chapter_icons/${title}Normaal.svg?v=20230117')`;\n\n let ariaLabel = has(\"finalScore\")(\n chapter.querySelector(\"button[data-groupid]\").dataset\n )\n ? chapter.querySelector(\"button[data-groupid]\").dataset\n .finalScore == 1\n ? \"Voltooid\"\n : `Huidige stap`\n : `Nog niet voltooid`;\n\n let selected =\n chapter\n .querySelector(\"button[data-groupid]\")\n .getAttribute(\"data-groupid\") === currentChapter\n ? true\n : false;\n\n chapter.classList.toggle(\"show\", toshow.includes(title));\n chapter.setAttribute(\"aria-hidden\", !toshow.includes(title));\n chapter.setAttribute(\"aria-label\", ariaLabel);\n chapter.classList.toggle(\"selected\", selected);\n chapter.style.setProperty(\"--bg\", bgpath);\n });\n }\n let actielijstID = saved.actielijstID || false;\n let btn = doc.querySelector(\"nav button.actielijst\");\n if (actielijstID) {\n btn.setAttribute(\"value\", actielijstID);\n btn.dataset.groupid = actielijstID;\n } else {\n btn.setAttribute(\"value\", \"\");\n btn.dataset.groupid = \"\";\n }\n }\n };\n\n $(doc).on(\"bb:stateChange\", () => {\n applystate();\n });\n\n $(doc).on(\"bb:preHandleData\", (_e, data) => {\n if (data && data.groups && data.groups.length) {\n lastKnownScrollPos = doc.querySelector(\".column--chapters\").scrollTop;\n }\n });\n\n $(doc).on(\"bb:postHandleData\", (_e, data) => {\n if (data && data.groups && data.groups.length) {\n let saved = state.has(\"p-chapters-helper\")\n ? state.get(\"p-chapters-helper\")\n : {};\n saved.currentChapter = getCurrentChapterID(data.groups);\n if (!has(\"chaptermap\")(saved)) saved.chaptermap = {};\n const props = getmetadata(data).props;\n if (props.has(\"p-chapters-helper-show\")) {\n let toshow = props.get(\"p-chapters-helper-show\").split(\"|\");\n saved.toshow = toshow.map(title => title.replace(/\\s/g, \"\"));\n saved.toshow = saved.toshow.filter(title => title !== \"false\");\n }\n if (props.has(\"p-chapters-helper-chapterid\")) {\n saved.chaptermap[props.get(\"p-chapters-helper-chapterid\")] =\n saved.currentChapter;\n }\n\n state.set(\"p-chapters-helper\", saved);\n\n // A small helper for the auto-scroll in case of small window size:\n if (window.innerWidth <= 943) {\n scrollconfig.props = { selector: \".l-content--left\" };\n } else {\n scrollconfig.props = \"default\";\n }\n }\n });\n\n $(doc).on(\"bb:finalHandleData\", (_e, data) => {\n if (data && data.groups && data.groups.length) {\n applystate();\n // Finally, scroll the jumplist to the right place.\n //let currentChapter = doc.querySelector(\".bb-jumplist li.selected\");\n let scrollSection = doc.querySelector(\".column--chapters\");\n scrollSection.scrollTo(0, lastKnownScrollPos);\n\n /*\n The desired scroll Y pos is the half the\n height of the column minus the selected\n icons total height offset (plus half \n it's own height).\n */\n let height = scrollSection.offsetHeight;\n let middle = height / 2;\n let posInList = Array.from(doc.querySelectorAll(\".bb-jumplist li.show\"))\n .map(item => item.className.includes(\"selected\"))\n .indexOf(true);\n let avgIconHeight = 110; // Guestimate magic number.\n let currentChapterIconOffset =\n avgIconHeight * posInList + avgIconHeight / 2;\n let desiredY = -1 * (middle - currentChapterIconOffset);\n\n window.setTimeout(e => {\n // Scroll to the desiredY\n scrollSection.scrollTo({\n top: desiredY,\n left: 0,\n behavior: \"smooth\"\n });\n }, 100);\n }\n });\n})(window, document, jQuery);\n","// custom-radios.js\n\n/*\n * A simple plugin to replace\n * radios with a custom design.\n * Cross-browser and working with all\n * forms of output: grids and radios\n *\n * Note you'll have to provide your own styling to the faux .p-custom-radios-label\n *\n * Author: Niels Giesen\n * Copyright Berkeley Bridge 2019\n *\n */\n\n((doc, $) => {\n $(doc).on(\"bb:postHandleData\", (e, data) => {\n // If there are any checkboxes, deal with them\n let checkboxes = $(\"#bb-q\").find(\n 'input[type=\"radio\"]:not(.p-custom-radios)'\n );\n checkboxes.each((i, checkbox) => {\n checkbox.className += \" a-offscreen p-custom-radios\";\n checkbox.insertAdjacentHTML(\n \"afterEnd\",\n `\n \n `\n );\n });\n });\n})(document, jQuery);\n","(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"printJS\"] = factory();\n\telse\n\t\troot[\"printJS\"] = factory();\n})(window, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 0);\n/******/ })\n/************************************************************************/\n/******/ ({\n\n/***/ \"./src/index.js\":\n/*!**********************!*\\\n !*** ./src/index.js ***!\n \\**********************/\n/*! exports provided: default */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _sass_index_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./sass/index.scss */ \"./src/sass/index.scss\");\n/* harmony import */ var _sass_index_scss__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_sass_index_scss__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _js_init__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./js/init */ \"./src/js/init.js\");\n\n\nvar printJS = _js_init__WEBPACK_IMPORTED_MODULE_1__[\"default\"].init;\n\nif (typeof window !== 'undefined') {\n window.printJS = printJS;\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (printJS);\n\n/***/ }),\n\n/***/ \"./src/js/browser.js\":\n/*!***************************!*\\\n !*** ./src/js/browser.js ***!\n \\***************************/\n/*! exports provided: default */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\nvar Browser = {\n // Firefox 1.0+\n isFirefox: function isFirefox() {\n return typeof InstallTrigger !== 'undefined';\n },\n // Internet Explorer 6-11\n isIE: function isIE() {\n return navigator.userAgent.indexOf('MSIE') !== -1 || !!document.documentMode;\n },\n // Edge 20+\n isEdge: function isEdge() {\n return !Browser.isIE() && !!window.StyleMedia;\n },\n // Chrome 1+\n isChrome: function isChrome() {\n var context = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window;\n return !!context.chrome;\n },\n // At least Safari 3+: \"[object HTMLElementConstructor]\"\n isSafari: function isSafari() {\n return Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0 || navigator.userAgent.toLowerCase().indexOf('safari') !== -1;\n },\n // IOS Chrome\n isIOSChrome: function isIOSChrome() {\n return navigator.userAgent.toLowerCase().indexOf('crios') !== -1;\n }\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (Browser);\n\n/***/ }),\n\n/***/ \"./src/js/functions.js\":\n/*!*****************************!*\\\n !*** ./src/js/functions.js ***!\n \\*****************************/\n/*! exports provided: addWrapper, capitalizePrint, collectStyles, addHeader, cleanUp, isRawHTML */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"addWrapper\", function() { return addWrapper; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"capitalizePrint\", function() { return capitalizePrint; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"collectStyles\", function() { return collectStyles; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"addHeader\", function() { return addHeader; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"cleanUp\", function() { return cleanUp; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"isRawHTML\", function() { return isRawHTML; });\n/* harmony import */ var _modal__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./modal */ \"./src/js/modal.js\");\n/* harmony import */ var _browser__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./browser */ \"./src/js/browser.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\nfunction addWrapper(htmlData, params) {\n var bodyStyle = 'font-family:' + params.font + ' !important; font-size: ' + params.font_size + ' !important; width:100%;';\n return '
' + htmlData + '
';\n}\nfunction capitalizePrint(obj) {\n return obj.charAt(0).toUpperCase() + obj.slice(1);\n}\nfunction collectStyles(element, params) {\n var win = document.defaultView || window; // String variable to hold styling for each element\n\n var elementStyle = ''; // Loop over computed styles\n\n var styles = win.getComputedStyle(element, '');\n\n for (var key = 0; key < styles.length; key++) {\n // Check if style should be processed\n if (params.targetStyles.indexOf('*') !== -1 || params.targetStyle.indexOf(styles[key]) !== -1 || targetStylesMatch(params.targetStyles, styles[key])) {\n if (styles.getPropertyValue(styles[key])) elementStyle += styles[key] + ':' + styles.getPropertyValue(styles[key]) + ';';\n }\n } // Print friendly defaults (deprecated)\n\n\n elementStyle += 'max-width: ' + params.maxWidth + 'px !important; font-size: ' + params.font_size + ' !important;';\n return elementStyle;\n}\n\nfunction targetStylesMatch(styles, value) {\n for (var i = 0; i < styles.length; i++) {\n if (_typeof(value) === 'object' && value.indexOf(styles[i]) !== -1) return true;\n }\n\n return false;\n}\n\nfunction addHeader(printElement, params) {\n // Create the header container div\n var headerContainer = document.createElement('div'); // Check if the header is text or raw html\n\n if (isRawHTML(params.header)) {\n headerContainer.innerHTML = params.header;\n } else {\n // Create header element\n var headerElement = document.createElement('h1'); // Create header text node\n\n var headerNode = document.createTextNode(params.header); // Build and style\n\n headerElement.appendChild(headerNode);\n headerElement.setAttribute('style', params.headerStyle);\n headerContainer.appendChild(headerElement);\n }\n\n printElement.insertBefore(headerContainer, printElement.childNodes[0]);\n}\nfunction cleanUp(params) {\n // If we are showing a feedback message to user, remove it\n if (params.showModal) _modal__WEBPACK_IMPORTED_MODULE_0__[\"default\"].close(); // Check for a finished loading hook function\n\n if (params.onLoadingEnd) params.onLoadingEnd(); // If preloading pdf files, clean blob url\n\n if (params.showModal || params.onLoadingStart) window.URL.revokeObjectURL(params.printable); // Run onPrintDialogClose callback\n\n var event = 'mouseover';\n\n if (_browser__WEBPACK_IMPORTED_MODULE_1__[\"default\"].isChrome() || _browser__WEBPACK_IMPORTED_MODULE_1__[\"default\"].isFirefox()) {\n // Ps.: Firefox will require an extra click in the document to fire the focus event.\n event = 'focus';\n }\n\n var handler = function handler() {\n // Make sure the event only happens once.\n window.removeEventListener(event, handler);\n params.onPrintDialogClose(); // Remove iframe from the DOM\n\n var iframe = document.getElementById(params.frameId);\n\n if (iframe) {\n iframe.remove();\n }\n };\n\n window.addEventListener(event, handler);\n}\nfunction isRawHTML(raw) {\n var regexHtml = new RegExp('<([A-Za-z][A-Za-z0-9]*)\\\\b[^>]*>(.*?)\\\\1>');\n return regexHtml.test(raw);\n}\n\n/***/ }),\n\n/***/ \"./src/js/html.js\":\n/*!************************!*\\\n !*** ./src/js/html.js ***!\n \\************************/\n/*! exports provided: default */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _functions__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./functions */ \"./src/js/functions.js\");\n/* harmony import */ var _print__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./print */ \"./src/js/print.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n print: function print(params, printFrame) {\n // Get the DOM printable element\n var printElement = isHtmlElement(params.printable) ? params.printable : document.getElementById(params.printable); // Check if the element exists\n\n if (!printElement) {\n window.console.error('Invalid HTML element id: ' + params.printable);\n return;\n } // Clone the target element including its children (if available)\n\n\n params.printableElement = cloneElement(printElement, params); // Add header\n\n if (params.header) {\n Object(_functions__WEBPACK_IMPORTED_MODULE_0__[\"addHeader\"])(params.printableElement, params);\n } // Print html element contents\n\n\n _print__WEBPACK_IMPORTED_MODULE_1__[\"default\"].send(params, printFrame);\n }\n});\n\nfunction cloneElement(element, params) {\n // Clone the main node (if not already inside the recursion process)\n var clone = element.cloneNode(); // Loop over and process the children elements / nodes (including text nodes)\n\n var childNodesArray = Array.prototype.slice.call(element.childNodes);\n\n for (var i = 0; i < childNodesArray.length; i++) {\n // Check if we are skipping the current element\n if (params.ignoreElements.indexOf(childNodesArray[i].id) !== -1) {\n continue;\n } // Clone the child element\n\n\n var clonedChild = cloneElement(childNodesArray[i], params); // Attach the cloned child to the cloned parent node\n\n clone.appendChild(clonedChild);\n } // Get all styling for print element (for nodes of type element only)\n\n\n if (params.scanStyles && element.nodeType === 1) {\n clone.setAttribute('style', Object(_functions__WEBPACK_IMPORTED_MODULE_0__[\"collectStyles\"])(element, params));\n } // Check if the element needs any state processing (copy user input data)\n\n\n switch (element.tagName) {\n case 'SELECT':\n // Copy the current selection value to its clone\n clone.value = element.value;\n break;\n\n case 'CANVAS':\n // Copy the canvas content to its clone\n clone.getContext('2d').drawImage(element, 0, 0);\n break;\n }\n\n return clone;\n}\n\nfunction isHtmlElement(printable) {\n // Check if element is instance of HTMLElement or has nodeType === 1 (for elements in iframe)\n return _typeof(printable) === 'object' && printable && (printable instanceof HTMLElement || printable.nodeType === 1);\n}\n\n/***/ }),\n\n/***/ \"./src/js/image.js\":\n/*!*************************!*\\\n !*** ./src/js/image.js ***!\n \\*************************/\n/*! exports provided: default */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _functions__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./functions */ \"./src/js/functions.js\");\n/* harmony import */ var _print__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./print */ \"./src/js/print.js\");\n/* harmony import */ var _browser__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./browser */ \"./src/js/browser.js\");\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n print: function print(params, printFrame) {\n // Check if we are printing one image or multiple images\n if (params.printable.constructor !== Array) {\n // Create array with one image\n params.printable = [params.printable];\n } // Create printable element (container)\n\n\n params.printableElement = document.createElement('div'); // Create all image elements and append them to the printable container\n\n params.printable.forEach(function (src) {\n // Create the image element\n var img = document.createElement('img');\n img.setAttribute('style', params.imageStyle); // Set image src with the file url\n\n img.src = src; // The following block is for Firefox, which for some reason requires the image's src to be fully qualified in\n // order to print it\n\n if (_browser__WEBPACK_IMPORTED_MODULE_2__[\"default\"].isFirefox()) {\n var fullyQualifiedSrc = img.src;\n img.src = fullyQualifiedSrc;\n } // Create the image wrapper\n\n\n var imageWrapper = document.createElement('div'); // Append image to the wrapper element\n\n imageWrapper.appendChild(img); // Append wrapper to the printable element\n\n params.printableElement.appendChild(imageWrapper);\n }); // Check if we are adding a print header\n\n if (params.header) Object(_functions__WEBPACK_IMPORTED_MODULE_0__[\"addHeader\"])(params.printableElement, params); // Print image\n\n _print__WEBPACK_IMPORTED_MODULE_1__[\"default\"].send(params, printFrame);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/js/init.js\":\n/*!************************!*\\\n !*** ./src/js/init.js ***!\n \\************************/\n/*! exports provided: default */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _browser__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./browser */ \"./src/js/browser.js\");\n/* harmony import */ var _modal__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modal */ \"./src/js/modal.js\");\n/* harmony import */ var _pdf__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./pdf */ \"./src/js/pdf.js\");\n/* harmony import */ var _html__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./html */ \"./src/js/html.js\");\n/* harmony import */ var _raw_html__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./raw-html */ \"./src/js/raw-html.js\");\n/* harmony import */ var _image__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./image */ \"./src/js/image.js\");\n/* harmony import */ var _json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./json */ \"./src/js/json.js\");\n\n\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n\n\n\n\n\nvar printTypes = ['pdf', 'html', 'image', 'json', 'raw-html'];\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n init: function init() {\n var params = {\n printable: null,\n fallbackPrintable: null,\n type: 'pdf',\n header: null,\n headerStyle: 'font-weight: 300;',\n maxWidth: 800,\n properties: null,\n gridHeaderStyle: 'font-weight: bold; padding: 5px; border: 1px solid #dddddd;',\n gridStyle: 'border: 1px solid lightgray; margin-bottom: -1px;',\n showModal: false,\n onError: function onError(error) {\n throw error;\n },\n onLoadingStart: null,\n onLoadingEnd: null,\n onPrintDialogClose: function onPrintDialogClose() {},\n onIncompatibleBrowser: function onIncompatibleBrowser() {},\n modalMessage: 'Retrieving Document...',\n frameId: 'printJS',\n printableElement: null,\n documentTitle: 'Document',\n targetStyle: ['clear', 'display', 'width', 'min-width', 'height', 'min-height', 'max-height'],\n targetStyles: ['border', 'box', 'break', 'text-decoration'],\n ignoreElements: [],\n repeatTableHeader: true,\n css: null,\n style: null,\n scanStyles: true,\n base64: false,\n // Deprecated\n onPdfOpen: null,\n font: 'TimesNewRoman',\n font_size: '12pt',\n honorMarginPadding: true,\n honorColor: false,\n imageStyle: 'max-width: 100%;'\n }; // Check if a printable document or object was supplied\n\n var args = arguments[0];\n\n if (args === undefined) {\n throw new Error('printJS expects at least 1 attribute.');\n } // Process parameters\n\n\n switch (_typeof(args)) {\n case 'string':\n params.printable = encodeURI(args);\n params.fallbackPrintable = params.printable;\n params.type = arguments[1] || params.type;\n break;\n\n case 'object':\n params.printable = args.printable;\n params.fallbackPrintable = typeof args.fallbackPrintable !== 'undefined' ? args.fallbackPrintable : params.printable;\n params.fallbackPrintable = params.base64 ? \"data:application/pdf;base64,\".concat(params.fallbackPrintable) : params.fallbackPrintable;\n\n for (var k in params) {\n if (k === 'printable' || k === 'fallbackPrintable') continue;\n params[k] = typeof args[k] !== 'undefined' ? args[k] : params[k];\n }\n\n break;\n\n default:\n throw new Error('Unexpected argument type! Expected \"string\" or \"object\", got ' + _typeof(args));\n } // Validate printable\n\n\n if (!params.printable) throw new Error('Missing printable information.'); // Validate type\n\n if (!params.type || typeof params.type !== 'string' || printTypes.indexOf(params.type.toLowerCase()) === -1) {\n throw new Error('Invalid print type. Available types are: pdf, html, image and json.');\n } // Check if we are showing a feedback message to the user (useful for large files)\n\n\n if (params.showModal) _modal__WEBPACK_IMPORTED_MODULE_1__[\"default\"].show(params); // Check for a print start hook function\n\n if (params.onLoadingStart) params.onLoadingStart(); // To prevent duplication and issues, remove any used printFrame from the DOM\n\n var usedFrame = document.getElementById(params.frameId);\n if (usedFrame) usedFrame.parentNode.removeChild(usedFrame); // Create a new iframe for the print job\n\n var printFrame = document.createElement('iframe');\n\n if (_browser__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isFirefox()) {\n // Set the iframe to be is visible on the page (guaranteed by fixed position) but hidden using opacity 0, because\n // this works in Firefox. The height needs to be sufficient for some part of the document other than the PDF\n // viewer's toolbar to be visible in the page\n printFrame.setAttribute('style', 'width: 1px; height: 100px; position: fixed; left: 0; top: 0; opacity: 0; border-width: 0; margin: 0; padding: 0');\n } else {\n // Hide the iframe in other browsers\n printFrame.setAttribute('style', 'visibility: hidden; height: 0; width: 0; position: absolute; border: 0');\n } // Set iframe element id\n\n\n printFrame.setAttribute('id', params.frameId); // For non pdf printing, pass an html document string to srcdoc (force onload callback)\n\n if (params.type !== 'pdf') {\n printFrame.srcdoc = '' + params.documentTitle + ''; // Attach css files\n\n if (params.css) {\n // Add support for single file\n if (!Array.isArray(params.css)) params.css = [params.css]; // Create link tags for each css file\n\n params.css.forEach(function (file) {\n printFrame.srcdoc += '';\n });\n }\n\n printFrame.srcdoc += '';\n } // Check printable type\n\n\n switch (params.type) {\n case 'pdf':\n // Check browser support for pdf and if not supported we will just open the pdf file instead\n if (_browser__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isIE()) {\n try {\n console.info('Print.js doesn\\'t support PDF printing in Internet Explorer.');\n var win = window.open(params.fallbackPrintable, '_blank');\n win.focus();\n params.onIncompatibleBrowser();\n } catch (error) {\n params.onError(error);\n } finally {\n // Make sure there is no loading modal opened\n if (params.showModal) _modal__WEBPACK_IMPORTED_MODULE_1__[\"default\"].close();\n if (params.onLoadingEnd) params.onLoadingEnd();\n }\n } else {\n _pdf__WEBPACK_IMPORTED_MODULE_2__[\"default\"].print(params, printFrame);\n }\n\n break;\n\n case 'image':\n _image__WEBPACK_IMPORTED_MODULE_5__[\"default\"].print(params, printFrame);\n break;\n\n case 'html':\n _html__WEBPACK_IMPORTED_MODULE_3__[\"default\"].print(params, printFrame);\n break;\n\n case 'raw-html':\n _raw_html__WEBPACK_IMPORTED_MODULE_4__[\"default\"].print(params, printFrame);\n break;\n\n case 'json':\n _json__WEBPACK_IMPORTED_MODULE_6__[\"default\"].print(params, printFrame);\n break;\n }\n }\n});\n\n/***/ }),\n\n/***/ \"./src/js/json.js\":\n/*!************************!*\\\n !*** ./src/js/json.js ***!\n \\************************/\n/*! exports provided: default */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _functions__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./functions */ \"./src/js/functions.js\");\n/* harmony import */ var _print__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./print */ \"./src/js/print.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n print: function print(params, printFrame) {\n // Check if we received proper data\n if (_typeof(params.printable) !== 'object') {\n throw new Error('Invalid javascript data object (JSON).');\n } // Validate repeatTableHeader\n\n\n if (typeof params.repeatTableHeader !== 'boolean') {\n throw new Error('Invalid value for repeatTableHeader attribute (JSON).');\n } // Validate properties\n\n\n if (!params.properties || !Array.isArray(params.properties)) {\n throw new Error('Invalid properties array for your JSON data.');\n } // We will format the property objects to keep the JSON api compatible with older releases\n\n\n params.properties = params.properties.map(function (property) {\n return {\n field: _typeof(property) === 'object' ? property.field : property,\n displayName: _typeof(property) === 'object' ? property.displayName : property,\n columnSize: _typeof(property) === 'object' && property.columnSize ? property.columnSize + ';' : 100 / params.properties.length + '%;'\n };\n }); // Create a print container element\n\n params.printableElement = document.createElement('div'); // Check if we are adding a print header\n\n if (params.header) {\n Object(_functions__WEBPACK_IMPORTED_MODULE_0__[\"addHeader\"])(params.printableElement, params);\n } // Build the printable html data\n\n\n params.printableElement.innerHTML += jsonToHTML(params); // Print the json data\n\n _print__WEBPACK_IMPORTED_MODULE_1__[\"default\"].send(params, printFrame);\n }\n});\n\nfunction jsonToHTML(params) {\n // Get the row and column data\n var data = params.printable;\n var properties = params.properties; // Create a html table\n\n var htmlData = '
'; // Check if the header should be repeated\n\n if (params.repeatTableHeader) {\n htmlData += '';\n } // Add the table header row\n\n\n htmlData += '
'; // Add the table header columns\n\n for (var a = 0; a < properties.length; a++) {\n htmlData += '
';\n } // Add the closing tag for the table header row\n\n\n htmlData += '
'; // If the table header is marked as repeated, add the closing tag\n\n if (params.repeatTableHeader) {\n htmlData += '';\n } // Create the table body\n\n\n htmlData += ''; // Add the table data rows\n\n for (var i = 0; i < data.length; i++) {\n // Add the row starting tag\n htmlData += '
'; // Print selected properties only\n\n for (var n = 0; n < properties.length; n++) {\n var stringData = data[i]; // Support nested objects\n\n var property = properties[n].field.split('.');\n\n if (property.length > 1) {\n for (var p = 0; p < property.length; p++) {\n stringData = stringData[property[p]];\n }\n } else {\n stringData = stringData[properties[n].field];\n } // Add the row contents and styles\n\n\n htmlData += '
';\n } // Add the table and body closing tags\n\n\n htmlData += '
';\n return htmlData;\n}\n\n/***/ }),\n\n/***/ \"./src/js/modal.js\":\n/*!*************************!*\\\n !*** ./src/js/modal.js ***!\n \\*************************/\n/*! exports provided: default */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\nvar Modal = {\n show: function show(params) {\n // Build modal\n var modalStyle = 'font-family:sans-serif; ' + 'display:table; ' + 'text-align:center; ' + 'font-weight:300; ' + 'font-size:30px; ' + 'left:0; top:0;' + 'position:fixed; ' + 'z-index: 9990;' + 'color: #0460B5; ' + 'width: 100%; ' + 'height: 100%; ' + 'background-color:rgba(255,255,255,.9);' + 'transition: opacity .3s ease;'; // Create wrapper\n\n var printModal = document.createElement('div');\n printModal.setAttribute('style', modalStyle);\n printModal.setAttribute('id', 'printJS-Modal'); // Create content div\n\n var contentDiv = document.createElement('div');\n contentDiv.setAttribute('style', 'display:table-cell; vertical-align:middle; padding-bottom:100px;'); // Add close button (requires print.css)\n\n var closeButton = document.createElement('div');\n closeButton.setAttribute('class', 'printClose');\n closeButton.setAttribute('id', 'printClose');\n contentDiv.appendChild(closeButton); // Add spinner (requires print.css)\n\n var spinner = document.createElement('span');\n spinner.setAttribute('class', 'printSpinner');\n contentDiv.appendChild(spinner); // Add message\n\n var messageNode = document.createTextNode(params.modalMessage);\n contentDiv.appendChild(messageNode); // Add contentDiv to printModal\n\n printModal.appendChild(contentDiv); // Append print modal element to document body\n\n document.getElementsByTagName('body')[0].appendChild(printModal); // Add event listener to close button\n\n document.getElementById('printClose').addEventListener('click', function () {\n Modal.close();\n });\n },\n close: function close() {\n var printModal = document.getElementById('printJS-Modal');\n\n if (printModal) {\n printModal.parentNode.removeChild(printModal);\n }\n }\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (Modal);\n\n/***/ }),\n\n/***/ \"./src/js/pdf.js\":\n/*!***********************!*\\\n !*** ./src/js/pdf.js ***!\n \\***********************/\n/*! exports provided: default */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _print__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./print */ \"./src/js/print.js\");\n/* harmony import */ var _functions__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./functions */ \"./src/js/functions.js\");\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n print: function print(params, printFrame) {\n // Check if we have base64 data\n if (params.base64) {\n var bytesArray = Uint8Array.from(atob(params.printable), function (c) {\n return c.charCodeAt(0);\n });\n createBlobAndPrint(params, printFrame, bytesArray);\n return;\n } // Format pdf url\n\n\n params.printable = /^(blob|http|\\/\\/)/i.test(params.printable) ? params.printable : window.location.origin + (params.printable.charAt(0) !== '/' ? '/' + params.printable : params.printable); // Get the file through a http request (Preload)\n\n var req = new window.XMLHttpRequest();\n req.responseType = 'arraybuffer';\n req.addEventListener('error', function () {\n Object(_functions__WEBPACK_IMPORTED_MODULE_1__[\"cleanUp\"])(params);\n params.onError(req.statusText, req); // Since we don't have a pdf document available, we will stop the print job\n });\n req.addEventListener('load', function () {\n // Check for errors\n if ([200, 201].indexOf(req.status) === -1) {\n Object(_functions__WEBPACK_IMPORTED_MODULE_1__[\"cleanUp\"])(params);\n params.onError(req.statusText, req); // Since we don't have a pdf document available, we will stop the print job\n\n return;\n } // Print requested document\n\n\n createBlobAndPrint(params, printFrame, req.response);\n });\n req.open('GET', params.printable, true);\n req.send();\n }\n});\n\nfunction createBlobAndPrint(params, printFrame, data) {\n // Pass response or base64 data to a blob and create a local object url\n var localPdf = new window.Blob([data], {\n type: 'application/pdf'\n });\n localPdf = window.URL.createObjectURL(localPdf); // Set iframe src with pdf document url\n\n printFrame.setAttribute('src', localPdf);\n _print__WEBPACK_IMPORTED_MODULE_0__[\"default\"].send(params, printFrame);\n}\n\n/***/ }),\n\n/***/ \"./src/js/print.js\":\n/*!*************************!*\\\n !*** ./src/js/print.js ***!\n \\*************************/\n/*! exports provided: default */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _browser__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./browser */ \"./src/js/browser.js\");\n/* harmony import */ var _functions__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./functions */ \"./src/js/functions.js\");\n\n\nvar Print = {\n send: function send(params, printFrame) {\n // Append iframe element to document body\n document.getElementsByTagName('body')[0].appendChild(printFrame); // Get iframe element\n\n var iframeElement = document.getElementById(params.frameId); // Wait for iframe to load all content\n\n iframeElement.onload = function () {\n if (params.type === 'pdf') {\n // Add a delay for Firefox. In my tests, 1000ms was sufficient but 100ms was not\n if (_browser__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isFirefox()) {\n setTimeout(function () {\n return performPrint(iframeElement, params);\n }, 1000);\n } else {\n performPrint(iframeElement, params);\n }\n\n return;\n } // Get iframe element document\n\n\n var printDocument = iframeElement.contentWindow || iframeElement.contentDocument;\n if (printDocument.document) printDocument = printDocument.document; // Append printable element to the iframe body\n\n printDocument.body.appendChild(params.printableElement); // Add custom style\n\n if (params.type !== 'pdf' && params.style) {\n // Create style element\n var style = document.createElement('style');\n style.innerHTML = params.style; // Append style element to iframe's head\n\n printDocument.head.appendChild(style);\n } // If printing images, wait for them to load inside the iframe\n\n\n var images = printDocument.getElementsByTagName('img');\n\n if (images.length > 0) {\n loadIframeImages(Array.from(images)).then(function () {\n return performPrint(iframeElement, params);\n });\n } else {\n performPrint(iframeElement, params);\n }\n };\n }\n};\n\nfunction performPrint(iframeElement, params) {\n try {\n iframeElement.focus(); // If Edge or IE, try catch with execCommand\n\n if (_browser__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isEdge() || _browser__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isIE()) {\n try {\n iframeElement.contentWindow.document.execCommand('print', false, null);\n } catch (e) {\n iframeElement.contentWindow.print();\n }\n } else {\n // Other browsers\n iframeElement.contentWindow.print();\n }\n } catch (error) {\n params.onError(error);\n } finally {\n if (_browser__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isFirefox()) {\n // Move the iframe element off-screen and make it invisible\n iframeElement.style.visibility = 'hidden';\n iframeElement.style.left = '-1px';\n }\n\n Object(_functions__WEBPACK_IMPORTED_MODULE_1__[\"cleanUp\"])(params);\n }\n}\n\nfunction loadIframeImages(images) {\n var promises = images.map(function (image) {\n if (image.src && image.src !== window.location.href) {\n return loadIframeImage(image);\n }\n });\n return Promise.all(promises);\n}\n\nfunction loadIframeImage(image) {\n return new Promise(function (resolve) {\n var pollImage = function pollImage() {\n !image || typeof image.naturalWidth === 'undefined' || image.naturalWidth === 0 || !image.complete ? setTimeout(pollImage, 500) : resolve();\n };\n\n pollImage();\n });\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Print);\n\n/***/ }),\n\n/***/ \"./src/js/raw-html.js\":\n/*!****************************!*\\\n !*** ./src/js/raw-html.js ***!\n \\****************************/\n/*! exports provided: default */\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _print__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./print */ \"./src/js/print.js\");\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n print: function print(params, printFrame) {\n // Create printable element (container)\n params.printableElement = document.createElement('div');\n params.printableElement.setAttribute('style', 'width:100%'); // Set our raw html as the printable element inner html content\n\n params.printableElement.innerHTML = params.printable; // Print html contents\n\n _print__WEBPACK_IMPORTED_MODULE_0__[\"default\"].send(params, printFrame);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/sass/index.scss\":\n/*!*****************************!*\\\n !*** ./src/sass/index.scss ***!\n \\*****************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n// extracted by mini-css-extract-plugin\n\n/***/ }),\n\n/***/ 0:\n/*!****************************!*\\\n !*** multi ./src/index.js ***!\n \\****************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(/*! ./src/index.js */\"./src/index.js\");\n\n\n/***/ })\n\n/******/ })[\"default\"];\n});\n//# sourceMappingURL=print.map","/*\n * end-tools:\n *\n * Place up to four functions in the\n * top or bottom of bb-q on any node.\n *\n * 1) A download report button\n * 2) An email report widget\n * 3) A print option.\n * 4) A feedback widget.\n *\n * Author: Tim Bauwens\n * Copyright 2020 Berkeley Bridge\n *\n */\n\nimport print from \"print-js\";\nimport { gt, bb, _ } from \"$json\";\nimport { getmetadata } from \"../../js/lib/getmetadata\";\n\n(($, win, doc) => {\n var translations = {\n \"Rapport downloaden\": {\n nl: \"Rapport downloaden\",\n en: \"Download report\"\n },\n \"Verzend rapport via e-mail\": {\n nl: \"Verzend rapport via e-mail\",\n en: \"Send report via e-mail\"\n },\n \"Was dit nuttig?\": {\n nl: \"Was dit nuttig?\",\n en: \"Was this useful?\"\n },\n \"Verzend\": {\n nl: \"Verzend\",\n en: \"Send\"\n },\n \"vul hier uw e-mail in\": {\n nl: \"vul hier uw e-mail in\",\n en: \"provide your e-mail here\"\n },\n \"jouw@email.com\": {\n nl: \"jouw@email.com\",\n en: \"your@email.com\"\n },\n \"E-mail is verzonden...\": {\n nl: \"E-mail is verzonden.\",\n en: \"E-mail has been sent.\"\n },\n \"Bedankt voor uw feedback\": {\n nl: \"Bedankt voor uw feedback\",\n en: \"Thanks for your feedback\"\n },\n \"Ja\": {\n nl: \"Ja\",\n en: \"Yes\"\n },\n \"Nee\": {\n nl: \"Nee\",\n en: \"No\"\n },\n \"prepping\": {\n nl: \"voorbereiden...\",\n en: \"preparing...\"\n },\n \"impossible\": {\n nl: \"niet mogelijk.\",\n en: \"not posssible.\"\n }\n };\n\n gt.addTranslations(translations);\n\n var metadata,\n emailSent,\n REPORTDOC = \"\", // Because there could be multiple, but we only handle one.\n SHOWONTOP = \"true\",\n DESIRED_TOOLS = [];\n\n $(function () {\n $(doc).on(\"bb:preHandleData\", (event, data) => {\n if (data && data.groups && data.groups.length && data.sessionid) {\n // Check in case metadata has been added or changed\n metadata = getmetadata(data).props;\n\n if (\n metadata.has(\"reportdoc\") &&\n metadata.get(\"reportdoc\").split(\".\").pop() === \"pdf\"\n ) {\n REPORTDOC = metadata.get(\"reportdoc\");\n }\n if (metadata.has(\"desiredtools\")) {\n DESIRED_TOOLS.length = 0;\n metadata\n .get(\"desiredtools\")\n .split(\"|\")\n .forEach(entry => {\n DESIRED_TOOLS.push(entry);\n });\n }\n if (metadata.has(\"showontop\")) {\n SHOWONTOP = metadata.get(\"showontop\");\n } else {\n SHOWONTOP = \"true\";\n }\n\n emailSent = emailSent || false;\n }\n });\n });\n\n $(function () {\n $(doc).on(\"bb:postHandleData\", function (event, data) {\n // Unset mode for hooks\n bb.Mode.unset(\"hasThreeInOne\");\n if (data && data.groups && data.groups.length && data.sessionid) {\n if (metadata.has(\"end-tools\") && metadata.get(\"end-tools\")) {\n // Set mode for hooks\n bb.Mode.set(\"hasThreeInOne\");\n\n // Hide and reset the support inputs.\n $(\".bb-g-endtools-feedback-vote\").hide();\n $(\".bb-g-endtools-email\").hide();\n $(\".bbm-endtools-email\").val(\"\");\n\n // Create the container for the functions.\n var $container = $('');\n\n if (DESIRED_TOOLS.indexOf(\"download\") > -1 && REPORTDOC.length) {\n // Make a download report button\n var $download = $(\n ''\n );\n $download.append(`\n \n \n ${_(\"Rapport downloaden\")}\n \n `);\n $container.append($download);\n }\n\n if (DESIRED_TOOLS.indexOf(\"print\") > -1 && REPORTDOC.length) {\n // Make the print button.\n var $print = $(\n ''\n );\n var $printbtn = $(`\n \n `).on(\"click\", e => {\n printJS({\n printable: `${REPORTDOC}?guid=${data.uniqueid}:${data.dbname}:${data.sessionid}`,\n type: \"pdf\",\n showModal: false\n });\n });\n $print.append($printbtn);\n $container.append($print);\n }\n\n if (DESIRED_TOOLS.indexOf(\"email\") > -1) {\n // Make the email widget\n var $email = $('');\n\n if (emailSent) {\n $email.append(\n '\"\n );\n emailSent = false;\n } else {\n $email.append(\n ''\n ).append(`\n \n `);\n\n // Handler\n $(doc).off(\".end-tools-events\", \".opt-for-email\");\n $(doc).on(\n \"click.end-tools-events\",\n \".opt-for-email\",\n function (e) {\n $(\".opt-for-email\")\n .html(_(\"Verzend\") + ' ⇾ ')\n .attr(\"class\", \"email-send bb-next\")\n .prop(\"disabled\", \"disabled\");\n $(\".email-address\")\n .attr(\"class\", \"email-address set\")\n .focus();\n }\n );\n $(doc).off(\".end-tools-events\", \".email-address\");\n $(doc).on(\n \"\\\n propertychange.end-tools \\\n change.end-tools-events \\\n click.end-tools-events \\\n keyup.end-tools-events \\\n input.end-tools-events \\\n paste.end-tools-events\",\n \".email-address\",\n function () {\n var input = $(\"input.email-address\").val();\n var regex =\n /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n if (regex.test(input)) {\n $(\"button.email-send\")\n .addClass(\"validated\")\n .removeAttr(\"disabled\");\n emailSent = true;\n $(\".bbm-endtools-email\").val(input);\n } else {\n $(\"button.email-send\")\n .removeClass(\"validated\")\n .prop(\"disabled\", \"disabled\");\n $(\".bbm-endtools-email\").val(\"\");\n }\n }\n );\n }\n $container.append($email);\n }\n\n if (DESIRED_TOOLS.indexOf(\"feedback\") > -1) {\n // Make the feedback buttons.\n var $feedback = $(\n ''\n );\n $feedback\n .append(\n `\n \n `\n )\n .append(\"\").append(`\n \n `);\n\n // Handler\n var group;\n if (data && data.userinfo)\n $feedback.data(\"userinfo\", data.userinfo);\n group = data.groups.filter(function (g) {\n return g.current;\n })[0];\n $feedback.data(\"nodename\", group.name);\n if (data && data.modelname)\n $feedback.data(\"modelname\", data.modelname);\n if (data && data.modelversion)\n $feedback.data(\"modelversion\", data.modelversion);\n $(doc).off(\".end-tools-events\", \".feedback-button\");\n $(doc).one(\n \"click.end-tools-events\",\n \".feedback-button\",\n function (e) {\n var vote =\n $(e.target).data(\"value\") !== undefined\n ? $(e.target).data(\"value\")\n : $(e.target).parents(\"button\").data(\"value\");\n\n // Add the vote to the hiddden interface.\n $(\"input.bbm-endtools-feedback-vote\").attr(\"value\", vote);\n $feedback.html(\n '\"\n );\n bb.updatemis();\n }\n );\n $container.append($feedback);\n }\n\n // Reveal top or bottom depending on conf.\n if (SHOWONTOP === \"false\") {\n $(\"fieldset.selected\").append($container);\n setTimeout(function () {\n $container.toggleClass(\"showing\");\n }, 800);\n } else {\n $(\"#bb-q\").prepend($container);\n $(\"html,body\").animate({ scrollTop: 0 });\n setTimeout(function () {\n $container.toggleClass(\"showing\");\n }, 800);\n }\n }\n }\n });\n });\n})(jQuery, window, document);\n","import { bb } from \"$json\";\n/* headings:\n *\n * Turn labels whose font class (as provided the JSON object) match the\n * regular expression /^Standard title$|^Heading[^1-6]*([1-6]?)/ into headings.\n *\n * If the class has no numbering (e.g. 'Standard Title' instead of\n * 'Heading 2'), level 1 will be presumed.\n *\n * Since a model can run anywhere, it is possible to set a base level\n * for headings in arbitrary.headings.baseLevel (in\n * conf.json).\n *\n * If you want to force titles in 'addtobottom' nodes to duck below\n * the top ('cleared') node, declare arbitrary.headings.duck = true in\n * conf.json\n *\n * Author: Niels Giesen\n * Copyright 2016, 2018 Berkeley Bridge\n *\n */\n(function ($, win, doc) {\n var duck = false,\n baseLevel,\n topLevel,\n re = /^Standard title$|^Heading[^1-6]*([1-6]?)/;\n\n $(function () {\n try {\n baseLevel = bb.conf.arbitrary.headings.baseLevel;\n if (baseLevel === undefined) throw \"baseLevel is not defined\";\n topLevel = baseLevel - 1;\n } catch (err) {\n topLevel = 0;\n }\n\n try {\n duck = bb.conf.arbitrary.headings.duck;\n } catch (err) {}\n\n $(doc).on(\"bb:preHandleData\", function (event, data) {\n if (data && data.groups && data.groups.length) {\n $.each(data.groups, function (_, group) {\n $.each(group.controls, function (_, ctl) {\n var klass = ctl[\"font-class\"],\n _level,\n m;\n if (ctl.controltype === \"label\" && ((m = klass.match(re)), m)) {\n _level = Number(m[1]) || 1;\n ctl._subtype = \"heading\";\n ctl._level =\n duck && group.screenmode !== \"clear\"\n ? _level + 1 + topLevel\n : _level + topLevel;\n }\n });\n });\n }\n });\n });\n})(jQuery, window, document);\n","/* history:\n *\n * Manage history using the html5 history api and sessionStorage\n *\n * Could have support for crunchbang ( #!modelname=thisandthat )\n *\n * Author: Niels Giesen\n * Copyright 2013, 2014, 2015 Berkeley Bridge\n *\n */\nimport { bb, _ } from \"$json\";\nimport { has } from \"$json/lib/functional\";\nimport { setSettled } from \"$json/lib/settled\";\n\n(function ($, win, history, location) {\n var crunchbang = false;\n\n if (history && history.pushState) {\n if (!location.origin) {\n location.origin =\n location.protocol +\n \"//\" +\n location.hostname +\n (location.port ? \":\" + location.port : \"\");\n }\n\n $(function () {\n var apinav,\n storage,\n params = $.parseQuery(location.hash.slice(2)),\n _title_sep = \" \",\n _title = document.title;\n\n try {\n storage = window.sessionStorage;\n } catch (err) {\n storage = null;\n }\n\n function directory(loc) {\n return loc.origin + loc.pathname.replace(/[^/]+$/, \"\");\n }\n\n function restoreState(state) {\n if (state.sessionid) {\n // restore case\n bb.ajax\n .post({\n url: \"action\",\n data: state\n })\n .then(setSettled);\n } else if (bb.getVar(\"sessionid\")) {\n // exit running case and restore model view\n bb.exit(() => bb.menu(state).then(setSettled));\n } else {\n // restore model view\n bb.menu(state).then(setSettled);\n }\n }\n\n function ditchState() {\n storage && storage.removeItem(\"state\");\n history.replaceState(null, null, null);\n setSettled();\n }\n\n if (location.search !== \"\") ditchState();\n\n var initial_state =\n history.state || (storage && JSON.parse(storage.getItem(\"state\")));\n\n if (initial_state) {\n // Detect explicit edit of the crunchbang - this should\n // override the dbname parameter and instead use the modelname\n if (params.modelname && params.modelname !== initial_state.modelname) {\n initial_state.modelname = params.modelname;\n delete initial_state.dbname;\n delete initial_state.sessionid;\n }\n\n if (initial_state.directory === directory(location)) {\n bb.Mode.set(\"isLoggedIn\"); // Yes, just an assumption it will go allright.\n restoreState(initial_state);\n } else {\n ditchState();\n }\n } else if (params.modelname) {\n // Bookmarked with crunchbang, but no state\n bb.Router(params);\n } else {\n setSettled();\n }\n\n $(document).on(\"bb:jsonError\", ditchState);\n\n $(document).on(\"bb:preHandleData\", function (event, data) {\n if (data && data.uniqueid) {\n var title,\n state = {\n fmt: \"json\",\n uniqueid: data.uniqueid,\n // Save the 'directory part'\n directory: directory(location)\n };\n if (has(\"dbname\", data) && data.sessionid) {\n state.dbname = data.dbname;\n state.sessionid = data.sessionid;\n state.modelname = data.modelname; // Needed to get interpret explicit change to location\n\n if (data.modeldescription) {\n title = [_title, data.modeldescription.replace(/_/g, \" \")].join(\n _title_sep\n );\n }\n } else if (data.models) {\n var model = $.grep(data.models, function (m) {\n return m.selected;\n })[0],\n dbname = model ? model.dbname : null;\n if (dbname !== null) {\n state.dbname = dbname;\n title = [_title, model.modelname, \"-\", _(\"overview\")].join(\n _title_sep\n );\n } else {\n title = [_title, _(\"Your models\")].join(_title_sep);\n }\n }\n if (!apinav) {\n try {\n storage && storage.setItem(\"state\", JSON.stringify(state));\n } catch (e) {\n // Guard against QuotaExceededError (which always happens on Safari Private Browsing on iOS)\n }\n if (history.state && history.state.sessionid && state.sessionid) {\n history.replaceState(\n state,\n null,\n location.origin +\n location.pathname +\n ((crunchbang && \"#!modelname=\" + data.modelname) || \"\")\n );\n } else {\n if (data.modelname && crunchbang) {\n history.pushState(\n state,\n null,\n location.origin +\n location.pathname +\n \"#!modelname=\" +\n data.modelname\n );\n } else {\n history.pushState(\n state,\n null,\n location.origin + location.pathname\n );\n }\n }\n }\n if (title && document.title !== title) {\n document.title = title;\n }\n }\n // Something went miserably wrong. Clear history to get out of this mess.\n if (\n data &&\n ((data.error && data.error.summary) ||\n (data.groups && !data.groups.length) ||\n data.status === \"logout successful\")\n ) {\n // Extra check - may be we are but updating\n if (\n data &&\n data.error &&\n data.error.code &&\n data.error.code === 14 && // Error loading case\n data.error.subcode === 1002\n )\n // Updating\n return;\n ditchState();\n }\n apinav = false;\n });\n\n win.addEventListener(\"popstate\", function (e) {\n apinav = true;\n if (e.state) {\n if (e.state.directory === directory(location)) restoreState(e.state);\n else ditchState();\n }\n });\n });\n }\n})(jQuery, window, window.history, window.location);\n","//\n// showdown.js -- A javascript port of Markdown.\n//\n// Copyright (c) 2007 John Fraser.\n//\n// Original Markdown Copyright (c) 2004-2005 John Gruber\n// \n//\n// Redistributable under a BSD-style open source license.\n// See license.txt for more information.\n//\n// The full source distribution is at:\n//\n//\t\t\t\tA A L\n//\t\t\t\tT C A\n//\t\t\t\tT K B\n//\n// \n//\n\n//\n// Wherever possible, Showdown is a straight, line-by-line port\n// of the Perl version of Markdown.\n//\n// This is not a normal parser design; it's basically just a\n// series of string substitutions. It's hard to read and\n// maintain this way, but keeping Showdown close to the original\n// design makes it easier to port new features.\n//\n// More importantly, Showdown behaves like markdown.pl in most\n// edge cases. So web applications can do client-side preview\n// in Javascript, and then build identical HTML on the server.\n//\n// This port needs the new RegExp functionality of ECMA 262,\n// 3rd Edition (i.e. Javascript 1.5). Most modern web browsers\n// should do fine. Even with the new regular expression features,\n// We do a lot of work to emulate Perl's regex functionality.\n// The tricky changes in this file mostly have the \"attacklab:\"\n// label. Major or self-explanatory changes don't.\n//\n// Smart diff tools like Araxis Merge will be able to match up\n// this file with markdown.pl in a useful way. A little tweaking\n// helps: in a copy of markdown.pl, replace \"#\" with \"//\" and\n// replace \"$text\" with \"text\". Be sure to ignore whitespace\n// and line endings.\n//\n\n//\n// Showdown usage:\n//\n// var text = \"Markdown *rocks*.\";\n//\n// var converter = new Showdown.converter();\n// var html = converter.makeHtml(text);\n//\n// alert(html);\n//\n// Note: move the sample code to the bottom of this\n// file before uncommenting it.\n//\n\n//\n// Showdown namespace\n//\nvar Showdown = {};\n\n//\n// converter\n//\n// Wraps all \"globals\" so that the only thing\n// exposed is makeHtml().\n//\nShowdown.converter = function () {\n //\n // Globals:\n //\n\n // Global hashes, used by various utility routines\n var g_urls;\n var g_titles;\n var g_html_blocks;\n\n // Used to track when we're inside an ordered or unordered list\n // (see _ProcessListItems() for details):\n var g_list_level = 0;\n\n this.makeHtml = function (text, inline_only) {\n //\n // Main function. The order in which other subs are called here is\n // essential. Link and image substitutions need to happen before\n // _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the \n // and tags get encoded.\n //\n\n // Clear the global hashes. If we don't clear these, you get conflicts\n // from other articles when generating a page which contains more than\n // one article (e.g. an index page that shows the N most recent\n // articles):\n g_urls = new Array();\n g_titles = new Array();\n g_html_blocks = new Array();\n\n // attacklab: Replace ~ with ~T\n // This lets us use tilde as an escape char to avoid md5 hashes\n // The choice of character is arbitray; anything that isn't\n // magic in Markdown will work.\n text = text.replace(/~/g, \"~T\");\n\n // attacklab: Replace $ with ~D\n // RegExp interprets $ as a special character\n // when it's in a replacement string\n text = text.replace(/\\$/g, \"~D\");\n\n // Standardize line endings\n text = text.replace(/\\r\\n/g, \"\\n\"); // DOS to Unix\n text = text.replace(/\\r/g, \"\\n\"); // Mac to Unix\n\n // Make sure text begins and ends with a couple of newlines:\n text = \"\\n\\n\" + text + \"\\n\\n\";\n\n // Convert all tabs to spaces.\n text = _Detab(text);\n\n // Strip any lines consisting only of spaces and tabs.\n // This makes subsequent regexen easier to write, because we can\n // match consecutive blank lines with /\\n+/ instead of something\n // contorted like /[ \\t]*\\n+/ .\n text = text.replace(/^[ \\t]+$/gm, \"\");\n\n // Turn block-level HTML blocks into hash entries\n text = _HashHTMLBlocks(text);\n\n // Strip link definitions, store in hashes.\n text = _StripLinkDefinitions(text);\n\n if (inline_only) text = _RunSpanGamut(text);\n else text = _RunBlockGamut(text);\n\n text = _UnescapeSpecialChars(text);\n\n // attacklab: Restore dollar signs\n text = text.replace(/~D/g, \"$$\");\n\n // attacklab: Restore tildes\n text = text.replace(/~T/g, \"~\");\n\n return text;\n };\n\n var _StripLinkDefinitions = function (text) {\n //\n // Strips link definitions from text, stores the URLs and titles in\n // hash references.\n //\n\n // Link defs are in the form: ^[id]: url \"optional title\"\n\n /*\n var text = text.replace(/\n ^[ ]{0,3}\\[(.+)\\]: // id = $1 attacklab: g_tab_width - 1\n [ \\t]*\n \\n?\t\t\t\t// maybe *one* newline\n [ \\t]*\n (\\S+?)>?\t\t\t// url = $2\n [ \\t]*\n \\n?\t\t\t\t// maybe one newline\n [ \\t]*\n (?:\n (\\n*)\t\t\t\t// any lines skipped = $3 attacklab: lookbehind removed\n [\"(]\n (.+?)\t\t\t\t// title = $4\n [\")]\n [ \\t]*\n )?\t\t\t\t\t// title is optional\n (?:\\n+|$)\n /gm,\n function(){...});\n */\n var text = text.replace(\n /^[ ]{0,3}\\[(.+)\\]:[ \\t]*\\n?[ \\t]*(\\S+?)>?[ \\t]*\\n?[ \\t]*(?:(\\n*)[\"(](.+?)[\")][ \\t]*)?(?:\\n+|\\Z)/gm,\n function (wholeMatch, m1, m2, m3, m4) {\n m1 = m1.toLowerCase();\n g_urls[m1] = _EncodeAmpsAndAngles(m2); // Link IDs are case-insensitive\n if (m3) {\n // Oops, found blank lines, so it's not a title.\n // Put back the parenthetical statement we stole.\n return m3 + m4;\n } else if (m4) {\n g_titles[m1] = m4.replace(/\"/g, \""\");\n }\n\n // Completely remove the definition from the text\n return \"\";\n }\n );\n\n return text;\n };\n\n var _HashHTMLBlocks = function (text) {\n // attacklab: Double up blank lines to reduce lookaround\n text = text.replace(/\\n/g, \"\\n\\n\");\n\n // Hashify HTML blocks:\n // We only want to do this for block-level HTML tags, such as headers,\n // lists, and tables. That's because we still want to wrap
\");\n }\n );\n\n text = text.replace(\n /^(.+)[ \\t]*\\n-+[ \\t]*\\n+/gm,\n function (matchFound, m1) {\n return hashBlock(\"
\" + _RunSpanGamut(m1) + \"
\");\n }\n );\n\n // atx-style headers:\n // # Header 1\n // ## Header 2\n // ## Header 2 with closing hashes ##\n // ...\n // ###### Header 6\n //\n\n /*\n text = text.replace(/\n ^(\\#{1,6})\t\t\t\t// $1 = string of #'s\n [ \\t]*\n (.+?)\t\t\t\t\t// $2 = Header text\n [ \\t]*\n \\#*\t\t\t\t\t\t// optional closing #'s (not counted)\n \\n+\n /gm, function() {...});\n */\n\n text = text.replace(\n /^(\\#{1,6})[ \\t]*(.+?)[ \\t]*\\#*\\n+/gm,\n function (wholeMatch, m1, m2) {\n var h_level = m1.length;\n return hashBlock(\n \"\" + _RunSpanGamut(m2) + \"\"\n );\n }\n );\n\n return text;\n };\n\n // This declaration keeps Dojo compressor from outputting garbage:\n var _ProcessListItems;\n\n var _DoLists = function (text) {\n //\n // Form HTML ordered (numbered) and unordered (bulleted) lists.\n //\n\n // attacklab: add sentinel to hack around khtml/safari bug:\n // http://bugs.webkit.org/show_bug.cgi?id=11231\n text += \"~0\";\n\n // Re-usable pattern to match any entirel ul or ol list:\n\n /*\n var whole_list = /\n (\t\t\t\t\t\t\t\t\t// $1 = whole list\n (\t\t\t\t\t\t\t\t// $2\n [ ]{0,3}\t\t\t\t\t// attacklab: g_tab_width - 1\n ([*+-]|\\d+[.])\t\t\t\t// $3 = first list item marker\n [ \\t]+\n )\n [^\\r]+?\n (\t\t\t\t\t\t\t\t// $4\n ~0\t\t\t\t\t\t\t// sentinel for workaround; should be $\n |\n \\n{2,}\n (?=\\S)\n (?!\t\t\t\t\t\t\t// Negative lookahead for another list item marker\n [ \\t]*\n (?:[*+-]|\\d+[.])[ \\t]+\n )\n )\n )/g\n */\n var whole_list =\n /^(([ ]{0,3}([*+-]|\\d+[.])[ \\t]+)[^\\r]+?(~0|\\n{2,}(?=\\S)(?![ \\t]*(?:[*+-]|\\d+[.])[ \\t]+)))/gm;\n\n if (g_list_level) {\n text = text.replace(whole_list, function (wholeMatch, m1, m2) {\n var list = m1;\n var list_type = m2.search(/[*+-]/g) > -1 ? \"ul\" : \"ol\";\n\n // Turn double returns into triple returns, so that we can make a\n // paragraph for the last item in a list, if necessary:\n list = list.replace(/\\n{2,}/g, \"\\n\\n\\n\");\n var result = _ProcessListItems(list);\n\n // Trim any trailing whitespace, to put the closing `$list_type>`\n // up on the preceding line, to get it past the current stupid\n // HTML block parser. This is a hack to work around the terrible\n // hack that is the HTML block parser.\n result = result.replace(/\\s+$/, \"\");\n result = \"<\" + list_type + \">\" + result + \"\" + list_type + \">\\n\";\n return result;\n });\n } else {\n whole_list =\n /(\\n\\n|^\\n?)(([ ]{0,3}([*+-]|\\d+[.])[ \\t]+)[^\\r]+?(~0|\\n{2,}(?=\\S)(?![ \\t]*(?:[*+-]|\\d+[.])[ \\t]+)))/g;\n text = text.replace(whole_list, function (wholeMatch, m1, m2, m3) {\n var runup = m1;\n var list = m2;\n\n var list_type = m3.search(/[*+-]/g) > -1 ? \"ul\" : \"ol\";\n // Turn double returns into triple returns, so that we can make a\n // paragraph for the last item in a list, if necessary:\n var list = list.replace(/\\n{2,}/g, \"\\n\\n\\n\");\n var result = _ProcessListItems(list);\n result =\n runup + \"<\" + list_type + \">\\n\" + result + \"\" + list_type + \">\\n\";\n return result;\n });\n }\n\n // attacklab: strip sentinel\n text = text.replace(/~0/, \"\");\n\n return text;\n };\n\n _ProcessListItems = function (list_str) {\n //\n // Process the contents of a single ordered or unordered list, splitting it\n // into individual list items.\n //\n // The $g_list_level global keeps track of when we're inside a list.\n // Each time we enter a list, we increment it; when we leave a list,\n // we decrement. If it's zero, we're not in a list anymore.\n //\n // We do this because when we're not inside a list, we want to treat\n // something like this:\n //\n // I recommend upgrading to version\n // 8. Oops, now this line is treated\n // as a sub-list.\n //\n // As a single paragraph, despite the fact that the second line starts\n // with a digit-period-space sequence.\n //\n // Whereas when we're inside a list (or sub-list), that line will be\n // treated as the start of a sub-list. What a kludge, huh? This is\n // an aspect of Markdown's syntax that's hard to parse perfectly\n // without resorting to mind-reading. Perhaps the solution is to\n // change the syntax rules such that sub-lists must start with a\n // starting cardinal number; e.g. \"1.\" or \"a.\".\n\n g_list_level++;\n\n // trim trailing blank lines:\n list_str = list_str.replace(/\\n{2,}$/, \"\\n\");\n\n // attacklab: add sentinel to emulate \\z\n list_str += \"~0\";\n\n /*\n list_str = list_str.replace(/\n (\\n)?\t\t\t\t\t\t\t// leading line = $1\n (^[ \\t]*)\t\t\t\t\t\t// leading whitespace = $2\n ([*+-]|\\d+[.]) [ \\t]+\t\t\t// list marker = $3\n ([^\\r]+?\t\t\t\t\t\t// list item text = $4\n (\\n{1,2}))\n (?= \\n* (~0 | \\2 ([*+-]|\\d+[.]) [ \\t]+))\n /gm, function(){...});\n */\n list_str = list_str.replace(\n /(\\n)?(^[ \\t]*)([*+-]|\\d+[.])[ \\t]+([^\\r]+?(\\n{1,2}))(?=\\n*(~0|\\2([*+-]|\\d+[.])[ \\t]+))/gm,\n function (wholeMatch, m1, m2, m3, m4) {\n var item = m4;\n var leading_line = m1;\n var leading_space = m2;\n\n if (leading_line || item.search(/\\n{2,}/) > -1) {\n item = _RunBlockGamut(_Outdent(item));\n } else {\n // Recursion for sub-lists:\n item = _DoLists(_Outdent(item));\n item = item.replace(/\\n$/, \"\"); // chomp(item)\n item = _RunSpanGamut(item);\n }\n\n return \"
\" + item + \"
\\n\";\n }\n );\n\n // attacklab: strip sentinel\n list_str = list_str.replace(/~0/g, \"\");\n\n g_list_level--;\n return list_str;\n };\n\n var _DoCodeBlocks = function (text) {\n //\n // Process Markdown `
` blocks.\n //\n\n /*\n text = text.replace(text,\n /(?:\\n\\n|^)\n (\t\t\t\t\t\t\t\t// $1 = the code block -- one or more lines, starting with a space/tab\n (?:\n (?:[ ]{4}|\\t)\t\t\t// Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width\n .*\\n+\n )+\n )\n (\\n*[ ]{0,3}[^ \\t\\n]|(?=~0))\t// attacklab: g_tab_width\n /g,function(){...});\n */\n\n // attacklab: sentinel workarounds for lack of \\A and \\Z, safari\\khtml bug\n text += \"~0\";\n\n text = text.replace(\n /(?:\\n\\n|^)((?:(?:[ ]{4}|\\t).*\\n+)+)(\\n*[ ]{0,3}[^ \\t\\n]|(?=~0))/g,\n function (wholeMatch, m1, m2) {\n var codeblock = m1;\n var nextChar = m2;\n\n codeblock = _EncodeCode(_Outdent(codeblock));\n codeblock = _Detab(codeblock);\n codeblock = codeblock.replace(/^\\n+/g, \"\"); // trim leading newlines\n codeblock = codeblock.replace(/\\n+$/g, \"\"); // trim trailing whitespace\n\n codeblock = \"
\" + codeblock + \"\\n
\";\n\n return hashBlock(codeblock) + nextChar;\n }\n );\n\n // attacklab: strip sentinel\n text = text.replace(/~0/, \"\");\n\n return text;\n };\n\n var hashBlock = function (text) {\n text = text.replace(/(^\\n+|\\n+$)/g, \"\");\n return \"\\n\\n~K\" + (g_html_blocks.push(text) - 1) + \"K\\n\\n\";\n };\n\n var _DoCodeSpans = function (text) {\n //\n // * Backtick quotes are used for spans.\n //\n // * You can use multiple backticks as the delimiters if you want to\n // include literal backticks in the code span. So, this input:\n //\n // Just type ``foo `bar` baz`` at the prompt.\n //\n // Will translate to:\n //\n //
Just type foo `bar` baz at the prompt.
\n //\n //\tThere's no arbitrary limit to the number of backticks you\n //\tcan use as delimters. If you need three consecutive backticks\n //\tin your code, use four for delimiters, etc.\n //\n // * You can use spaces to get literal backticks at the edges:\n //\n // ... type `` `bar` `` ...\n //\n // Turns to:\n //\n // ... type `bar` ...\n //\n\n /*\n text = text.replace(/\n (^|[^\\\\])\t\t\t\t\t// Character before opening ` can't be a backslash\n (`+)\t\t\t\t\t\t// $2 = Opening run of `\n (\t\t\t\t\t\t\t// $3 = The code block\n [^\\r]*?\n [^`]\t\t\t\t\t// attacklab: work around lack of lookbehind\n )\n \\2\t\t\t\t\t\t\t// Matching closer\n (?!`)\n /gm, function(){...});\n */\n\n text = text.replace(\n /(^|[^\\\\])(`+)([^\\r]*?[^`])\\2(?!`)/gm,\n function (wholeMatch, m1, m2, m3, m4) {\n var c = m3;\n c = c.replace(/^([ \\t]*)/g, \"\"); // leading whitespace\n c = c.replace(/[ \\t]*$/g, \"\"); // trailing whitespace\n c = _EncodeCode(c);\n return m1 + \"\" + c + \"\";\n }\n );\n\n return text;\n };\n\n var _EncodeCode = function (text) {\n //\n // Encode/escape certain characters inside Markdown code runs.\n // The point is that in code, these characters are literals,\n // and lose their special Markdown meanings.\n //\n // Encode all ampersands; HTML entities are not\n // entities within a Markdown code span.\n text = text.replace(/&/g, \"&\");\n\n // Do the angle bracket song and dance:\n text = text.replace(//g, \">\");\n\n // Now, escape characters that are magic in Markdown:\n text = escapeCharacters(text, \"*_{}[]\\\\\", false);\n\n // jj the line above breaks this:\n //---\n\n //* Item\n\n // 1. Subitem\n\n // special char: *\n //---\n\n return text;\n };\n\n var _DoItalicsAndBold = function (text) {\n // must go first:\n text = text.replace(\n /(\\*\\*|__)(?=\\S)([^\\r]*?\\S[*_]*)\\1/g,\n \"$2\"\n );\n\n text = text.replace(/(\\*|_)(?=\\S)([^\\r]*?\\S)\\1/g, \"$2\");\n\n return text;\n };\n\n var _DoBlockQuotes = function (text) {\n /*\n text = text.replace(/\n (\t\t\t\t\t\t\t\t// Wrap whole match in $1\n (\n ^[ \\t]*>[ \\t]?\t\t\t// '>' at the start of a line\n .+\\n\t\t\t\t\t// rest of the first line\n (.+\\n)*\t\t\t\t\t// subsequent consecutive lines\n \\n*\t\t\t\t\t\t// blanks\n )+\n )\n /gm, function(){...});\n */\n\n text = text.replace(\n /((^[ \\t]*>[ \\t]?.+\\n(.+\\n)*\\n*)+)/gm,\n function (wholeMatch, m1) {\n var bq = m1;\n\n // attacklab: hack around Konqueror 3.5.4 bug:\n // \"----------bug\".replace(/^-/g,\"\") == \"bug\"\n\n bq = bq.replace(/^[ \\t]*>[ \\t]?/gm, \"~0\"); // trim one level of quoting\n\n // attacklab: clean up hack\n bq = bq.replace(/~0/g, \"\");\n\n bq = bq.replace(/^[ \\t]+$/gm, \"\"); // trim whitespace-only lines\n bq = _RunBlockGamut(bq); // recurse\n\n bq = bq.replace(/(^|\\n)/g, \"$1 \");\n // These leading spaces screw with
content, so we need to fix that:\n bq = bq.replace(\n /(\\s*
[^\\r]+?<\\/pre>)/gm,\n function (wholeMatch, m1) {\n var pre = m1;\n // attacklab: hack around Konqueror 3.5.4 bug:\n pre = pre.replace(/^ /gm, \"~0\");\n pre = pre.replace(/~0/g, \"\");\n return pre;\n }\n );\n\n return hashBlock(\"
\\n\" + bq + \"\\n
\");\n }\n );\n return text;\n };\n\n var _FormParagraphs = function (text) {\n //\n // Params:\n // $text - string to process with html
tags\n //\n\n // Strip leading and trailing lines:\n text = text.replace(/^\\n+/g, \"\");\n text = text.replace(/\\n+$/g, \"\");\n\n var grafs = text.split(/\\n{2,}/g);\n var grafsOut = new Array();\n\n //\n // Wrap
tags.\n //\n var end = grafs.length;\n for (var i = 0; i < end; i++) {\n var str = grafs[i];\n\n // if this is an HTML marker, copy it\n if (str.search(/~K(\\d+)K/g) >= 0) {\n grafsOut.push(str);\n } else if (str.search(/\\S/) >= 0) {\n str = _RunSpanGamut(str);\n str = str.replace(/^([ \\t]*)/g, \"
\");\n str += \"
\";\n grafsOut.push(str);\n }\n }\n\n //\n // Unhashify HTML blocks\n //\n end = grafsOut.length;\n for (var i = 0; i < end; i++) {\n // if this is a marker for an html block...\n while (grafsOut[i].search(/~K(\\d+)K/) >= 0) {\n var blockText = g_html_blocks[RegExp.$1];\n blockText = blockText.replace(/\\$/g, \"$$$$\"); // Escape any dollar signs\n grafsOut[i] = grafsOut[i].replace(/~K\\d+K/, blockText);\n }\n }\n\n return grafsOut.join(\"\\n\\n\");\n };\n\n var _EncodeAmpsAndAngles = function (text) {\n // Smart processing for ampersands and angle brackets that need to be encoded.\n\n // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:\n // http://bumppo.net/projects/amputator/\n text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\\w+);)/g, \"&\");\n\n // Encode naked <'s\n text = text.replace(/<(?![a-z\\/?\\$!])/gi, \"<\");\n\n return text;\n };\n\n var _EncodeBackslashEscapes = function (text) {\n //\n // Parameter: String.\n // Returns:\tThe string, with after processing the following backslash\n // escape sequences.\n //\n\n // attacklab: The polite way to do this is with the new\n // escapeCharacters() function:\n //\n // text = escapeCharacters(text,\"\\\\\",true);\n // text = escapeCharacters(text,\"`*_{}[]()>#+-.!\",true);\n //\n // ...but we're sidestepping its use of the (slow) RegExp constructor\n // as an optimization for Firefox. This function gets called a LOT.\n\n text = text.replace(/\\\\(\\\\)/g, escapeCharacters_callback);\n text = text.replace(/\\\\([`*_{}\\[\\]()>#+-.!])/g, escapeCharacters_callback);\n return text;\n };\n\n var _DoAutoLinks = function (text) {\n text = text.replace(\n /<((https?|ftp|dict):[^'\">\\s]+)>/gi,\n '$1'\n );\n\n // Email addresses: \n\n /*\n text = text.replace(/\n <\n (?:mailto:)?\n (\n [-.\\w]+\n \\@\n [-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]+\n )\n >\n /gi, _DoAutoLinks_callback());\n */\n text = text.replace(\n /<(?:mailto:)?([-.\\w]+\\@[-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]+)>/gi,\n function (wholeMatch, m1) {\n return _EncodeEmailAddress(_UnescapeSpecialChars(m1));\n }\n );\n\n return text;\n };\n\n var _EncodeEmailAddress = function (addr) {\n //\n // Input: an email address, e.g. \"foo@example.com\"\n //\n // Output: the email address as a mailto link, with each character\n //\tof the address encoded as either a decimal or hex entity, in\n //\tthe hopes of foiling most address harvesting spam bots. E.g.:\n //\n //\tfoo\n // @example.com\n //\n // Based on a filter by Matthew Wickline, posted to the BBEdit-Talk\n // mailing list: \n //\n\n // attacklab: why can't javascript speak hex?\n function char2hex(ch) {\n var hexDigits = \"0123456789ABCDEF\";\n var dec = ch.charCodeAt(0);\n return hexDigits.charAt(dec >> 4) + hexDigits.charAt(dec & 15);\n }\n\n var encode = [\n function (ch) {\n return \"\" + ch.charCodeAt(0) + \";\";\n },\n function (ch) {\n return \"\" + char2hex(ch) + \";\";\n },\n function (ch) {\n return ch;\n }\n ];\n\n addr = \"mailto:\" + addr;\n\n addr = addr.replace(/./g, function (ch) {\n if (ch == \"@\") {\n // this *must* be encoded. I insist.\n ch = encode[Math.floor(Math.random() * 2)](ch);\n } else if (ch != \":\") {\n // leave ':' alone (to spot mailto: later)\n var r = Math.random();\n // roughly 10% raw, 45% hex, 45% dec\n ch = r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch);\n }\n return ch;\n });\n\n addr = '' + addr + \"\";\n addr = addr.replace(/\">.+:/g, '\">'); // strip the mailto: from the visible part\n\n return addr;\n };\n\n var _UnescapeSpecialChars = function (text) {\n //\n // Swap back in all the special characters we've hidden.\n //\n text = text.replace(/~E(\\d+)E/g, function (wholeMatch, m1) {\n var charCodeToReplace = parseInt(m1);\n return String.fromCharCode(charCodeToReplace);\n });\n return text;\n };\n\n var _Outdent = function (text) {\n //\n // Remove one level of line-leading tabs or spaces\n //\n\n // attacklab: hack around Konqueror 3.5.4 bug:\n // \"----------bug\".replace(/^-/g,\"\") == \"bug\"\n\n text = text.replace(/^(\\t|[ ]{1,4})/gm, \"~0\"); // attacklab: g_tab_width\n\n // attacklab: clean up hack\n text = text.replace(/~0/g, \"\");\n\n return text;\n };\n\n var _Detab = function (text) {\n // attacklab: Detab's completely rewritten for speed.\n // In perl we could fix it by anchoring the regexp with \\G.\n // In javascript we're less fortunate.\n\n // expand first n-1 tabs\n text = text.replace(/\\t(?=\\t)/g, \" \"); // attacklab: g_tab_width\n\n // replace the nth with two sentinels\n text = text.replace(/\\t/g, \"~A~B\");\n\n // use the sentinel to anchor our regex so it doesn't explode\n text = text.replace(/~B(.+?)~A/g, function (wholeMatch, m1, m2) {\n var leadingText = m1;\n var numSpaces = 4 - (leadingText.length % 4); // attacklab: g_tab_width\n\n // there *must* be a better way to do this:\n for (var i = 0; i < numSpaces; i++) leadingText += \" \";\n\n return leadingText;\n });\n\n // clean up sentinels\n text = text.replace(/~A/g, \" \"); // attacklab: g_tab_width\n text = text.replace(/~B/g, \"\");\n\n return text;\n };\n\n //\n // attacklab: Utility functions\n //\n\n var escapeCharacters = function (text, charsToEscape, afterBackslash) {\n // First we have to escape the escape characters so that\n // we can build a character class out of them\n var regexString =\n \"([\" + charsToEscape.replace(/([\\[\\]\\\\])/g, \"\\\\$1\") + \"])\";\n\n if (afterBackslash) {\n regexString = \"\\\\\\\\\" + regexString;\n }\n\n var regex = new RegExp(regexString, \"g\");\n text = text.replace(regex, escapeCharacters_callback);\n\n return text;\n };\n\n var escapeCharacters_callback = function (wholeMatch, m1) {\n var charCodeToEscape = m1.charCodeAt(0);\n return \"~E\" + charCodeToEscape + \"E\";\n };\n}; // end of Showdown.converter\n\nexport default Showdown;\n","import { default as Showdown } from \"$showdown\";\nexport { converter };\n\nconst converter = new Showdown.converter();\n\nconst orig = converter.makeHtml.bind(converter);\nconverter.makeHtml = (text, inline) =>\n orig(text, inline).replace(/ {\n const container = doc.querySelector(\".p-info-sources--content\");\n const infoButton = doc.createElement(\"span\");\n infoButton.className = \"p-info-sources--toggleSpan\";\n infoButton.innerHTML = `\n \n `;\n\n $(doc).on(\"bb:postHandleData\", (_e, data) => {\n toggleInfosource(null, false);\n if (data && data.informationsources && data.informationsources.length) {\n container.querySelectorAll(\".p-info-source--item\").forEach(old => {\n container.removeChild(old);\n });\n const info = data.informationsources.map(getInfo);\n info.forEach(item => {\n let template = `\n