').append(btn.title);\n }\n } else if (btn.list) {\n // Add button to list\n button.addClass('push_button');\n $('#' + btn.list + '_opts').append(button);\n if (btn.isDefault) {\n $('#cur_' + btn.list).append(button.children().clone());\n const svgicon = btn.svgicon || btn.id;\n placementObj['#cur_' + btn.list] = svgicon;\n }\n } else if (btn.includeWith) {\n // Add to flyout menu / make flyout menu\n const opts = btn.includeWith;\n // opts.button, default, position\n refBtn = $(opts.button);\n\n flyoutHolder = refBtn.parent();\n // Create a flyout menu if there isn't one already\n let tlsId;\n if (!refBtn.parent().hasClass('tools_flyout')) {\n // Create flyout placeholder\n tlsId = refBtn[0].id.replace('tool_', 'tools_');\n showBtn = refBtn.clone()\n .attr('id', tlsId + '_show')\n .append($('
', {class: 'flyout_arrow_horiz'}));\n\n refBtn.before(showBtn);\n // Create a flyout div\n flyoutHolder = makeFlyoutHolder(tlsId, refBtn);\n }\n\n refData = Actions.getButtonData(opts.button);\n\n if (opts.isDefault) {\n placementObj['#' + tlsId + '_show'] = btn.id;\n }\n // TODO: Find way to set the current icon using the iconloader if this is not default\n\n // Include data for extension button as well as ref button\n const curH = holders['#' + flyoutHolder[0].id] = [{\n sel: '#' + id,\n fn: btn.events.click,\n icon: btn.id,\n key: btn.key,\n isDefault: Boolean(btn.includeWith && btn.includeWith.isDefault)\n }, refData];\n\n // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'}\n\n const pos = ('position' in opts) ? opts.position : 'last';\n const len = flyoutHolder.children().length;\n\n // Add at given position or end\n if (!isNaN(pos) && pos >= 0 && pos < len) {\n flyoutHolder.children().eq(pos).before(button);\n } else {\n flyoutHolder.append(button);\n curH.reverse();\n }\n }\n\n if (!svgicons) {\n button.append(icon);\n }\n\n if (!btn.list) {\n // Add given events to button\n $.each(btn.events, function (name, func) {\n if (name === 'click' && btn.type === 'mode') {\n // `touch.js` changes `touchstart` to `mousedown`,\n // so we must map extension click events as well\n if (isTouch() && name === 'click') {\n name = 'mousedown';\n }\n if (btn.includeWith) {\n button.bind(name, func);\n } else {\n button.bind(name, function () {\n if (toolButtonClick(button)) {\n func();\n }\n });\n }\n if (btn.key) {\n $(document).bind('keydown', btn.key, func);\n if (btn.title) {\n button.attr('title', btn.title + ' [' + btn.key + ']');\n }\n }\n } else {\n button.bind(name, func);\n }\n });\n }\n\n setupFlyouts(holders);\n });\n\n $.each(btnSelects, function () {\n addAltDropDown(this.elem, this.list, this.callback, {seticon: true});\n });\n\n if (svgicons) {\n return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new\n $.svgIcons(svgicons, {\n w: 24, h: 24,\n id_match: false,\n no_img: (!isWebkit()),\n fallback: fallbackObj,\n placement: placementObj,\n callback (icons) {\n // Non-ideal hack to make the icon match the current size\n // if (curPrefs.iconsize && curPrefs.iconsize !== 'm') {\n if (editor.pref('iconsize') !== 'm') {\n prepResize();\n }\n runCallback();\n resolve();\n }\n });\n });\n }\n }\n return runCallback();\n };\n\n /**\n * @param {string} color\n * @param {Float} opac\n * @param {string} type\n * @returns {module:jGraduate~Paint}\n */\n const getPaint = function (color, opac, type) {\n // update the editor's fill paint\n const opts = {alpha: opac};\n if (color.startsWith('url(#')) {\n let refElem = svgCanvas.getRefElem(color);\n if (refElem) {\n refElem = refElem.cloneNode(true);\n } else {\n refElem = $('#' + type + '_color defs *')[0];\n }\n opts[refElem.tagName] = refElem;\n } else if (color.startsWith('#')) {\n opts.solidColor = color.substr(1);\n } else {\n opts.solidColor = 'none';\n }\n return new $.jGraduate.Paint(opts);\n };\n\n // $('#text').focus(function () { textBeingEntered = true; });\n // $('#text').blur(function () { textBeingEntered = false; });\n\n // bind the selected event to our function that handles updates to the UI\n svgCanvas.bind('selected', selectedChanged);\n svgCanvas.bind('transition', elementTransition);\n svgCanvas.bind('changed', elementChanged);\n svgCanvas.bind('saved', saveHandler);\n svgCanvas.bind('exported', exportHandler);\n svgCanvas.bind('exportedPDF', function (win, data) {\n if (!data.output) { // Ignore Chrome\n return;\n }\n const {exportWindowName} = data;\n if (exportWindowName) {\n exportWindow = window.open('', exportWindowName); // A hack to get the window via JSON-able name without opening a new one\n }\n if (!exportWindow || exportWindow.closed) {\n /* await */ $.alert(uiStrings.notification.popupWindowBlocked);\n return;\n }\n exportWindow.location.href = data.output;\n });\n svgCanvas.bind('zoomed', zoomChanged);\n svgCanvas.bind('zoomDone', zoomDone);\n svgCanvas.bind(\n 'updateCanvas',\n /**\n * @param {external:Window} win\n * @param {PlainObject} centerInfo\n * @param {false} centerInfo.center\n * @param {module:math.XYObject} centerInfo.newCtr\n * @listens module:svgcanvas.SvgCanvas#event:updateCanvas\n * @returns {void}\n */\n function (win, {center, newCtr}) {\n updateCanvas(center, newCtr);\n }\n );\n svgCanvas.bind('contextset', contextChanged);\n svgCanvas.bind('extension_added', extAdded);\n svgCanvas.textActions.setInputElem($('#text')[0]);\n\n let str = '
';\n $.each(palette, function (i, item) {\n str += '
';\n });\n $('#palette').append(str);\n\n // Set up editor background functionality\n const colorBlocks = ['#FFF', '#888', '#000', 'chessboard'];\n str = '';\n $.each(colorBlocks, function (i, e) {\n if (e === 'chessboard') {\n str += '
';\n } else {\n str += '
';\n }\n });\n $('#bg_blocks').append(str);\n const blocks = $('#bg_blocks div');\n const curBg = 'cur_background';\n blocks.each(function () {\n const blk = $(this);\n blk.click(function () {\n blocks.removeClass(curBg);\n $(this).addClass(curBg);\n });\n });\n\n setBackground(editor.pref('bkgd_color'), editor.pref('bkgd_url'));\n\n $('#image_save_opts input').val([editor.pref('img_save')]);\n\n /**\n * @type {module:jQuerySpinButton.ValueCallback}\n */\n const changeRectRadius = function (ctl) {\n svgCanvas.setRectRadius(ctl.value);\n };\n\n /**\n * @type {module:jQuerySpinButton.ValueCallback}\n */\n const changeFontSize = function (ctl) {\n svgCanvas.setFontSize(ctl.value);\n };\n\n /**\n * @type {module:jQuerySpinButton.ValueCallback}\n */\n const changeStrokeWidth = function (ctl) {\n let val = ctl.value;\n if (val === 0 && selectedElement && ['line', 'polyline'].includes(selectedElement.nodeName)) {\n val = ctl.value = 1;\n }\n svgCanvas.setStrokeWidth(val);\n };\n\n /**\n * @type {module:jQuerySpinButton.ValueCallback}\n */\n const changeRotationAngle = function (ctl) {\n svgCanvas.setRotationAngle(ctl.value);\n $('#tool_reorient').toggleClass('disabled', Number.parseInt(ctl.value) === 0);\n };\n\n /**\n * @param {external:jQuery.fn.SpinButton} ctl Spin Button\n * @param {string} [val=ctl.value]\n * @returns {void}\n */\n const changeOpacity = function (ctl, val) {\n if (Utils.isNullish(val)) { val = ctl.value; }\n $('#group_opacity').val(val);\n if (!ctl || !ctl.handle) {\n $('#opac_slider').slider('option', 'value', val);\n }\n svgCanvas.setOpacity(val / 100);\n };\n\n /**\n * @param {external:jQuery.fn.SpinButton} ctl Spin Button\n * @param {string} [val=ctl.value]\n * @param {boolean} noUndo\n * @returns {void}\n */\n const changeBlur = function (ctl, val, noUndo) {\n if (Utils.isNullish(val)) { val = ctl.value; }\n $('#blur').val(val);\n let complete = false;\n if (!ctl || !ctl.handle) {\n $('#blur_slider').slider('option', 'value', val);\n complete = true;\n }\n if (noUndo) {\n svgCanvas.setBlurNoUndo(val);\n } else {\n svgCanvas.setBlur(val, complete);\n }\n };\n\n $('#stroke_style').change(function () {\n svgCanvas.setStrokeAttr('stroke-dasharray', $(this).val());\n operaRepaint();\n });\n\n $('#stroke_linejoin').change(function () {\n svgCanvas.setStrokeAttr('stroke-linejoin', $(this).val());\n operaRepaint();\n });\n\n // Lose focus for select elements when changed (Allows keyboard shortcuts to work better)\n $('select').change(function () { $(this).blur(); });\n\n // fired when user wants to move elements to another layer\n let promptMoveLayerOnce = false;\n $('#selLayerNames').change(async function () {\n const destLayer = this.options[this.selectedIndex].value;\n const confirmStr = uiStrings.notification.QmoveElemsToLayer.replace('%s', destLayer);\n /**\n * @param {boolean} ok\n * @returns {void}\n */\n const moveToLayer = function (ok) {\n if (!ok) { return; }\n promptMoveLayerOnce = true;\n svgCanvas.moveSelectedToLayer(destLayer);\n svgCanvas.clearSelection();\n populateLayers();\n };\n if (destLayer) {\n if (promptMoveLayerOnce) {\n moveToLayer(true);\n } else {\n const ok = await $.confirm(confirmStr);\n if (!ok) {\n return;\n }\n moveToLayer(true);\n }\n }\n });\n\n $('#font_family').change(function () {\n svgCanvas.setFontFamily(this.value);\n });\n\n $('#seg_type').change(function () {\n svgCanvas.setSegType($(this).val());\n });\n\n $('#text').bind('keyup input', function () {\n svgCanvas.setTextContent(this.value);\n });\n\n $('#image_url').change(function () {\n setImageURL(this.value);\n });\n\n $('#link_url').change(function () {\n if (this.value.length) {\n svgCanvas.setLinkURL(this.value);\n } else {\n svgCanvas.removeHyperlink();\n }\n });\n\n $('#g_title').change(function () {\n svgCanvas.setGroupTitle(this.value);\n });\n\n $('.attr_changer').change(function () {\n const attr = this.getAttribute('data-attr');\n let val = this.value;\n const valid = isValidUnit(attr, val, selectedElement);\n\n if (!valid) {\n this.value = selectedElement.getAttribute(attr);\n /* await */ $.alert(uiStrings.notification.invalidAttrValGiven);\n return false;\n }\n\n if (attr !== 'id' && attr !== 'class') {\n if (isNaN(val)) {\n val = svgCanvas.convertToNum(attr, val);\n } else if (curConfig.baseUnit !== 'px') {\n // Convert unitless value to one with given unit\n\n const unitData = getTypeMap();\n\n if (selectedElement[attr] || svgCanvas.getMode() === 'pathedit' || attr === 'x' || attr === 'y') {\n val *= unitData[curConfig.baseUnit];\n }\n }\n }\n\n // if the user is changing the id, then de-select the element first\n // change the ID, then re-select it with the new ID\n if (attr === 'id') {\n const elem = selectedElement;\n svgCanvas.clearSelection();\n elem.id = val;\n svgCanvas.addToSelection([elem], true);\n } else {\n svgCanvas.changeSelectedAttribute(attr, val);\n }\n this.blur();\n return true;\n });\n\n // Prevent selection of elements when shift-clicking\n $('#palette').mouseover(function () {\n const inp = $('
');\n $(this).append(inp);\n inp.focus().remove();\n });\n\n $('.palette_item').mousedown(function (evt) {\n // shift key or right click for stroke\n const picker = evt.shiftKey || evt.button === 2 ? 'stroke' : 'fill';\n let color = $(this).data('rgb');\n let paint;\n\n // Webkit-based browsers returned 'initial' here for no stroke\n if (color === 'none' || color === 'transparent' || color === 'initial') {\n color = 'none';\n paint = new $.jGraduate.Paint();\n } else {\n paint = new $.jGraduate.Paint({alpha: 100, solidColor: color.substr(1)});\n }\n\n paintBox[picker].setPaint(paint);\n svgCanvas.setColor(picker, color);\n\n if (color !== 'none' && svgCanvas.getPaintOpacity(picker) !== 1) {\n svgCanvas.setPaintOpacity(picker, 1.0);\n }\n updateToolButtonState();\n }).bind('contextmenu', function (e) { e.preventDefault(); });\n\n $('#toggle_stroke_tools').on('click', function () {\n $('#tools_bottom').toggleClass('expanded');\n });\n\n (function () {\n const wArea = workarea[0];\n\n let lastX = null, lastY = null,\n panning = false, keypan = false;\n\n $('#svgcanvas').bind('mousemove mouseup', function (evt) {\n if (panning === false) { return true; }\n\n wArea.scrollLeft -= (evt.clientX - lastX);\n wArea.scrollTop -= (evt.clientY - lastY);\n\n lastX = evt.clientX;\n lastY = evt.clientY;\n\n if (evt.type === 'mouseup') { panning = false; }\n return false;\n }).mousedown(function (evt) {\n if (evt.button === 1 || keypan === true) {\n panning = true;\n lastX = evt.clientX;\n lastY = evt.clientY;\n return false;\n }\n return true;\n });\n\n $(window).mouseup(function () {\n panning = false;\n });\n\n $(document).bind('keydown', 'space', function (evt) {\n svgCanvas.spaceKey = keypan = true;\n evt.preventDefault();\n }).bind('keyup', 'space', function (evt) {\n evt.preventDefault();\n svgCanvas.spaceKey = keypan = false;\n }).bind('keydown', 'shift', function (evt) {\n if (svgCanvas.getMode() === 'zoom') {\n workarea.css('cursor', zoomOutIcon);\n }\n }).bind('keyup', 'shift', function (evt) {\n if (svgCanvas.getMode() === 'zoom') {\n workarea.css('cursor', zoomInIcon);\n }\n });\n\n /**\n * @function module:SVGEditor.setPanning\n * @param {boolean} active\n * @returns {void}\n */\n editor.setPanning = function (active) {\n svgCanvas.spaceKey = keypan = active;\n };\n }());\n\n (function () {\n const button = $('#main_icon');\n const overlay = $('#main_icon span');\n const list = $('#main_menu');\n\n let onButton = false;\n let height = 0;\n let jsHover = true;\n let setClick = false;\n\n /*\n // Currently unused\n const hideMenu = function () {\n list.fadeOut(200);\n };\n */\n\n $(window).mouseup(function (evt) {\n if (!onButton) {\n button.removeClass('buttondown');\n // do not hide if it was the file input as that input needs to be visible\n // for its change event to fire\n if (evt.target.tagName !== 'INPUT') {\n list.fadeOut(200);\n } else if (!setClick) {\n setClick = true;\n $(evt.target).click(function () {\n list.css('margin-left', '-9999px').show();\n });\n }\n }\n onButton = false;\n }).mousedown(function (evt) {\n // $('.contextMenu').hide();\n const islib = $(evt.target).closest('div.tools_flyout, .contextMenu').length;\n if (!islib) {\n $('.tools_flyout:visible,.contextMenu').fadeOut(250);\n }\n });\n\n overlay.bind('mousedown', function () {\n if (!button.hasClass('buttondown')) {\n // Margin must be reset in case it was changed before;\n list.css('margin-left', 0).show();\n if (!height) {\n height = list.height();\n }\n // Using custom animation as slideDown has annoying 'bounce effect'\n list.css('height', 0).animate({\n height\n }, 200);\n onButton = true;\n } else {\n list.fadeOut(200);\n }\n button.toggleClass('buttondown buttonup');\n }).hover(function () {\n onButton = true;\n }).mouseout(function () {\n onButton = false;\n });\n\n const listItems = $('#main_menu li');\n\n // Check if JS method of hovering needs to be used (Webkit bug)\n listItems.mouseover(function () {\n jsHover = ($(this).css('background-color') === 'rgba(0, 0, 0, 0)');\n\n listItems.unbind('mouseover');\n if (jsHover) {\n listItems.mouseover(function () {\n this.style.backgroundColor = '#FFC';\n }).mouseout(function () {\n this.style.backgroundColor = 'transparent';\n return true;\n });\n }\n });\n }());\n // Made public for UI customization.\n // TODO: Group UI functions into a public editor.ui interface.\n /**\n * See {@link http://api.jquery.com/bind/#bind-eventType-eventData-handler}.\n * @callback module:SVGEditor.DropDownCallback\n * @param {external:jQuery.Event} ev See {@link http://api.jquery.com/Types/#Event}\n * @listens external:jQuery.Event\n * @returns {void|boolean} Calls `preventDefault()` and `stopPropagation()`\n */\n /**\n * @function module:SVGEditor.addDropDown\n * @param {Element|string} elem DOM Element or selector\n * @param {module:SVGEditor.DropDownCallback} callback Mouseup callback\n * @param {boolean} dropUp\n * @returns {void}\n */\n editor.addDropDown = function (elem, callback, dropUp) {\n if (!$(elem).length) { return; } // Quit if called on non-existent element\n const button = $(elem).find('button');\n const list = $(elem).find('ul').attr('id', $(elem)[0].id + '-list');\n if (dropUp) {\n $(elem).addClass('dropup');\n } else {\n // Move list to place where it can overflow container\n $('#option_lists').append(list);\n }\n list.find('li').bind('mouseup', callback);\n\n let onButton = false;\n $(window).mouseup(function (evt) {\n if (!onButton) {\n button.removeClass('down');\n list.hide();\n }\n onButton = false;\n });\n\n button.bind('mousedown', function () {\n if (!button.hasClass('down')) {\n if (!dropUp) {\n const pos = $(elem).position();\n list.css({\n top: pos.top + 24,\n left: pos.left - 10\n });\n }\n list.show();\n onButton = true;\n } else {\n list.hide();\n }\n button.toggleClass('down');\n }).hover(function () {\n onButton = true;\n }).mouseout(function () {\n onButton = false;\n });\n };\n\n editor.addDropDown('#font_family_dropdown', function () {\n $('#font_family').val($(this).text()).change();\n });\n\n editor.addDropDown('#opacity_dropdown', function () {\n if ($(this).find('div').length) { return; }\n const perc = Number.parseInt($(this).text().split('%')[0]);\n changeOpacity(false, perc);\n }, true);\n\n // For slider usage, see: http://jqueryui.com/demos/slider/\n $('#opac_slider').slider({\n start () {\n $('#opacity_dropdown li:not(.special)').hide();\n },\n stop () {\n $('#opacity_dropdown li').show();\n $(window).mouseup();\n },\n slide (evt, ui) {\n changeOpacity(ui);\n }\n });\n\n editor.addDropDown('#blur_dropdown', $.noop);\n\n let slideStart = false;\n $('#blur_slider').slider({\n max: 10,\n step: 0.1,\n stop (evt, ui) {\n slideStart = false;\n changeBlur(ui);\n $('#blur_dropdown li').show();\n $(window).mouseup();\n },\n start () {\n slideStart = true;\n },\n slide (evt, ui) {\n changeBlur(ui, null, slideStart);\n }\n });\n\n editor.addDropDown('#zoom_dropdown', function () {\n const item = $(this);\n const val = item.data('val');\n if (val) {\n zoomChanged(window, val);\n } else {\n changeZoom({value: Number.parseFloat(item.text())});\n }\n }, true);\n\n addAltDropDown('#stroke_linecap', '#linecap_opts', function () {\n setStrokeOpt(this, true);\n }, {dropUp: true});\n\n addAltDropDown('#stroke_linejoin', '#linejoin_opts', function () {\n setStrokeOpt(this, true);\n }, {dropUp: true});\n\n addAltDropDown('#tool_position', '#position_opts', function () {\n const letter = this.id.replace('tool_pos', '').charAt(0);\n svgCanvas.alignSelectedElements(letter, 'page');\n }, {multiclick: true});\n\n /*\n\n When a flyout icon is selected\n (if flyout) {\n - Change the icon\n - Make pressing the button run its stuff\n }\n - Run its stuff\n\n When its shortcut key is pressed\n - If not current in list, do as above\n , else:\n - Just run its stuff\n\n */\n\n // Unfocus text input when workarea is mousedowned.\n (function () {\n let inp;\n /**\n *\n * @returns {void}\n */\n const unfocus = function () {\n $(inp).blur();\n };\n\n $('#svg_editor').find('button, select, input:not(#text)').focus(function () {\n inp = this;\n uiContext = 'toolbars';\n workarea.mousedown(unfocus);\n }).blur(function () {\n uiContext = 'canvas';\n workarea.unbind('mousedown', unfocus);\n // Go back to selecting text if in textedit mode\n if (svgCanvas.getMode() === 'textedit') {\n $('#text').focus();\n }\n });\n }());\n\n /**\n *\n * @returns {void}\n */\n const clickFHPath = function () {\n if (toolButtonClick('#tool_fhpath')) {\n svgCanvas.setMode('fhpath');\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickLine = function () {\n if (toolButtonClick('#tool_line')) {\n svgCanvas.setMode('line');\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickSquare = function () {\n if (toolButtonClick('#tool_square')) {\n svgCanvas.setMode('square');\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickRect = function () {\n if (toolButtonClick('#tool_rect')) {\n svgCanvas.setMode('rect');\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickFHRect = function () {\n if (toolButtonClick('#tool_fhrect')) {\n svgCanvas.setMode('fhrect');\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickCircle = function () {\n if (toolButtonClick('#tool_circle')) {\n svgCanvas.setMode('circle');\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickEllipse = function () {\n if (toolButtonClick('#tool_ellipse')) {\n svgCanvas.setMode('ellipse');\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickFHEllipse = function () {\n if (toolButtonClick('#tool_fhellipse')) {\n svgCanvas.setMode('fhellipse');\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickImage = function () {\n if (toolButtonClick('#tool_image')) {\n svgCanvas.setMode('image');\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickZoom = function () {\n if (toolButtonClick('#tool_zoom')) {\n svgCanvas.setMode('zoom');\n workarea.css('cursor', zoomInIcon);\n }\n };\n\n /**\n * @param {Float} multiplier\n * @returns {void}\n */\n const zoomImage = function (multiplier) {\n const res = svgCanvas.getResolution();\n multiplier = multiplier ? res.zoom * multiplier : 1;\n // setResolution(res.w * multiplier, res.h * multiplier, true);\n $('#zoom').val(multiplier * 100);\n svgCanvas.setZoom(multiplier);\n zoomDone();\n updateCanvas(true);\n };\n\n /**\n *\n * @returns {void}\n */\n const dblclickZoom = function () {\n if (toolButtonClick('#tool_zoom')) {\n zoomImage();\n setSelectMode();\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickText = function () {\n if (toolButtonClick('#tool_text')) {\n svgCanvas.setMode('text');\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickPath = function () {\n if (toolButtonClick('#tool_path')) {\n svgCanvas.setMode('path');\n }\n };\n\n /**\n * Delete is a contextual tool that only appears in the ribbon if\n * an element has been selected.\n * @returns {void}\n */\n const deleteSelected = function () {\n if (!Utils.isNullish(selectedElement) || multiselected) {\n svgCanvas.deleteSelectedElements();\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const cutSelected = function () {\n if (!Utils.isNullish(selectedElement) || multiselected) {\n svgCanvas.cutSelectedElements();\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const copySelected = function () {\n if (!Utils.isNullish(selectedElement) || multiselected) {\n svgCanvas.copySelectedElements();\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const pasteInCenter = function () {\n const zoom = svgCanvas.getZoom();\n const x = (workarea[0].scrollLeft + workarea.width() / 2) / zoom - svgCanvas.contentW;\n const y = (workarea[0].scrollTop + workarea.height() / 2) / zoom - svgCanvas.contentH;\n svgCanvas.pasteElements('point', x, y);\n };\n\n /**\n *\n * @returns {void}\n */\n const moveToTopSelected = function () {\n if (!Utils.isNullish(selectedElement)) {\n svgCanvas.moveToTopSelectedElement();\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const moveToBottomSelected = function () {\n if (!Utils.isNullish(selectedElement)) {\n svgCanvas.moveToBottomSelectedElement();\n }\n };\n\n /**\n * @param {\"Up\"|\"Down\"} dir\n * @returns {void}\n */\n const moveUpDownSelected = function (dir) {\n if (!Utils.isNullish(selectedElement)) {\n svgCanvas.moveUpDownSelected(dir);\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const convertToPath = function () {\n if (!Utils.isNullish(selectedElement)) {\n svgCanvas.convertToPath();\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const reorientPath = function () {\n if (!Utils.isNullish(selectedElement)) {\n path.reorient();\n }\n };\n\n /**\n *\n * @returns {Promise
} Resolves to `undefined`\n */\n const makeHyperlink = async function () {\n if (!Utils.isNullish(selectedElement) || multiselected) {\n const url = await $.prompt(uiStrings.notification.enterNewLinkURL, 'http://');\n if (url) {\n svgCanvas.makeHyperlink(url);\n }\n }\n };\n\n /**\n * @param {Float} dx\n * @param {Float} dy\n * @returns {void}\n */\n const moveSelected = function (dx, dy) {\n if (!Utils.isNullish(selectedElement) || multiselected) {\n if (curConfig.gridSnapping) {\n // Use grid snap value regardless of zoom level\n const multi = svgCanvas.getZoom() * curConfig.snappingStep;\n dx *= multi;\n dy *= multi;\n }\n svgCanvas.moveSelectedElements(dx, dy);\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const linkControlPoints = function () {\n $('#tool_node_link').toggleClass('push_button_pressed tool_button');\n const linked = $('#tool_node_link').hasClass('push_button_pressed');\n path.linkControlPoints(linked);\n };\n\n /**\n *\n * @returns {void}\n */\n const clonePathNode = function () {\n if (path.getNodePoint()) {\n path.clonePathNode();\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const deletePathNode = function () {\n if (path.getNodePoint()) {\n path.deletePathNode();\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const addSubPath = function () {\n const button = $('#tool_add_subpath');\n const sp = !button.hasClass('push_button_pressed');\n button.toggleClass('push_button_pressed tool_button');\n path.addSubPath(sp);\n };\n\n /**\n *\n * @returns {void}\n */\n const opencloseSubPath = function () {\n path.opencloseSubPath();\n };\n\n /**\n *\n * @returns {void}\n */\n const selectNext = function () {\n svgCanvas.cycleElement(1);\n };\n\n /**\n *\n * @returns {void}\n */\n const selectPrev = function () {\n svgCanvas.cycleElement(0);\n };\n\n /**\n * @param {0|1} cw\n * @param {Integer} step\n * @returns {void}\n */\n const rotateSelected = function (cw, step) {\n if (Utils.isNullish(selectedElement) || multiselected) { return; }\n if (!cw) { step *= -1; }\n const angle = Number.parseFloat($('#angle').val()) + step;\n svgCanvas.setRotationAngle(angle);\n updateContextPanel();\n };\n\n /**\n * @fires module:svgcanvas.SvgCanvas#event:ext_onNewDocument\n * @returns {Promise} Resolves to `undefined`\n */\n const clickClear = async function () {\n const [x, y] = curConfig.dimensions;\n const ok = await $.confirm(uiStrings.notification.QwantToClear);\n if (!ok) {\n return;\n }\n setSelectMode();\n svgCanvas.clear();\n svgCanvas.setResolution(x, y);\n updateCanvas(true);\n zoomImage();\n populateLayers();\n updateContextPanel();\n prepPaints();\n svgCanvas.runExtensions('onNewDocument');\n };\n\n /**\n *\n * @returns {false}\n */\n const clickBold = function () {\n svgCanvas.setBold(!svgCanvas.getBold());\n updateContextPanel();\n return false;\n };\n\n /**\n *\n * @returns {false}\n */\n const clickItalic = function () {\n svgCanvas.setItalic(!svgCanvas.getItalic());\n updateContextPanel();\n return false;\n };\n\n /**\n *\n * @returns {void}\n */\n const clickSave = function () {\n // In the future, more options can be provided here\n const saveOpts = {\n images: editor.pref('img_save'),\n round_digits: 6\n };\n svgCanvas.save(saveOpts);\n };\n\n let loadingURL;\n /**\n *\n * @returns {Promise} Resolves to `undefined`\n */\n const clickExport = async function () {\n const imgType = await $.select('Select an image type for export: ', [\n // See http://kangax.github.io/jstests/toDataUrl_mime_type_test/ for a useful list of MIME types and browser support\n // 'ICO', // Todo: Find a way to preserve transparency in SVG-Edit if not working presently and do full packaging for x-icon; then switch back to position after 'PNG'\n 'PNG',\n 'JPEG', 'BMP', 'WEBP', 'PDF'\n ], function () {\n const sel = $(this);\n if (sel.val() === 'JPEG' || sel.val() === 'WEBP') {\n if (!$('#image-slider').length) {\n $(``).appendTo(sel.parent());\n }\n } else {\n $('#image-slider').parent().remove();\n }\n }); // todo: replace hard-coded msg with uiStrings.notification.\n if (!imgType) {\n return;\n }\n // Open placeholder window (prevents popup)\n let exportWindowName;\n\n /**\n *\n * @returns {void}\n */\n function openExportWindow () {\n const {loadingImage} = uiStrings.notification;\n if (curConfig.exportWindowType === 'new') {\n editor.exportWindowCt++;\n }\n exportWindowName = curConfig.canvasName + editor.exportWindowCt;\n let popHTML, popURL;\n if (loadingURL) {\n popURL = loadingURL;\n } else {\n popHTML = `\n \n \n ${loadingImage}\n \n ${loadingImage}
\n `;\n if (typeof URL !== 'undefined' && URL.createObjectURL) {\n const blob = new Blob([popHTML], {type: 'text/html'});\n popURL = URL.createObjectURL(blob);\n } else {\n popURL = 'data:text/html;base64;charset=utf-8,' + Utils.encode64(popHTML);\n }\n loadingURL = popURL;\n }\n exportWindow = window.open(popURL, exportWindowName);\n }\n const chrome = isChrome();\n if (imgType === 'PDF') {\n if (!customExportPDF && !chrome) {\n openExportWindow();\n }\n svgCanvas.exportPDF(exportWindowName);\n } else {\n if (!customExportImage) {\n openExportWindow();\n }\n const quality = Number.parseInt($('#image-slider').val()) / 100;\n /* const results = */ await svgCanvas.rasterExport(imgType, quality, exportWindowName);\n }\n };\n\n /**\n * By default, svgCanvas.open() is a no-op. It is up to an extension\n * mechanism (opera widget, etc.) to call `setCustomHandlers()` which\n * will make it do something.\n * @returns {void}\n */\n const clickOpen = function () {\n svgCanvas.open();\n };\n\n /**\n *\n * @returns {void}\n */\n const clickImport = function () {\n /* */\n };\n\n /**\n *\n * @returns {void}\n */\n const clickUndo = function () {\n if (undoMgr.getUndoStackSize() > 0) {\n undoMgr.undo();\n populateLayers();\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickRedo = function () {\n if (undoMgr.getRedoStackSize() > 0) {\n undoMgr.redo();\n populateLayers();\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickGroup = function () {\n // group\n if (multiselected) {\n svgCanvas.groupSelectedElements();\n // ungroup\n } else if (selectedElement) {\n svgCanvas.ungroupSelectedElement();\n }\n };\n\n /**\n *\n * @returns {void}\n */\n const clickClone = function () {\n svgCanvas.cloneSelectedElements(20, 20);\n };\n\n /**\n *\n * @returns {void}\n */\n const clickAlign = function () {\n const letter = this.id.replace('tool_align', '').charAt(0);\n svgCanvas.alignSelectedElements(letter, $('#align_relative_to').val());\n };\n\n /**\n *\n * @returns {void}\n */\n const clickWireframe = function () {\n $('#tool_wireframe').toggleClass('push_button_pressed tool_button');\n workarea.toggleClass('wireframe');\n\n if (supportsNonSS) { return; }\n const wfRules = $('#wireframe_rules');\n if (!wfRules.length) {\n /* wfRules = */ $('').appendTo('head');\n } else {\n wfRules.empty();\n }\n\n updateWireFrame();\n };\n\n $('#svg_docprops_container, #svg_prefs_container').draggable({\n cancel: 'button,fieldset',\n containment: 'window'\n }).css('position', 'absolute');\n\n let docprops = false;\n let preferences = false;\n\n /**\n *\n * @returns {void}\n */\n const showDocProperties = function () {\n if (docprops) { return; }\n docprops = true;\n\n // This selects the correct radio button by using the array notation\n $('#image_save_opts input').val([editor.pref('img_save')]);\n\n // update resolution option with actual resolution\n const res = svgCanvas.getResolution();\n if (curConfig.baseUnit !== 'px') {\n res.w = convertUnit(res.w) + curConfig.baseUnit;\n res.h = convertUnit(res.h) + curConfig.baseUnit;\n }\n\n $('#canvas_width').val(res.w);\n $('#canvas_height').val(res.h);\n $('#canvas_title').val(svgCanvas.getDocumentTitle());\n\n $('#svg_docprops').show();\n };\n\n /**\n *\n * @returns {void}\n */\n const showPreferences = function () {\n if (preferences) { return; }\n preferences = true;\n $('#main_menu').hide();\n\n // Update background color with current one\n const canvasBg = curPrefs.bkgd_color;\n const url = editor.pref('bkgd_url');\n blocks.each(function () {\n const blk = $(this);\n const isBg = blk.data('bgcolor') === canvasBg;\n blk.toggleClass(curBg, isBg);\n });\n if (!canvasBg) { blocks.eq(0).addClass(curBg); }\n if (url) {\n $('#canvas_bg_url').val(url);\n }\n $('#grid_snapping_on').prop('checked', curConfig.gridSnapping);\n $('#grid_snapping_step').attr('value', curConfig.snappingStep);\n $('#grid_color').attr('value', curConfig.gridColor);\n\n $('#svg_prefs').show();\n };\n\n /**\n *\n * @returns {void}\n */\n const openHomePage = function () {\n window.open(homePage, '_blank');\n };\n\n /**\n *\n * @returns {void}\n */\n const hideSourceEditor = function () {\n $('#svg_source_editor').hide();\n editingsource = false;\n $('#svg_source_textarea').blur();\n };\n\n /**\n *\n * @returns {Promise} Resolves to `undefined`\n */\n const saveSourceEditor = async function () {\n if (!editingsource) { return; }\n\n const saveChanges = function () {\n svgCanvas.clearSelection();\n hideSourceEditor();\n zoomImage();\n populateLayers();\n updateTitle();\n prepPaints();\n };\n\n if (!svgCanvas.setSvgString($('#svg_source_textarea').val())) {\n const ok = await $.confirm(uiStrings.notification.QerrorsRevertToSource);\n if (!ok) {\n return;\n }\n saveChanges();\n return;\n }\n saveChanges();\n setSelectMode();\n };\n\n /**\n *\n * @returns {void}\n */\n const hideDocProperties = function () {\n $('#svg_docprops').hide();\n $('#canvas_width,#canvas_height').removeAttr('disabled');\n $('#resolution')[0].selectedIndex = 0;\n $('#image_save_opts input').val([editor.pref('img_save')]);\n docprops = false;\n };\n\n /**\n *\n * @returns {void}\n */\n const hidePreferences = function () {\n $('#svg_prefs').hide();\n preferences = false;\n };\n\n /**\n *\n * @returns {boolean} Whether there were problems saving the document properties\n */\n const saveDocProperties = function () {\n // set title\n const newTitle = $('#canvas_title').val();\n updateTitle(newTitle);\n svgCanvas.setDocumentTitle(newTitle);\n\n // update resolution\n const width = $('#canvas_width'), w = width.val();\n const height = $('#canvas_height'), h = height.val();\n\n if (w !== 'fit' && !isValidUnit('width', w)) {\n width.parent().addClass('error');\n /* await */ $.alert(uiStrings.notification.invalidAttrValGiven);\n return false;\n }\n\n width.parent().removeClass('error');\n\n if (h !== 'fit' && !isValidUnit('height', h)) {\n height.parent().addClass('error');\n /* await */ $.alert(uiStrings.notification.invalidAttrValGiven);\n return false;\n }\n\n height.parent().removeClass('error');\n\n if (!svgCanvas.setResolution(w, h)) {\n /* await */ $.alert(uiStrings.notification.noContentToFitTo);\n return false;\n }\n\n // Set image save option\n editor.pref('img_save', $('#image_save_opts :checked').val());\n updateCanvas();\n hideDocProperties();\n return true;\n };\n\n /**\n * Save user preferences based on current values in the UI.\n * @function module:SVGEditor.savePreferences\n * @returns {Promise}\n */\n const savePreferences = editor.savePreferences = async function () {\n // Set background\n const color = $('#bg_blocks div.cur_background').data('bgcolor') || '#FFF';\n setBackground(color, $('#canvas_bg_url').val());\n\n // set language\n const lang = $('#lang_select').val();\n if (lang && lang !== editor.pref('lang')) {\n const {langParam, langData} = await editor.putLocale(lang, goodLangs, curConfig);\n await setLang(langParam, langData);\n }\n\n // set icon size\n setIconSize($('#iconsize').val());\n\n // set grid setting\n curConfig.gridSnapping = $('#grid_snapping_on')[0].checked;\n curConfig.snappingStep = $('#grid_snapping_step').val();\n curConfig.gridColor = $('#grid_color').val();\n curConfig.showRulers = $('#show_rulers')[0].checked;\n\n $('#rulers').toggle(curConfig.showRulers);\n if (curConfig.showRulers) { updateRulers(); }\n curConfig.baseUnit = $('#base_unit').val();\n\n svgCanvas.setConfig(curConfig);\n\n updateCanvas();\n hidePreferences();\n };\n\n let resetScrollPos = $.noop;\n\n /**\n *\n * @returns {Promise} Resolves to `undefined`\n */\n const cancelOverlays = async function () {\n $('#dialog_box').hide();\n if (!editingsource && !docprops && !preferences) {\n if (curContext) {\n svgCanvas.leaveContext();\n }\n return;\n }\n\n if (editingsource) {\n if (origSource !== $('#svg_source_textarea').val()) {\n const ok = await $.confirm(uiStrings.notification.QignoreSourceChanges);\n if (ok) {\n hideSourceEditor();\n }\n } else {\n hideSourceEditor();\n }\n } else if (docprops) {\n hideDocProperties();\n } else if (preferences) {\n hidePreferences();\n }\n resetScrollPos();\n };\n\n const winWh = {width: $(window).width(), height: $(window).height()};\n\n // Fix for Issue 781: Drawing area jumps to top-left corner on window resize (IE9)\n if (isIE()) {\n resetScrollPos = function () {\n if (workarea[0].scrollLeft === 0 && workarea[0].scrollTop === 0) {\n workarea[0].scrollLeft = curScrollPos.left;\n workarea[0].scrollTop = curScrollPos.top;\n }\n };\n\n curScrollPos = {\n left: workarea[0].scrollLeft,\n top: workarea[0].scrollTop\n };\n\n $(window).resize(resetScrollPos);\n editor.ready(function () {\n // TODO: Find better way to detect when to do this to minimize\n // flickering effect\n return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new\n setTimeout(function () {\n resetScrollPos();\n resolve();\n }, 500);\n });\n });\n\n workarea.scroll(function () {\n curScrollPos = {\n left: workarea[0].scrollLeft,\n top: workarea[0].scrollTop\n };\n });\n }\n\n $(window).resize(function (evt) {\n $.each(winWh, function (type, val) {\n const curval = $(window)[type]();\n workarea[0]['scroll' + (type === 'width' ? 'Left' : 'Top')] -= (curval - val) / 2;\n winWh[type] = curval;\n });\n setFlyoutPositions();\n });\n\n workarea.scroll(function () {\n // TODO: jQuery's scrollLeft/Top() wouldn't require a null check\n if ($('#ruler_x').length) {\n $('#ruler_x')[0].scrollLeft = workarea[0].scrollLeft;\n }\n if ($('#ruler_y').length) {\n $('#ruler_y')[0].scrollTop = workarea[0].scrollTop;\n }\n });\n\n $('#url_notice').click(function () {\n /* await */ $.alert(this.title);\n });\n\n $('#change_image_url').click(promptImgURL);\n\n // added these event handlers for all the push buttons so they\n // behave more like buttons being pressed-in and not images\n (function () {\n const toolnames = [\n 'clear', 'open', 'save', 'source', 'delete',\n 'delete_multi', 'paste', 'clone', 'clone_multi',\n 'move_top', 'move_bottom'\n ];\n const curClass = 'tool_button_current';\n\n let allTools = '';\n\n $.each(toolnames, function (i, item) {\n allTools += (i ? ',' : '') + '#tool_' + item;\n });\n\n $(allTools).mousedown(function () {\n $(this).addClass(curClass);\n }).bind('mousedown mouseout', function () {\n $(this).removeClass(curClass);\n });\n\n $('#tool_undo, #tool_redo').mousedown(function () {\n if (!$(this).hasClass('disabled')) { $(this).addClass(curClass); }\n }).bind('mousedown mouseout', function () {\n $(this).removeClass(curClass);\n });\n }());\n\n // switch modifier key in tooltips if mac\n // NOTE: This code is not used yet until I can figure out how to successfully bind ctrl/meta\n // in Opera and Chrome\n if (isMac() && !window.opera) {\n const shortcutButtons = [\n 'tool_clear', 'tool_save', 'tool_source',\n 'tool_undo', 'tool_redo', 'tool_clone'\n ];\n let i = shortcutButtons.length;\n while (i--) {\n const button = document.getElementById(shortcutButtons[i]);\n if (button) {\n const {title} = button;\n const index = title.indexOf('Ctrl+');\n button.title = [\n title.substr(0, index),\n 'Cmd+',\n title.substr(index + 5)\n ].join('');\n }\n }\n }\n\n /**\n * @param {external:jQuery} elem\n * @todo Go back to the color boxes having white background-color and then setting\n * background-image to none.png (otherwise partially transparent gradients look weird)\n * @returns {void}\n */\n const colorPicker = function (elem) {\n const picker = elem.attr('id') === 'stroke_color' ? 'stroke' : 'fill';\n // const opacity = (picker == 'stroke' ? $('#stroke_opacity') : $('#fill_opacity'));\n const title = picker === 'stroke'\n ? uiStrings.ui.pick_stroke_paint_opacity\n : uiStrings.ui.pick_fill_paint_opacity;\n // let wasNone = false; // Currently unused\n const pos = elem.offset();\n let {paint} = paintBox[picker];\n $('#color_picker')\n .draggable({\n cancel: '.jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker',\n containment: 'window'\n })\n .css(curConfig.colorPickerCSS || {left: pos.left - 140, bottom: 40})\n .jGraduate(\n {\n paint,\n window: {pickerTitle: title},\n images: {clientPath: curConfig.jGraduatePath},\n newstop: 'inverse'\n },\n function (p) {\n paint = new $.jGraduate.Paint(p);\n paintBox[picker].setPaint(paint);\n svgCanvas.setPaint(picker, paint);\n $('#color_picker').hide();\n },\n function () {\n $('#color_picker').hide();\n }\n );\n };\n\n /**\n * Paint box class.\n */\n class PaintBox {\n /**\n * @param {string|Element|external:jQuery} container\n * @param {\"fill\"} type\n */\n constructor (container, type) {\n const cur = curConfig[type === 'fill' ? 'initFill' : 'initStroke'];\n // set up gradients to be used for the buttons\n const svgdocbox = new DOMParser().parseFromString(\n ``,\n 'text/xml'\n );\n\n let docElem = svgdocbox.documentElement;\n docElem = $(container)[0].appendChild(document.importNode(docElem, true));\n docElem.setAttribute('width', 16.5);\n\n this.rect = docElem.firstElementChild;\n this.defs = docElem.getElementsByTagName('defs')[0];\n this.grad = this.defs.firstElementChild;\n this.paint = new $.jGraduate.Paint({solidColor: cur.color});\n this.type = type;\n }\n\n /**\n * @param {module:jGraduate~Paint} paint\n * @param {boolean} apply\n * @returns {void}\n */\n setPaint (paint, apply) {\n this.paint = paint;\n\n const ptype = paint.type;\n const opac = paint.alpha / 100;\n\n let fillAttr = 'none';\n switch (ptype) {\n case 'solidColor':\n fillAttr = (paint[ptype] !== 'none') ? '#' + paint[ptype] : paint[ptype];\n break;\n case 'linearGradient':\n case 'radialGradient': {\n this.grad.remove();\n this.grad = this.defs.appendChild(paint[ptype]);\n const id = this.grad.id = 'gradbox_' + this.type;\n fillAttr = 'url(#' + id + ')';\n break;\n }\n }\n\n this.rect.setAttribute('fill', fillAttr);\n this.rect.setAttribute('opacity', opac);\n\n if (apply) {\n svgCanvas.setColor(this.type, this._paintColor, true);\n svgCanvas.setPaintOpacity(this.type, this._paintOpacity, true);\n }\n }\n\n /**\n * @param {boolean} apply\n * @returns {void}\n */\n update (apply) {\n if (!selectedElement) { return; }\n\n const {type} = this;\n switch (selectedElement.tagName) {\n case 'use':\n case 'image':\n case 'foreignObject':\n // These elements don't have fill or stroke, so don't change\n // the current value\n return;\n case 'g':\n case 'a': {\n const childs = selectedElement.getElementsByTagName('*');\n\n let gPaint = null;\n for (let i = 0, len = childs.length; i < len; i++) {\n const elem = childs[i];\n const p = elem.getAttribute(type);\n if (i === 0) {\n gPaint = p;\n } else if (gPaint !== p) {\n gPaint = null;\n break;\n }\n }\n\n if (gPaint === null) {\n // No common color, don't update anything\n this._paintColor = null;\n return;\n }\n this._paintColor = gPaint;\n this._paintOpacity = 1;\n break;\n } default: {\n this._paintOpacity = Number.parseFloat(selectedElement.getAttribute(type + '-opacity'));\n if (Number.isNaN(this._paintOpacity)) {\n this._paintOpacity = 1.0;\n }\n\n const defColor = type === 'fill' ? 'black' : 'none';\n this._paintColor = selectedElement.getAttribute(type) || defColor;\n }\n }\n\n if (apply) {\n svgCanvas.setColor(type, this._paintColor, true);\n svgCanvas.setPaintOpacity(type, this._paintOpacity, true);\n }\n\n this._paintOpacity *= 100;\n\n const paint = getPaint(this._paintColor, this._paintOpacity, type);\n // update the rect inside #fill_color/#stroke_color\n this.setPaint(paint);\n }\n\n /**\n * @returns {void}\n */\n prep () {\n const ptype = this.paint.type;\n\n switch (ptype) {\n case 'linearGradient':\n case 'radialGradient': {\n const paint = new $.jGraduate.Paint({copy: this.paint});\n svgCanvas.setPaint(this.type, paint);\n break;\n }\n }\n }\n }\n PaintBox.ctr = 0;\n\n paintBox.fill = new PaintBox('#fill_color', 'fill');\n paintBox.stroke = new PaintBox('#stroke_color', 'stroke');\n\n $('#stroke_width').val(curConfig.initStroke.width);\n $('#group_opacity').val(curConfig.initOpacity * 100);\n\n // Use this SVG elem to test vectorEffect support\n const testEl = paintBox.fill.rect.cloneNode(false);\n testEl.setAttribute('style', 'vector-effect:non-scaling-stroke');\n const supportsNonSS = (testEl.style.vectorEffect === 'non-scaling-stroke');\n testEl.removeAttribute('style');\n const svgdocbox = paintBox.fill.rect.ownerDocument;\n // Use this to test support for blur element. Seems to work to test support in Webkit\n const blurTest = svgdocbox.createElementNS(NS.SVG, 'feGaussianBlur');\n if (blurTest.stdDeviationX === undefined) {\n $('#tool_blur').hide();\n }\n $(blurTest).remove();\n\n // Test for zoom icon support\n (function () {\n const pre = '-' + uaPrefix.toLowerCase() + '-zoom-';\n const zoom = pre + 'in';\n workarea.css('cursor', zoom);\n if (workarea.css('cursor') === zoom) {\n zoomInIcon = zoom;\n zoomOutIcon = pre + 'out';\n }\n workarea.css('cursor', 'auto');\n }());\n\n // Test for embedImage support (use timeout to not interfere with page load)\n setTimeout(function () {\n svgCanvas.embedImage('images/logo.png', function (datauri) {\n if (!datauri) {\n // Disable option\n $('#image_save_opts [value=embed]').attr('disabled', 'disabled');\n $('#image_save_opts input').val(['ref']);\n editor.pref('img_save', 'ref');\n $('#image_opt_embed').css('color', '#666').attr(\n 'title',\n uiStrings.notification.featNotSupported\n );\n }\n });\n }, 1000);\n\n $('#fill_color, #tool_fill .icon_label').click(function () {\n colorPicker($('#fill_color'));\n updateToolButtonState();\n });\n\n $('#stroke_color, #tool_stroke .icon_label').click(function () {\n colorPicker($('#stroke_color'));\n updateToolButtonState();\n });\n\n $('#group_opacityLabel').click(function () {\n $('#opacity_dropdown button').mousedown();\n $(window).mouseup();\n });\n\n $('#zoomLabel').click(function () {\n $('#zoom_dropdown button').mousedown();\n $(window).mouseup();\n });\n\n $('#tool_move_top').mousedown(function (evt) {\n $('#tools_stacking').show();\n evt.preventDefault();\n });\n\n $('.layer_button').mousedown(function () {\n $(this).addClass('layer_buttonpressed');\n }).mouseout(function () {\n $(this).removeClass('layer_buttonpressed');\n }).mouseup(function () {\n $(this).removeClass('layer_buttonpressed');\n });\n\n $('.push_button').mousedown(function () {\n if (!$(this).hasClass('disabled')) {\n $(this).addClass('push_button_pressed').removeClass('push_button');\n }\n }).mouseout(function () {\n $(this).removeClass('push_button_pressed').addClass('push_button');\n }).mouseup(function () {\n $(this).removeClass('push_button_pressed').addClass('push_button');\n });\n\n // ask for a layer name\n $('#layer_new').click(async function () {\n let uniqName,\n i = svgCanvas.getCurrentDrawing().getNumLayers();\n do {\n uniqName = uiStrings.layers.layer + ' ' + (++i);\n } while (svgCanvas.getCurrentDrawing().hasLayer(uniqName));\n\n const newName = await $.prompt(uiStrings.notification.enterUniqueLayerName, uniqName);\n if (!newName) { return; }\n if (svgCanvas.getCurrentDrawing().hasLayer(newName)) {\n /* await */ $.alert(uiStrings.notification.dupeLayerName);\n return;\n }\n svgCanvas.createLayer(newName);\n updateContextPanel();\n populateLayers();\n });\n\n /**\n *\n * @returns {void}\n */\n function deleteLayer () {\n if (svgCanvas.deleteCurrentLayer()) {\n updateContextPanel();\n populateLayers();\n // This matches what SvgCanvas does\n // TODO: make this behavior less brittle (svg-editor should get which\n // layer is selected from the canvas and then select that one in the UI)\n $('#layerlist tr.layer').removeClass('layersel');\n $('#layerlist tr.layer:first').addClass('layersel');\n }\n }\n\n /**\n *\n * @returns {Promise}\n */\n async function cloneLayer () {\n const name = svgCanvas.getCurrentDrawing().getCurrentLayerName() + ' copy';\n\n const newName = await $.prompt(uiStrings.notification.enterUniqueLayerName, name);\n if (!newName) { return; }\n if (svgCanvas.getCurrentDrawing().hasLayer(newName)) {\n /* await */ $.alert(uiStrings.notification.dupeLayerName);\n return;\n }\n svgCanvas.cloneLayer(newName);\n updateContextPanel();\n populateLayers();\n }\n\n /**\n *\n * @returns {void}\n */\n function mergeLayer () {\n if ($('#layerlist tr.layersel').index() === svgCanvas.getCurrentDrawing().getNumLayers() - 1) {\n return;\n }\n svgCanvas.mergeLayer();\n updateContextPanel();\n populateLayers();\n }\n\n /**\n * @param {Integer} pos\n * @returns {void}\n */\n function moveLayer (pos) {\n const total = svgCanvas.getCurrentDrawing().getNumLayers();\n\n let curIndex = $('#layerlist tr.layersel').index();\n if (curIndex > 0 || curIndex < total - 1) {\n curIndex += pos;\n svgCanvas.setCurrentLayerPosition(total - curIndex - 1);\n populateLayers();\n }\n }\n\n $('#layer_delete').click(deleteLayer);\n\n $('#layer_up').click(() => {\n moveLayer(-1);\n });\n\n $('#layer_down').click(() => {\n moveLayer(1);\n });\n\n $('#layer_rename').click(async function () {\n // const curIndex = $('#layerlist tr.layersel').prevAll().length; // Currently unused\n const oldName = $('#layerlist tr.layersel td.layername').text();\n const newName = await $.prompt(uiStrings.notification.enterNewLayerName, '');\n if (!newName) { return; }\n if (oldName === newName || svgCanvas.getCurrentDrawing().hasLayer(newName)) {\n /* await */ $.alert(uiStrings.notification.layerHasThatName);\n return;\n }\n\n svgCanvas.renameCurrentLayer(newName);\n populateLayers();\n });\n\n const SIDEPANEL_MAXWIDTH = 300;\n const SIDEPANEL_OPENWIDTH = 150;\n let sidedrag = -1, sidedragging = false, allowmove = false;\n\n /**\n * @param {Float} delta\n * @fires module:svgcanvas.SvgCanvas#event:ext_workareaResized\n * @returns {void}\n */\n const changeSidePanelWidth = function (delta) {\n const rulerX = $('#ruler_x');\n $('#sidepanels').width('+=' + delta);\n $('#layerpanel').width('+=' + delta);\n rulerX.css('right', Number.parseInt(rulerX.css('right')) + delta);\n workarea.css('right', Number.parseInt(workarea.css('right')) + delta);\n svgCanvas.runExtensions('workareaResized');\n };\n\n /**\n * @param {Event} evt\n * @returns {void}\n */\n const resizeSidePanel = function (evt) {\n if (!allowmove) { return; }\n if (sidedrag === -1) { return; }\n sidedragging = true;\n let deltaX = sidedrag - evt.pageX;\n const sideWidth = $('#sidepanels').width();\n if (sideWidth + deltaX > SIDEPANEL_MAXWIDTH) {\n deltaX = SIDEPANEL_MAXWIDTH - sideWidth;\n // sideWidth = SIDEPANEL_MAXWIDTH;\n } else if (sideWidth + deltaX < 2) {\n deltaX = 2 - sideWidth;\n // sideWidth = 2;\n }\n if (deltaX === 0) { return; }\n sidedrag -= deltaX;\n changeSidePanelWidth(deltaX);\n };\n\n /**\n * If width is non-zero, then fully close it; otherwise fully open it.\n * @param {boolean} close Forces the side panel closed\n * @returns {void}\n */\n const toggleSidePanel = function (close) {\n const dpr = window.devicePixelRatio || 1;\n const w = $('#sidepanels').width();\n const isOpened = (dpr < 1 ? w : w / dpr) > 2;\n const zoomAdjustedSidepanelWidth = (dpr < 1 ? 1 : dpr) * SIDEPANEL_OPENWIDTH;\n const deltaX = (isOpened || close ? 0 : zoomAdjustedSidepanelWidth) - w;\n changeSidePanelWidth(deltaX);\n };\n\n $('#sidepanel_handle')\n .mousedown(function (evt) {\n sidedrag = evt.pageX;\n $(window).mousemove(resizeSidePanel);\n allowmove = false;\n // Silly hack for Chrome, which always runs mousemove right after mousedown\n setTimeout(function () {\n allowmove = true;\n }, 20);\n })\n .mouseup(function (evt) {\n if (!sidedragging) { toggleSidePanel(); }\n sidedrag = -1;\n sidedragging = false;\n });\n\n $(window).mouseup(function () {\n sidedrag = -1;\n sidedragging = false;\n $('#svg_editor').unbind('mousemove', resizeSidePanel);\n });\n\n populateLayers();\n\n // function changeResolution (x,y) {\n // const {zoom} = svgCanvas.getResolution();\n // setResolution(x * zoom, y * zoom);\n // }\n\n const centerCanvas = () => {\n // this centers the canvas vertically in the workarea (horizontal handled in CSS)\n workarea.css('line-height', workarea.height() + 'px');\n };\n\n $(window).bind('load resize', centerCanvas);\n\n /**\n * @type {module:jQuerySpinButton.StepCallback}\n */\n function stepFontSize (elem, step) {\n const origVal = Number(elem.value);\n const sugVal = origVal + step;\n const increasing = sugVal >= origVal;\n if (step === 0) { return origVal; }\n\n if (origVal >= 24) {\n if (increasing) {\n return Math.round(origVal * 1.1);\n }\n return Math.round(origVal / 1.1);\n }\n if (origVal <= 1) {\n if (increasing) {\n return origVal * 2;\n }\n return origVal / 2;\n }\n return sugVal;\n }\n\n /**\n * @type {module:jQuerySpinButton.StepCallback}\n */\n function stepZoom (elem, step) {\n const origVal = Number(elem.value);\n if (origVal === 0) { return 100; }\n const sugVal = origVal + step;\n if (step === 0) { return origVal; }\n\n if (origVal >= 100) {\n return sugVal;\n }\n if (sugVal >= origVal) {\n return origVal * 2;\n }\n return origVal / 2;\n }\n\n // function setResolution (w, h, center) {\n // updateCanvas();\n // // w -= 0; h -= 0;\n // // $('#svgcanvas').css({width: w, height: h});\n // // $('#canvas_width').val(w);\n // // $('#canvas_height').val(h);\n // //\n // // if (center) {\n // // const wArea = workarea;\n // // const scrollY = h/2 - wArea.height()/2;\n // // const scrollX = w/2 - wArea.width()/2;\n // // wArea[0].scrollTop = scrollY;\n // // wArea[0].scrollLeft = scrollX;\n // // }\n // }\n\n $('#resolution').change(function () {\n const wh = $('#canvas_width,#canvas_height');\n if (!this.selectedIndex) {\n if ($('#canvas_width').val() === 'fit') {\n wh.removeAttr('disabled').val(100);\n }\n } else if (this.value === 'content') {\n wh.val('fit').attr('disabled', 'disabled');\n } else {\n const dims = this.value.split('x');\n $('#canvas_width').val(dims[0]);\n $('#canvas_height').val(dims[1]);\n wh.removeAttr('disabled');\n }\n });\n\n // Prevent browser from erroneously repopulating fields\n $('input,select').attr('autocomplete', 'off');\n\n const dialogSelectors = [\n '#tool_source_cancel', '#tool_docprops_cancel',\n '#tool_prefs_cancel', '.overlay'\n ];\n /* eslint-disable jsdoc/require-property */\n /**\n * Associate all button actions as well as non-button keyboard shortcuts.\n * @namespace {PlainObject} module:SVGEditor~Actions\n */\n const Actions = (function () {\n /* eslint-enable jsdoc/require-property */\n /**\n * @typedef {PlainObject} module:SVGEditor.ToolButton\n * @property {string} sel The CSS selector for the tool\n * @property {external:jQuery.Function} fn A handler to be attached to the `evt`\n * @property {string} evt The event for which the `fn` listener will be added\n * @property {module:SVGEditor.Key} [key] [key, preventDefault, NoDisableInInput]\n * @property {string} [parent] Selector\n * @property {boolean} [hidekey] Whether to show key value in title\n * @property {string} [icon] The button ID\n * @property {boolean} isDefault For flyout holders\n */\n /**\n *\n * @name module:SVGEditor~ToolButtons\n * @type {module:SVGEditor.ToolButton[]}\n */\n const toolButtons = [\n {sel: '#tool_select', fn: clickSelect, evt: 'click', key: ['V', true]},\n {sel: '#tool_fhpath', fn: clickFHPath, evt: 'click', key: ['Q', true]},\n {sel: '#tool_line', fn: clickLine, evt: 'click', key: ['L', true],\n parent: '#tools_line', prepend: true},\n {sel: '#tool_rect', fn: clickRect, evt: 'mouseup',\n key: ['R', true], parent: '#tools_rect', icon: 'rect'},\n {sel: '#tool_square', fn: clickSquare, evt: 'mouseup',\n parent: '#tools_rect', icon: 'square'},\n {sel: '#tool_fhrect', fn: clickFHRect, evt: 'mouseup',\n parent: '#tools_rect', icon: 'fh_rect'},\n {sel: '#tool_ellipse', fn: clickEllipse, evt: 'mouseup',\n key: ['E', true], parent: '#tools_ellipse', icon: 'ellipse'},\n {sel: '#tool_circle', fn: clickCircle, evt: 'mouseup',\n parent: '#tools_ellipse', icon: 'circle'},\n {sel: '#tool_fhellipse', fn: clickFHEllipse, evt: 'mouseup',\n parent: '#tools_ellipse', icon: 'fh_ellipse'},\n {sel: '#tool_path', fn: clickPath, evt: 'click', key: ['P', true]},\n {sel: '#tool_text', fn: clickText, evt: 'click', key: ['T', true]},\n {sel: '#tool_image', fn: clickImage, evt: 'mouseup'},\n {sel: '#tool_zoom', fn: clickZoom, evt: 'mouseup', key: ['Z', true]},\n {sel: '#tool_clear', fn: clickClear, evt: 'mouseup', key: ['N', true]},\n {sel: '#tool_save', fn () {\n if (editingsource) {\n saveSourceEditor();\n } else {\n clickSave();\n }\n }, evt: 'mouseup', key: ['S', true]},\n {sel: '#tool_export', fn: clickExport, evt: 'mouseup'},\n {sel: '#tool_open', fn: clickOpen, evt: 'mouseup', key: ['O', true]},\n {sel: '#tool_import', fn: clickImport, evt: 'mouseup'},\n {sel: '#tool_source', fn: showSourceEditor, evt: 'click', key: ['U', true]},\n {sel: '#tool_wireframe', fn: clickWireframe, evt: 'click', key: ['F', true]},\n {\n key: ['esc', false, false],\n fn () {\n if (dialogSelectors.every((sel) => {\n return $(sel + ':hidden').length;\n })) {\n svgCanvas.clearSelection();\n }\n },\n hidekey: true\n },\n {sel: dialogSelectors.join(','), fn: cancelOverlays, evt: 'click',\n key: ['esc', false, false], hidekey: true},\n {sel: '#tool_source_save', fn: saveSourceEditor, evt: 'click'},\n {sel: '#tool_docprops_save', fn: saveDocProperties, evt: 'click'},\n {sel: '#tool_docprops', fn: showDocProperties, evt: 'click'},\n {sel: '#tool_prefs_save', fn: savePreferences, evt: 'click'},\n {sel: '#tool_editor_prefs', fn: showPreferences, evt: 'click'},\n {sel: '#tool_editor_homepage', fn: openHomePage, evt: 'click'},\n {sel: '#tool_open', fn () { window.dispatchEvent(new CustomEvent('openImage')); }, evt: 'click'},\n {sel: '#tool_import', fn () { window.dispatchEvent(new CustomEvent('importImage')); }, evt: 'click'},\n {sel: '#tool_delete,#tool_delete_multi', fn: deleteSelected,\n evt: 'click', key: ['del/backspace', true]},\n {sel: '#tool_reorient', fn: reorientPath, evt: 'click'},\n {sel: '#tool_node_link', fn: linkControlPoints, evt: 'click'},\n {sel: '#tool_node_clone', fn: clonePathNode, evt: 'click'},\n {sel: '#tool_node_delete', fn: deletePathNode, evt: 'click'},\n {sel: '#tool_openclose_path', fn: opencloseSubPath, evt: 'click'},\n {sel: '#tool_add_subpath', fn: addSubPath, evt: 'click'},\n {sel: '#tool_move_top', fn: moveToTopSelected, evt: 'click', key: 'ctrl+shift+]'},\n {sel: '#tool_move_bottom', fn: moveToBottomSelected, evt: 'click', key: 'ctrl+shift+['},\n {sel: '#tool_topath', fn: convertToPath, evt: 'click'},\n {sel: '#tool_make_link,#tool_make_link_multi', fn: makeHyperlink, evt: 'click'},\n {sel: '#tool_undo', fn: clickUndo, evt: 'click'},\n {sel: '#tool_redo', fn: clickRedo, evt: 'click'},\n {sel: '#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: ['D', true]},\n {sel: '#tool_group_elements', fn: clickGroup, evt: 'click', key: ['G', true]},\n {sel: '#tool_ungroup', fn: clickGroup, evt: 'click'},\n {sel: '#tool_unlink_use', fn: clickGroup, evt: 'click'},\n {sel: '[id^=tool_align]', fn: clickAlign, evt: 'click'},\n // these two lines are required to make Opera work properly with the flyout mechanism\n // {sel: '#tools_rect_show', fn: clickRect, evt: 'click'},\n // {sel: '#tools_ellipse_show', fn: clickEllipse, evt: 'click'},\n {sel: '#tool_bold', fn: clickBold, evt: 'mousedown'},\n {sel: '#tool_italic', fn: clickItalic, evt: 'mousedown'},\n {sel: '#sidepanel_handle', fn: toggleSidePanel, key: ['X']},\n {sel: '#copy_save_done', fn: cancelOverlays, evt: 'click'},\n\n // Shortcuts not associated with buttons\n\n {key: 'ctrl+left', fn () { rotateSelected(0, 1); }},\n {key: 'ctrl+right', fn () { rotateSelected(1, 1); }},\n {key: 'ctrl+shift+left', fn () { rotateSelected(0, 5); }},\n {key: 'ctrl+shift+right', fn () { rotateSelected(1, 5); }},\n {key: 'shift+O', fn: selectPrev},\n {key: 'shift+P', fn: selectNext},\n {key: [modKey + 'up', true], fn () { zoomImage(2); }},\n {key: [modKey + 'down', true], fn () { zoomImage(0.5); }},\n {key: [modKey + ']', true], fn () { moveUpDownSelected('Up'); }},\n {key: [modKey + '[', true], fn () { moveUpDownSelected('Down'); }},\n {key: ['up', true], fn () { moveSelected(0, -1); }},\n {key: ['down', true], fn () { moveSelected(0, 1); }},\n {key: ['left', true], fn () { moveSelected(-1, 0); }},\n {key: ['right', true], fn () { moveSelected(1, 0); }},\n {key: 'shift+up', fn () { moveSelected(0, -10); }},\n {key: 'shift+down', fn () { moveSelected(0, 10); }},\n {key: 'shift+left', fn () { moveSelected(-10, 0); }},\n {key: 'shift+right', fn () { moveSelected(10, 0); }},\n {key: ['alt+up', true], fn () { svgCanvas.cloneSelectedElements(0, -1); }},\n {key: ['alt+down', true], fn () { svgCanvas.cloneSelectedElements(0, 1); }},\n {key: ['alt+left', true], fn () { svgCanvas.cloneSelectedElements(-1, 0); }},\n {key: ['alt+right', true], fn () { svgCanvas.cloneSelectedElements(1, 0); }},\n {key: ['alt+shift+up', true], fn () { svgCanvas.cloneSelectedElements(0, -10); }},\n {key: ['alt+shift+down', true], fn () { svgCanvas.cloneSelectedElements(0, 10); }},\n {key: ['alt+shift+left', true], fn () { svgCanvas.cloneSelectedElements(-10, 0); }},\n {key: ['alt+shift+right', true], fn () { svgCanvas.cloneSelectedElements(10, 0); }},\n {key: 'a', fn () { svgCanvas.selectAllInCurrentLayer(); }},\n {key: modKey + 'a', fn () { svgCanvas.selectAllInCurrentLayer(); }},\n\n // Standard shortcuts\n {key: modKey + 'z', fn: clickUndo},\n {key: modKey + 'shift+z', fn: clickRedo},\n {key: modKey + 'y', fn: clickRedo},\n\n {key: modKey + 'x', fn: cutSelected},\n {key: modKey + 'c', fn: copySelected},\n {key: modKey + 'v', fn: pasteInCenter}\n ];\n\n // Tooltips not directly associated with a single function\n const keyAssocs = {\n '4/Shift+4': '#tools_rect_show',\n '5/Shift+5': '#tools_ellipse_show'\n };\n\n return {\n /** @lends module:SVGEditor~Actions */\n /**\n * @returns {void}\n */\n setAll () {\n const flyouts = {};\n const keyHandler = {}; // will contain the action for each pressed key\n\n toolButtons.forEach((opts) => {\n // Bind function to button\n let btn;\n if (opts.sel) {\n btn = $q(opts.sel);\n if (btn === null) { return true; } // Skip if markup does not exist\n if (opts.evt) {\n // `touch.js` changes `touchstart` to `mousedown`,\n // so we must map tool button click events as well\n if (isTouch() && opts.evt === 'click') {\n opts.evt = 'mousedown';\n }\n btn.addEventListener(opts.evt, opts.fn);\n }\n\n // Add to parent flyout menu, if able to be displayed\n if (opts.parent && $(opts.parent + '_show').length) {\n let fH = $(opts.parent);\n if (!fH.length) {\n fH = makeFlyoutHolder(opts.parent.substr(1));\n }\n if (opts.prepend) {\n btn.style.margin = 'initial';\n }\n fH[opts.prepend ? 'prepend' : 'append'](btn);\n\n if (!Array.isArray(flyouts[opts.parent])) {\n flyouts[opts.parent] = [];\n }\n flyouts[opts.parent].push(opts);\n }\n }\n\n // Bind function to shortcut key\n if (opts.key) {\n // Set shortcut based on options\n let keyval = opts.key;\n let pd = false;\n if (Array.isArray(opts.key)) {\n keyval = opts.key[0];\n if (opts.key.length > 1) { pd = opts.key[1]; }\n }\n keyval = String(keyval);\n const {fn} = opts;\n keyval.split('/').forEach((key) => { keyHandler[key] = {fn, pd}; });\n\n // Put shortcut in title\n if (opts.sel && !opts.hidekey && btn.title) {\n const newTitle = `${btn.title.split('[')[0]} (${keyval})`;\n keyAssocs[keyval] = opts.sel;\n // Disregard for menu items\n if (btn.closest('#main_menu') === null) {\n btn.title = newTitle;\n }\n }\n }\n return true;\n });\n // register the keydown event\n document.addEventListener('keydown', (e) => {\n // only track keyboard shortcuts for the body containing the SVG-Editor\n if (e.target.nodeName !== 'BODY') return;\n // normalize key\n const key = `${(e.metaKey) ? 'meta+' : ''}${(e.ctrlKey) ? 'ctrl+' : ''}${e.key.toLowerCase()}`;\n // return if no shortcut defined for this key\n if (!keyHandler[key]) return;\n // launch associated handler and preventDefault if necessary\n keyHandler[key].fn();\n if (keyHandler[key].pd) {\n e.preventDefault();\n }\n });\n\n // Setup flyouts\n setupFlyouts(flyouts);\n\n // Misc additional actions\n\n // Make 'return' keypress trigger the change event\n $('.attr_changer, #image_url').bind(\n 'keydown',\n 'return',\n function (evt) {\n $(this).change();\n evt.preventDefault();\n }\n );\n\n $(window).bind('keydown', 'tab', function (e) {\n if (uiContext === 'canvas') {\n e.preventDefault();\n selectNext();\n }\n }).bind('keydown', 'shift+tab', function (e) {\n if (uiContext === 'canvas') {\n e.preventDefault();\n selectPrev();\n }\n });\n\n $('#tool_zoom').dblclick(dblclickZoom);\n },\n /**\n * @returns {void}\n */\n setTitles () {\n $.each(keyAssocs, function (keyval, sel) {\n const menu = ($(sel).parents('#main_menu').length);\n\n $(sel).each(function () {\n let t;\n if (menu) {\n t = $(this).text().split(' [')[0];\n } else {\n t = this.title.split(' [')[0];\n }\n let keyStr = '';\n // Shift+Up\n $.each(keyval.split('/'), function (i, key) {\n const modBits = key.split('+');\n let mod = '';\n if (modBits.length > 1) {\n mod = modBits[0] + '+';\n key = modBits[1];\n }\n keyStr += (i ? '/' : '') + mod + (uiStrings['key_' + key] || key);\n });\n if (menu) {\n this.lastChild.textContent = t + ' [' + keyStr + ']';\n } else {\n this.title = t + ' [' + keyStr + ']';\n }\n });\n });\n },\n /**\n * @param {string} sel Selector to match\n * @returns {module:SVGEditor.ToolButton}\n */\n getButtonData (sel) {\n return Object.values(toolButtons).find((btn) => {\n return btn.sel === sel;\n });\n }\n };\n }());\n\n // Select given tool\n editor.ready(function () {\n let tool;\n const itool = curConfig.initTool,\n container = $('#tools_left, #svg_editor .tools_flyout'),\n preTool = container.find('#tool_' + itool),\n regTool = container.find('#' + itool);\n if (preTool.length) {\n tool = preTool;\n } else if (regTool.length) {\n tool = regTool;\n } else {\n tool = $('#tool_select');\n }\n tool.click().mouseup();\n\n if (curConfig.wireframe) {\n $('#tool_wireframe').click();\n }\n\n if (curConfig.showlayers) {\n toggleSidePanel();\n }\n\n $('#rulers').toggle(Boolean(curConfig.showRulers));\n\n if (curConfig.showRulers) {\n $('#show_rulers')[0].checked = true;\n }\n\n if (curConfig.baseUnit) {\n $('#base_unit').val(curConfig.baseUnit);\n }\n\n if (curConfig.gridSnapping) {\n $('#grid_snapping_on')[0].checked = true;\n }\n\n if (curConfig.snappingStep) {\n $('#grid_snapping_step').val(curConfig.snappingStep);\n }\n\n if (curConfig.gridColor) {\n $('#grid_color').val(curConfig.gridColor);\n }\n });\n\n // init SpinButtons\n $('#rect_rx').SpinButton({\n min: 0, max: 1000, stateObj, callback: changeRectRadius\n });\n $('#stroke_width').SpinButton({\n min: 0, max: 99, smallStep: 0.1, stateObj, callback: changeStrokeWidth\n });\n $('#angle').SpinButton({\n min: -180, max: 180, step: 5, stateObj, callback: changeRotationAngle\n });\n $('#font_size').SpinButton({\n min: 0.001, stepfunc: stepFontSize, stateObj, callback: changeFontSize\n });\n $('#group_opacity').SpinButton({\n min: 0, max: 100, step: 5, stateObj, callback: changeOpacity\n });\n $('#blur').SpinButton({\n min: 0, max: 10, step: 0.1, stateObj, callback: changeBlur\n });\n $('#zoom').SpinButton({\n min: 0.001, max: 10000, step: 50, stepfunc: stepZoom,\n stateObj, callback: changeZoom\n // Set default zoom\n }).val(\n svgCanvas.getZoom() * 100\n );\n\n $('#workarea').contextMenu(\n {\n menu: 'cmenu_canvas',\n inSpeed: 0\n },\n function (action, el, pos) {\n switch (action) {\n case 'delete':\n deleteSelected();\n break;\n case 'cut':\n cutSelected();\n break;\n case 'copy':\n copySelected();\n break;\n case 'paste':\n svgCanvas.pasteElements();\n break;\n case 'paste_in_place':\n svgCanvas.pasteElements('in_place');\n break;\n case 'group':\n case 'group_elements':\n svgCanvas.groupSelectedElements();\n break;\n case 'ungroup':\n svgCanvas.ungroupSelectedElement();\n break;\n case 'move_front':\n moveToTopSelected();\n break;\n case 'move_up':\n moveUpDownSelected('Up');\n break;\n case 'move_down':\n moveUpDownSelected('Down');\n break;\n case 'move_back':\n moveToBottomSelected();\n break;\n default:\n if (hasCustomHandler(action)) {\n getCustomHandler(action).call();\n }\n break;\n }\n }\n );\n\n /**\n * Implements {@see module:jQueryContextMenu.jQueryContextMenuListener}.\n * @param {\"dupe\"|\"delete\"|\"merge_down\"|\"merge_all\"} action\n * @param {external:jQuery} el\n * @param {{x: Float, y: Float, docX: Float, docY: Float}} pos\n * @returns {void}\n */\n const lmenuFunc = function (action, el, pos) {\n switch (action) {\n case 'dupe':\n /* await */ cloneLayer();\n break;\n case 'delete':\n deleteLayer();\n break;\n case 'merge_down':\n mergeLayer();\n break;\n case 'merge_all':\n svgCanvas.mergeAllLayers();\n updateContextPanel();\n populateLayers();\n break;\n }\n };\n\n $('#layerlist').contextMenu(\n {\n menu: 'cmenu_layers',\n inSpeed: 0\n },\n lmenuFunc\n );\n\n $('#layer_moreopts').contextMenu(\n {\n menu: 'cmenu_layers',\n inSpeed: 0,\n allowLeft: true\n },\n lmenuFunc\n );\n\n $('.contextMenu li').mousedown(function (ev) {\n ev.preventDefault();\n });\n\n $('#cmenu_canvas li').disableContextMenu();\n canvMenu.enableContextMenuItems('#delete,#cut,#copy');\n\n /**\n * @returns {void}\n */\n function enableOrDisableClipboard () {\n let svgeditClipboard;\n try {\n svgeditClipboard = localStorage.getItem('svgedit_clipboard');\n } catch (err) {}\n canvMenu[(svgeditClipboard ? 'en' : 'dis') + 'ableContextMenuItems'](\n '#paste,#paste_in_place'\n );\n }\n enableOrDisableClipboard();\n\n window.addEventListener('storage', function (e) {\n if (e.key !== 'svgedit_clipboard') { return; }\n\n enableOrDisableClipboard();\n });\n\n window.addEventListener('beforeunload', function (e) {\n // Suppress warning if page is empty\n if (undoMgr.getUndoStackSize() === 0) {\n editor.showSaveWarning = false;\n }\n\n // showSaveWarning is set to 'false' when the page is saved.\n if (!curConfig.no_save_warning && editor.showSaveWarning) {\n // Browser already asks question about closing the page\n e.returnValue = uiStrings.notification.unsavedChanges; // Firefox needs this when beforeunload set by addEventListener (even though message is not used)\n return uiStrings.notification.unsavedChanges;\n }\n return true;\n });\n\n /**\n * Expose the `uiStrings`.\n * @function module:SVGEditor.canvas.getUIStrings\n * @returns {module:SVGEditor.uiStrings}\n */\n editor.canvas.getUIStrings = function () {\n return uiStrings;\n };\n\n /**\n * @function module:SVGEditor.openPrep\n * @returns {boolean|Promise} Resolves to boolean indicating `true` if there were no changes\n * and `false` after the user confirms.\n */\n editor.openPrep = function () {\n $('#main_menu').hide();\n if (undoMgr.getUndoStackSize() === 0) {\n return true;\n }\n return $.confirm(uiStrings.notification.QwantToOpen);\n };\n\n /**\n *\n * @param {Event} e\n * @returns {void}\n */\n function onDragEnter (e) {\n e.stopPropagation();\n e.preventDefault();\n // and indicator should be displayed here, such as \"drop files here\"\n }\n\n /**\n *\n * @param {Event} e\n * @returns {void}\n */\n function onDragOver (e) {\n e.stopPropagation();\n e.preventDefault();\n }\n\n /**\n *\n * @param {Event} e\n * @returns {void}\n */\n function onDragLeave (e) {\n e.stopPropagation();\n e.preventDefault();\n // hypothetical indicator should be removed here\n }\n // Use HTML5 File API: http://www.w3.org/TR/FileAPI/\n // if browser has HTML5 File API support, then we will show the open menu item\n // and provide a file input to click. When that change event fires, it will\n // get the text contents of the file and send it to the canvas\n if (window.FileReader) {\n /**\n * @param {Event} e\n * @returns {void}\n */\n const importImage = function (e) {\n $.process_cancel(uiStrings.notification.loadingImage);\n e.stopPropagation();\n e.preventDefault();\n $('#workarea').removeAttr('style');\n $('#main_menu').hide();\n const file = (e.type === 'drop') ? e.dataTransfer.files[0] : this.files[0];\n if (!file) {\n $('#dialog_box').hide();\n return;\n }\n /* if (file.type === 'application/pdf') { // Todo: Handle PDF imports\n\n }\n else */\n if (!file.type.includes('image')) {\n return;\n }\n // Detected an image\n // svg handling\n let reader;\n if (file.type.includes('svg')) {\n reader = new FileReader();\n reader.onloadend = function (ev) {\n const newElement = svgCanvas.importSvgString(ev.target.result, true);\n svgCanvas.ungroupSelectedElement();\n svgCanvas.ungroupSelectedElement();\n svgCanvas.groupSelectedElements();\n svgCanvas.alignSelectedElements('m', 'page');\n svgCanvas.alignSelectedElements('c', 'page');\n // highlight imported element, otherwise we get strange empty selectbox\n svgCanvas.selectOnly([newElement]);\n $('#dialog_box').hide();\n };\n reader.readAsText(file);\n } else {\n // bitmap handling\n reader = new FileReader();\n reader.onloadend = function ({target: {result}}) {\n /**\n * Insert the new image until we know its dimensions.\n * @param {Float} width\n * @param {Float} height\n * @returns {void}\n */\n const insertNewImage = function (width, height) {\n const newImage = svgCanvas.addSVGElementFromJson({\n element: 'image',\n attr: {\n x: 0,\n y: 0,\n width,\n height,\n id: svgCanvas.getNextId(),\n style: 'pointer-events:inherit'\n }\n });\n svgCanvas.setHref(newImage, result);\n svgCanvas.selectOnly([newImage]);\n svgCanvas.alignSelectedElements('m', 'page');\n svgCanvas.alignSelectedElements('c', 'page');\n updateContextPanel();\n $('#dialog_box').hide();\n };\n // create dummy img so we know the default dimensions\n let imgWidth = 100;\n let imgHeight = 100;\n const img = new Image();\n img.style.opacity = 0;\n img.addEventListener('load', function () {\n imgWidth = img.offsetWidth || img.naturalWidth || img.width;\n imgHeight = img.offsetHeight || img.naturalHeight || img.height;\n insertNewImage(imgWidth, imgHeight);\n });\n img.src = result;\n };\n reader.readAsDataURL(file);\n }\n };\n\n workarea[0].addEventListener('dragenter', onDragEnter);\n workarea[0].addEventListener('dragover', onDragOver);\n workarea[0].addEventListener('dragleave', onDragLeave);\n workarea[0].addEventListener('drop', importImage);\n\n const open = $('').change(async function (e) {\n const ok = await editor.openPrep();\n if (!ok) { return; }\n svgCanvas.clear();\n if (this.files.length === 1) {\n $.process_cancel(uiStrings.notification.loadingImage);\n const reader = new FileReader();\n reader.onloadend = async function ({target}) {\n await loadSvgString(target.result);\n updateCanvas();\n };\n reader.readAsText(this.files[0]);\n }\n });\n $('#tool_open').show();\n $(window).on('openImage', () => open.click());\n\n const imgImport = $('').change(importImage);\n $('#tool_import').show();\n $(window).on('importImage', () => imgImport.click());\n }\n\n updateCanvas(true);\n // const revnums = 'svg-editor.js ($Rev$) ';\n // revnums += svgCanvas.getVersion();\n // $('#copyright')[0].setAttribute('title', revnums);\n\n const loadedExtensionNames = [];\n /**\n * @function module:SVGEditor.setLang\n * @param {string} lang The language code\n * @param {module:locale.LocaleStrings} allStrings See {@tutorial LocaleDocs}\n * @fires module:svgcanvas.SvgCanvas#event:ext_langReady\n * @fires module:svgcanvas.SvgCanvas#event:ext_langChanged\n * @returns {Promise} A Promise which resolves to `undefined`\n */\n const setLang = editor.setLang = async function (lang, allStrings) {\n editor.langChanged = true;\n editor.pref('lang', lang);\n $('#lang_select').val(lang);\n if (!allStrings) {\n return;\n }\n // Todo: Remove `allStrings.lang` property in locale in\n // favor of just `lang`?\n document.documentElement.lang = allStrings.lang; // lang;\n // Todo: Add proper RTL Support!\n // Todo: Use RTL detection instead and take out of locales?\n // document.documentElement.dir = allStrings.dir;\n $.extend(uiStrings, allStrings);\n\n // const notif = allStrings.notification; // Currently unused\n // $.extend will only replace the given strings\n const oldLayerName = $('#layerlist tr.layersel td.layername').text();\n const renameLayer = (oldLayerName === uiStrings.common.layer + ' 1');\n\n svgCanvas.setUiStrings(allStrings);\n Actions.setTitles();\n\n if (renameLayer) {\n svgCanvas.renameCurrentLayer(uiStrings.common.layer + ' 1');\n populateLayers();\n }\n\n // In case extensions loaded before the locale, now we execute a callback on them\n if (extsPreLang.length) {\n await Promise.all(extsPreLang.map((ext) => {\n loadedExtensionNames.push(ext.name);\n return ext.langReady({\n lang,\n uiStrings,\n importLocale: getImportLocale({defaultLang: lang, defaultName: ext.name})\n });\n }));\n extsPreLang.length = 0;\n } else {\n loadedExtensionNames.forEach((loadedExtensionName) => {\n svgCanvas.runExtension(\n loadedExtensionName,\n 'langReady',\n /** @type {module:svgcanvas.SvgCanvas#event:ext_langReady} */ {\n lang, uiStrings, importLocale: getImportLocale({defaultLang: lang, defaultName: loadedExtensionName})\n }\n );\n });\n }\n svgCanvas.runExtensions('langChanged', /** @type {module:svgcanvas.SvgCanvas#event:ext_langChanged} */ lang);\n\n // Update flyout tooltips\n setFlyoutTitles();\n\n // Copy title for certain tool elements\n const elems = {\n '#stroke_color': '#tool_stroke .icon_label, #tool_stroke .color_block',\n '#fill_color': '#tool_fill label, #tool_fill .color_block',\n '#linejoin_miter': '#cur_linejoin',\n '#linecap_butt': '#cur_linecap'\n };\n\n $.each(elems, function (source, dest) {\n $(dest).attr('title', $(source)[0].title);\n });\n\n // Copy alignment titles\n $('#multiselected_panel div[id^=tool_align]').each(function () {\n $('#tool_pos' + this.id.substr(10))[0].title = this.title;\n });\n };\n localeInit(\n /**\n * @implements {module:locale.LocaleEditorInit}\n */\n {\n /**\n * Gets an array of results from extensions with a `addLangData` method,\n * returning an object with a `data` property set to its locales (to be\n * merged with regular locales).\n * @param {string} langParam\n * @fires module:svgcanvas.SvgCanvas#event:ext_addLangData\n * @todo Can we forego this in favor of `langReady` (or forego `langReady`)?\n * @returns {module:locale.AddLangExtensionLocaleData[]}\n */\n addLangData (langParam) {\n return svgCanvas.runExtensions(\n 'addLangData',\n /**\n * @function\n * @type {module:svgcanvas.ExtensionVarBuilder}\n * @param {string} name\n * @returns {module:svgcanvas.SvgCanvas#event:ext_addLangData}\n */\n (name) => { // We pass in a function as we don't know the extension name here when defining this `addLangData` method\n return {\n lang: langParam,\n importLocale: getImportLocale({defaultLang: langParam, defaultName: name})\n };\n },\n true\n );\n },\n curConfig\n }\n );\n // Load extensions\n // Bit of a hack to run extensions in local Opera/IE9\n if (document.location.protocol === 'file:') {\n setTimeout(extAndLocaleFunc, 100);\n } else {\n // Returns a promise (if we wanted to fire 'extensions-loaded' event,\n // potentially useful to hide interface as some extension locales\n // are only available after this)\n extAndLocaleFunc();\n }\n};\n\n/**\n* @callback module:SVGEditor.ReadyCallback\n* @returns {Promise|void}\n*/\n/**\n* Queues a callback to be invoked when the editor is ready (or\n* to be invoked immediately if it is already ready--i.e.,\n* if `runCallbacks` has been run).\n* @function module:SVGEditor.ready\n* @param {module:SVGEditor.ReadyCallback} cb Callback to be queued to invoke\n* @returns {Promise} Resolves when all callbacks, including the supplied have resolved\n*/\neditor.ready = function (cb) { // eslint-disable-line promise/prefer-await-to-callbacks\n return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new\n if (isReady) {\n resolve(cb()); // eslint-disable-line node/callback-return, promise/prefer-await-to-callbacks\n return;\n }\n callbacks.push([cb, resolve, reject]);\n });\n};\n\n/**\n* Invokes the callbacks previous set by `svgEditor.ready`\n* @function module:SVGEditor.runCallbacks\n* @returns {Promise} Resolves to `undefined` if all callbacks succeeded and rejects otherwise\n*/\neditor.runCallbacks = async function () {\n try {\n await Promise.all(callbacks.map(([cb]) => {\n return cb(); // eslint-disable-line promise/prefer-await-to-callbacks\n }));\n } catch (err) {\n callbacks.forEach(([, , reject]) => {\n reject();\n });\n throw err;\n }\n callbacks.forEach(([, resolve]) => {\n resolve();\n });\n isReady = true;\n};\n\n/**\n * @function module:SVGEditor.loadFromString\n * @param {string} str The SVG string to load\n * @param {PlainObject} [opts={}]\n * @param {boolean} [opts.noAlert=false] Option to avoid alert to user and instead get rejected promise\n * @returns {Promise}\n */\neditor.loadFromString = function (str, {noAlert} = {}) {\n return editor.ready(async function () {\n try {\n await loadSvgString(str, {noAlert});\n } catch (err) {\n if (noAlert) {\n throw err;\n }\n }\n });\n};\n\n/**\n* Not presently in use.\n* @function module:SVGEditor.disableUI\n* @param {PlainObject} featList\n* @returns {void}\n*/\neditor.disableUI = function (featList) {\n // $(function () {\n // $('#tool_wireframe, #tool_image, #main_button, #tool_source, #sidepanels').remove();\n // $('#tools_top').css('left', 5);\n // });\n};\n\n/**\n * @callback module:SVGEditor.URLLoadCallback\n * @param {boolean} success\n * @returns {void}\n */\n/**\n * @function module:SVGEditor.loadFromURL\n * @param {string} url URL from which to load an SVG string via Ajax\n * @param {PlainObject} [opts={}] May contain properties: `cache`, `callback`\n * @param {boolean} [opts.cache]\n * @param {boolean} [opts.noAlert]\n * @returns {Promise} Resolves to `undefined` or rejects upon bad loading of\n * the SVG (or upon failure to parse the loaded string) when `noAlert` is\n * enabled\n */\neditor.loadFromURL = function (url, {cache, noAlert} = {}) {\n return editor.ready(function () {\n return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new\n $.ajax({\n url,\n dataType: 'text',\n cache: Boolean(cache),\n beforeSend () {\n $.process_cancel(uiStrings.notification.loadingImage);\n },\n success (str) {\n resolve(loadSvgString(str, {noAlert}));\n },\n error (xhr, stat, err) {\n if (xhr.status !== 404 && xhr.responseText) {\n resolve(loadSvgString(xhr.responseText, {noAlert}));\n return;\n }\n if (noAlert) {\n reject(new Error('URLLoadFail'));\n return;\n }\n $.alert(uiStrings.notification.URLLoadFail + ': \\n' + err);\n resolve();\n },\n complete () {\n $('#dialog_box').hide();\n }\n });\n });\n });\n};\n\n/**\n* @function module:SVGEditor.loadFromDataURI\n* @param {string} str The Data URI to base64-decode (if relevant) and load\n* @param {PlainObject} [opts={}]\n* @param {boolean} [opts.noAlert]\n* @returns {Promise} Resolves to `undefined` and rejects if loading SVG string fails and `noAlert` is enabled\n*/\neditor.loadFromDataURI = function (str, {noAlert} = {}) {\n return editor.ready(function () {\n let base64 = false;\n let pre = str.match(/^data:image\\/svg\\+xml;base64,/);\n if (pre) {\n base64 = true;\n } else {\n pre = str.match(/^data:image\\/svg\\+xml(?:;|;utf8)?,/);\n }\n if (pre) {\n pre = pre[0];\n }\n const src = str.slice(pre.length);\n return loadSvgString(base64 ? Utils.decode64(src) : decodeURIComponent(src), {noAlert});\n });\n};\n\n/**\n * @function module:SVGEditor.addExtension\n * @param {string} name Used internally; no need for i18n.\n * @param {module:svgcanvas.ExtensionInitCallback} init Config to be invoked on this module\n * @param {module:svgcanvas.ExtensionInitArgs} initArgs\n * @throws {Error} If called too early\n * @returns {Promise} Resolves to `undefined`\n*/\neditor.addExtension = function (name, init, initArgs) {\n // Note that we don't want this on editor.ready since some extensions\n // may want to run before then (like server_opensave).\n // $(function () {\n if (!svgCanvas) {\n throw new Error('Extension added too early');\n }\n return svgCanvas.addExtension.call(this, name, init, initArgs);\n // });\n};\n\n// Defer injection to wait out initial menu processing. This probably goes\n// away once all context menu behavior is brought to context menu.\neditor.ready(() => {\n injectExtendedContextMenuItemsIntoDom();\n});\n\nlet extensionsAdded = false;\nconst messageQueue = [];\n/**\n * @param {PlainObject} info\n * @param {any} info.data\n * @param {string} info.origin\n * @fires module:svgcanvas.SvgCanvas#event:message\n * @returns {void}\n */\nconst messageListener = ({data, origin}) => { // eslint-disable-line no-shadow\n // console.log('data, origin, extensionsAdded', data, origin, extensionsAdded);\n const messageObj = {data, origin};\n if (!extensionsAdded) {\n messageQueue.push(messageObj);\n } else {\n // Extensions can handle messages at this stage with their own\n // canvas `message` listeners\n svgCanvas.call('message', messageObj);\n }\n};\nwindow.addEventListener('message', messageListener);\n\n// Run init once DOM is loaded\n// jQuery(editor.init);\n\n(async () => {\ntry {\n // We wait a micro-task to let the svgEditor variable be defined for module checks\n await Promise.resolve();\n editor.init();\n} catch (err) {\n console.error(err); // eslint-disable-line no-console\n}\n})();\n\nexport default editor;\n","// TO BUILD AN IIFE VERSION OF THIS FILE (AS CAN WORK ON OLDER BROWSERS),\n// RUN THE FOLLOWING ON THE COMMAND LINE FROM THE PROJECT ROOT:\n// `npm run build-by-config`. REPEAT AFTER ANY MODIFICATIONS\n// TO svgedit-config-es.js.\n\n/*\nThe svgedit-config-es.js file is intended for the setting of configuration\n or preferences which must run early on; if this is not needed, it is\n recommended that you create an extension instead (for greater\n reusability and modularity). This file needs to be in the parent\n folder of the editor folder. It is referenced in the code as\n '../svgedit-config-es.js'.\n*/\n\n// CONFIG AND EXTENSION SETTING\n/*\nFor default config and extensions (and available options) available to\n`setConfig()`, see the file `docs/tutorials/ConfigOptions.md`\n*/\n\n// eslint-disable-next-line node/file-extension-in-import\nimport 'core-js/stable';\n// eslint-disable-next-line node/file-extension-in-import\nimport 'regenerator-runtime/runtime';\nimport svgEditor from './svgedit.js';\n\n// URL OVERRIDE CONFIG\nsvgEditor.setConfig({\n /* To override the ability for URLs to set URL-based SVG content,\n uncomment the following: */\n // preventURLContentLoading: true,\n /* To override the ability for URLs to set other configuration (including\n extension config), uncomment the following: */\n // preventAllURLConfig: true,\n /* To override the ability for URLs to set their own extensions, uncomment the\n following (note that if `setConfig()` is used in extension code, it will still\n be additive to extensions, however): */\n // lockExtensions: true,\n});\n\nsvgEditor.setConfig({\n /*\n Provide default values here which differ from that of the editor but\n which the URL can override\n */\n}, {allowInitialUserOverride: true});\n\n// EXTENSION CONFIG\nsvgEditor.setConfig({\n extensions: [\n // 'ext-overview_window.js', 'ext-markers.js', 'ext-connector.js',\n // 'ext-eyedropper.js', 'ext-shapes.js', 'ext-imagelib.js',\n // 'ext-grid.js', 'ext-polygon.js', 'ext-star.js', 'ext-panning.js',\n // 'ext-storage.js'\n ],\n // noDefaultExtensions can only be meaningfully used in\n // `svgedit-config-es.js` or in the URL\n noDefaultExtensions: false\n});\n\n// OTHER CONFIG\nsvgEditor.setConfig({\n // canvasName: 'default',\n // canvas_expansion: 3,\n // initFill: {\n // color: 'FF0000', // solid red\n // opacity: 1\n // },\n // initStroke: {\n // width: 5,\n // color: '000000', // solid black\n // opacity: 1\n // },\n // initOpacity: 1,\n // colorPickerCSS: null,\n // initTool: 'select',\n // exportWindowType: 'new', // 'same'\n // wireframe: false,\n // showlayers: false,\n // no_save_warning: false,\n // PATH CONFIGURATION\n // imgPath: 'images/',\n // langPath: '/src/editor/locale/',\n // extPath: 'extensions/',\n // jGraduatePath: 'jgraduate/images/',\n /*\n Uncomment the following to allow at least same domain (embedded) access,\n including `file:///` access.\n Setting as `['*']` would allow any domain to access but would be unsafe to\n data privacy and integrity.\n */\n // May be 'null' (as a string) when used as a `file:///` URL\n // allowedOrigins: [location.origin || 'null'],\n // DOCUMENT PROPERTIES\n // dimensions: [640, 480],\n // EDITOR OPTIONS\n // gridSnapping: false,\n // gridColor: '#000',\n // baseUnit: 'px',\n // snappingStep: 10,\n // showRulers: true,\n // EXTENSION-RELATED (GRID)\n // showGrid: false, // Set by ext-grid.js\n // EXTENSION-RELATED (STORAGE)\n // Some interaction with `ext-storage.js`; prevent even the loading of\n // previously saved local storage\n // noStorageOnLoad: false,\n // Some interaction with `ext-storage.js`; strongly discouraged from\n // modification as it bypasses user privacy by preventing them from\n // choosing whether to keep local storage or not\n // forceStorage: false,\n // Used by `ext-storage.js`; empty any prior storage if the user\n // declines to store\n // emptyStorageOnDecline: true,\n});\n\n// PREF CHANGES\n/*\nsetConfig() can also be used to set preferences in addition to\n configuration (see defaultPrefs in svg-editor.js for a list of\n possible settings), but at least if you are using ext-storage.js\n to store preferences, it will probably be better to let your\n users control these.\nAs with configuration, one may use allowInitialUserOverride, but\n in the case of preferences, any previously stored preferences\n will also thereby be enabled to override this setting (and at a\n higher priority than any URL preference setting overrides).\n Failing to use allowInitialUserOverride will ensure preferences\n are hard-coded here regardless of URL or prior user storage setting.\n*/\nsvgEditor.setConfig({\n // Set dynamically within locale.js if not previously set\n // lang: '',\n // Will default to 's' if the window height is smaller than the minimum\n // height and 'm' otherwise\n // iconsize: '',\n /**\n * When showing the preferences dialog, svg-editor.js currently relies\n * on `curPrefs` instead of `svgEditor.pref`, so allowing an override for\n * `bkgd_color` means that this value won't have priority over block\n * auto-detection as far as determining which color shows initially\n * in the preferences dialog (though it can be changed and saved).\n */\n // bkgd_color: '#FFF',\n // bkgd_url: '',\n // img_save: 'embed',\n // Only shows in UI as far as alert notices\n // save_notice_done: false,\n // export_notice_done: false\n});\nsvgEditor.setConfig(\n {\n // Indicate pref settings here if you wish to allow user storage or URL\n // settings to be able to override your default preferences (unless\n // other config options have already explicitly prevented one or the\n // other)\n },\n {allowInitialUserOverride: true}\n);\n","!function(n,r){var t,e;\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=r():\"function\"==typeof define&&define.amd?define(\"underscore\",r):(t=n._,e=r(),(n._=e).noConflict=function(){return n._=t,e})}(this,function(){\n// Underscore.js 1.10.2\n// https://underscorejs.org\n// (c) 2009-2020 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n// Underscore may be freely distributed under the MIT license.\nvar n=\"object\"==typeof self&&self.self===self&&self||\"object\"==typeof global&&global.global===global&&global||Function(\"return this\")()||{},e=Array.prototype,i=Object.prototype,p=\"undefined\"!=typeof Symbol?Symbol.prototype:null,u=e.push,f=e.slice,s=i.toString,o=i.hasOwnProperty,r=Array.isArray,a=Object.keys,t=Object.create,c=n.isNaN,l=n.isFinite,v=function(){};function h(n){return n instanceof h?n:this instanceof h?void(this._wrapped=n):new h(n)}var g=h.VERSION=\"1.10.2\";function y(u,o,n){if(void 0===o)return u;switch(null==n?3:n){case 1:return function(n){return u.call(o,n)};case 3:return function(n,r,t){return u.call(o,n,r,t)};case 4:return function(n,r,t,e){return u.call(o,n,r,t,e)}}return function(){return u.apply(o,arguments)}}function d(n,r,t){return null==n?ur:Cn(n)?y(n,r,t):Ln(n)&&!Kn(n)?ir(n):or(n)}function m(n,r){return d(n,r,1/0)}function b(n,r,t){return h.iteratee!==m?h.iteratee(n,r):d(n,r,t)}function j(u,o){return o=null==o?u.length-1:+o,function(){for(var n=Math.max(arguments.length-o,0),r=Array(n),t=0;t\":\">\",'\"':\""\",\"'\":\"'\",\"`\":\"`\"},lr=Mn(cr);function pr(r){var t=function(n){return r[n]},n=\"(?:\"+Sn(r).join(\"|\")+\")\",e=RegExp(n),u=RegExp(n,\"g\");return function(n){return n=null==n?\"\":\"\"+n,e.test(n)?n.replace(u,t):n}}var sr=pr(cr),vr=pr(lr);var hr=0;var gr=h.templateSettings={evaluate:/<%([\\s\\S]+?)%>/g,interpolate:/<%=([\\s\\S]+?)%>/g,escape:/<%-([\\s\\S]+?)%>/g},yr=/(.)^/,dr={\"'\":\"'\",\"\\\\\":\"\\\\\",\"\\r\":\"r\",\"\\n\":\"n\",\"\\u2028\":\"u2028\",\"\\u2029\":\"u2029\"},mr=/\\\\|'|\\r|\\n|\\u2028|\\u2029/g,br=function(n){return\"\\\\\"+dr[n]};function jr(n,r){return n._chain?h(r).chain():r}function _r(t){return E(En(t),function(n){var r=h[n]=t[n];h.prototype[n]=function(){var n=[this._wrapped];return u.apply(n,arguments),jr(this,r.apply(h,n))}}),h}E([\"pop\",\"push\",\"reverse\",\"shift\",\"sort\",\"splice\",\"unshift\"],function(r){var t=e[r];h.prototype[r]=function(){var n=this._wrapped;return t.apply(n,arguments),\"shift\"!==r&&\"splice\"!==r||0!==n.length||delete n[0],jr(this,n)}}),E([\"concat\",\"join\",\"slice\"],function(n){var r=e[n];h.prototype[n]=function(){return jr(this,r.apply(this._wrapped,arguments))}}),h.prototype.valueOf=h.prototype.toJSON=h.prototype.value=function(){return this._wrapped},h.prototype.toString=function(){return String(this._wrapped)};var wr=_r({default:h,VERSION:g,iteratee:m,restArguments:j,each:E,forEach:E,map:N,collect:N,reduce:I,foldl:I,inject:I,reduceRight:T,foldr:T,find:B,detect:B,filter:R,select:R,reject:function(n,r,t){return R(n,mn(b(r)),t)},every:F,all:F,some:q,any:q,contains:D,includes:D,include:D,invoke:W,pluck:z,where:function(n,r){return R(n,ir(r))},findWhere:function(n,r){return B(n,ir(r))},max:P,min:function(n,e,r){var t,u,o=1/0,i=1/0;if(null==e||\"number\"==typeof e&&\"object\"!=typeof n[0]&&null!=n)for(var a=0,f=(n=M(n)?n:On(n)).length;a 0) {\n throw new Error('Invalid string. Length must be a multiple of 4')\n }\n\n // the number of equal signs (place holders)\n // if there are two placeholders, than the two characters before it\n // represent one byte\n // if there is only one, then the three characters before it represent 2 bytes\n // this is just a cheap hack to not do indexOf twice\n placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0;\n\n // base64 is 4/3 + up to two characters of the original data\n arr = new Arr(len * 3 / 4 - placeHolders);\n\n // if there are placeholders, only get up to the last complete 4 chars\n l = placeHolders > 0 ? len - 4 : len;\n\n var L = 0;\n\n for (i = 0, j = 0; i < l; i += 4, j += 3) {\n tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)];\n arr[L++] = (tmp >> 16) & 0xFF;\n arr[L++] = (tmp >> 8) & 0xFF;\n arr[L++] = tmp & 0xFF;\n }\n\n if (placeHolders === 2) {\n tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4);\n arr[L++] = tmp & 0xFF;\n } else if (placeHolders === 1) {\n tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2);\n arr[L++] = (tmp >> 8) & 0xFF;\n arr[L++] = tmp & 0xFF;\n }\n\n return arr\n}\n\nfunction tripletToBase64 (num) {\n return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n var tmp;\n var output = [];\n for (var i = start; i < end; i += 3) {\n tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);\n output.push(tripletToBase64(tmp));\n }\n return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n if (!inited) {\n init();\n }\n var tmp;\n var len = uint8.length;\n var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes\n var output = '';\n var parts = [];\n var maxChunkLength = 16383; // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)));\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1];\n output += lookup[tmp >> 2];\n output += lookup[(tmp << 4) & 0x3F];\n output += '==';\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + (uint8[len - 1]);\n output += lookup[tmp >> 10];\n output += lookup[(tmp >> 4) & 0x3F];\n output += lookup[(tmp << 2) & 0x3F];\n output += '=';\n }\n\n parts.push(output);\n\n return parts.join('')\n}\n\nfunction read (buffer, offset, isLE, mLen, nBytes) {\n var e, m;\n var eLen = nBytes * 8 - mLen - 1;\n var eMax = (1 << eLen) - 1;\n var eBias = eMax >> 1;\n var nBits = -7;\n var i = isLE ? (nBytes - 1) : 0;\n var d = isLE ? -1 : 1;\n var s = buffer[offset + i];\n\n i += d;\n\n e = s & ((1 << (-nBits)) - 1);\n s >>= (-nBits);\n nBits += eLen;\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1);\n e >>= (-nBits);\n nBits += mLen;\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias;\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen);\n e = e - eBias;\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nfunction write (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c;\n var eLen = nBytes * 8 - mLen - 1;\n var eMax = (1 << eLen) - 1;\n var eBias = eMax >> 1;\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0);\n var i = isLE ? 0 : (nBytes - 1);\n var d = isLE ? 1 : -1;\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;\n\n value = Math.abs(value);\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0;\n e = eMax;\n } else {\n e = Math.floor(Math.log(value) / Math.LN2);\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--;\n c *= 2;\n }\n if (e + eBias >= 1) {\n value += rt / c;\n } else {\n value += rt * Math.pow(2, 1 - eBias);\n }\n if (value * c >= 2) {\n e++;\n c /= 2;\n }\n\n if (e + eBias >= eMax) {\n m = 0;\n e = eMax;\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen);\n e = e + eBias;\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);\n e = 0;\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m;\n eLen += mLen;\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128;\n}\n\nvar toString = {}.toString;\n\nvar isArray = Array.isArray || function (arr) {\n return toString.call(arr) == '[object Array]';\n};\n\n/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n\nvar INSPECT_MAX_BYTES = 50;\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : true;\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nvar _kMaxLength = kMaxLength();\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n if (kMaxLength() < length) {\n throw new RangeError('Invalid typed array length')\n }\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = new Uint8Array(length);\n that.__proto__ = Buffer.prototype;\n } else {\n // Fallback: Return an object instance of the Buffer class\n if (that === null) {\n that = new Buffer(length);\n }\n that.length = length;\n }\n\n return that\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n return new Buffer(arg, encodingOrOffset, length)\n }\n\n // Common case.\n if (typeof arg === 'number') {\n if (typeof encodingOrOffset === 'string') {\n throw new Error(\n 'If encoding is specified then the first argument must be a string'\n )\n }\n return allocUnsafe(this, arg)\n }\n return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192; // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n arr.__proto__ = Buffer.prototype;\n return arr\n};\n\nfunction from (that, value, encodingOrOffset, length) {\n if (typeof value === 'number') {\n throw new TypeError('\"value\" argument must not be a number')\n }\n\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n return fromArrayBuffer(that, value, encodingOrOffset, length)\n }\n\n if (typeof value === 'string') {\n return fromString(that, value, encodingOrOffset)\n }\n\n return fromObject(that, value)\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n return from(null, value, encodingOrOffset, length)\n};\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype;\n Buffer.__proto__ = Uint8Array;\n}\n\nfunction assertSize (size) {\n if (typeof size !== 'number') {\n throw new TypeError('\"size\" argument must be a number')\n } else if (size < 0) {\n throw new RangeError('\"size\" argument must not be negative')\n }\n}\n\nfunction alloc (that, size, fill, encoding) {\n assertSize(size);\n if (size <= 0) {\n return createBuffer(that, size)\n }\n if (fill !== undefined) {\n // Only pay attention to encoding if it's a string. This\n // prevents accidentally sending in a number that would\n // be interpretted as a start offset.\n return typeof encoding === 'string'\n ? createBuffer(that, size).fill(fill, encoding)\n : createBuffer(that, size).fill(fill)\n }\n return createBuffer(that, size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n return alloc(null, size, fill, encoding)\n};\n\nfunction allocUnsafe (that, size) {\n assertSize(size);\n that = createBuffer(that, size < 0 ? 0 : checked(size) | 0);\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < size; ++i) {\n that[i] = 0;\n }\n }\n return that\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n return allocUnsafe(null, size)\n};\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n return allocUnsafe(null, size)\n};\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') {\n encoding = 'utf8';\n }\n\n if (!Buffer.isEncoding(encoding)) {\n throw new TypeError('\"encoding\" must be a valid string encoding')\n }\n\n var length = byteLength(string, encoding) | 0;\n that = createBuffer(that, length);\n\n var actual = that.write(string, encoding);\n\n if (actual !== length) {\n // Writing a hex string, for example, that contains invalid characters will\n // cause everything after the first invalid character to be ignored. (e.g.\n // 'abxxcd' will be treated as 'ab')\n that = that.slice(0, actual);\n }\n\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = array.length < 0 ? 0 : checked(array.length) | 0;\n that = createBuffer(that, length);\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255;\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n array.byteLength; // this throws if `array` is not a valid ArrayBuffer\n\n if (byteOffset < 0 || array.byteLength < byteOffset) {\n throw new RangeError('\\'offset\\' is out of bounds')\n }\n\n if (array.byteLength < byteOffset + (length || 0)) {\n throw new RangeError('\\'length\\' is out of bounds')\n }\n\n if (byteOffset === undefined && length === undefined) {\n array = new Uint8Array(array);\n } else if (length === undefined) {\n array = new Uint8Array(array, byteOffset);\n } else {\n array = new Uint8Array(array, byteOffset, length);\n }\n\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = array;\n that.__proto__ = Buffer.prototype;\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromArrayLike(that, array);\n }\n return that\n}\n\nfunction fromObject (that, obj) {\n if (internalIsBuffer(obj)) {\n var len = checked(obj.length) | 0;\n that = createBuffer(that, len);\n\n if (that.length === 0) {\n return that\n }\n\n obj.copy(that, 0, 0, len);\n return that\n }\n\n if (obj) {\n if ((typeof ArrayBuffer !== 'undefined' &&\n obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n if (typeof obj.length !== 'number' || isnan(obj.length)) {\n return createBuffer(that, 0)\n }\n return fromArrayLike(that, obj)\n }\n\n if (obj.type === 'Buffer' && isArray(obj.data)) {\n return fromArrayLike(that, obj.data)\n }\n }\n\n throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength()` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (length) {\n if (+length != length) { // eslint-disable-line eqeqeq\n length = 0;\n }\n return Buffer.alloc(+length)\n}\nBuffer.isBuffer = isBuffer;\nfunction internalIsBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!internalIsBuffer(a) || !internalIsBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length;\n var y = b.length;\n\n for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i];\n y = b[i];\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n};\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'latin1':\n case 'binary':\n case 'base64':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n};\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n\n if (list.length === 0) {\n return Buffer.alloc(0)\n }\n\n var i;\n if (length === undefined) {\n length = 0;\n for (i = 0; i < list.length; ++i) {\n length += list[i].length;\n }\n }\n\n var buffer = Buffer.allocUnsafe(length);\n var pos = 0;\n for (i = 0; i < list.length; ++i) {\n var buf = list[i];\n if (!internalIsBuffer(buf)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n buf.copy(buffer, pos);\n pos += buf.length;\n }\n return buffer\n};\n\nfunction byteLength (string, encoding) {\n if (internalIsBuffer(string)) {\n return string.length\n }\n if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n return string.byteLength\n }\n if (typeof string !== 'string') {\n string = '' + string;\n }\n\n var len = string.length;\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false;\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'latin1':\n case 'binary':\n return len\n case 'utf8':\n case 'utf-8':\n case undefined:\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase();\n loweredCase = true;\n }\n }\n}\nBuffer.byteLength = byteLength;\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false;\n\n // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n // property of a typed array.\n\n // This behaves neither like String nor Uint8Array in that we set start/end\n // to their upper/lower bounds if the value passed is out of range.\n // undefined is handled specially as per ECMA-262 6th Edition,\n // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n if (start === undefined || start < 0) {\n start = 0;\n }\n // Return early if start > this.length. Done here to prevent potential uint32\n // coercion fail below.\n if (start > this.length) {\n return ''\n }\n\n if (end === undefined || end > this.length) {\n end = this.length;\n }\n\n if (end <= 0) {\n return ''\n }\n\n // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n end >>>= 0;\n start >>>= 0;\n\n if (end <= start) {\n return ''\n }\n\n if (!encoding) encoding = 'utf8';\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'latin1':\n case 'binary':\n return latin1Slice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase();\n loweredCase = true;\n }\n }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true;\n\nfunction swap (b, n, m) {\n var i = b[n];\n b[n] = b[m];\n b[m] = i;\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n var len = this.length;\n if (len % 2 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 16-bits')\n }\n for (var i = 0; i < len; i += 2) {\n swap(this, i, i + 1);\n }\n return this\n};\n\nBuffer.prototype.swap32 = function swap32 () {\n var len = this.length;\n if (len % 4 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 32-bits')\n }\n for (var i = 0; i < len; i += 4) {\n swap(this, i, i + 3);\n swap(this, i + 1, i + 2);\n }\n return this\n};\n\nBuffer.prototype.swap64 = function swap64 () {\n var len = this.length;\n if (len % 8 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 64-bits')\n }\n for (var i = 0; i < len; i += 8) {\n swap(this, i, i + 7);\n swap(this, i + 1, i + 6);\n swap(this, i + 2, i + 5);\n swap(this, i + 3, i + 4);\n }\n return this\n};\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0;\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n};\n\nBuffer.prototype.equals = function equals (b) {\n if (!internalIsBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n};\n\nBuffer.prototype.inspect = function inspect () {\n var str = '';\n var max = INSPECT_MAX_BYTES;\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ');\n if (this.length > max) str += ' ... ';\n }\n return ''\n};\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n if (!internalIsBuffer(target)) {\n throw new TypeError('Argument must be a Buffer')\n }\n\n if (start === undefined) {\n start = 0;\n }\n if (end === undefined) {\n end = target ? target.length : 0;\n }\n if (thisStart === undefined) {\n thisStart = 0;\n }\n if (thisEnd === undefined) {\n thisEnd = this.length;\n }\n\n if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n throw new RangeError('out of range index')\n }\n\n if (thisStart >= thisEnd && start >= end) {\n return 0\n }\n if (thisStart >= thisEnd) {\n return -1\n }\n if (start >= end) {\n return 1\n }\n\n start >>>= 0;\n end >>>= 0;\n thisStart >>>= 0;\n thisEnd >>>= 0;\n\n if (this === target) return 0\n\n var x = thisEnd - thisStart;\n var y = end - start;\n var len = Math.min(x, y);\n\n var thisCopy = this.slice(thisStart, thisEnd);\n var targetCopy = target.slice(start, end);\n\n for (var i = 0; i < len; ++i) {\n if (thisCopy[i] !== targetCopy[i]) {\n x = thisCopy[i];\n y = targetCopy[i];\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n};\n\n// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,\n// OR the last index of `val` in `buffer` at offset <= `byteOffset`.\n//\n// Arguments:\n// - buffer - a Buffer to search\n// - val - a string, Buffer, or number\n// - byteOffset - an index into `buffer`; will be clamped to an int32\n// - encoding - an optional encoding, relevant is val is a string\n// - dir - true for indexOf, false for lastIndexOf\nfunction bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {\n // Empty buffer means no match\n if (buffer.length === 0) return -1\n\n // Normalize byteOffset\n if (typeof byteOffset === 'string') {\n encoding = byteOffset;\n byteOffset = 0;\n } else if (byteOffset > 0x7fffffff) {\n byteOffset = 0x7fffffff;\n } else if (byteOffset < -0x80000000) {\n byteOffset = -0x80000000;\n }\n byteOffset = +byteOffset; // Coerce to Number.\n if (isNaN(byteOffset)) {\n // byteOffset: it it's undefined, null, NaN, \"foo\", etc, search whole buffer\n byteOffset = dir ? 0 : (buffer.length - 1);\n }\n\n // Normalize byteOffset: negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = buffer.length + byteOffset;\n if (byteOffset >= buffer.length) {\n if (dir) return -1\n else byteOffset = buffer.length - 1;\n } else if (byteOffset < 0) {\n if (dir) byteOffset = 0;\n else return -1\n }\n\n // Normalize val\n if (typeof val === 'string') {\n val = Buffer.from(val, encoding);\n }\n\n // Finally, search either indexOf (if dir is true) or lastIndexOf\n if (internalIsBuffer(val)) {\n // Special case: looking for empty string/buffer always fails\n if (val.length === 0) {\n return -1\n }\n return arrayIndexOf(buffer, val, byteOffset, encoding, dir)\n } else if (typeof val === 'number') {\n val = val & 0xFF; // Search for a byte value [0-255]\n if (Buffer.TYPED_ARRAY_SUPPORT &&\n typeof Uint8Array.prototype.indexOf === 'function') {\n if (dir) {\n return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)\n } else {\n return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)\n }\n }\n return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding, dir) {\n var indexSize = 1;\n var arrLength = arr.length;\n var valLength = val.length;\n\n if (encoding !== undefined) {\n encoding = String(encoding).toLowerCase();\n if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n encoding === 'utf16le' || encoding === 'utf-16le') {\n if (arr.length < 2 || val.length < 2) {\n return -1\n }\n indexSize = 2;\n arrLength /= 2;\n valLength /= 2;\n byteOffset /= 2;\n }\n }\n\n function read (buf, i) {\n if (indexSize === 1) {\n return buf[i]\n } else {\n return buf.readUInt16BE(i * indexSize)\n }\n }\n\n var i;\n if (dir) {\n var foundIndex = -1;\n for (i = byteOffset; i < arrLength; i++) {\n if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n if (foundIndex === -1) foundIndex = i;\n if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n } else {\n if (foundIndex !== -1) i -= i - foundIndex;\n foundIndex = -1;\n }\n }\n } else {\n if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength;\n for (i = byteOffset; i >= 0; i--) {\n var found = true;\n for (var j = 0; j < valLength; j++) {\n if (read(arr, i + j) !== read(val, j)) {\n found = false;\n break\n }\n }\n if (found) return i\n }\n }\n\n return -1\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n return this.indexOf(val, byteOffset, encoding) !== -1\n};\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n return bidirectionalIndexOf(this, val, byteOffset, encoding, true)\n};\n\nBuffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {\n return bidirectionalIndexOf(this, val, byteOffset, encoding, false)\n};\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0;\n var remaining = buf.length - offset;\n if (!length) {\n length = remaining;\n } else {\n length = Number(length);\n if (length > remaining) {\n length = remaining;\n }\n }\n\n // must be an even number of digits\n var strLen = string.length;\n if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2;\n }\n for (var i = 0; i < length; ++i) {\n var parsed = parseInt(string.substr(i * 2, 2), 16);\n if (isNaN(parsed)) return i\n buf[offset + i] = parsed;\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction latin1Write (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8';\n length = this.length;\n offset = 0;\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset;\n length = this.length;\n offset = 0;\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0;\n if (isFinite(length)) {\n length = length | 0;\n if (encoding === undefined) encoding = 'utf8';\n } else {\n encoding = length;\n length = undefined;\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n throw new Error(\n 'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n )\n }\n\n var remaining = this.length - offset;\n if (length === undefined || length > remaining) length = remaining;\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('Attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8';\n\n var loweredCase = false;\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'latin1':\n case 'binary':\n return latin1Write(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase();\n loweredCase = true;\n }\n }\n};\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n};\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return fromByteArray(buf)\n } else {\n return fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end);\n var res = [];\n\n var i = start;\n while (i < end) {\n var firstByte = buf[i];\n var codePoint = null;\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1;\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint;\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte;\n }\n break\n case 2:\n secondByte = buf[i + 1];\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F);\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint;\n }\n }\n break\n case 3:\n secondByte = buf[i + 1];\n thirdByte = buf[i + 2];\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F);\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint;\n }\n }\n break\n case 4:\n secondByte = buf[i + 1];\n thirdByte = buf[i + 2];\n fourthByte = buf[i + 3];\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F);\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint;\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD;\n bytesPerSequence = 1;\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000;\n res.push(codePoint >>> 10 & 0x3FF | 0xD800);\n codePoint = 0xDC00 | codePoint & 0x3FF;\n }\n\n res.push(codePoint);\n i += bytesPerSequence;\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000;\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length;\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = '';\n var i = 0;\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n );\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = '';\n end = Math.min(buf.length, end);\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i] & 0x7F);\n }\n return ret\n}\n\nfunction latin1Slice (buf, start, end) {\n var ret = '';\n end = Math.min(buf.length, end);\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i]);\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length;\n\n if (!start || start < 0) start = 0;\n if (!end || end < 0 || end > len) end = len;\n\n var out = '';\n for (var i = start; i < end; ++i) {\n out += toHex(buf[i]);\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end);\n var res = '';\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256);\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length;\n start = ~~start;\n end = end === undefined ? len : ~~end;\n\n if (start < 0) {\n start += len;\n if (start < 0) start = 0;\n } else if (start > len) {\n start = len;\n }\n\n if (end < 0) {\n end += len;\n if (end < 0) end = 0;\n } else if (end > len) {\n end = len;\n }\n\n if (end < start) end = start;\n\n var newBuf;\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = this.subarray(start, end);\n newBuf.__proto__ = Buffer.prototype;\n } else {\n var sliceLen = end - start;\n newBuf = new Buffer(sliceLen, undefined);\n for (var i = 0; i < sliceLen; ++i) {\n newBuf[i] = this[i + start];\n }\n }\n\n return newBuf\n};\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0;\n byteLength = byteLength | 0;\n if (!noAssert) checkOffset(offset, byteLength, this.length);\n\n var val = this[offset];\n var mul = 1;\n var i = 0;\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul;\n }\n\n return val\n};\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0;\n byteLength = byteLength | 0;\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length);\n }\n\n var val = this[offset + --byteLength];\n var mul = 1;\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul;\n }\n\n return val\n};\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length);\n return this[offset]\n};\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length);\n return this[offset] | (this[offset + 1] << 8)\n};\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length);\n return (this[offset] << 8) | this[offset + 1]\n};\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length);\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n};\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length);\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n};\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0;\n byteLength = byteLength | 0;\n if (!noAssert) checkOffset(offset, byteLength, this.length);\n\n var val = this[offset];\n var mul = 1;\n var i = 0;\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul;\n }\n mul *= 0x80;\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength);\n\n return val\n};\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0;\n byteLength = byteLength | 0;\n if (!noAssert) checkOffset(offset, byteLength, this.length);\n\n var i = byteLength;\n var mul = 1;\n var val = this[offset + --i];\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul;\n }\n mul *= 0x80;\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength);\n\n return val\n};\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length);\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n};\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length);\n var val = this[offset] | (this[offset + 1] << 8);\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n};\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length);\n var val = this[offset + 1] | (this[offset] << 8);\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n};\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length);\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n};\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length);\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n};\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length);\n return read(this, offset, true, 23, 4)\n};\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length);\n return read(this, offset, false, 23, 4)\n};\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length);\n return read(this, offset, true, 52, 8)\n};\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length);\n return read(this, offset, false, 52, 8)\n};\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!internalIsBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value;\n offset = offset | 0;\n byteLength = byteLength | 0;\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1;\n checkInt(this, value, offset, byteLength, maxBytes, 0);\n }\n\n var mul = 1;\n var i = 0;\n this[offset] = value & 0xFF;\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF;\n }\n\n return offset + byteLength\n};\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value;\n offset = offset | 0;\n byteLength = byteLength | 0;\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1;\n checkInt(this, value, offset, byteLength, maxBytes, 0);\n }\n\n var i = byteLength - 1;\n var mul = 1;\n this[offset + i] = value & 0xFF;\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF;\n }\n\n return offset + byteLength\n};\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value;\n offset = offset | 0;\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0);\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value);\n this[offset] = (value & 0xff);\n return offset + 1\n};\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1;\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8;\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value;\n offset = offset | 0;\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0);\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff);\n this[offset + 1] = (value >>> 8);\n } else {\n objectWriteUInt16(this, value, offset, true);\n }\n return offset + 2\n};\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value;\n offset = offset | 0;\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0);\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8);\n this[offset + 1] = (value & 0xff);\n } else {\n objectWriteUInt16(this, value, offset, false);\n }\n return offset + 2\n};\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1;\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff;\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value;\n offset = offset | 0;\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0);\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24);\n this[offset + 2] = (value >>> 16);\n this[offset + 1] = (value >>> 8);\n this[offset] = (value & 0xff);\n } else {\n objectWriteUInt32(this, value, offset, true);\n }\n return offset + 4\n};\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value;\n offset = offset | 0;\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0);\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24);\n this[offset + 1] = (value >>> 16);\n this[offset + 2] = (value >>> 8);\n this[offset + 3] = (value & 0xff);\n } else {\n objectWriteUInt32(this, value, offset, false);\n }\n return offset + 4\n};\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value;\n offset = offset | 0;\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1);\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit);\n }\n\n var i = 0;\n var mul = 1;\n var sub = 0;\n this[offset] = value & 0xFF;\n while (++i < byteLength && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n sub = 1;\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF;\n }\n\n return offset + byteLength\n};\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value;\n offset = offset | 0;\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1);\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit);\n }\n\n var i = byteLength - 1;\n var mul = 1;\n var sub = 0;\n this[offset + i] = value & 0xFF;\n while (--i >= 0 && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n sub = 1;\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF;\n }\n\n return offset + byteLength\n};\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value;\n offset = offset | 0;\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80);\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value);\n if (value < 0) value = 0xff + value + 1;\n this[offset] = (value & 0xff);\n return offset + 1\n};\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value;\n offset = offset | 0;\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff);\n this[offset + 1] = (value >>> 8);\n } else {\n objectWriteUInt16(this, value, offset, true);\n }\n return offset + 2\n};\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value;\n offset = offset | 0;\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8);\n this[offset + 1] = (value & 0xff);\n } else {\n objectWriteUInt16(this, value, offset, false);\n }\n return offset + 2\n};\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value;\n offset = offset | 0;\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff);\n this[offset + 1] = (value >>> 8);\n this[offset + 2] = (value >>> 16);\n this[offset + 3] = (value >>> 24);\n } else {\n objectWriteUInt32(this, value, offset, true);\n }\n return offset + 4\n};\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value;\n offset = offset | 0;\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);\n if (value < 0) value = 0xffffffff + value + 1;\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24);\n this[offset + 1] = (value >>> 16);\n this[offset + 2] = (value >>> 8);\n this[offset + 3] = (value & 0xff);\n } else {\n objectWriteUInt32(this, value, offset, false);\n }\n return offset + 4\n};\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4);\n }\n write(buf, value, offset, littleEndian, 23, 4);\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n};\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n};\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8);\n }\n write(buf, value, offset, littleEndian, 52, 8);\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n};\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n};\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0;\n if (!end && end !== 0) end = this.length;\n if (targetStart >= target.length) targetStart = target.length;\n if (!targetStart) targetStart = 0;\n if (end > 0 && end < start) end = start;\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length;\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start;\n }\n\n var len = end - start;\n var i;\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; --i) {\n target[i + targetStart] = this[i + start];\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; ++i) {\n target[i + targetStart] = this[i + start];\n }\n } else {\n Uint8Array.prototype.set.call(\n target,\n this.subarray(start, start + len),\n targetStart\n );\n }\n\n return len\n};\n\n// Usage:\n// buffer.fill(number[, offset[, end]])\n// buffer.fill(buffer[, offset[, end]])\n// buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n // Handle string cases:\n if (typeof val === 'string') {\n if (typeof start === 'string') {\n encoding = start;\n start = 0;\n end = this.length;\n } else if (typeof end === 'string') {\n encoding = end;\n end = this.length;\n }\n if (val.length === 1) {\n var code = val.charCodeAt(0);\n if (code < 256) {\n val = code;\n }\n }\n if (encoding !== undefined && typeof encoding !== 'string') {\n throw new TypeError('encoding must be a string')\n }\n if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding)\n }\n } else if (typeof val === 'number') {\n val = val & 255;\n }\n\n // Invalid ranges are not set to a default, so can range check early.\n if (start < 0 || this.length < start || this.length < end) {\n throw new RangeError('Out of range index')\n }\n\n if (end <= start) {\n return this\n }\n\n start = start >>> 0;\n end = end === undefined ? this.length : end >>> 0;\n\n if (!val) val = 0;\n\n var i;\n if (typeof val === 'number') {\n for (i = start; i < end; ++i) {\n this[i] = val;\n }\n } else {\n var bytes = internalIsBuffer(val)\n ? val\n : utf8ToBytes(new Buffer(val, encoding).toString());\n var len = bytes.length;\n for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len];\n }\n }\n\n return this\n};\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g;\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '');\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '=';\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity;\n var codePoint;\n var length = string.length;\n var leadSurrogate = null;\n var bytes = [];\n\n for (var i = 0; i < length; ++i) {\n codePoint = string.charCodeAt(i);\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint;\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n leadSurrogate = codePoint;\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000;\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n }\n\n leadSurrogate = null;\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint);\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n );\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n );\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n );\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = [];\n for (var i = 0; i < str.length; ++i) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF);\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo;\n var byteArray = [];\n for (var i = 0; i < str.length; ++i) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i);\n hi = c >> 8;\n lo = c % 256;\n byteArray.push(lo);\n byteArray.push(hi);\n }\n\n return byteArray\n}\n\n\nfunction base64ToBytes (str) {\n return toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; ++i) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i];\n }\n return i\n}\n\nfunction isnan (val) {\n return val !== val // eslint-disable-line no-self-compare\n}\n\n\n// the following is from is-buffer, also by Feross Aboukhadijeh and with same lisence\n// The _isBuffer check is for Safari 5-7 support, because it's missing\n// Object.prototype.constructor. Remove this eventually\nfunction isBuffer(obj) {\n return obj != null && (!!obj._isBuffer || isFastBuffer(obj) || isSlowBuffer(obj))\n}\n\nfunction isFastBuffer (obj) {\n return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)\n}\n\n// For Node v0.10 support. Remove this eventually.\nfunction isSlowBuffer (obj) {\n return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isFastBuffer(obj.slice(0, 0))\n}\n\nexport { Buffer, INSPECT_MAX_BYTES, SlowBuffer, isBuffer, _kMaxLength as kMaxLength };\n","/**\n * jsPDF - PDF Document creation from JavaScript\n * Version 1.0.150-git Built on 2014-05-30T00:40\n * CommitID dcbc9fcb9b\n *\n * Copyright (c) 2010-2014 James Hall, https://github.com/MrRio/jsPDF\n * 2010 Aaron Spike, https://github.com/acspike\n * 2012 Willow Systems Corporation, willow-systems.com\n * 2012 Pablo Hess, https://github.com/pablohess\n * 2012 Florian Jenett, https://github.com/fjenett\n * 2013 Warren Weckesser, https://github.com/warrenweckesser\n * 2013 Youssef Beddad, https://github.com/lifof\n * 2013 Lee Driscoll, https://github.com/lsdriscoll\n * 2013 Stefan Slonevskiy, https://github.com/stefslon\n * 2013 Jeremy Morel, https://github.com/jmorel\n * 2013 Christoph Hartmann, https://github.com/chris-rock\n * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria\n * 2014 James Makes, https://github.com/dollaruw\n * 2014 Diego Casorran, https://github.com/diegocr\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * Contributor(s):\n * siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango,\n * kim3er, mfo, alnorth,\n */\n/**\n * jsPDF addHTML PlugIn\n * Copyright (c) 2014 Diego Casorran\n * Licensed under the MIT License.\n * http://opensource.org/licenses/mit-license\n */\n/**\n * jsPDF addImage plugin\n * Copyright (c) 2012 Jason Siefken, https://github.com/siefkenj/\n * 2013 Chris Dowling, https://github.com/gingerchris\n * 2013 Trinh Ho, https://github.com/ineedfat\n * 2013 Edwin Alejandro Perez, https://github.com/eaparango\n * 2013 Norah Smith, https://github.com/burnburnrocket\n * 2014 Diego Casorran, https://github.com/diegocr\n * 2014 James Robb, https://github.com/jamesbrobb\n */\n/**\n * jsPDF Cell plugin\n * Copyright (c) 2013 Youssef Beddad, youssef.beddad@gmail.com\n * 2013 Eduardo Menezes de Morais, eduardo.morais@usp.br\n * 2013 Lee Driscoll, https://github.com/lsdriscoll\n * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria\n * 2014 James Hall, james@parall.ax\n * 2014 Diego Casorran, https://github.com/diegocr\n */\n/**\n * jsPDF fromHTML plugin. BETA stage. API subject to change. Needs browser\n * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com\n * 2014 Juan Pablo Gaviria, https://github.com/juanpgaviria\n * 2014 Diego Casorran, https://github.com/diegocr\n * 2014 Daniel Husar, https://github.com/danielhusar\n * 2014 Wolfgang Gassler, https://github.com/woolfg\n */\n/**\n * jsPDF JavaScript plugin\n * Copyright (c) 2013 Youssef Beddad, youssef.beddad@gmail.com\n */\n/**\n * jsPDF PNG PlugIn\n * Copyright (c) 2014 James Robb, https://github.com/jamesbrobb\n */\n/**\njsPDF Silly SVG plugin\nCopyright (c) 2012 Willow Systems Corporation, willow-systems.com\n*/\n/**\n * jsPDF split_text_to_size plugin - MIT license.\n * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com\n * 2014 Diego Casorran, https://github.com/diegocr\n */\n/**\njsPDF standard_fonts_metrics plugin\nCopyright (c) 2012 Willow Systems Corporation, willow-systems.com\nMIT license.\n*/\n/**\n * jsPDF total_pages plugin\n * Copyright (c) 2013 Eduardo Menezes de Morais, eduardo.morais@usp.br\n */\n/* Blob.js\n * A Blob implementation.\n * 2014-05-27\n * By Eli Grey, http://eligrey.com\n * By Devin Samarin, https://github.com/eboyjr\n * License: X11/MIT\n * See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md\n */\n/* FileSaver.js\n * A saveAs() FileSaver implementation.\n * 2014-05-27\n * By Eli Grey, http://eligrey.com\n * License: X11/MIT\n * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md\n */\n/*\n * Copyright (c) 2012 chick307 \n * Licensed under the MIT License.\n * http://opensource.org/licenses/mit-license\n */\n/*\n Deflate.js - https://github.com/gildas-lormeau/zip.js\n Copyright (c) 2013 Gildas Lormeau. All rights reserved.\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n 1. Redistributions of source code must retain the above copyright notice,\n this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the distribution.\n 3. The names of the authors may not be used to endorse or promote products\n derived from this software without specific prior written permission.\n THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,\n INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\n FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,\n INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,\n INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\n OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n/*\n# PNG.js\n# Copyright (c) 2011 Devon Govett\n# MIT LICENSE\n#\n*/\n/*\n * Extracted from pdf.js\n * https://github.com/andreasgal/pdf.js\n * Copyright (c) 2011 Mozilla Foundation\n * Contributors: Andreas Gal \n * Chris G Jones \n * Shaon Barman \n * Vivien Nicolas <21@vingtetun.org>\n * Justin D'Arcangelo \n * Yury Delendik\n */\n/**\n * JavaScript Polyfill functions for jsPDF\n * Collected from public resources by\n * https://github.com/diegocr\n */\n!function(t,e){e[\"true\"]=t;var r=function(t){\"use strict\";function e(e){var r={};this.subscribe=function(t,e,n){if(\"function\"!=typeof e)return!1;r.hasOwnProperty(t)||(r[t]={});var s=Math.random().toString(35);return r[t][s]=[e,!!n],s},this.unsubscribe=function(t){for(var e in r)if(r[e][t])return delete r[e][t],!0;return!1},this.publish=function(n){if(r.hasOwnProperty(n)){var s=Array.prototype.slice.call(arguments,1),o=[];for(var i in r[n]){var a=r[n][i];try{a[0].apply(e,s)}catch(u){t.console&&console.error(\"jsPDF PubSub Error\",u.message,u)}a[1]&&o.push(i)}o.length&&o.forEach(this.unsubscribe)}}}function r(a,u,c,l){var f={};\"object\"==typeof a&&(f=a,a=f.orientation,u=f.unit||u,c=f.format||c,l=f.compress||f.compressPdf||l),u=u||\"mm\",c=c||\"a4\",a=(\"\"+(a||\"P\")).toLowerCase();var d,h,p,m,w,y=(\"\"+c).toLowerCase(),g=!!l&&\"function\"==typeof Uint8Array,v=f.textColor||\"0 g\",b=f.drawColor||\"0 G\",q=f.fontSize||16,x=f.lineHeight||1.15,k=f.lineWidth||.200025,_=2,A=!1,C=[],S={},E={},z=0,I=[],T=[],B=0,O=0,P=0,R={title:\"\",subject:\"\",author:\"\",keywords:\"\",creator:\"\"},D={},U=new e(D),F=function(t){return t.toFixed(2)},L=function(t){return t.toFixed(3)},j=function(t){return(\"0\"+parseInt(t)).slice(-2)},N=function(t){A?I[z].push(t):(P+=t.length+1,T.push(t))},M=function(){return _++,C[_]=P,N(_+\" 0 obj\"),_},H=function(t){N(\"stream\"),N(t),N(\"endstream\")},G=function(){var e,n,o,i,a,u,c,l=m*h,f=w*h;for(c=t.adler32cs||r.adler32cs,g&&\"undefined\"==typeof c&&(g=!1),e=1;z>=e;e++){if(M(),N(\"<>\"),N(\"endobj\"),n=I[e].join(\"\\n\"),M(),g){for(o=[],i=n.length;i--;)o[i]=n.charCodeAt(i);u=c.from(n),a=new s(6),a.append(new Uint8Array(o)),n=a.flush(),o=new Uint8Array(n.length+6),o.set(new Uint8Array([120,156])),o.set(n,2),o.set(new Uint8Array([255&u,u>>8&255,u>>16&255,u>>24&255]),n.length+2),n=String.fromCharCode.apply(null,o),N(\"<>\")}else N(\"<>\");H(n),N(\"endobj\")}C[1]=P,N(\"1 0 obj\"),N(\"<i;i++)d+=3+2*i+\" 0 R \";N(d+\"]\"),N(\"/Count \"+z),N(\"/MediaBox [0 0 \"+F(l)+\" \"+F(f)+\"]\"),N(\">>\"),N(\"endobj\")},J=function(t){t.objectNumber=M(),N(\"<>\"),N(\"endobj\")},V=function(){for(var t in S)S.hasOwnProperty(t)&&J(S[t])},W=function(){U.publish(\"putXobjectDict\")},X=function(){N(\"/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]\"),N(\"/Font <<\");for(var t in S)S.hasOwnProperty(t)&&N(\"/\"+t+\" \"+S[t].objectNumber+\" 0 R\");N(\">>\"),N(\"/XObject <<\"),W(),N(\">>\")},Y=function(){V(),U.publish(\"putResources\"),C[2]=P,N(\"2 0 obj\"),N(\"<<\"),X(),N(\">>\"),N(\"endobj\"),U.publish(\"postPutResources\")},K=function(t,e,r){E.hasOwnProperty(e)||(E[e]={}),E[e][r]=t},Q=function(t,e,r,n){var s=\"F\"+(Object.keys(S).length+1).toString(10),o=S[s]={id:s,PostScriptName:t,fontName:e,fontStyle:r,encoding:n,metadata:{}};return K(s,e,r),U.publish(\"addFont\",o),s},$=function(){for(var t=\"helvetica\",e=\"times\",r=\"courier\",n=\"normal\",s=\"bold\",o=\"italic\",i=\"bolditalic\",a=\"StandardEncoding\",u=[[\"Helvetica\",t,n],[\"Helvetica-Bold\",t,s],[\"Helvetica-Oblique\",t,o],[\"Helvetica-BoldOblique\",t,i],[\"Courier\",r,n],[\"Courier-Bold\",r,s],[\"Courier-Oblique\",r,o],[\"Courier-BoldOblique\",r,i],[\"Times-Roman\",e,n],[\"Times-Bold\",e,s],[\"Times-Italic\",e,o],[\"Times-BoldItalic\",e,i]],c=0,l=u.length;l>c;c++){var f=Q(u[c][0],u[c][1],u[c][2],a),d=u[c][0].split(\"-\");K(f,d[0],d[1]||\"\")}U.publish(\"addFonts\",{fonts:S,dictionary:E})},Z=function(e){return e.foo=function(){try{return e.apply(this,arguments)}catch(r){var n=r.stack||\"\";~n.indexOf(\" at \")&&(n=n.split(\" at \")[1]);var s=\"Error in function \"+n.split(\"\\n\")[0].split(\"<\")[0]+\": \"+r.message;if(!t.console)throw new Error(s);console.log(s,r),t.alert&&alert(s),console.trace()}},e.foo.bar=e,e.foo},te=function(t,e){var r,n,s,o,i,a,u,c,l;if(e=e||{},s=e.sourceEncoding||\"Unicode\",i=e.outputEncoding,(e.autoencode||i)&&S[d].metadata&&S[d].metadata[s]&&S[d].metadata[s].encoding&&(o=S[d].metadata[s].encoding,!i&&S[d].encoding&&(i=S[d].encoding),!i&&o.codePages&&(i=o.codePages[0]),\"string\"==typeof i&&(i=o[i]),i)){for(u=!1,a=[],r=0,n=t.length;n>r;r++)c=i[t.charCodeAt(r)],c?a.push(String.fromCharCode(c)):a.push(t[r]),a[r].charCodeAt(0)>>8&&(u=!0);t=a.join(\"\")}for(r=t.length;void 0===u&&0!==r;)t.charCodeAt(r-1)>>8&&(u=!0),r--;if(!u)return t;for(a=e.noBOM?[]:[254,255],r=0,n=t.length;n>r;r++){if(c=t.charCodeAt(r),l=c>>8,l>>8)throw new Error(\"Character at position \"+r+\" of string '\"+t+\"' exceeds 16bits. Cannot be encoded into UCS-2 BE\");a.push(l),a.push(c-(l<<8))}return String.fromCharCode.apply(void 0,a)},ee=function(t,e){return te(t,e).replace(/\\\\/g,\"\\\\\\\\\").replace(/\\(/g,\"\\\\(\").replace(/\\)/g,\"\\\\)\")},re=function(){N(\"/Producer (jsPDF \"+r.version+\")\");for(var t in R)R.hasOwnProperty(t)&&R[t]&&N(\"/\"+t.substr(0,1).toUpperCase()+t.substr(1)+\" (\"+ee(R[t])+\")\");var e=new Date;N([\"/CreationDate (D:\",e.getFullYear(),j(e.getMonth()+1),j(e.getDate()),j(e.getHours()),j(e.getMinutes()),j(e.getSeconds()),\")\"].join(\"\"))},ne=function(){N(\"/Type /Catalog\"),N(\"/Pages 1 0 R\"),N(\"/OpenAction [3 0 R /FitH null]\"),N(\"/PageLayout /OneColumn\"),U.publish(\"putCatalog\")},se=function(){N(\"/Size \"+(_+1)),N(\"/Root \"+_+\" 0 R\"),N(\"/Info \"+(_-1)+\" 0 R\")},oe=function(){z++,A=!0,I[z]=[]},ie=function(){oe(),N(F(k*h)+\" w\"),N(b),0!==B&&N(B+\" J\"),0!==O&&N(O+\" j\"),U.publish(\"addPage\",{pageNumber:z})},ae=function(t,e){var r;t=void 0!==t?t:S[d].fontName,e=void 0!==e?e:S[d].fontStyle;try{r=E[t][e]||E[t].normal}catch(n){}if(!r)throw new Error(\"Unable to look up font label for font '\"+t+\"', '\"+e+\"'. Refer to getFontList() for available fonts.\");return r},ue=function(){A=!1,_=2,T=[],C=[],N(\"%PDF-\"+o),G(),Y(),M(),N(\"<<\"),re(),N(\">>\"),N(\"endobj\"),M(),N(\"<<\"),ne(),N(\">>\"),N(\"endobj\");var t,e=P,r=\"0000000000\";for(N(\"xref\"),N(\"0 \"+(_+1)),N(r+\" 65535 f \"),t=1;_>=t;t++)N((r+C[t]).slice(-10)+\" 00000 n \");return N(\"trailer\"),N(\"<<\"),se(),N(\">>\"),N(\"startxref\"),N(e),N(\"%%EOF\"),A=!0,T.join(\"\\n\")},ce=function(t){var e=\"S\";return\"F\"===t?e=\"f\":\"FD\"===t||\"DF\"===t?e=\"B\":(\"f\"===t||\"f*\"===t||\"B\"===t||\"B*\"===t)&&(e=t),e},le=function(){for(var t=ue(),e=t.length,r=new ArrayBuffer(e),n=new Uint8Array(r);e--;)n[e]=t.charCodeAt(e);return r},fe=function(){return new Blob([le()],{type:\"application/pdf\"})},de=Z(function(e,r){switch(e){case void 0:return ue();case\"save\":if(navigator.getUserMedia&&(void 0===t.URL||void 0===t.URL.createObjectURL))return D.output(\"dataurlnewwindow\");n(fe(),r),\"function\"==typeof n.unload&&t.setTimeout&&setTimeout(n.unload,70);break;case\"arraybuffer\":return le();case\"blob\":return fe();case\"datauristring\":case\"dataurlstring\":return\"data:application/pdf;base64,\"+btoa(ue());case\"datauri\":case\"dataurl\":t.document.location.href=\"data:application/pdf;base64,\"+btoa(ue());break;case\"dataurlnewwindow\":t.open(\"data:application/pdf;base64,\"+btoa(ue()));break;default:throw new Error('Output type \"'+e+'\" is not supported.')}});switch(u){case\"pt\":h=1;break;case\"mm\":h=72/25.4;break;case\"cm\":h=72/2.54;break;case\"in\":h=72;break;case\"px\":h=96/72;break;case\"pc\":h=12;break;case\"em\":h=12;break;case\"ex\":h=6;break;default:throw\"Invalid unit: \"+u}if(i.hasOwnProperty(y))w=i[y][1]/h,m=i[y][0]/h;else try{w=c[1],m=c[0]}catch(he){throw new Error(\"Invalid format: \"+c)}if(\"p\"===a||\"portrait\"===a)a=\"p\",m>w&&(p=m,m=w,w=p);else{if(\"l\"!==a&&\"landscape\"!==a)throw\"Invalid orientation: \"+a;a=\"l\",w>m&&(p=m,m=w,w=p)}D.internal={pdfEscape:ee,getStyle:ce,getFont:function(){return S[ae.apply(D,arguments)]},getFontSize:function(){return q},getLineHeight:function(){return q*x},write:function(t){N(1===arguments.length?t:Array.prototype.join.call(arguments,\" \"))},getCoordinateString:function(t){return F(t*h)},getVerticalCoordinateString:function(t){return F((w-t)*h)},collections:{},newObject:M,putStream:H,events:U,scaleFactor:h,pageSize:{width:m,height:w},output:function(t,e){return de(t,e)},getNumberOfPages:function(){return I.length-1},pages:I},D.addPage=function(){return ie(),this},D.text=function(t,e,r,n,s){function o(t){return t=t.split(\"\t\").join(Array(f.TabLen||9).join(\" \")),ee(t,n)}\"number\"==typeof t&&(p=r,r=e,e=t,t=p),\"string\"==typeof t&&t.match(/[\\n\\r]/)&&(t=t.split(/\\r\\n|\\r|\\n/g)),\"number\"==typeof n&&(s=n,n=null);var i=\"\",a=\"Td\";if(s){s*=Math.PI/180;var u=Math.cos(s),c=Math.sin(s);i=[F(u),F(c),F(-1*c),F(u),\"\"].join(\" \"),a=\"Tm\"}if(n=n||{},\"noBOM\"in n||(n.noBOM=!0),\"autoencode\"in n||(n.autoencode=!0),\"string\"==typeof t)t=o(t);else{if(!(t instanceof Array))throw new Error('Type of text must be string or Array. \"'+t+'\" is not recognized.');for(var l=t.concat(),m=[],y=l.length;y--;)m.push(o(l.shift()));t=m.join(\") Tj\\nT* (\")}return N(\"BT\\n/\"+d+\" \"+q+\" Tf\\n\"+q*x+\" TL\\n\"+v+\"\\n\"+i+F(e*h)+\" \"+F((w-r)*h)+\" \"+a+\"\\n(\"+t+\") Tj\\nET\"),this},D.line=function(t,e,r,n){return this.lines([[r-t,n-e]],t,e)},D.lines=function(t,e,r,n,s,o){var i,a,u,c,l,f,d,m,y,g,v;for(\"number\"==typeof t&&(p=r,r=e,e=t,t=p),n=n||[1,1],N(L(e*h)+\" \"+L((w-r)*h)+\" m \"),i=n[0],a=n[1],c=t.length,g=e,v=r,u=0;c>u;u++)l=t[u],2===l.length?(g=l[0]*i+g,v=l[1]*a+v,N(L(g*h)+\" \"+L((w-v)*h)+\" l\")):(f=l[0]*i+g,d=l[1]*a+v,m=l[2]*i+g,y=l[3]*a+v,g=l[4]*i+g,v=l[5]*a+v,N(L(f*h)+\" \"+L((w-d)*h)+\" \"+L(m*h)+\" \"+L((w-y)*h)+\" \"+L(g*h)+\" \"+L((w-v)*h)+\" c\"));return o&&N(\" h\"),null!==s&&N(ce(s)),this},D.rect=function(t,e,r,n,s){ce(s);return N([F(t*h),F((w-e)*h),F(r*h),F(-n*h),\"re\"].join(\" \")),null!==s&&N(ce(s)),this},D.triangle=function(t,e,r,n,s,o,i){return this.lines([[r-t,n-e],[s-r,o-n],[t-s,e-o]],t,e,[1,1],i,!0),this},D.roundedRect=function(t,e,r,n,s,o,i){var a=4/3*(Math.SQRT2-1);return this.lines([[r-2*s,0],[s*a,0,s,o-o*a,s,o],[0,n-2*o],[0,o*a,-(s*a),o,-s,o],[-r+2*s,0],[-(s*a),0,-s,-(o*a),-s,-o],[0,-n+2*o],[0,-(o*a),s*a,-o,s,-o]],t+s,e,[1,1],i),this},D.ellipse=function(t,e,r,n,s){var o=4/3*(Math.SQRT2-1)*r,i=4/3*(Math.SQRT2-1)*n;return N([F((t+r)*h),F((w-e)*h),\"m\",F((t+r)*h),F((w-(e-i))*h),F((t+o)*h),F((w-(e-n))*h),F(t*h),F((w-(e-n))*h),\"c\"].join(\" \")),N([F((t-o)*h),F((w-(e-n))*h),F((t-r)*h),F((w-(e-i))*h),F((t-r)*h),F((w-e)*h),\"c\"].join(\" \")),N([F((t-r)*h),F((w-(e+i))*h),F((t-o)*h),F((w-(e+n))*h),F(t*h),F((w-(e+n))*h),\"c\"].join(\" \")),N([F((t+o)*h),F((w-(e+n))*h),F((t+r)*h),F((w-(e+i))*h),F((t+r)*h),F((w-e)*h),\"c\"].join(\" \")),null!==s&&N(ce(s)),this},D.circle=function(t,e,r,n){return this.ellipse(t,e,r,r,n)},D.setProperties=function(t){for(var e in R)R.hasOwnProperty(e)&&t[e]&&(R[e]=t[e]);return this},D.setFontSize=function(t){return q=t,this},D.setFont=function(t,e){return d=ae(t,e),this},D.setFontStyle=D.setFontType=function(t){return d=ae(void 0,t),this},D.getFontList=function(){var t,e,r,n={};for(t in E)if(E.hasOwnProperty(t)){n[t]=r=[];for(e in E[t])E[t].hasOwnProperty(e)&&r.push(e)}return n},D.setLineWidth=function(t){return N((t*h).toFixed(2)+\" w\"),this},D.setDrawColor=function(t,e,r,n){var s;return s=void 0===e||void 0===n&&t===e===r?\"string\"==typeof t?t+\" G\":F(t/255)+\" G\":void 0===n?\"string\"==typeof t?[t,e,r,\"RG\"].join(\" \"):[F(t/255),F(e/255),F(r/255),\"RG\"].join(\" \"):\"string\"==typeof t?[t,e,r,n,\"K\"].join(\" \"):[F(t),F(e),F(r),F(n),\"K\"].join(\" \"),N(s),this},D.setFillColor=function(t,e,r,n){var s;return s=void 0===e||void 0===n&&t===e===r?\"string\"==typeof t?t+\" g\":F(t/255)+\" g\":void 0===n?\"string\"==typeof t?[t,e,r,\"rg\"].join(\" \"):[F(t/255),F(e/255),F(r/255),\"rg\"].join(\" \"):\"string\"==typeof t?[t,e,r,n,\"k\"].join(\" \"):[F(t),F(e),F(r),F(n),\"k\"].join(\" \"),N(s),this},D.setTextColor=function(t,e,r){if(\"string\"==typeof t&&/^#[0-9A-Fa-f]{6}$/.test(t)){var n=parseInt(t.substr(1),16);t=n>>16&255,e=n>>8&255,r=255&n}return v=0===t&&0===e&&0===r||\"undefined\"==typeof e?L(t/255)+\" g\":[L(t/255),L(e/255),L(r/255),\"rg\"].join(\" \"),this},D.CapJoinStyles={0:0,butt:0,but:0,miter:0,1:1,round:1,rounded:1,circle:1,2:2,projecting:2,project:2,square:2,bevel:2},D.setLineCap=function(t){var e=this.CapJoinStyles[t];if(void 0===e)throw new Error(\"Line cap style of '\"+t+\"' is not recognized. See or extend .CapJoinStyles property for valid styles\");return B=e,N(e+\" J\"),this},D.setLineJoin=function(t){var e=this.CapJoinStyles[t];if(void 0===e)throw new Error(\"Line join style of '\"+t+\"' is not recognized. See or extend .CapJoinStyles property for valid styles\");return O=e,N(e+\" j\"),this},D.output=de,D.save=function(t){D.output(\"save\",t)};for(var pe in r.API)r.API.hasOwnProperty(pe)&&(\"events\"===pe&&r.API.events.length?!function(t,e){var r,n,s;for(s=e.length-1;-1!==s;s--)r=e[s][0],n=e[s][1],t.subscribe.apply(t,[r].concat(\"function\"==typeof n?[n]:n))}(U,r.API.events):D[pe]=r.API[pe]);return $(),d=\"F1\",ie(),U.publish(\"initialized\"),D}var o=\"1.3\",i={a0:[2383.94,3370.39],a1:[1683.78,2383.94],a2:[1190.55,1683.78],a3:[841.89,1190.55],a4:[595.28,841.89],a5:[419.53,595.28],a6:[297.64,419.53],a7:[209.76,297.64],a8:[147.4,209.76],a9:[104.88,147.4],a10:[73.7,104.88],b0:[2834.65,4008.19],b1:[2004.09,2834.65],b2:[1417.32,2004.09],b3:[1000.63,1417.32],b4:[708.66,1000.63],b5:[498.9,708.66],b6:[354.33,498.9],b7:[249.45,354.33],b8:[175.75,249.45],b9:[124.72,175.75],b10:[87.87,124.72],c0:[2599.37,3676.54],c1:[1836.85,2599.37],c2:[1298.27,1836.85],c3:[918.43,1298.27],c4:[649.13,918.43],c5:[459.21,649.13],c6:[323.15,459.21],c7:[229.61,323.15],c8:[161.57,229.61],c9:[113.39,161.57],c10:[79.37,113.39],dl:[311.81,623.62],letter:[612,792],\"government-letter\":[576,756],legal:[612,1008],\"junior-legal\":[576,360],ledger:[1224,792],tabloid:[792,1224],\"credit-card\":[153,243]};return r.API={events:[]},r.version=\"1.0.150-git 2014-05-30T00:40:diegocr\",\"function\"==typeof define&&define.amd?define(function(){return r}):t.jsPDF=r,r}(\"undefined\"!=typeof self&&self||\"undefined\"!=typeof window&&window||this);!function(t){\"use strict\";t.addHTML=function(t,e,r,n,s){if(\"undefined\"==typeof html2canvas&&\"undefined\"==typeof rasterizeHTML)throw new Error(\"You need either https://github.com/niklasvh/html2canvas or https://github.com/cburgmer/rasterizeHTML.js\");\"number\"!=typeof e&&(n=e,s=r),\"function\"==typeof n&&(s=n,n=null);var o=this.internal,i=o.scaleFactor,a=o.pageSize.width,u=o.pageSize.height;if(n=n||{},n.onrendered=function(t){e=parseInt(e)||0,r=parseInt(r)||0;var o=n.dim||{},c=o.h||0,l=o.w||Math.min(a,t.width/i)-e,f=\"JPEG\";if(n.format&&(f=n.format),t.height>u&&n.pagesplit){var d=function(){for(var n=0;;){var o=document.createElement(\"canvas\");o.width=Math.min(a*i,t.width),o.height=Math.min(u*i,t.height-n);var c=o.getContext(\"2d\");c.drawImage(t,0,n,t.width,o.height,0,0,o.width,o.height);var d=[o,e,n?0:r,o.width/i,o.height/i,f,null,\"SLOW\"];if(this.addImage.apply(this,d),n+=o.height,n>=t.height)break;this.addPage()}s(l,n,null,d)}.bind(this);if(\"CANVAS\"===t.nodeName){var h=new Image;h.onload=d,h.src=t.toDataURL(\"image/png\"),t=h}else d()}else{var p=Math.random().toString(35),m=[t,e,r,l,c,f,p,\"SLOW\"];this.addImage.apply(this,m),s(l,c,p,m)}}.bind(this),\"undefined\"!=typeof html2canvas&&!n.rstz)return html2canvas(t,n);if(\"undefined\"!=typeof rasterizeHTML){var c=\"drawDocument\";return\"string\"==typeof t&&(c=/^http/.test(t)?\"drawURL\":\"drawHTML\"),n.width=n.width||a*i,rasterizeHTML[c](t,void 0,n).then(function(t){n.onrendered(t.image)},function(t){s(null,t)})}return null}}(r.API),function(t){\"use strict\";var e=\"addImage_\",r=[\"jpeg\",\"jpg\",\"png\"],n=function(t){var e=this.internal.newObject(),r=this.internal.write,s=this.internal.putStream;if(t.n=e,r(\"<>\"),\"trns\"in t&&t.trns.constructor==Array){for(var o=\"\",i=0,a=t.trns.length;a>i;i++)o+=t.trns[i]+\" \"+t.trns[i]+\" \";r(\"/Mask [\"+o+\"]\")}if(\"smask\"in t&&r(\"/SMask \"+(e+1)+\" 0 R\"),r(\"/Length \"+t.data.length+\">>\"),s(t.data),r(\"endobj\"),\"smask\"in t){var u=\"/Predictor 15 /Colors 1 /BitsPerComponent \"+t.bpc+\" /Columns \"+t.w,c={w:t.w,h:t.h,cs:\"DeviceGray\",bpc:t.bpc,dp:u,data:t.smask};\"f\"in t&&(c.f=t.f),n.call(this,c)}t.cs===this.color_spaces.INDEXED&&(this.internal.newObject(),r(\"<< /Length \"+t.pal.length+\">>\"),s(this.arrayBufferToBinaryString(new Uint8Array(t.pal))),r(\"endobj\"))},s=function(){var t=this.internal.collections[e+\"images\"];for(var r in t)n.call(this,t[r])},o=function(){var t,r=this.internal.collections[e+\"images\"],n=this.internal.write;for(var s in r)t=r[s],n(\"/I\"+t.i,t.n,\"0\",\"R\")},i=function(e){return e&&\"string\"==typeof e&&(e=e.toUpperCase()),e in t.image_compression?e:t.image_compression.NONE},a=function(){var t=this.internal.collections[e+\"images\"];return t||(this.internal.collections[e+\"images\"]=t={},this.internal.events.subscribe(\"putResources\",s),this.internal.events.subscribe(\"putXobjectDict\",o)),t},u=function(t){var e=0;return t&&(e=Object.keys?Object.keys(t).length:function(t){var e=0;for(var r in t)t.hasOwnProperty(r)&&e++;return e}(t)),e},c=function(t){return\"undefined\"==typeof t||null===t},l=function(){return void 0},f=function(t){return-1===r.indexOf(t)},d=function(e){return\"function\"!=typeof t[\"process\"+e.toUpperCase()]},h=function(t){return\"object\"==typeof t&&1===t.nodeType},p=function(t,e){if(\"IMG\"===t.nodeName&&t.hasAttribute(\"src\")&&0===(\"\"+t.getAttribute(\"src\")).indexOf(\"data:image/\"))return t.getAttribute(\"src\");if(\"CANVAS\"===t.nodeName)var r=t;else{var r=document.createElement(\"canvas\");r.width=t.clientWidth||t.width,r.height=t.clientHeight||t.height;var n=r.getContext(\"2d\");if(!n)throw\"addImage requires canvas to be supported by browser.\";n.drawImage(t,0,0,r.width,r.height)}return r.toDataURL(\"png\"==e?\"image/png\":\"image/jpeg\")},m=function(t,e){var r;if(e)for(var n in e)if(t===e[n].alias){r=e[n];break}return r},w=function(t,e,r){return t||e||(t=-96,e=-96),0>t&&(t=-1*r.w*72/t/this.internal.scaleFactor),0>e&&(e=-1*r.h*72/e/this.internal.scaleFactor),0===t&&(t=e*r.w/r.h),0===e&&(e=t*r.h/r.w),[t,e]},y=function(t,e,r,n,s,o,i){var a=w.call(this,r,n,s),u=this.internal.getCoordinateString,c=this.internal.getVerticalCoordinateString;r=a[0],n=a[1],i[o]=s,this.internal.write(\"q\",u(r),\"0 0\",u(n),u(t),c(e+n),\"cm /I\"+s.i,\"Do Q\")};t.color_spaces={DEVICE_RGB:\"DeviceRGB\",DEVICE_GRAY:\"DeviceGray\",DEVICE_CMYK:\"DeviceCMYK\",CAL_GREY:\"CalGray\",CAL_RGB:\"CalRGB\",LAB:\"Lab\",ICC_BASED:\"ICCBased\",INDEXED:\"Indexed\",PATTERN:\"Pattern\",SEPERATION:\"Seperation\",DEVICE_N:\"DeviceN\"},t.decode={DCT_DECODE:\"DCTDecode\",FLATE_DECODE:\"FlateDecode\",LZW_DECODE:\"LZWDecode\",JPX_DECODE:\"JPXDecode\",JBIG2_DECODE:\"JBIG2Decode\",ASCII85_DECODE:\"ASCII85Decode\",ASCII_HEX_DECODE:\"ASCIIHexDecode\",RUN_LENGTH_DECODE:\"RunLengthDecode\",CCITT_FAX_DECODE:\"CCITTFaxDecode\"},t.image_compression={NONE:\"NONE\",FAST:\"FAST\",MEDIUM:\"MEDIUM\",SLOW:\"SLOW\"},t.isString=function(t){return\"string\"==typeof t},t.extractInfoFromBase64DataURI=function(t){return/^data:([\\w]+?\\/([\\w]+?));base64,(.+?)$/g.exec(t)},t.supportsArrayBuffer=function(){return\"undefined\"!=typeof ArrayBuffer&&\"undefined\"!=typeof Uint8Array},t.isArrayBuffer=function(t){return this.supportsArrayBuffer()?t instanceof ArrayBuffer:!1},t.isArrayBufferView=function(t){return this.supportsArrayBuffer()?\"undefined\"==typeof Uint32Array?!1:t instanceof Int8Array||t instanceof Uint8Array||\"undefined\"!=typeof Uint8ClampedArray&&t instanceof Uint8ClampedArray||t instanceof Int16Array||t instanceof Uint16Array||t instanceof Int32Array||t instanceof Uint32Array||t instanceof Float32Array||t instanceof Float64Array:!1},t.binaryStringToUint8Array=function(t){for(var e=t.length,r=new Uint8Array(e),n=0;e>n;n++)r[n]=t.charCodeAt(n);return r},t.arrayBufferToBinaryString=function(t){this.isArrayBuffer(t)&&(t=new Uint8Array(t));for(var e=\"\",r=t.byteLength,n=0;r>n;n++)e+=String.fromCharCode(t[n]);return e},t.arrayBufferToBase64=function(t){for(var e,r,n,s,o,i=\"\",a=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\",u=new Uint8Array(t),c=u.byteLength,l=c%3,f=c-l,d=0;f>d;d+=3)o=u[d]<<16|u[d+1]<<8|u[d+2],e=(16515072&o)>>18,r=(258048&o)>>12,n=(4032&o)>>6,s=63&o,i+=a[e]+a[r]+a[n]+a[s];return 1==l?(o=u[f],e=(252&o)>>2,r=(3&o)<<4,i+=a[e]+a[r]+\"==\"):2==l&&(o=u[f]<<8|u[f+1],e=(64512&o)>>10,r=(1008&o)>>4,n=(15&o)<<2,i+=a[e]+a[r]+a[n]+\"=\"),i},t.createImageInfo=function(t,e,r,n,s,o,i,a,u,c,l,f){var d={alias:a,w:e,h:r,cs:n,bpc:s,i:i,data:t};return o&&(d.f=o),u&&(d.dp=u),c&&(d.trns=c),l&&(d.pal=l),f&&(d.smask=f),d},t.addImage=function(t,e,n,s,o,w,g,v){if(\"number\"==typeof e){var b=w;w=o,o=s,s=n,n=e,e=b}var q,x,k=a.call(this);if(v=i(v),e=(e||\"JPEG\").toLowerCase(),c(g)&&(g=l(t)),h(t)&&(t=p(t,e)),this.isString(t)){var _=this.extractInfoFromBase64DataURI(t);_?(e=_[2],t=atob(_[3]),this.supportsArrayBuffer()&&(x=t,t=this.binaryStringToUint8Array(t))):255!==t.charCodeAt(0)&&(q=m(t,k))}if(f(e))throw new Error(\"addImage currently only supports formats \"+r+\", not '\"+e+\"'\");if(d(e))throw new Error(\"please ensure that the plugin for '\"+e+\"' support is added\");var A=u(k),C=q;if(C||(C=this[\"process\"+e.toUpperCase()](t,A,g,v,x)),!C)throw new Error(\"An unkwown error occurred whilst processing the image\");return y.call(this,n,s,o,w,C,A,k),this};var g=function(t){var e,r;if(255===!t.charCodeAt(0)||216===!t.charCodeAt(1)||255===!t.charCodeAt(2)||224===!t.charCodeAt(3)||!t.charCodeAt(6)===\"J\".charCodeAt(0)||!t.charCodeAt(7)===\"F\".charCodeAt(0)||!t.charCodeAt(8)===\"I\".charCodeAt(0)||!t.charCodeAt(9)===\"F\".charCodeAt(0)||0===!t.charCodeAt(10))throw new Error(\"getJpegSize requires a binary string jpeg file\");for(var n=256*t.charCodeAt(4)+t.charCodeAt(5),s=4,o=t.length;o>s;){if(s+=n,255!==t.charCodeAt(s))throw new Error(\"getJpegSize could not find the size of the image\");if(192===t.charCodeAt(s+1)||193===t.charCodeAt(s+1)||194===t.charCodeAt(s+1)||195===t.charCodeAt(s+1)||196===t.charCodeAt(s+1)||197===t.charCodeAt(s+1)||198===t.charCodeAt(s+1)||199===t.charCodeAt(s+1))return r=256*t.charCodeAt(s+5)+t.charCodeAt(s+6),e=256*t.charCodeAt(s+7)+t.charCodeAt(s+8),[e,r];s+=2,n=256*t.charCodeAt(s)+t.charCodeAt(s+1)}},v=function(t){var e=t[0]<<8|t[1];if(65496!==e)throw new Error(\"Supplied data is not a JPEG\");for(var r,n,s,o=t.length,i=(t[4]<<8)+t[5],a=4;o>a;){if(a+=i,r=b(t,a),i=(r[2]<<8)+r[3],(192===r[1]||194===r[1])&&255===r[0]&&i>7)return r=b(t,a+5),n=(r[2]<<8)+r[3],s=(r[0]<<8)+r[1],{width:n,height:s};a+=2}throw new Error(\"getJpegSizeFromBytes could not find the size of the image\")},b=function(t,e){return t.subarray(e,e+4)};t.processJPEG=function(t,e,r,n,s){var o,i=this.color_spaces.DEVICE_RGB,a=this.decode.DCT_DECODE,u=8;return this.isString(t)?(o=g(t),this.createImageInfo(t,o[0],o[1],i,u,a,e,r)):(this.isArrayBuffer(t)&&(t=new Uint8Array(t)),this.isArrayBufferView(t)?(o=v(t),t=s||this.arrayBufferToBinaryString(t),this.createImageInfo(t,o.width,o.height,i,u,a,e,r)):null)},t.processJPG=function(){return this.processJPEG.apply(this,arguments)}}(r.API),function(t){\"use strict\";t.autoPrint=function(){var t;return this.internal.events.subscribe(\"postPutResources\",function(){t=this.internal.newObject(),this.internal.write(\"<< /S/Named /Type/Action /N/Print >>\",\"endobj\")}),this.internal.events.subscribe(\"putCatalog\",function(){this.internal.write(\"/OpenAction \"+t+\" 0 R\")}),this}}(r.API),function(t){\"use strict\";var e,r,n,s,o=3,i=13,a={x:void 0,y:void 0,w:void 0,h:void 0,ln:void 0},u=1,c=function(t,e,r,n,s){a={x:t,y:e,w:r,h:n,ln:s}},l=function(){return a},f={left:0,top:0,bottom:0};t.setHeaderFunction=function(t){s=t},t.getTextDimensions=function(t){e=this.internal.getFont().fontName,r=this.table_font_size||this.internal.getFontSize(),n=this.internal.getFont().fontStyle;var s,o,i=19.049976/25.4;return o=document.createElement(\"font\"),o.id=\"jsPDFCell\",o.style.fontStyle=n,o.style.fontName=e,o.style.fontSize=r+\"pt\",o.innerText=t,document.body.appendChild(o),s={w:(o.offsetWidth+1)*i,h:(o.offsetHeight+1)*i},document.body.removeChild(o),s},t.cellAddPage=function(){var t=this.margins||f;this.addPage(),c(t.left,t.top,void 0,void 0),u+=1},t.cellInitialize=function(){a={x:void 0,y:void 0,w:void 0,h:void 0,ln:void 0},u=1},t.cell=function(t,e,r,n,s,a,u){var d=l();if(void 0!==d.ln)if(d.ln===a)t=d.x+d.w,e=d.y;else{var h=this.margins||f;d.y+d.h+n+i>=this.internal.pageSize.height-h.bottom&&(this.cellAddPage(),this.printHeaders&&this.tableHeaderRow&&this.printHeaderRow(a,!0)),e=l().y+l().h}if(void 0!==s[0])if(this.printingHeaderRow?this.rect(t,e,r,n,\"FD\"):this.rect(t,e,r,n),\"right\"===u){if(s instanceof Array)for(var p=0;pr;r+=1)s=t[r],e?-1===e(o,s)&&(o=s):s>o&&(o=s);return o},t.table=function(e,r,n,s,o){if(!n)throw\"No data for PDF table\";var i,c,l,d,h,p,m,w,y,g,v=[],b=[],q={},x={},k=[],_=[],A=!1,C=!0,S=12,E=f;if(E.width=this.internal.pageSize.width,o&&(o.autoSize===!0&&(A=!0),o.printHeaders===!1&&(C=!1),o.fontSize&&(S=o.fontSize),o.margins&&(E=o.margins)),this.lnMod=0,a={x:void 0,y:void 0,w:void 0,h:void 0,ln:void 0},u=1,this.printHeaders=C,this.margins=E,this.setFontSize(S),this.table_font_size=S,void 0===s||null===s)v=Object.keys(n[0]);else if(s[0]&&\"string\"!=typeof s[0]){var z=19.049976/25.4;for(c=0,l=s.length;l>c;c+=1)i=s[c],v.push(i.name),b.push(i.prompt),x[i.name]=i.width*z}else v=s;if(A)for(g=function(t){return t[i]},c=0,l=v.length;l>c;c+=1){for(i=v[c],q[i]=n.map(g),k.push(this.getTextDimensions(b[c]||i).w),p=q[i],m=0,d=p.length;d>m;m+=1)h=p[m],k.push(this.getTextDimensions(h).w);x[i]=t.arrayMax(k)}if(C){var I=this.calculateLineHeight(v,x,b.length?b:v);for(c=0,l=v.length;l>c;c+=1)i=v[c],_.push([e,r,x[i],I,String(b.length?b[c]:i)]);this.setTableHeaderRow(_),this.printHeaderRow(1,!1)}for(c=0,l=n.length;l>c;c+=1){var I;for(w=n[c],I=this.calculateLineHeight(v,x,w),m=0,y=v.length;y>m;m+=1)i=v[m],this.cell(e,r,x[i],I,w[i],c+2,i.align)}return this.lastCellPos=a,this.table_x=e,this.table_y=r,this},t.calculateLineHeight=function(t,e,r){for(var n,s=0,i=0;is&&(s=a)}return s},t.setTableHeaderRow=function(t){this.tableHeaderRow=t},t.printHeaderRow=function(t,e){if(!this.tableHeaderRow)throw\"Property tableHeaderRow does not exist.\";var r,n,o,i;if(this.printingHeaderRow=!0,void 0!==s){var a=s(this,u);c(a[0],a[1],a[2],a[3],-1)}this.setFontStyle(\"bold\");var l=[];for(o=0,i=this.tableHeaderRow.length;i>o;o+=1)this.setFillColor(200,200,200),r=this.tableHeaderRow[o],e&&(r[1]=this.margins&&this.margins.top||0,l.push(r)),n=[].concat(r),this.cell.apply(this,n.concat(t));l.length>0&&this.setTableHeaderRow(l),this.setFontStyle(\"normal\"),this.printingHeaderRow=!1}}(r.API),function(t){var e,r,n,s,o,i,a,u,c,l,f,d,h,p,m,w,y;e=function(){function t(){}return function(e){return t.prototype=e,new t}}(),a=function(t){var e,r,n,s,o,i,a;for(r=0,n=t.length,e=void 0,s=!1,i=!1;!s&&r!==n;)e=t[r]=t[r].trimLeft(),e&&(s=!0),r++;for(r=n-1;n&&!i&&-1!==r;)e=t[r]=t[r].trimRight(),e&&(i=!0),r--;for(o=/\\s+$/g,a=!0,r=0;r!==n;)e=t[r].replace(/\\s+/g,\" \"),a&&(e=e.trimLeft()),e&&(a=o.test(e)),t[r]=e,r++;return t},u=function(t,e,r,n){return this.pdf=t,this.x=e,this.y=r,this.settings=n,this.init(),this},c=function(t){var e,r,s;for(e=void 0,s=t.split(\",\"),r=s.shift();!e&&r;)e=n[r.trim().toLowerCase()],r=s.shift();return e},l=function(t){t=\"auto\"===t?\"0px\":t,t.indexOf(\"em\")>-1&&!isNaN(Number(t.replace(\"em\",\"\")))&&(t=18.719*Number(t.replace(\"em\",\"\"))+\"px\"),t.indexOf(\"pt\")>-1&&!isNaN(Number(t.replace(\"pt\",\"\")))&&(t=1.333*Number(t.replace(\"pt\",\"\"))+\"px\");var e,r,n;return r=void 0,e=16,(n=f[t])?n:(n={\"xx-small\":9,\"x-small\":11,small:13,medium:16,large:19,\"x-large\":23,\"xx-large\":28,auto:0}[{css_line_height_string:t}],n!==r?f[t]=n/e:(n=parseFloat(t))?f[t]=n/e:(n=t.match(/([\\d\\.]+)(px)/),f[t]=3===n.length?parseFloat(n[1])/e:1))},i=function(t){var e,r,n;return n=function(t){var e;return e=function(t){return document.defaultView&&document.defaultView.getComputedStyle?document.defaultView.getComputedStyle(t,null):t.currentStyle?t.currentStyle:t.style}(t),function(t){return t=t.replace(/-\\D/g,function(t){return t.charAt(1).toUpperCase()}),e[t]}}(t),e={},r=void 0,e[\"font-family\"]=c(n(\"font-family\"))||\"times\",e[\"font-style\"]=s[n(\"font-style\")]||\"normal\",e[\"text-align\"]=TextAlignMap[n(\"text-align\")]||\"left\",r=o[n(\"font-weight\")]||\"normal\",\"bold\"===r&&(e[\"font-style\"]=\"normal\"===e[\"font-style\"]?r:r+e[\"font-style\"]),e[\"font-size\"]=l(n(\"font-size\"))||1,e[\"line-height\"]=l(n(\"line-height\"))||1,e.display=\"inline\"===n(\"display\")?\"inline\":\"block\",\"block\"===e.display&&(e[\"margin-top\"]=l(n(\"margin-top\"))||0,e[\"margin-bottom\"]=l(n(\"margin-bottom\"))||0,e[\"padding-top\"]=l(n(\"padding-top\"))||0,e[\"padding-bottom\"]=l(n(\"padding-bottom\"))||0,e[\"margin-left\"]=l(n(\"margin-left\"))||0,e[\"margin-right\"]=l(n(\"margin-right\"))||0,e[\"padding-left\"]=l(n(\"padding-left\"))||0,e[\"padding-right\"]=l(n(\"padding-right\"))||0),e},d=function(t,e,r){var n,s,o,i,a;if(o=!1,s=void 0,i=void 0,a=void 0,n=r[\"#\"+t.id])if(\"function\"==typeof n)o=n(t,e);else for(s=0,i=n.length;!o&&s!==i;)o=n[s](t,e),s++;if(n=r[t.nodeName],!o&&n)if(\"function\"==typeof n)o=n(t,e);else for(s=0,i=n.length;!o&&s!==i;)o=n[s](t,e),s++;return o},y=function(t,e){var r,n,s,o,i,a,u,c,l,f;for(r=[],n=[],s=0,f=t.rows[0].cells.length,c=t.clientWidth;f>s;)l=t.rows[0].cells[s],n[s]={name:l.textContent.toLowerCase().replace(/\\s+/g,\"\"),prompt:l.textContent.replace(/\\r?\\n/g,\"\"),width:l.clientWidth/c*e.pdf.internal.pageSize.width},s++;for(s=1;su;){if(s=o[u],\"object\"==typeof s){if(1===s.nodeType&&\"HEADER\"===s.nodeName){var w=s,b=e.pdf.margins_doc.top;e.pdf.internal.events.subscribe(\"addPage\",function(){e.y=b,r(w,e,n),e.pdf.margins_doc.top=e.y+10,e.y+=10},!1)}if(8===s.nodeType&&\"#comment\"===s.nodeName)~s.textContent.indexOf(\"ADD_PAGE\")&&(e.pdf.addPage(),e.y=e.pdf.margins_doc.top);else if(1!==s.nodeType||g[s.nodeName])if(3===s.nodeType){var q=s.nodeValue;if(s.nodeValue&&\"LI\"===s.parentNode.nodeName)if(\"OL\"===s.parentNode.parentNode.nodeName)q=v++ +\". \"+q;else{var x=16*a[\"font-size\"],k=2;x>20&&(k=3),m=function(t,e){this.pdf.circle(t,e,k,\"FD\")}}e.addText(q,a)}else\"string\"==typeof s&&e.addText(s,a);else if(\"IMG\"===s.nodeName&&h[s.getAttribute(\"src\")])e.pdf.internal.pageSize.height-e.pdf.margins_doc.bottome.pdf.margins_doc.top&&(e.pdf.addPage(),e.y=e.pdf.margins_doc.top),e.pdf.addImage(h[s.getAttribute(\"src\")],e.x,e.y,s.width,s.height),e.y+=s.height;else if(\"TABLE\"===s.nodeName)p=y(s,e),e.y+=10,e.pdf.table(e.x,e.y,p.rows,p.headers,{autoSize:!1,printHeaders:!0,margins:e.pdf.margins_doc}),e.y=e.pdf.lastCellPos.y+e.pdf.lastCellPos.h+20;else if(\"OL\"===s.nodeName||\"UL\"===s.nodeName)v=1,d(s,e,n)||r(s,e,n),e.y+=10;else if(\"LI\"===s.nodeName){var _=e.x;e.x+=\"UL\"===s.parentNode.nodeName?22:10,e.y+=3,d(s,e,n)||r(s,e,n),e.x=_}else d(s,e,n)||r(s,e,n)}u++}return c?e.setBlockBoundary(m):void 0},h={},p=function(t,e,r,n){function s(){e.pdf.internal.events.publish(\"imagesLoaded\"),n()}function o(t,e,r){if(t){var n=new Image;++u,n.crossOrigin=\"\",n.onerror=n.onload=function(){n.complete&&(0===n.src.indexOf(\"data:image/\")&&(n.width=e||n.width||0,n.height=r||n.height||0),n.width+n.height&&(h[t]=h[t]||n)),--u||s()},n.src=t}}for(var i=t.getElementsByTagName(\"img\"),a=i.length,u=0;a--;)o(i[a].getAttribute(\"src\"),i[a].width,i[a].height);return u||s()},m=function(t,e,n,s){var o=t.getElementsByTagName(\"footer\");if(o.length>0){o=o[0];var i=e.pdf.internal.write,a=e.y;e.pdf.internal.write=function(){},r(o,e,n);var u=Math.ceil(e.y-a)+5;e.y=a,e.pdf.internal.write=i,e.pdf.margins_doc.bottom+=u;\nfor(var c=function(t){var s=void 0!==t?t.pageNumber:1,i=e.y;e.y=e.pdf.internal.pageSize.height-e.pdf.margins_doc.bottom,e.pdf.margins_doc.bottom-=u;for(var a=o.getElementsByTagName(\"span\"),c=0;c-1&&(a[c].innerHTML=s),(\" \"+a[c].className+\" \").replace(/[\\n\\t]/g,\" \").indexOf(\" totalPages \")>-1&&(a[c].innerHTML=\"###jsPDFVarTotalPages###\");r(o,e,n),e.pdf.margins_doc.bottom+=u,e.y=i},l=o.getElementsByTagName(\"span\"),f=0;f-1&&e.pdf.internal.events.subscribe(\"htmlRenderingFinished\",e.pdf.putTotalPages.bind(e.pdf,\"###jsPDFVarTotalPages###\"),!0);e.pdf.internal.events.subscribe(\"addPage\",c,!1),c(),g.FOOTER=1}s()},w=function(t,e,n,s,o,i){if(!e)return!1;\"string\"==typeof e||e.parentNode||(e=\"\"+e.innerHTML),\"string\"==typeof e&&(e=function(t){var e,r,n,s;return n=\"jsPDFhtmlText\"+Date.now().toString()+(1e3*Math.random()).toFixed(0),s=\"position: absolute !important;clip: rect(1px 1px 1px 1px); /* IE6, IE7 */clip: rect(1px, 1px, 1px, 1px);padding:0 !important;border:0 !important;height: 1px !important;width: 1px !important; top:auto;left:-100px;overflow: hidden;\",r=document.createElement(\"div\"),r.style.cssText=s,r.innerHTML='',document.body.appendChild(r),e=window.frames[n],e.document.body.innerHTML=t,e.document.body}(e.replace(/<\\/?script[^>]*?>/gi,\"\")));var a=new u(t,n,s,o);return i=i||function(){},p.call(this,e,a,o.elementHandlers,function(){m.call(this,e,a,o.elementHandlers,function(){r(e,a,o.elementHandlers),a.pdf.internal.events.publish(\"htmlRenderingFinished\"),i(a.dispose())})}),a.dispose()},u.prototype.init=function(){return this.paragraph={text:[],style:[]},this.pdf.internal.write(\"q\")},u.prototype.dispose=function(){return this.pdf.internal.write(\"Q\"),{x:this.x,y:this.y}},u.prototype.splitFragmentsIntoLines=function(t,r){var n,s,o,i,a,u,c,l,f,d,h,p,m,w,y;for(s=12,h=this.pdf.internal.scaleFactor,a={},o=void 0,d=void 0,i=void 0,u=void 0,y=void 0,f=void 0,l=void 0,c=void 0,p=[],m=[p],n=0,w=this.settings.width;t.length;)if(u=t.shift(),y=r.shift(),u)if(o=y[\"font-family\"],d=y[\"font-style\"],i=a[o+d],i||(i=this.pdf.internal.getFont(o,d).metadata.Unicode,a[o+d]=i),f={widths:i.widths,kerning:i.kerning,fontSize:y[\"font-size\"]*s,textIndent:n},l=this.pdf.getStringUnitWidth(u,f)*f.fontSize/h,n+l>w){for(c=this.pdf.splitTextToSize(u,w,f),p.push([c.shift(),y]);c.length;)p=[[c.shift(),y]],m.push(p);n=this.pdf.getStringUnitWidth(p[0][0],f)*f.fontSize/h}else p.push([u,y]),n+=l;if(void 0!==y[\"text-align\"]&&(\"center\"===y[\"text-align\"]||\"right\"===y[\"text-align\"]||\"justify\"===y[\"text-align\"]))for(var g=0;g0&&(m[g][0][1]=e(m[g][0][1]));var b=w-v;if(\"right\"===y[\"text-align\"])m[g][0][1][\"margin-left\"]=b;else if(\"center\"===y[\"text-align\"])m[g][0][1][\"margin-left\"]=b/2;else if(\"justify\"===y[\"text-align\"]){var q=m[g][0][0].split(\" \").length-1;m[g][0][1][\"word-spacing\"]=b/q,g===m.length-1&&(m[g][0][1][\"word-spacing\"]=0)}}return m},u.prototype.RenderTextFragment=function(t,e){var r,n;this.pdf.internal.pageSize.height-this.pdf.margins_doc.bottom0&&this.pdf.internal.write(e[\"word-spacing\"].toFixed(2),\"Tw\"),this.pdf.internal.write(\"/\"+n.id,(r*e[\"font-size\"]).toFixed(2),\"Tf\",\"(\"+this.pdf.internal.pdfEscape(t)+\") Tj\"),void 0!==e[\"word-spacing\"]&&this.pdf.internal.write(0,\"Tw\")},u.prototype.renderParagraph=function(t){var e,r,n,s,o,i,u,c,l,f,d,h,p,m,w;if(s=a(this.paragraph.text),m=this.paragraph.style,e=this.paragraph.blockstyle,p=this.paragraph.blockstyle||{},this.paragraph={text:[],style:[],blockstyle:{},priorblockstyle:e},s.join(\"\").trim()){c=this.splitFragmentsIntoLines(s,m),u=void 0,l=void 0,r=12,n=r/this.pdf.internal.scaleFactor,h=(Math.max((e[\"margin-top\"]||0)-(p[\"margin-bottom\"]||0),0)+(e[\"padding-top\"]||0))*n,d=((e[\"margin-bottom\"]||0)+(e[\"padding-bottom\"]||0))*n,f=this.pdf.internal.write,o=void 0,i=void 0,this.y+=h,f(\"q\",\"BT\",this.pdf.internal.getCoordinateString(this.x),this.pdf.internal.getVerticalCoordinateString(this.y),\"Td\");for(var y=0;c.length;){for(u=c.shift(),l=0,o=0,i=u.length;o!==i;)u[o][0].trim()&&(l=Math.max(l,u[o][1][\"line-height\"],u[o][1][\"font-size\"]),w=7*u[o][1][\"font-size\"]),o++;var g=0;for(void 0!==u[0][1][\"margin-left\"]&&u[0][1][\"margin-left\"]>0&&(wantedIndent=this.pdf.internal.getCoordinateString(u[0][1][\"margin-left\"]),g=wantedIndent-y,y=wantedIndent),f(g,(-1*r*l).toFixed(2),\"Td\"),o=0,i=u.length;o!==i;)u[o][0]&&this.RenderTextFragment(u[o][0],u[o][1]),o++;this.y+=l*n}return t&&\"function\"==typeof t&&t.call(this,this.x-9,this.y-w/2),f(\"ET\",\"Q\"),this.y+=d}},u.prototype.setBlockBoundary=function(t){return this.renderParagraph(t)},u.prototype.setBlockStyle=function(t){return this.paragraph.blockstyle=t},u.prototype.addText=function(t,e){return this.paragraph.text.push(t),this.paragraph.style.push(e)},n={helvetica:\"helvetica\",\"sans-serif\":\"helvetica\",\"times new roman\":\"times\",serif:\"times\",times:\"times\",monospace:\"courier\",courier:\"courier\"},o={100:\"normal\",200:\"normal\",300:\"normal\",400:\"normal\",500:\"bold\",600:\"bold\",700:\"bold\",800:\"bold\",900:\"bold\",normal:\"normal\",bold:\"bold\",bolder:\"bold\",lighter:\"normal\"},s={normal:\"normal\",italic:\"italic\",oblique:\"italic\"},TextAlignMap={left:\"left\",right:\"right\",center:\"center\",justify:\"justify\"},f={normal:1},t.fromHTML=function(t,e,r,n,s,o){\"use strict\";return this.margins_doc=o||{top:0,bottom:0},n||(n={}),n.elementHandlers||(n.elementHandlers={}),w(this,t,e||4,r||4,n,s)}}(r.API),function(t){\"use strict\";var e,r,n;t.addJS=function(t){return n=t,this.internal.events.subscribe(\"postPutResources\",function(){e=this.internal.newObject(),this.internal.write(\"<< /Names [(EmbeddedJS) \"+(e+1)+\" 0 R] >>\",\"endobj\"),r=this.internal.newObject(),this.internal.write(\"<< /S /JavaScript /JS (\",n,\") >>\",\"endobj\")}),this.internal.events.subscribe(\"putCatalog\",function(){void 0!==e&&void 0!==r&&this.internal.write(\"/Names <>\")}),this}}(r.API),function(t){\"use strict\";var e=function(){return\"function\"!=typeof PNG||\"function\"!=typeof i},r=function(e){return e!==t.image_compression.NONE&&n()},n=function(){var t=\"function\"==typeof s;if(!t)throw new Error(\"requires deflate.js for compression\");return t},o=function(e,r,n,o){var i=5,l=d;switch(o){case t.image_compression.FAST:i=3,l=f;break;case t.image_compression.MEDIUM:i=6,l=h;break;case t.image_compression.SLOW:i=9,l=p}e=c(e,r,n,l);var m=new Uint8Array(a(i)),w=u(e),y=new s(i),g=y.append(e),v=y.flush(),b=m.length+g.length+v.length,q=new Uint8Array(b+4);return q.set(m),q.set(g,m.length),q.set(v,m.length+g.length),q[b++]=w>>>24&255,q[b++]=w>>>16&255,q[b++]=w>>>8&255,q[b++]=255&w,t.arrayBufferToBinaryString(q)},a=function(t,e){var r=8,n=Math.LOG2E*Math.log(32768)-8,s=n<<4|r,o=s<<8,i=Math.min(3,(e-1&255)>>1);return o|=i<<6,o|=0,o+=31-o%31,[s,255&o&255]},u=function(t,e){for(var r,n=1,s=65535&n,o=n>>>16&65535,i=t.length,a=0;i>0;){r=i>e?e:i,i-=r;do s+=t[a++],o+=s;while(--r);s%=65521,o%=65521}return(o<<16|s)>>>0},c=function(t,e,r,n){for(var s,o,i,a=t.length/e,u=new Uint8Array(t.length+a),c=w(),l=0;a>l;l++){if(i=l*e,s=t.subarray(i,i+e),n)u.set(n(s,r,o),i+l);else{for(var f=0,d=c.length,h=[];d>f;f++)h[f]=c[f](s,r,o);var p=y(h.concat());u.set(h[p],i+l)}o=s}return u},l=function(t){var e=Array.apply([],t);return e.unshift(0),e},f=function(t,e){var r,n=[],s=0,o=t.length;for(n[0]=1;o>s;s++)r=t[s-e]||0,n[s+1]=t[s]-r+256&255;return n},d=function(t,e,r){var n,s=[],o=0,i=t.length;for(s[0]=2;i>o;o++)n=r&&r[o]||0,s[o+1]=t[o]-n+256&255;return s},h=function(t,e,r){var n,s,o=[],i=0,a=t.length;for(o[0]=3;a>i;i++)n=t[i-e]||0,s=r&&r[i]||0,o[i+1]=t[i]+256-(n+s>>>1)&255;return o},p=function(t,e,r){var n,s,o,i,a=[],u=0,c=t.length;for(a[0]=4;c>u;u++)n=t[u-e]||0,s=r&&r[u]||0,o=r&&r[u-e]||0,i=m(n,s,o),a[u+1]=t[u]-i+256&255;return a},m=function(t,e,r){var n=t+e-r,s=Math.abs(n-t),o=Math.abs(n-e),i=Math.abs(n-r);return o>=s&&i>=s?t:i>=o?e:r},w=function(){return[l,f,d,h,p]},y=function(t){for(var e,r,n,s=0,o=t.length;o>s;)e=g(t[s].slice(1)),(r>e||!r)&&(r=e,n=s),s++;return n},g=function(t){for(var e=0,r=t.length,n=0;r>e;)n+=Math.abs(t[e++]);return n};t.processPNG=function(t,n,s,i){var a,u,c,l,f,d,h=this.color_spaces.DEVICE_RGB,p=this.decode.FLATE_DECODE,m=8;if(this.isArrayBuffer(t)&&(t=new Uint8Array(t)),this.isArrayBufferView(t)){if(e())throw new Error(\"PNG support requires png.js and zlib.js\");if(a=new PNG(t),t=a.imgData,m=a.bits,h=a.colorSpace,l=a.colors,-1!==[4,6].indexOf(a.colorType)){if(8===a.bits)for(var w,y,g=window[\"Uint\"+a.pixelBitlength+\"Array\"],v=new g(a.decodePixels().buffer),b=v.length,q=new Uint8Array(b*a.colors),x=new Uint8Array(b),k=a.pixelBitlength-a.bits,_=0,A=0;b>_;_++){for(w=v[_],y=0;k>y;)q[A++]=w>>>y&255,y+=a.bits;x[_]=w>>>y&255}if(16===a.bits){for(var w,v=new Uint32Array(a.decodePixels().buffer),b=v.length,q=new Uint8Array(b*(32/a.pixelBitlength)*a.colors),x=new Uint8Array(b*(32/a.pixelBitlength)),C=a.colors>1,_=0,A=0,S=0;b>_;)w=v[_++],q[A++]=w>>>0&255,C&&(q[A++]=w>>>16&255,w=v[_++],q[A++]=w>>>0&255),x[S++]=w>>>16&255;m=8}r(i)?(t=o(q,a.width*a.colors,a.colors,i),d=o(x,a.width,1,i)):(t=q,d=x,p=null)}if(3===a.colorType&&(h=this.color_spaces.INDEXED,f=a.palette,a.transparency.indexed)){for(var E=a.transparency.indexed,z=0,_=0,b=E.length;b>_;++_)z+=E[_];if(z/=255,z===b-1&&-1!==E.indexOf(0))c=[E.indexOf(0)];else if(z!==b){for(var v=a.decodePixels(),x=new Uint8Array(v.length),_=0,b=v.length;b>_;_++)x[_]=E[v[_]];d=o(x,a.width,1)}}return u=p===this.decode.FLATE_DECODE?\"/Predictor 15 /Colors \"+l+\" /BitsPerComponent \"+m+\" /Columns \"+a.width:\"/Colors \"+l+\" /BitsPerComponent \"+m+\" /Columns \"+a.width,(this.isArrayBuffer(t)||this.isArrayBufferView(t))&&(t=this.arrayBufferToBinaryString(t)),(d&&this.isArrayBuffer(d)||this.isArrayBufferView(d))&&(d=this.arrayBufferToBinaryString(d)),this.createImageInfo(t,a.width,a.height,h,m,p,n,s,u,c,f,d)}throw new Error(\"Unsupported PNG image data, try using JPEG instead.\")}}(r.API),function(t){\"use strict\";t.addSVG=function(t,e,r,n,s){function o(t,e){var r=e.createElement(\"style\");r.type=\"text/css\",r.styleSheet?r.styleSheet.cssText=t:r.appendChild(e.createTextNode(t)),e.getElementsByTagName(\"head\")[0].appendChild(r)}function i(t){var e=\"childframe\",r=t.createElement(\"iframe\");return o(\".jsPDF_sillysvg_iframe {display:none;position:absolute;}\",t),r.name=e,r.setAttribute(\"width\",0),r.setAttribute(\"height\",0),r.setAttribute(\"frameborder\",\"0\"),r.setAttribute(\"scrolling\",\"no\"),r.setAttribute(\"seamless\",\"seamless\"),r.setAttribute(\"class\",\"jsPDF_sillysvg_iframe\"),t.body.appendChild(r),r}function a(t,e){var r=(e.contentWindow||e.contentDocument).document;return r.write(t),r.close(),r.getElementsByTagName(\"svg\")[0]}function u(t){for(var e=parseFloat(t[1]),r=parseFloat(t[2]),n=[],s=3,o=t.length;o>s;)\"c\"===t[s]?(n.push([parseFloat(t[s+1]),parseFloat(t[s+2]),parseFloat(t[s+3]),parseFloat(t[s+4]),parseFloat(t[s+5]),parseFloat(t[s+6])]),s+=7):\"l\"===t[s]?(n.push([parseFloat(t[s+1]),parseFloat(t[s+2])]),s+=3):s+=1;return[e,r,n]}var c;if(e===c||e===c)throw new Error(\"addSVG needs values for 'x' and 'y'\");var l=i(document),f=a(t,l),d=[1,1],h=parseFloat(f.getAttribute(\"width\")),p=parseFloat(f.getAttribute(\"height\"));h&&p&&(n&&s?d=[n/h,s/p]:n?d=[n/h,n/h]:s&&(d=[s/p,s/p]));var m,w,y,g,v=f.childNodes;for(m=0,w=v.length;w>m;m++)y=v[m],y.tagName&&\"PATH\"===y.tagName.toUpperCase()&&(g=u(y.getAttribute(\"d\").split(\" \")),g[0]=g[0]*d[0]+e,g[1]=g[1]*d[1]+r,this.lines.call(this,g[2],g[0],g[1],d));return this}}(r.API),function(t){\"use strict\";var e=t.getCharWidthsArray=function(t,e){e||(e={});var r,n,s,o=e.widths?e.widths:this.internal.getFont().metadata.Unicode.widths,i=o.fof?o.fof:1,a=e.kerning?e.kerning:this.internal.getFont().metadata.Unicode.kerning,u=a.fof?a.fof:1,c=0,l=o[0]||i,f=[];for(r=0,n=t.length;n>r;r++)s=t.charCodeAt(r),f.push((o[s]||l)/i+(a[s]&&a[s][c]||0)/u),c=s;return f},r=function(t){for(var e=t.length,r=0;e;)e--,r+=t[e];return r},n=t.getStringUnitWidth=function(t,n){return r(e.call(this,t,n))},s=function(t,e,r,n){for(var s=[],o=0,i=t.length,a=0;o!==i&&a+e[o]n&&(s.push(t.slice(u,o)),a=0,u=o),a+=e[o],o++;return u!==o&&s.push(t.slice(u,o)),s},o=function(t,o,i){i||(i={});var a,u,c,l,f,d,h=[],p=[h],m=i.textIndent||0,w=0,y=0,g=t.split(\" \"),v=e(\" \",i)[0];if(d=-1===i.lineIndent?g[0].length+2:i.lineIndent||0){var b=Array(d).join(\" \"),q=[];g.map(function(t){t=t.split(/\\s*\\n/),t.length>1?q=q.concat(t.map(function(t,e){return(e&&t.length?\"\\n\":\"\")+t})):q.push(t[0])}),g=q,d=n(b,i)}for(c=0,l=g.length;l>c;c++){var x=0;if(a=g[c],d&&\"\\n\"==a[0]&&(a=a.substr(1),x=1),u=e(a,i),y=r(u),m+w+y>o||x){if(y>o){for(f=s(a,u,o-(m+w),o),h.push(f.shift()),h=[f.pop()];f.length;)p.push([f.shift()]);y=r(u.slice(a.length-h[0].length))}else h=[a];p.push(h),m=y+d,w=v}else h.push(a),m+=w+y,w=v}if(d)var k=function(t,e){return(e?b:\"\")+t.join(\" \")};else var k=function(t){return t.join(\" \")};return p.map(k)};t.splitTextToSize=function(t,e,r){r||(r={});var n,s=r.fontSize||this.internal.getFontSize(),i=function(t){var e={0:1},r={};if(t.widths&&t.kerning)return{widths:t.widths,kerning:t.kerning};var n=this.internal.getFont(t.fontName,t.fontStyle),s=\"Unicode\";return n.metadata[s]?{widths:n.metadata[s].widths||e,kerning:n.metadata[s].kerning||r}:{widths:e,kerning:r}}.call(this,r);n=Array.isArray(t)?t:t.split(/\\r?\\n/);var a=1*this.internal.scaleFactor*e/s;i.textIndent=r.textIndent?1*r.textIndent*this.internal.scaleFactor/s:0,i.lineIndent=r.lineIndent;var u,c,l=[];for(u=0,c=n.length;c>u;u++)l=l.concat(o(n[u],a,i));return l}}(r.API),function(t){\"use strict\";var e=function(t){for(var e=\"0123456789abcdef\",r=\"klmnopqrstuvwxyz\",n={},s=0;su;u++)s+=String.fromCharCode(o[u]);r.push(s)}else if(\"Blob\"===e(t)||\"File\"===e(t)){if(!i)throw new a(\"NOT_READABLE_ERR\");var l=new i;r.push(l.readAsBinaryString(t))}else t instanceof n?\"base64\"===t.encoding&&m?r.push(m(t.data)):\"URI\"===t.encoding?r.push(decodeURIComponent(t.data)):\"raw\"===t.encoding&&r.push(t.data):(\"string\"!=typeof t&&(t+=\"\"),r.push(unescape(encodeURIComponent(t))))},s.getBlob=function(t){return arguments.length||(t=null),new n(this.data.join(\"\"),t,\"raw\")},s.toString=function(){return\"[object BlobBuilder]\"},o.slice=function(t,e,r){var s=arguments.length;return 3>s&&(r=null),new n(this.data.slice(t,s>1?e:this.data.length),r,this.encoding)\n},o.toString=function(){return\"[object Blob]\"},o.close=function(){this.size=this.data.length=0},r}(t);t.Blob=function(t,e){var n=e?e.type||\"\":\"\",s=new r;if(t)for(var o=0,i=t.length;i>o;o++)s.append(t[o]);return s.getBlob(n)}}(\"undefined\"!=typeof self&&self||\"undefined\"!=typeof window&&window||this.content||this);var n=n||\"undefined\"!=typeof navigator&&navigator.msSaveOrOpenBlob&&navigator.msSaveOrOpenBlob.bind(navigator)||function(t){\"use strict\";if(\"undefined\"==typeof navigator||!/MSIE [1-9]\\./.test(navigator.userAgent)){var e=t.document,r=function(){return t.URL||t.webkitURL||t},n=e.createElementNS(\"http://www.w3.org/1999/xhtml\",\"a\"),s=!t.externalHost&&\"download\"in n,o=function(r){var n=e.createEvent(\"MouseEvents\");n.initMouseEvent(\"click\",!0,!1,t,0,0,0,0,0,!1,!1,!1,!1,0,null),r.dispatchEvent(n)},i=t.webkitRequestFileSystem,a=t.requestFileSystem||i||t.mozRequestFileSystem,u=function(e){(t.setImmediate||t.setTimeout)(function(){throw e},0)},c=\"application/octet-stream\",l=0,f=[],d=function(){for(var t=f.length;t--;){var e=f[t];\"string\"==typeof e?r().revokeObjectURL(e):e.remove()}f.length=0},h=function(t,e,r){e=[].concat(e);for(var n=e.length;n--;){var s=t[\"on\"+e[n]];if(\"function\"==typeof s)try{s.call(t,r||t)}catch(o){u(o)}}},p=function(e,u){var d,p,m,w=this,y=e.type,g=!1,v=function(){var t=r().createObjectURL(e);return f.push(t),t},b=function(){h(w,\"writestart progress write writeend\".split(\" \"))},q=function(){(g||!d)&&(d=v(e)),p?p.location.href=d:window.open(d,\"_blank\"),w.readyState=w.DONE,b()},x=function(t){return function(){return w.readyState!==w.DONE?t.apply(this,arguments):void 0}},k={create:!0,exclusive:!1};return w.readyState=w.INIT,u||(u=\"download\"),s?(d=v(e),n.href=d,n.download=u,o(n),w.readyState=w.DONE,b(),void 0):(t.chrome&&y&&y!==c&&(m=e.slice||e.webkitSlice,e=m.call(e,0,e.size,c),g=!0),i&&\"download\"!==u&&(u+=\".download\"),(y===c||i)&&(p=t),a?(l+=e.size,a(t.TEMPORARY,l,x(function(t){t.root.getDirectory(\"saved\",k,x(function(t){var r=function(){t.getFile(u,k,x(function(t){t.createWriter(x(function(r){r.onwriteend=function(e){p.location.href=t.toURL(),f.push(t),w.readyState=w.DONE,h(w,\"writeend\",e)},r.onerror=function(){var t=r.error;t.code!==t.ABORT_ERR&&q()},\"writestart progress write abort\".split(\" \").forEach(function(t){r[\"on\"+t]=w[\"on\"+t]}),r.write(e),w.abort=function(){r.abort(),w.readyState=w.DONE},w.readyState=w.WRITING}),q)}),q)};t.getFile(u,{create:!1},x(function(t){t.remove(),r()}),x(function(t){t.code===t.NOT_FOUND_ERR?r():q()}))}),q)}),q),void 0):(q(),void 0))},m=p.prototype,w=function(t,e){return new p(t,e)};return m.abort=function(){var t=this;t.readyState=t.DONE,h(t,\"abort\")},m.readyState=m.INIT=0,m.WRITING=1,m.DONE=2,m.error=m.onwritestart=m.onprogress=m.onwrite=m.onabort=m.onerror=m.onwriteend=null,t.addEventListener(\"unload\",d,!1),w.unload=function(){d(),t.removeEventListener(\"unload\",d,!1)},w}}(\"undefined\"!=typeof self&&self||\"undefined\"!=typeof window&&window||this.content);\"undefined\"!=typeof module&&null!==module?module.exports=n:\"undefined\"!=typeof define&&null!==define&&null!=define.amd&&define([],function(){return n}),void function(t,e){\"object\"==typeof module?module.exports=e():t.adler32cs=e()}(r,function(){var t=\"function\"==typeof ArrayBuffer&&\"function\"==typeof Uint8Array,e=null,r=function(){if(!t)return function(){return!1};try{var r=require(\"buffer\");\"function\"==typeof r.Buffer&&(e=r.Buffer)}catch(n){}return function(t){return t instanceof ArrayBuffer||null!==e&&t instanceof e}}(),n=function(){return null!==e?function(t){return new e(t,\"utf8\").toString(\"binary\")}:function(t){return unescape(encodeURIComponent(t))}}(),s=65521,o=function(t,e){for(var r=65535&t,n=t>>>16,o=0,i=e.length;i>o;o++)r=(r+(255&e.charCodeAt(o)))%s,n=(n+r)%s;return(n<<16|r)>>>0},i=function(t,e){for(var r=65535&t,n=t>>>16,o=0,i=e.length;i>o;o++)r=(r+e[o])%s,n=(n+r)%s;return(n<<16|r)>>>0},a={},u=a.Adler32=function(){var e=function(t){if(!(this instanceof e))throw new TypeError(\"Constructor cannot called be as a function.\");if(!isFinite(t=null==t?1:+t))throw new Error(\"First arguments needs to be a finite number.\");this.checksum=t>>>0},s=e.prototype={};return s.constructor=e,e.from=function(t){return t.prototype=s,t}(function(t){if(!(this instanceof e))throw new TypeError(\"Constructor cannot called be as a function.\");if(null==t)throw new Error(\"First argument needs to be a string.\");this.checksum=o(1,t.toString())}),e.fromUtf8=function(t){return t.prototype=s,t}(function(t){if(!(this instanceof e))throw new TypeError(\"Constructor cannot called be as a function.\");if(null==t)throw new Error(\"First argument needs to be a string.\");var r=n(t.toString());this.checksum=o(1,r)}),t&&(e.fromBuffer=function(t){return t.prototype=s,t}(function(t){if(!(this instanceof e))throw new TypeError(\"Constructor cannot called be as a function.\");if(!r(t))throw new Error(\"First argument needs to be ArrayBuffer.\");var n=new Uint8Array(t);return this.checksum=i(1,n)})),s.update=function(t){if(null==t)throw new Error(\"First argument needs to be a string.\");return t=t.toString(),this.checksum=o(this.checksum,t)},s.updateUtf8=function(t){if(null==t)throw new Error(\"First argument needs to be a string.\");var e=n(t.toString());return this.checksum=o(this.checksum,e)},t&&(s.updateBuffer=function(t){if(!r(t))throw new Error(\"First argument needs to be ArrayBuffer.\");var e=new Uint8Array(t);return this.checksum=i(this.checksum,e)}),s.clone=function(){return new u(this.checksum)},e}();return a.from=function(t){if(null==t)throw new Error(\"First argument needs to be a string.\");return o(1,t.toString())},a.fromUtf8=function(t){if(null==t)throw new Error(\"First argument needs to be a string.\");var e=n(t.toString());return o(1,e)},t&&(a.fromBuffer=function(t){if(!r(t))throw new Error(\"First argument need to be ArrayBuffer.\");var e=new Uint8Array(t);return i(1,e)}),a});var s=function(){function t(){function t(t){var e,r,s,o,a,u,c=n.dyn_tree,l=n.stat_desc.static_tree,f=n.stat_desc.extra_bits,h=n.stat_desc.extra_base,p=n.stat_desc.max_length,m=0;for(o=0;i>=o;o++)t.bl_count[o]=0;for(c[2*t.heap[t.heap_max]+1]=0,e=t.heap_max+1;d>e;e++)r=t.heap[e],o=c[2*c[2*r+1]+1]+1,o>p&&(o=p,m++),c[2*r+1]=o,r>n.max_code||(t.bl_count[o]++,a=0,r>=h&&(a=f[r-h]),u=c[2*r],t.opt_len+=u*(o+a),l&&(t.static_len+=u*(l[2*r+1]+a)));if(0!==m){do{for(o=p-1;0===t.bl_count[o];)o--;t.bl_count[o]--,t.bl_count[o+1]+=2,t.bl_count[p]--,m-=2}while(m>0);for(o=p;0!==o;o--)for(r=t.bl_count[o];0!==r;)s=t.heap[--e],s>n.max_code||(c[2*s+1]!=o&&(t.opt_len+=(o-c[2*s+1])*c[2*s],c[2*s+1]=o),r--)}}function e(t,e){var r=0;do r|=1&t,t>>>=1,r<<=1;while(--e>0);return r>>>1}function r(t,r,n){var s,o,a,u=[],c=0;for(s=1;i>=s;s++)u[s]=c=c+n[s-1]<<1;for(o=0;r>=o;o++)a=t[2*o+1],0!==a&&(t[2*o]=e(u[a]++,a))}var n=this;n.build_tree=function(e){var s,o,i,a=n.dyn_tree,u=n.stat_desc.static_tree,c=n.stat_desc.elems,l=-1;for(e.heap_len=0,e.heap_max=d,s=0;c>s;s++)0!==a[2*s]?(e.heap[++e.heap_len]=l=s,e.depth[s]=0):a[2*s+1]=0;for(;e.heap_len<2;)i=e.heap[++e.heap_len]=2>l?++l:0,a[2*i]=1,e.depth[i]=0,e.opt_len--,u&&(e.static_len-=u[2*i+1]);for(n.max_code=l,s=Math.floor(e.heap_len/2);s>=1;s--)e.pqdownheap(a,s);i=c;do s=e.heap[1],e.heap[1]=e.heap[e.heap_len--],e.pqdownheap(a,1),o=e.heap[1],e.heap[--e.heap_max]=s,e.heap[--e.heap_max]=o,a[2*i]=a[2*s]+a[2*o],e.depth[i]=Math.max(e.depth[s],e.depth[o])+1,a[2*s+1]=a[2*o+1]=i,e.heap[1]=i++,e.pqdownheap(a,1);while(e.heap_len>=2);e.heap[--e.heap_max]=e.heap[1],t(e),r(a,n.max_code,e.bl_count)}}function e(t,e,r,n,s){var o=this;o.static_tree=t,o.extra_bits=e,o.extra_base=r,o.elems=n,o.max_length=s}function r(t,e,r,n,s){var o=this;o.good_length=t,o.max_lazy=e,o.nice_length=r,o.max_chain=n,o.func=s}function n(t,e,r,n){var s=t[2*e],o=t[2*r];return o>s||s==o&&n[e]<=n[r]}function s(){function r(){var t;for(Ie=2*Ce,Be[Pe-1]=0,t=0;Pe-1>t;t++)Be[t]=0;We=L[Xe].max_lazy,Ke=L[Xe].good_length,Qe=L[Xe].nice_length,Ve=L[Xe].max_chain,Me=0,Fe=0,Ge=0,Le=Je=Z-1,Ne=0,Oe=0}function s(){var t;for(t=0;f>t;t++)$e[2*t]=0;for(t=0;a>t;t++)Ze[2*t]=0;for(t=0;u>t;t++)tr[2*t]=0;$e[2*h]=1,er.opt_len=er.static_len=0,ar=cr=0}function o(){rr.dyn_tree=$e,rr.stat_desc=e.static_l_desc,nr.dyn_tree=Ze,nr.stat_desc=e.static_d_desc,sr.dyn_tree=tr,sr.stat_desc=e.static_bl_desc,fr=0,dr=0,lr=8,s()}function i(t,e){var r,n,s=-1,o=t[1],i=0,a=7,u=4;for(0===o&&(a=138,u=3),t[2*(e+1)+1]=65535,r=0;e>=r;r++)n=o,o=t[2*(r+1)+1],++ii?tr[2*n]+=i:0!==n?(n!=s&&tr[2*n]++,tr[2*m]++):10>=i?tr[2*w]++:tr[2*y]++,i=0,s=n,0===o?(a=138,u=3):n==o?(a=6,u=3):(a=7,u=4))}function c(){var e;for(i($e,rr.max_code),i(Ze,nr.max_code),sr.build_tree(er),e=u-1;e>=3&&0===tr[2*t.bl_order[e]+1];e--);return er.opt_len+=3*(e+1)+5+5+4,e}function d(t){er.pending_buf[er.pending++]=t}function p(t){d(255&t),d(t>>>8&255)}function O(t){d(t>>8&255),d(255&t&255)}function re(t,e){var r,n=e;dr>g-n?(r=t,fr|=r<>>g-dr,dr+=n-g):(fr|=t<=r;r++)if(n=o,o=t[2*(r+1)+1],!(++ii){do ne(n,tr);while(0!==--i)}else 0!==n?(n!=s&&(ne(n,tr),i--),ne(m,tr),re(i-3,2)):10>=i?(ne(w,tr),re(i-3,3)):(ne(y,tr),re(i-11,7));i=0,s=n,0===o?(a=138,u=3):n==o?(a=6,u=3):(a=7,u=4)}}function oe(e,r,n){var s;for(re(e-257,5),re(r-1,5),re(n-4,4),s=0;n>s;s++)re(tr[2*t.bl_order[s]+1],3);se($e,e-1),se(Ze,r-1)}function ie(){16==dr?(p(fr),fr=0,dr=0):dr>=8&&(d(255&fr),fr>>>=8,dr-=8)}function ae(){re(Q<<1,3),ne(h,e.static_ltree),ie(),9>1+lr+10-dr&&(re(Q<<1,3),ne(h,e.static_ltree),ie()),lr=7}function ue(e,r){var n,s,o;if(er.pending_buf[ur+2*ar]=e>>>8&255,er.pending_buf[ur+2*ar+1]=255&e,er.pending_buf[or+ar]=255&r,ar++,0===e?$e[2*r]++:(cr++,e--,$e[2*(t._length_code[r]+l+1)]++,Ze[2*t.d_code(e)]++),0===(8191&ar)&&Xe>2){for(n=8*ar,s=Me-Fe,o=0;a>o;o++)n+=Ze[2*o]*(5+t.extra_dbits[o]);if(n>>>=3,cra);ne(h,e),lr=e[2*h+1]}function le(){dr>8?p(fr):dr>0&&d(255&fr),fr=0,dr=0}function fe(t,e,r){le(),lr=8,r&&(p(e),p(~e)),er.pending_buf.set(ze.subarray(t,t+e),er.pending),er.pending+=e}function de(t,e,r){re((K<<1)+(r?1:0),3),fe(t,e,!0)}function he(t,r,n){var o,i,a=0;Xe>0?(rr.build_tree(er),nr.build_tree(er),a=c(),o=er.opt_len+3+7>>>3,i=er.static_len+3+7>>>3,o>=i&&(o=i)):o=i=r+5,o>=r+4&&-1!=t?de(t,r,n):i==o?(re((Q<<1)+(n?1:0),3),ce(e.static_ltree,e.static_dtree)):(re(($<<1)+(n?1:0),3),oe(rr.max_code+1,nr.max_code+1,a+1),ce($e,Ze)),s(),n&&le()}function pe(t){he(Fe>=0?Fe:-1,Me-Fe,t),Fe=Me,qe.flush_pending()}function me(){var t,e,r,n;do{if(n=Ie-Ge-Me,0===n&&0===Me&&0===Ge)n=Ce;else if(-1==n)n--;else if(Me>=Ce+Ce-ee){ze.set(ze.subarray(Ce,Ce+Ce),0),He-=Ce,Me-=Ce,Fe-=Ce,t=Pe,r=t;do e=65535&Be[--r],Be[r]=e>=Ce?e-Ce:0;while(0!==--t);t=Ce,r=t;do e=65535&Te[--r],Te[r]=e>=Ce?e-Ce:0;while(0!==--t);n+=Ce}if(0===qe.avail_in)return;t=qe.read_buf(ze,Me+Ge,n),Ge+=t,Ge>=Z&&(Oe=255&ze[Me],Oe=(Oe<