/* PptxGenJS 3.12.0 @ 2023-03-20T03:12:31.353Z */ 'use strict'; var JSZip = require('jszip'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var JSZip__default = /*#__PURE__*/_interopDefaultLegacy(JSZip); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } function __spreadArray(to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); } /** * PptxGenJS Enums * NOTE: `enum` wont work for objects, so use `Object.freeze` */ // CONST var EMU = 914400; // One (1) inch (OfficeXML measures in EMU (English Metric Units)) var ONEPT = 12700; // One (1) point (pt) var CRLF = '\r\n'; // AKA: Chr(13) & Chr(10) var LAYOUT_IDX_SERIES_BASE = 2147483649; var REGEX_HEX_COLOR = /^[0-9a-fA-F]{6}$/; var LINEH_MODIFIER = 1.67; // AKA: Golden Ratio Typography var DEF_BULLET_MARGIN = 27; var DEF_CELL_BORDER = { type: 'solid', color: '666666', pt: 1 }; var DEF_CELL_MARGIN_IN = [0.05, 0.1, 0.05, 0.1]; // "Normal" margins in PPT-2021 ("Narrow" is `0.05` for all 4) var DEF_CHART_BORDER = { type: 'solid', color: '363636', pt: 1 }; var DEF_CHART_GRIDLINE = { color: '888888', style: 'solid', size: 1, cap: 'flat' }; var DEF_FONT_COLOR = '000000'; var DEF_FONT_SIZE = 12; var DEF_FONT_TITLE_SIZE = 18; var DEF_PRES_LAYOUT = 'LAYOUT_16x9'; var DEF_PRES_LAYOUT_NAME = 'DEFAULT'; var DEF_SHAPE_LINE_COLOR = '333333'; var DEF_SHAPE_SHADOW = { type: 'outer', blur: 3, offset: 23000 / 12700, angle: 90, color: '000000', opacity: 0.35, rotateWithShape: true }; var DEF_SLIDE_MARGIN_IN = [0.5, 0.5, 0.5, 0.5]; // TRBL-style var DEF_TEXT_SHADOW = { type: 'outer', blur: 8, offset: 4, angle: 270, color: '000000', opacity: 0.75 }; var DEF_TEXT_GLOW = { size: 8, color: 'FFFFFF', opacity: 0.75 }; var AXIS_ID_VALUE_PRIMARY = '2094734552'; var AXIS_ID_VALUE_SECONDARY = '2094734553'; var AXIS_ID_CATEGORY_PRIMARY = '2094734554'; var AXIS_ID_CATEGORY_SECONDARY = '2094734555'; var AXIS_ID_SERIES_PRIMARY = '2094734556'; var LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''); var BARCHART_COLORS = [ 'C0504D', '4F81BD', '9BBB59', '8064A2', '4BACC6', 'F79646', '628FC6', 'C86360', 'C0504D', '4F81BD', '9BBB59', '8064A2', '4BACC6', 'F79646', '628FC6', 'C86360' ]; var PIECHART_COLORS = [ '5DA5DA', 'FAA43A', '60BD68', 'F17CB0', 'B2912F', 'B276B2', 'DECF3F', 'F15854', 'A7A7A7', '5DA5DA', 'FAA43A', '60BD68', 'F17CB0', 'B2912F', 'B276B2', 'DECF3F', 'F15854', 'A7A7A7', ]; var TEXT_HALIGN; (function (TEXT_HALIGN) { TEXT_HALIGN["left"] = "left"; TEXT_HALIGN["center"] = "center"; TEXT_HALIGN["right"] = "right"; TEXT_HALIGN["justify"] = "justify"; })(TEXT_HALIGN || (TEXT_HALIGN = {})); var TEXT_VALIGN; (function (TEXT_VALIGN) { TEXT_VALIGN["b"] = "b"; TEXT_VALIGN["ctr"] = "ctr"; TEXT_VALIGN["t"] = "t"; })(TEXT_VALIGN || (TEXT_VALIGN = {})); var SLDNUMFLDID = '{F7021451-1387-4CA6-816F-3879F97B5CBC}'; // ENUM // TODO: 3.5 or v4.0: rationalize ts-def exported enum names/case! // NOTE: First tsdef enum named correctly (shapes -> 'Shape', colors -> 'Color'), etc. var OutputType; (function (OutputType) { OutputType["arraybuffer"] = "arraybuffer"; OutputType["base64"] = "base64"; OutputType["binarystring"] = "binarystring"; OutputType["blob"] = "blob"; OutputType["nodebuffer"] = "nodebuffer"; OutputType["uint8array"] = "uint8array"; })(OutputType || (OutputType = {})); var ChartType; (function (ChartType) { ChartType["area"] = "area"; ChartType["bar"] = "bar"; ChartType["bar3d"] = "bar3D"; ChartType["bubble"] = "bubble"; ChartType["bubble3d"] = "bubble3D"; ChartType["doughnut"] = "doughnut"; ChartType["line"] = "line"; ChartType["pie"] = "pie"; ChartType["radar"] = "radar"; ChartType["scatter"] = "scatter"; })(ChartType || (ChartType = {})); var ShapeType; (function (ShapeType) { ShapeType["accentBorderCallout1"] = "accentBorderCallout1"; ShapeType["accentBorderCallout2"] = "accentBorderCallout2"; ShapeType["accentBorderCallout3"] = "accentBorderCallout3"; ShapeType["accentCallout1"] = "accentCallout1"; ShapeType["accentCallout2"] = "accentCallout2"; ShapeType["accentCallout3"] = "accentCallout3"; ShapeType["actionButtonBackPrevious"] = "actionButtonBackPrevious"; ShapeType["actionButtonBeginning"] = "actionButtonBeginning"; ShapeType["actionButtonBlank"] = "actionButtonBlank"; ShapeType["actionButtonDocument"] = "actionButtonDocument"; ShapeType["actionButtonEnd"] = "actionButtonEnd"; ShapeType["actionButtonForwardNext"] = "actionButtonForwardNext"; ShapeType["actionButtonHelp"] = "actionButtonHelp"; ShapeType["actionButtonHome"] = "actionButtonHome"; ShapeType["actionButtonInformation"] = "actionButtonInformation"; ShapeType["actionButtonMovie"] = "actionButtonMovie"; ShapeType["actionButtonReturn"] = "actionButtonReturn"; ShapeType["actionButtonSound"] = "actionButtonSound"; ShapeType["arc"] = "arc"; ShapeType["bentArrow"] = "bentArrow"; ShapeType["bentUpArrow"] = "bentUpArrow"; ShapeType["bevel"] = "bevel"; ShapeType["blockArc"] = "blockArc"; ShapeType["borderCallout1"] = "borderCallout1"; ShapeType["borderCallout2"] = "borderCallout2"; ShapeType["borderCallout3"] = "borderCallout3"; ShapeType["bracePair"] = "bracePair"; ShapeType["bracketPair"] = "bracketPair"; ShapeType["callout1"] = "callout1"; ShapeType["callout2"] = "callout2"; ShapeType["callout3"] = "callout3"; ShapeType["can"] = "can"; ShapeType["chartPlus"] = "chartPlus"; ShapeType["chartStar"] = "chartStar"; ShapeType["chartX"] = "chartX"; ShapeType["chevron"] = "chevron"; ShapeType["chord"] = "chord"; ShapeType["circularArrow"] = "circularArrow"; ShapeType["cloud"] = "cloud"; ShapeType["cloudCallout"] = "cloudCallout"; ShapeType["corner"] = "corner"; ShapeType["cornerTabs"] = "cornerTabs"; ShapeType["cube"] = "cube"; ShapeType["curvedDownArrow"] = "curvedDownArrow"; ShapeType["curvedLeftArrow"] = "curvedLeftArrow"; ShapeType["curvedRightArrow"] = "curvedRightArrow"; ShapeType["curvedUpArrow"] = "curvedUpArrow"; ShapeType["custGeom"] = "custGeom"; ShapeType["decagon"] = "decagon"; ShapeType["diagStripe"] = "diagStripe"; ShapeType["diamond"] = "diamond"; ShapeType["dodecagon"] = "dodecagon"; ShapeType["donut"] = "donut"; ShapeType["doubleWave"] = "doubleWave"; ShapeType["downArrow"] = "downArrow"; ShapeType["downArrowCallout"] = "downArrowCallout"; ShapeType["ellipse"] = "ellipse"; ShapeType["ellipseRibbon"] = "ellipseRibbon"; ShapeType["ellipseRibbon2"] = "ellipseRibbon2"; ShapeType["flowChartAlternateProcess"] = "flowChartAlternateProcess"; ShapeType["flowChartCollate"] = "flowChartCollate"; ShapeType["flowChartConnector"] = "flowChartConnector"; ShapeType["flowChartDecision"] = "flowChartDecision"; ShapeType["flowChartDelay"] = "flowChartDelay"; ShapeType["flowChartDisplay"] = "flowChartDisplay"; ShapeType["flowChartDocument"] = "flowChartDocument"; ShapeType["flowChartExtract"] = "flowChartExtract"; ShapeType["flowChartInputOutput"] = "flowChartInputOutput"; ShapeType["flowChartInternalStorage"] = "flowChartInternalStorage"; ShapeType["flowChartMagneticDisk"] = "flowChartMagneticDisk"; ShapeType["flowChartMagneticDrum"] = "flowChartMagneticDrum"; ShapeType["flowChartMagneticTape"] = "flowChartMagneticTape"; ShapeType["flowChartManualInput"] = "flowChartManualInput"; ShapeType["flowChartManualOperation"] = "flowChartManualOperation"; ShapeType["flowChartMerge"] = "flowChartMerge"; ShapeType["flowChartMultidocument"] = "flowChartMultidocument"; ShapeType["flowChartOfflineStorage"] = "flowChartOfflineStorage"; ShapeType["flowChartOffpageConnector"] = "flowChartOffpageConnector"; ShapeType["flowChartOnlineStorage"] = "flowChartOnlineStorage"; ShapeType["flowChartOr"] = "flowChartOr"; ShapeType["flowChartPredefinedProcess"] = "flowChartPredefinedProcess"; ShapeType["flowChartPreparation"] = "flowChartPreparation"; ShapeType["flowChartProcess"] = "flowChartProcess"; ShapeType["flowChartPunchedCard"] = "flowChartPunchedCard"; ShapeType["flowChartPunchedTape"] = "flowChartPunchedTape"; ShapeType["flowChartSort"] = "flowChartSort"; ShapeType["flowChartSummingJunction"] = "flowChartSummingJunction"; ShapeType["flowChartTerminator"] = "flowChartTerminator"; ShapeType["folderCorner"] = "folderCorner"; ShapeType["frame"] = "frame"; ShapeType["funnel"] = "funnel"; ShapeType["gear6"] = "gear6"; ShapeType["gear9"] = "gear9"; ShapeType["halfFrame"] = "halfFrame"; ShapeType["heart"] = "heart"; ShapeType["heptagon"] = "heptagon"; ShapeType["hexagon"] = "hexagon"; ShapeType["homePlate"] = "homePlate"; ShapeType["horizontalScroll"] = "horizontalScroll"; ShapeType["irregularSeal1"] = "irregularSeal1"; ShapeType["irregularSeal2"] = "irregularSeal2"; ShapeType["leftArrow"] = "leftArrow"; ShapeType["leftArrowCallout"] = "leftArrowCallout"; ShapeType["leftBrace"] = "leftBrace"; ShapeType["leftBracket"] = "leftBracket"; ShapeType["leftCircularArrow"] = "leftCircularArrow"; ShapeType["leftRightArrow"] = "leftRightArrow"; ShapeType["leftRightArrowCallout"] = "leftRightArrowCallout"; ShapeType["leftRightCircularArrow"] = "leftRightCircularArrow"; ShapeType["leftRightRibbon"] = "leftRightRibbon"; ShapeType["leftRightUpArrow"] = "leftRightUpArrow"; ShapeType["leftUpArrow"] = "leftUpArrow"; ShapeType["lightningBolt"] = "lightningBolt"; ShapeType["line"] = "line"; ShapeType["lineInv"] = "lineInv"; ShapeType["mathDivide"] = "mathDivide"; ShapeType["mathEqual"] = "mathEqual"; ShapeType["mathMinus"] = "mathMinus"; ShapeType["mathMultiply"] = "mathMultiply"; ShapeType["mathNotEqual"] = "mathNotEqual"; ShapeType["mathPlus"] = "mathPlus"; ShapeType["moon"] = "moon"; ShapeType["noSmoking"] = "noSmoking"; ShapeType["nonIsoscelesTrapezoid"] = "nonIsoscelesTrapezoid"; ShapeType["notchedRightArrow"] = "notchedRightArrow"; ShapeType["octagon"] = "octagon"; ShapeType["parallelogram"] = "parallelogram"; ShapeType["pentagon"] = "pentagon"; ShapeType["pie"] = "pie"; ShapeType["pieWedge"] = "pieWedge"; ShapeType["plaque"] = "plaque"; ShapeType["plaqueTabs"] = "plaqueTabs"; ShapeType["plus"] = "plus"; ShapeType["quadArrow"] = "quadArrow"; ShapeType["quadArrowCallout"] = "quadArrowCallout"; ShapeType["rect"] = "rect"; ShapeType["ribbon"] = "ribbon"; ShapeType["ribbon2"] = "ribbon2"; ShapeType["rightArrow"] = "rightArrow"; ShapeType["rightArrowCallout"] = "rightArrowCallout"; ShapeType["rightBrace"] = "rightBrace"; ShapeType["rightBracket"] = "rightBracket"; ShapeType["round1Rect"] = "round1Rect"; ShapeType["round2DiagRect"] = "round2DiagRect"; ShapeType["round2SameRect"] = "round2SameRect"; ShapeType["roundRect"] = "roundRect"; ShapeType["rtTriangle"] = "rtTriangle"; ShapeType["smileyFace"] = "smileyFace"; ShapeType["snip1Rect"] = "snip1Rect"; ShapeType["snip2DiagRect"] = "snip2DiagRect"; ShapeType["snip2SameRect"] = "snip2SameRect"; ShapeType["snipRoundRect"] = "snipRoundRect"; ShapeType["squareTabs"] = "squareTabs"; ShapeType["star10"] = "star10"; ShapeType["star12"] = "star12"; ShapeType["star16"] = "star16"; ShapeType["star24"] = "star24"; ShapeType["star32"] = "star32"; ShapeType["star4"] = "star4"; ShapeType["star5"] = "star5"; ShapeType["star6"] = "star6"; ShapeType["star7"] = "star7"; ShapeType["star8"] = "star8"; ShapeType["stripedRightArrow"] = "stripedRightArrow"; ShapeType["sun"] = "sun"; ShapeType["swooshArrow"] = "swooshArrow"; ShapeType["teardrop"] = "teardrop"; ShapeType["trapezoid"] = "trapezoid"; ShapeType["triangle"] = "triangle"; ShapeType["upArrow"] = "upArrow"; ShapeType["upArrowCallout"] = "upArrowCallout"; ShapeType["upDownArrow"] = "upDownArrow"; ShapeType["upDownArrowCallout"] = "upDownArrowCallout"; ShapeType["uturnArrow"] = "uturnArrow"; ShapeType["verticalScroll"] = "verticalScroll"; ShapeType["wave"] = "wave"; ShapeType["wedgeEllipseCallout"] = "wedgeEllipseCallout"; ShapeType["wedgeRectCallout"] = "wedgeRectCallout"; ShapeType["wedgeRoundRectCallout"] = "wedgeRoundRectCallout"; })(ShapeType || (ShapeType = {})); /** * TODO: FUTURE: v4.0: rename to `ThemeColor` */ var SchemeColor; (function (SchemeColor) { SchemeColor["text1"] = "tx1"; SchemeColor["text2"] = "tx2"; SchemeColor["background1"] = "bg1"; SchemeColor["background2"] = "bg2"; SchemeColor["accent1"] = "accent1"; SchemeColor["accent2"] = "accent2"; SchemeColor["accent3"] = "accent3"; SchemeColor["accent4"] = "accent4"; SchemeColor["accent5"] = "accent5"; SchemeColor["accent6"] = "accent6"; })(SchemeColor || (SchemeColor = {})); var AlignH; (function (AlignH) { AlignH["left"] = "left"; AlignH["center"] = "center"; AlignH["right"] = "right"; AlignH["justify"] = "justify"; })(AlignH || (AlignH = {})); var AlignV; (function (AlignV) { AlignV["top"] = "top"; AlignV["middle"] = "middle"; AlignV["bottom"] = "bottom"; })(AlignV || (AlignV = {})); var SHAPE_TYPE; (function (SHAPE_TYPE) { SHAPE_TYPE["ACTION_BUTTON_BACK_OR_PREVIOUS"] = "actionButtonBackPrevious"; SHAPE_TYPE["ACTION_BUTTON_BEGINNING"] = "actionButtonBeginning"; SHAPE_TYPE["ACTION_BUTTON_CUSTOM"] = "actionButtonBlank"; SHAPE_TYPE["ACTION_BUTTON_DOCUMENT"] = "actionButtonDocument"; SHAPE_TYPE["ACTION_BUTTON_END"] = "actionButtonEnd"; SHAPE_TYPE["ACTION_BUTTON_FORWARD_OR_NEXT"] = "actionButtonForwardNext"; SHAPE_TYPE["ACTION_BUTTON_HELP"] = "actionButtonHelp"; SHAPE_TYPE["ACTION_BUTTON_HOME"] = "actionButtonHome"; SHAPE_TYPE["ACTION_BUTTON_INFORMATION"] = "actionButtonInformation"; SHAPE_TYPE["ACTION_BUTTON_MOVIE"] = "actionButtonMovie"; SHAPE_TYPE["ACTION_BUTTON_RETURN"] = "actionButtonReturn"; SHAPE_TYPE["ACTION_BUTTON_SOUND"] = "actionButtonSound"; SHAPE_TYPE["ARC"] = "arc"; SHAPE_TYPE["BALLOON"] = "wedgeRoundRectCallout"; SHAPE_TYPE["BENT_ARROW"] = "bentArrow"; SHAPE_TYPE["BENT_UP_ARROW"] = "bentUpArrow"; SHAPE_TYPE["BEVEL"] = "bevel"; SHAPE_TYPE["BLOCK_ARC"] = "blockArc"; SHAPE_TYPE["CAN"] = "can"; SHAPE_TYPE["CHART_PLUS"] = "chartPlus"; SHAPE_TYPE["CHART_STAR"] = "chartStar"; SHAPE_TYPE["CHART_X"] = "chartX"; SHAPE_TYPE["CHEVRON"] = "chevron"; SHAPE_TYPE["CHORD"] = "chord"; SHAPE_TYPE["CIRCULAR_ARROW"] = "circularArrow"; SHAPE_TYPE["CLOUD"] = "cloud"; SHAPE_TYPE["CLOUD_CALLOUT"] = "cloudCallout"; SHAPE_TYPE["CORNER"] = "corner"; SHAPE_TYPE["CORNER_TABS"] = "cornerTabs"; SHAPE_TYPE["CROSS"] = "plus"; SHAPE_TYPE["CUBE"] = "cube"; SHAPE_TYPE["CURVED_DOWN_ARROW"] = "curvedDownArrow"; SHAPE_TYPE["CURVED_DOWN_RIBBON"] = "ellipseRibbon"; SHAPE_TYPE["CURVED_LEFT_ARROW"] = "curvedLeftArrow"; SHAPE_TYPE["CURVED_RIGHT_ARROW"] = "curvedRightArrow"; SHAPE_TYPE["CURVED_UP_ARROW"] = "curvedUpArrow"; SHAPE_TYPE["CURVED_UP_RIBBON"] = "ellipseRibbon2"; SHAPE_TYPE["CUSTOM_GEOMETRY"] = "custGeom"; SHAPE_TYPE["DECAGON"] = "decagon"; SHAPE_TYPE["DIAGONAL_STRIPE"] = "diagStripe"; SHAPE_TYPE["DIAMOND"] = "diamond"; SHAPE_TYPE["DODECAGON"] = "dodecagon"; SHAPE_TYPE["DONUT"] = "donut"; SHAPE_TYPE["DOUBLE_BRACE"] = "bracePair"; SHAPE_TYPE["DOUBLE_BRACKET"] = "bracketPair"; SHAPE_TYPE["DOUBLE_WAVE"] = "doubleWave"; SHAPE_TYPE["DOWN_ARROW"] = "downArrow"; SHAPE_TYPE["DOWN_ARROW_CALLOUT"] = "downArrowCallout"; SHAPE_TYPE["DOWN_RIBBON"] = "ribbon"; SHAPE_TYPE["EXPLOSION1"] = "irregularSeal1"; SHAPE_TYPE["EXPLOSION2"] = "irregularSeal2"; SHAPE_TYPE["FLOWCHART_ALTERNATE_PROCESS"] = "flowChartAlternateProcess"; SHAPE_TYPE["FLOWCHART_CARD"] = "flowChartPunchedCard"; SHAPE_TYPE["FLOWCHART_COLLATE"] = "flowChartCollate"; SHAPE_TYPE["FLOWCHART_CONNECTOR"] = "flowChartConnector"; SHAPE_TYPE["FLOWCHART_DATA"] = "flowChartInputOutput"; SHAPE_TYPE["FLOWCHART_DECISION"] = "flowChartDecision"; SHAPE_TYPE["FLOWCHART_DELAY"] = "flowChartDelay"; SHAPE_TYPE["FLOWCHART_DIRECT_ACCESS_STORAGE"] = "flowChartMagneticDrum"; SHAPE_TYPE["FLOWCHART_DISPLAY"] = "flowChartDisplay"; SHAPE_TYPE["FLOWCHART_DOCUMENT"] = "flowChartDocument"; SHAPE_TYPE["FLOWCHART_EXTRACT"] = "flowChartExtract"; SHAPE_TYPE["FLOWCHART_INTERNAL_STORAGE"] = "flowChartInternalStorage"; SHAPE_TYPE["FLOWCHART_MAGNETIC_DISK"] = "flowChartMagneticDisk"; SHAPE_TYPE["FLOWCHART_MANUAL_INPUT"] = "flowChartManualInput"; SHAPE_TYPE["FLOWCHART_MANUAL_OPERATION"] = "flowChartManualOperation"; SHAPE_TYPE["FLOWCHART_MERGE"] = "flowChartMerge"; SHAPE_TYPE["FLOWCHART_MULTIDOCUMENT"] = "flowChartMultidocument"; SHAPE_TYPE["FLOWCHART_OFFLINE_STORAGE"] = "flowChartOfflineStorage"; SHAPE_TYPE["FLOWCHART_OFFPAGE_CONNECTOR"] = "flowChartOffpageConnector"; SHAPE_TYPE["FLOWCHART_OR"] = "flowChartOr"; SHAPE_TYPE["FLOWCHART_PREDEFINED_PROCESS"] = "flowChartPredefinedProcess"; SHAPE_TYPE["FLOWCHART_PREPARATION"] = "flowChartPreparation"; SHAPE_TYPE["FLOWCHART_PROCESS"] = "flowChartProcess"; SHAPE_TYPE["FLOWCHART_PUNCHED_TAPE"] = "flowChartPunchedTape"; SHAPE_TYPE["FLOWCHART_SEQUENTIAL_ACCESS_STORAGE"] = "flowChartMagneticTape"; SHAPE_TYPE["FLOWCHART_SORT"] = "flowChartSort"; SHAPE_TYPE["FLOWCHART_STORED_DATA"] = "flowChartOnlineStorage"; SHAPE_TYPE["FLOWCHART_SUMMING_JUNCTION"] = "flowChartSummingJunction"; SHAPE_TYPE["FLOWCHART_TERMINATOR"] = "flowChartTerminator"; SHAPE_TYPE["FOLDED_CORNER"] = "folderCorner"; SHAPE_TYPE["FRAME"] = "frame"; SHAPE_TYPE["FUNNEL"] = "funnel"; SHAPE_TYPE["GEAR_6"] = "gear6"; SHAPE_TYPE["GEAR_9"] = "gear9"; SHAPE_TYPE["HALF_FRAME"] = "halfFrame"; SHAPE_TYPE["HEART"] = "heart"; SHAPE_TYPE["HEPTAGON"] = "heptagon"; SHAPE_TYPE["HEXAGON"] = "hexagon"; SHAPE_TYPE["HORIZONTAL_SCROLL"] = "horizontalScroll"; SHAPE_TYPE["ISOSCELES_TRIANGLE"] = "triangle"; SHAPE_TYPE["LEFT_ARROW"] = "leftArrow"; SHAPE_TYPE["LEFT_ARROW_CALLOUT"] = "leftArrowCallout"; SHAPE_TYPE["LEFT_BRACE"] = "leftBrace"; SHAPE_TYPE["LEFT_BRACKET"] = "leftBracket"; SHAPE_TYPE["LEFT_CIRCULAR_ARROW"] = "leftCircularArrow"; SHAPE_TYPE["LEFT_RIGHT_ARROW"] = "leftRightArrow"; SHAPE_TYPE["LEFT_RIGHT_ARROW_CALLOUT"] = "leftRightArrowCallout"; SHAPE_TYPE["LEFT_RIGHT_CIRCULAR_ARROW"] = "leftRightCircularArrow"; SHAPE_TYPE["LEFT_RIGHT_RIBBON"] = "leftRightRibbon"; SHAPE_TYPE["LEFT_RIGHT_UP_ARROW"] = "leftRightUpArrow"; SHAPE_TYPE["LEFT_UP_ARROW"] = "leftUpArrow"; SHAPE_TYPE["LIGHTNING_BOLT"] = "lightningBolt"; SHAPE_TYPE["LINE_CALLOUT_1"] = "borderCallout1"; SHAPE_TYPE["LINE_CALLOUT_1_ACCENT_BAR"] = "accentCallout1"; SHAPE_TYPE["LINE_CALLOUT_1_BORDER_AND_ACCENT_BAR"] = "accentBorderCallout1"; SHAPE_TYPE["LINE_CALLOUT_1_NO_BORDER"] = "callout1"; SHAPE_TYPE["LINE_CALLOUT_2"] = "borderCallout2"; SHAPE_TYPE["LINE_CALLOUT_2_ACCENT_BAR"] = "accentCallout2"; SHAPE_TYPE["LINE_CALLOUT_2_BORDER_AND_ACCENT_BAR"] = "accentBorderCallout2"; SHAPE_TYPE["LINE_CALLOUT_2_NO_BORDER"] = "callout2"; SHAPE_TYPE["LINE_CALLOUT_3"] = "borderCallout3"; SHAPE_TYPE["LINE_CALLOUT_3_ACCENT_BAR"] = "accentCallout3"; SHAPE_TYPE["LINE_CALLOUT_3_BORDER_AND_ACCENT_BAR"] = "accentBorderCallout3"; SHAPE_TYPE["LINE_CALLOUT_3_NO_BORDER"] = "callout3"; SHAPE_TYPE["LINE_CALLOUT_4"] = "borderCallout3"; SHAPE_TYPE["LINE_CALLOUT_4_ACCENT_BAR"] = "accentCallout3"; SHAPE_TYPE["LINE_CALLOUT_4_BORDER_AND_ACCENT_BAR"] = "accentBorderCallout3"; SHAPE_TYPE["LINE_CALLOUT_4_NO_BORDER"] = "callout3"; SHAPE_TYPE["LINE"] = "line"; SHAPE_TYPE["LINE_INVERSE"] = "lineInv"; SHAPE_TYPE["MATH_DIVIDE"] = "mathDivide"; SHAPE_TYPE["MATH_EQUAL"] = "mathEqual"; SHAPE_TYPE["MATH_MINUS"] = "mathMinus"; SHAPE_TYPE["MATH_MULTIPLY"] = "mathMultiply"; SHAPE_TYPE["MATH_NOT_EQUAL"] = "mathNotEqual"; SHAPE_TYPE["MATH_PLUS"] = "mathPlus"; SHAPE_TYPE["MOON"] = "moon"; SHAPE_TYPE["NON_ISOSCELES_TRAPEZOID"] = "nonIsoscelesTrapezoid"; SHAPE_TYPE["NOTCHED_RIGHT_ARROW"] = "notchedRightArrow"; SHAPE_TYPE["NO_SYMBOL"] = "noSmoking"; SHAPE_TYPE["OCTAGON"] = "octagon"; SHAPE_TYPE["OVAL"] = "ellipse"; SHAPE_TYPE["OVAL_CALLOUT"] = "wedgeEllipseCallout"; SHAPE_TYPE["PARALLELOGRAM"] = "parallelogram"; SHAPE_TYPE["PENTAGON"] = "homePlate"; SHAPE_TYPE["PIE"] = "pie"; SHAPE_TYPE["PIE_WEDGE"] = "pieWedge"; SHAPE_TYPE["PLAQUE"] = "plaque"; SHAPE_TYPE["PLAQUE_TABS"] = "plaqueTabs"; SHAPE_TYPE["QUAD_ARROW"] = "quadArrow"; SHAPE_TYPE["QUAD_ARROW_CALLOUT"] = "quadArrowCallout"; SHAPE_TYPE["RECTANGLE"] = "rect"; SHAPE_TYPE["RECTANGULAR_CALLOUT"] = "wedgeRectCallout"; SHAPE_TYPE["REGULAR_PENTAGON"] = "pentagon"; SHAPE_TYPE["RIGHT_ARROW"] = "rightArrow"; SHAPE_TYPE["RIGHT_ARROW_CALLOUT"] = "rightArrowCallout"; SHAPE_TYPE["RIGHT_BRACE"] = "rightBrace"; SHAPE_TYPE["RIGHT_BRACKET"] = "rightBracket"; SHAPE_TYPE["RIGHT_TRIANGLE"] = "rtTriangle"; SHAPE_TYPE["ROUNDED_RECTANGLE"] = "roundRect"; SHAPE_TYPE["ROUNDED_RECTANGULAR_CALLOUT"] = "wedgeRoundRectCallout"; SHAPE_TYPE["ROUND_1_RECTANGLE"] = "round1Rect"; SHAPE_TYPE["ROUND_2_DIAG_RECTANGLE"] = "round2DiagRect"; SHAPE_TYPE["ROUND_2_SAME_RECTANGLE"] = "round2SameRect"; SHAPE_TYPE["SMILEY_FACE"] = "smileyFace"; SHAPE_TYPE["SNIP_1_RECTANGLE"] = "snip1Rect"; SHAPE_TYPE["SNIP_2_DIAG_RECTANGLE"] = "snip2DiagRect"; SHAPE_TYPE["SNIP_2_SAME_RECTANGLE"] = "snip2SameRect"; SHAPE_TYPE["SNIP_ROUND_RECTANGLE"] = "snipRoundRect"; SHAPE_TYPE["SQUARE_TABS"] = "squareTabs"; SHAPE_TYPE["STAR_10_POINT"] = "star10"; SHAPE_TYPE["STAR_12_POINT"] = "star12"; SHAPE_TYPE["STAR_16_POINT"] = "star16"; SHAPE_TYPE["STAR_24_POINT"] = "star24"; SHAPE_TYPE["STAR_32_POINT"] = "star32"; SHAPE_TYPE["STAR_4_POINT"] = "star4"; SHAPE_TYPE["STAR_5_POINT"] = "star5"; SHAPE_TYPE["STAR_6_POINT"] = "star6"; SHAPE_TYPE["STAR_7_POINT"] = "star7"; SHAPE_TYPE["STAR_8_POINT"] = "star8"; SHAPE_TYPE["STRIPED_RIGHT_ARROW"] = "stripedRightArrow"; SHAPE_TYPE["SUN"] = "sun"; SHAPE_TYPE["SWOOSH_ARROW"] = "swooshArrow"; SHAPE_TYPE["TEAR"] = "teardrop"; SHAPE_TYPE["TRAPEZOID"] = "trapezoid"; SHAPE_TYPE["UP_ARROW"] = "upArrow"; SHAPE_TYPE["UP_ARROW_CALLOUT"] = "upArrowCallout"; SHAPE_TYPE["UP_DOWN_ARROW"] = "upDownArrow"; SHAPE_TYPE["UP_DOWN_ARROW_CALLOUT"] = "upDownArrowCallout"; SHAPE_TYPE["UP_RIBBON"] = "ribbon2"; SHAPE_TYPE["U_TURN_ARROW"] = "uturnArrow"; SHAPE_TYPE["VERTICAL_SCROLL"] = "verticalScroll"; SHAPE_TYPE["WAVE"] = "wave"; })(SHAPE_TYPE || (SHAPE_TYPE = {})); var CHART_TYPE; (function (CHART_TYPE) { CHART_TYPE["AREA"] = "area"; CHART_TYPE["BAR"] = "bar"; CHART_TYPE["BAR3D"] = "bar3D"; CHART_TYPE["BUBBLE"] = "bubble"; CHART_TYPE["BUBBLE3D"] = "bubble3D"; CHART_TYPE["DOUGHNUT"] = "doughnut"; CHART_TYPE["LINE"] = "line"; CHART_TYPE["PIE"] = "pie"; CHART_TYPE["RADAR"] = "radar"; CHART_TYPE["SCATTER"] = "scatter"; })(CHART_TYPE || (CHART_TYPE = {})); var SCHEME_COLOR_NAMES; (function (SCHEME_COLOR_NAMES) { SCHEME_COLOR_NAMES["TEXT1"] = "tx1"; SCHEME_COLOR_NAMES["TEXT2"] = "tx2"; SCHEME_COLOR_NAMES["BACKGROUND1"] = "bg1"; SCHEME_COLOR_NAMES["BACKGROUND2"] = "bg2"; SCHEME_COLOR_NAMES["ACCENT1"] = "accent1"; SCHEME_COLOR_NAMES["ACCENT2"] = "accent2"; SCHEME_COLOR_NAMES["ACCENT3"] = "accent3"; SCHEME_COLOR_NAMES["ACCENT4"] = "accent4"; SCHEME_COLOR_NAMES["ACCENT5"] = "accent5"; SCHEME_COLOR_NAMES["ACCENT6"] = "accent6"; })(SCHEME_COLOR_NAMES || (SCHEME_COLOR_NAMES = {})); var MASTER_OBJECTS; (function (MASTER_OBJECTS) { MASTER_OBJECTS["chart"] = "chart"; MASTER_OBJECTS["image"] = "image"; MASTER_OBJECTS["line"] = "line"; MASTER_OBJECTS["rect"] = "rect"; MASTER_OBJECTS["text"] = "text"; MASTER_OBJECTS["placeholder"] = "placeholder"; })(MASTER_OBJECTS || (MASTER_OBJECTS = {})); var SLIDE_OBJECT_TYPES; (function (SLIDE_OBJECT_TYPES) { SLIDE_OBJECT_TYPES["chart"] = "chart"; SLIDE_OBJECT_TYPES["hyperlink"] = "hyperlink"; SLIDE_OBJECT_TYPES["image"] = "image"; SLIDE_OBJECT_TYPES["media"] = "media"; SLIDE_OBJECT_TYPES["online"] = "online"; SLIDE_OBJECT_TYPES["placeholder"] = "placeholder"; SLIDE_OBJECT_TYPES["table"] = "table"; SLIDE_OBJECT_TYPES["tablecell"] = "tablecell"; SLIDE_OBJECT_TYPES["text"] = "text"; SLIDE_OBJECT_TYPES["notes"] = "notes"; })(SLIDE_OBJECT_TYPES || (SLIDE_OBJECT_TYPES = {})); var PLACEHOLDER_TYPES; (function (PLACEHOLDER_TYPES) { PLACEHOLDER_TYPES["title"] = "title"; PLACEHOLDER_TYPES["body"] = "body"; PLACEHOLDER_TYPES["image"] = "pic"; PLACEHOLDER_TYPES["chart"] = "chart"; PLACEHOLDER_TYPES["table"] = "tbl"; PLACEHOLDER_TYPES["media"] = "media"; })(PLACEHOLDER_TYPES || (PLACEHOLDER_TYPES = {})); /** * NOTE: 20170304: BULLET_TYPES: Only default is used so far. I'd like to combine the two pieces of code that use these before implementing these as options * Since we close

within the text object bullets, its slightly more difficult than combining into a func and calling to get the paraProp * and i'm not sure if anyone will even use these... so, skipping for now. */ var BULLET_TYPES; (function (BULLET_TYPES) { BULLET_TYPES["DEFAULT"] = "•"; BULLET_TYPES["CHECK"] = "✓"; BULLET_TYPES["STAR"] = "★"; BULLET_TYPES["TRIANGLE"] = "▶"; })(BULLET_TYPES || (BULLET_TYPES = {})); // IMAGES (base64) var IMG_BROKEN = 'data:image/png;base64,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'; var IMG_PLAYBTN = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB4AAAAVnCAYAAACzfHDVAAAAYHpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjaVcjJDYAwDEXBu6ughBfH+YnLQSwSHVA+Yrkwx7HtPHabHuEWrQ+lBBAZ6TMweBWoCwUH8quZH6VWFXVT696zxp12ARkVFEqn8wB8AAAACXBIWXMAAC4jAAAuIwF4pT92AADZLklEQVR42uzdd5hV9Z0/8M+dmcsUZmDovYOhKCiKYhR7JJuoSTCWGFI0WUxijBoTTXazVlyza4maYm9rTRSJigVsqCDNQhHBAogKCEgRMjMMU+7vj93sL8kqClLmnPt6PY+PeXZM9vP9vO8jZ+Y955xMfJLjorBrRMuSgmiViyjN1Ee2oSCyucbIBAAAAAAAAADbXaYgcoWNUZcrirpMbdRsysa69wbF+rggGrf439vSF7seF12aFUTnxvoosGIAAAAAAACAXacgoqEgF++/VRgr4r5o+Kh/pvD//F8uiII+LaPrum/EXzqui2b1ddHGKgEAAAAAAAB2rVxEQWMmWrQtjHZlA6N2w2tR84//zP8pgHu3ib6NBdG+zdqorK6KVUXZaB85j3sGAAAAAAAAaAoaG6OwIBdtyneP2PBabPzbr/1dAdx3VHRtyESHiIhcYzQrLo7WmVzkcjmPgAYAAAAAAABoSgpy0eIfS+D/LYD7fy3abC6Inn/7X2hsjELlLwAAAAAAAEDT9D8lcM1fHwddFBFxyAVR9M686PVp/gfqayKiJiLqLBMAAAAAAABgh8hGRGlEUekn/6PFEb3ikNgQk6O+KCJi6dzoksv83/cB/1X9xoiaJdmoWxlRV1dk2QAAAAAAAAA7QTZbH9muERX96v7n9t7/q6Exinq3i86LI94pjOOisHUu+uYykfmof7h+Y8Sa6aVRt74gGhs9DRoAAAAAAABgZ2lsLIi69QWxeUUmSjs0/vedwR8hk4uydSfE+wVd6qOyMfMx7/mtj9jwUtbjngEAAAAAAAB2obrqolg7IxtR/9Ffb4wo7P5GtCwobRaVH/c/UvNmNuqqPfIZAAAAAAAAYFerqy6KmjezH/v1ktpoVZBr/PgCeMN7yl8AAAAAAACApmJLHW5jUVQWNDSP+Q3ZeLco4i9/+8X6teHRzwAAAAAAAABNSd3/dLn/oLAoqqIuVhXFxhhSGB/xqGjlLwAAAAAAAECTU1eTjaK/KXSLIv7SWB+bc5ko9YxnAAAAAAAAgATJFv393bz1EeV//c8F1gMAAAAAAACQDgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKREkRUAAACwrUpLSwuGDRvWfMCAAS26du3avKysrLiioqKkZcuWzZs1a1bcvHnz0tLS0rJsNtusuLi4ebNmzUoLCgo+8/eijY2N9Zs3b66pra2tqqur21xTU1NdVVVVs2nTptqNGzdWbdiwoeYvf/nL5hUrVlQtWLBgw6xZs6pqamoaJQYAAEDaKYABAACIiIghQ4aUHnTQQW379u3bql27dq3at2/fpkWLFq2bN29eWVpa2qpZs2bNCwsLm2ez2fLCwsLyoqKi8sLCwtKknK+hoaG6vr6+qqGh4S91dXV/aWhoqNq8eXNVTU3NuqqqqvUbNmxYu2rVqjWrV69e99Zbb6177rnnPpgzZ06NTwYAAABJogAGAADIA8OGDWt+xBFHdBwwYECnLl26dGjdunXHFi1adCgtLe1YUlLSvlmzZq0KCgqK07yDwsLCssLCwrKIaPdp/zuNjY21mzdvXrdp06ZVNTU172/YsGHl2rVr31+2bNnKBQsWrHjyySffnzVrVpVPGAAAAE1Fpuexsd9HfaF+ZcSal0ptCAAAIAE6deqUPf744zvtueeeXbp3796lbdu2XSorKzuXlpZ2KS0t7VBYWFhhSztGQ0PDxpqampU1NTXL169fv+yDDz5Y9s477yybPXv2sj/96U8rVqxYUWdLAAAAbE9t9q6Jog4f/TUFMAAAQEJks9nMt7/97Y4jRozo1bdv397t2rXrXl5e3rWsrKxzcXFx+4gosKUmp7G2tnZVTU3Nso0bNy5btWrV0tdff/2tJ598cvG999672noAAADYFgpgAACAhPne977X6a9Fb/v27Xu1bNmyV1lZWa8kvXOXLauvr9/wl7/8ZdG6desWL1u2bNHChQsX/fGPf1w8derUjbYDAADAliiAAQAAmqhsNps59dRTuxx66KH9+/Tp87n27dv3Ly8v719UVOSRzXlq06ZNKzZu3Pj6+++//8abb775xqOPPvrG3XffvcpmAAAA+CsFMAAAQBNx6qmndvniF784qHfv3v3btWv3uYqKis8VFhaW2wxbUl9fv37Dhg1vfPDBB68vXrz4jccee2z+jTfeuNxmAAAA8pMCGAAAYBc45phjWn/rW9/aq3///kPatGnTv6Kiop9HOLO9NDQ0VG/cuPGtNWvWLFy4cOGcO+6445WHHnporc0AAACknwIYAABgJzjjjDO6f+lLX9qrV69eg1u3bj2orKysR0RkbIadJFddXb103bp18xcvXjz30UcffeXqq69+x1oAAADSRwEMAACwnZWWlhb86le/2u3QQw8d1r17931btmw5qLCwsMxmaEoaGhqqP/zww/nvvPPOzGeeeWbW2LFj36ipqWm0GQAAgGRTAAMAAGwHP/7xj7t+9atf3bdXr15D27Ztu1c2m21jKyRJXV3dmg8++OCVRYsWvfznP/95xh/+8IdltgIAAJA8CmAAAIBtcOKJJ7Y75ZRTDujXr9+w1q1bD81ms61shTSpq6tbt3bt2pfffPPNWbfccsvUe++9d7WtAAAANH0KYAAAgE+hoqKi4IILLhg0YsSI/bp27bpfy5YtB2YymUKbIR/kcrmGDz/8cP6777474/nnn59x4YUXvrZx40aPiwYAAGiCFMAAAAAf4/jjj2/7/e9//8D+/fsf2Lp1630KCgpKbAUiGhsbN61fv37eW2+9NeWGG2545u67715lKwAAAE2DAhgAAOB/ZLPZzAUXXPC5I4888sDu3bsfWFFRsVtEFNgMbFl1dfWSd999d8qsWbNmnnvuuS+vW7euwVYAAAB2DQUwAACQ10pLSwsuvfTSQYcccsjBXbt2HVFWVtbDVmDb1dbWrnr//fdfmDp16uRf/vKXL65evbreVgAAAHYeBTAAAJB3Bg0aVHrBBRd8fs899zywQ4cOBxQVFbWwFdj+Ghsba9euXTtrzpw5T59//vmTX3755WpbAQAA2LEUwAAAQF4YNmxY8/POO+/gIUOGHOZ9vrDz/W0ZfNFFFz07a9asKlsBAADY/hTAAABAarVq1arwyiuv3HfEiBEjO3TocFBhYWGZrcCu19DQUP3+++8/O2XKlIk/+clPZm7cuLHRVgAAALYPBTAAAJAqrVq1Kvztb3+7/3777Xd4x44dRxQWFpbbCjRdDQ0NG99///0pM2bMeOqHP/zhC8pgAACAz0YBDAAApMJZZ53V45vf/OaRvXr1GllaWtrVRiB5ampq3l28ePHEO++8c9LVV1/9jo0AAABsPQUwAACQWMOHDy+/6KKLvjB48OCjW7RoMdBGID0+/PDDV+fNmzfhvPPOe3L69Ol/sREAAIBPRwEMAAAkSqtWrQpvuOGGQ/bbb79/atOmzX6ZTCZrK5BeuVyubs2aNTNmzJjx2JgxYyavW7euwVYAAAA+ngIYAABIhB//+Mddv/e9732lZ8+e/1RcXNzWRiD/1NbWfvD2228/dssttzz029/+9l0bAQAA+L8UwAAAQJNVUVFRcO21137+4IMPPrZ169b7ZTKZAlsBIqJxzZo1M59//vnxp5122hR3BQMAAPx/CmAAAKDJOeWUUzqefvrpx/bu3ftL2Wy2jY0AH6e+vn7j0qVLH/vd7373x+uvv36ZjQAAAPlOAQwAADQJ2Ww2c+uttx5wyCGHnNC6deu9I8LdvsDWaFy7du1L06ZN+/OPfvSjZ1evXl1vJQAAQD5SAAMAALtU//79S6655pp/2nPPPY8tLy/vayPAZ1VTU7NswYIF488999wHp06dutFGAACAfKIABgAAdomf//znPU855ZQTu3btemRhYWGZjQDbW2NjY92KFSuevOWWW+689NJLF9kIAACQDxTAAADATuMxz8Cusn79+rlPP/30f5188slT6+rqcjYCAACklQIYAADY4fr27Vv8hz/84a+Pee5nI8CuUlNT8+68efPu/8EPfvDgwoULN9kIAACQNgpgAABghxkyZEjpNddc89XBgwefWFxc3MFGgKaitrZ21dy5c+/5yU9+8uc5c+bU2AgAAJAWWyqAPYoNAADYJqNHj+4wb968n06ZMuXRYcOGnaH8BZqa4uLi9sOGDTtjypQpj86bN++nJ510UntbAQAA0s4dwAAAwFY599xze33/+9//dufOnY/IZDJZGwGSIpfL1S1fvvzJG2644fbLLrvsbRsBAACSyiOgAQCAz+y8887r+53vfOfbHTt2PDyTyRTaCJBUuVyuYcWKFU/cdNNN//XrX/96sY0AAABJowAGAAC22WWXXTboG9/4xg9at249zDaAtFm7du2su++++9pzzjnnNdsAAACSQgEMAABsNcUvkE8UwQAAQJIogAEAgE9N8Qvks7Vr18665557rvv5z38+3zYAAICmaksFcGHlwOj6UV9orIqoWZG1PQAAyBO/+MUvet9xxx3nHHrooT8pLS3tYiNAPiotLe2y7777HvP973+/X1lZ2ZIpU6assxUAAKCpKetcHwXlH/01BTAAAOS5M844o/u99957zpe//OWflZeX94qIjK0AeS5TXl7e8+CDDx71/e9/v3dEvDVjxowPrQUAAGgqFMAAAMD/ceKJJ7a77777fjJq1Kh/KS8v7xOKX4B/lCkvL+99+OGHj/rWt77VfvXq1Qvnz59fbS0AAMCutqUC2DuAAQAgzwwdOrTs+uuvP6l///4nFRYWltkI20NjY2Ns2rQpqquro6amJurr62PTpk2xefPmqK+vj+rq6qivr4/NmzfHpk2boqGhYZv/fxUWFkZJSUk0a9YsioqKoqysLIqKiqJZs2ZRUlISRUVFUVpa+r9/FRQUCIjtoqGhoeq11167a8yYMffMmTOnxkYAAIBdZUvvAFYAAwBAnujUqVP2nnvuGbXXXnudnM1mK22Ej9PQ0BAbN26MDRs2/J+/Nm7cGBs3boyamprYtGlTbNq0KWpqaqK2trbJnqe4uDhKSkqitLT0f/9eUVERFRUV0aJFi//zV0VFRRQWFvog8LHq6urWvvjii7eceOKJf169enW9jQAAADubAhgAAPLcXXfdddAXv/jF00tLS7vZRn7L5XKxYcOGWLt2baxbty7Wrl37d3+tW7cuNmzYkPd7atGiRbRu3TpatWoVrVu3jjZt2vzvf27dunW0aNHCh4morq5e+sgjj1zzne98Z6ptAAAAO5MCGAAA8tTVV189+MQTTzyzoqJioG3kj8bGxli5cmUsX748Pvjgg1i9evX//n3t2rXR2NhoSZ9RYWFhtGrVKtq1axdt27b937937tw5OnTo4LHTeWbDhg3z77333qvOPPPMebYBAADsDApgAADIM1/72tfaXHrppad27979qIjQRKVUQ0NDrFq1KlasWBHvv//+//595cqVTfqRzGlXXFwcHTp0iI4dO0bnzp2jY8eO0alTp2jXrp1HS6dYLpdrfOeddx76+c9/fv2ECRPW2QgAALAjKYABACBP9OrVq9ldd931jT322OM7hYWFZTaSHh9++GG88847sXTp0njvvfdixYoVsXr16mhoaLCchCgsLIz27dtHp06dolu3btG9e/fo3r27x0mnTENDQ9W8efNu++Y3v/nHJUuWbLYRAABgR1AAAwBAHrjrrrtG/NM//dOZJSUlXWwj2davXx9Lly6Nd955539L3w8//NBiUqqysvJ/y+C//tWqVSuLSbiamppljz322G9Gjx49xTYAAIDtTQEMAAAp9qtf/arPD3/4w5+1atVqL9tIno0bN8aSJUvirbfeikWLFsV7770XmzZtspg8V1JSEl27do0+ffpE3759o3fv3lFeXm4xCbRu3bqXr7322ivGjh27yDYAAIDtRQEMAAApNGjQoNI77rjju7vttttJBQUFWRtJhtWrV8ebb74ZixcvjiVLlsTy5cujsbHRYtiigoKC6Ny5c/Tu3Tt69+4d/fr1i7Zt21pMQjQ2Nta98cYbd33rW9+6ff78+TU2AgAAfFYKYAAASJHS0tKCBx988Jj99tvvn7PZbBsbaboaGhri7bffjrfeeisWLFgQS5YscXcv201FRUX06tUr+vbtG3379o2ePXtGYWGhxTRhdXV1a2bMmHHjV77ylYdqamr85gcAALDNFMAAAJASp59+erdf/vKX51ZWVu5jG03T6tWr47XXXouFCxfGm2++GRs3brQUdooWLVpE3759Y8CAATFw4EB3CDdh69evf/E//uM//vPqq69+xzYAAIBtoQAGAICEGzRoUOm99977w969ex+byWTc4teErF+/PubNmxcLFiyIN954Q+FLk9GiRYvo169fDBgwIPbYY4+orKy0lCYkl8s1LF68eNyJJ554rcdCAwAAW0sBDAAACXbNNdcMOemkk35RVlbWyzZ2vVwuF++++27MnTs3XnvttViyZIl3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B7lcrm7y5Mm//vKXv/yIbQAAwK63pXcAK4ABAMg7paWlBTNnzjyzT58+x9vG39uwYUOMGzcuZsyY4VHPQF7KZDKx3377xde//vWoqKiwkH+waNGiP+27775X1dTUeCwEAADsQgpgAAD4H926dctOnjz5V506dRppG/9fLpeLqVOnxp///OfYuHGjhQB5r6KiIkaNGhX777+/x0L/g+XLlz9+6KGHXvLuu+/W2QYAAOwaWyqAvQMYAIC8MXz48PInnnjiynbt2o2wjf/vnXfeiWuvvTaee+652Lx5s4UARMTmzZtjzpw58dprr0XPnj2jRYsWlvI/Kioq+n7rW98aMnXq1Ofee+89f3AAAMAusKV3ACuAAQDIC9/+9rc73n777X9o0aLFANv4b1VVVXHXXXfFvffeG+vXr7cQgI+wbt26eP7552P9+vWx2267RVFRkaVERElJSefjjjvuoA8++GDKK6+88hcbAQCAnUsBDABAXjv//PP7XXzxxX8oKSnpbBv/bfr06XHttdfGokWLLAPgU3jnnXdi2rRp0bp16+jc2R8nERHZbLbyC1/4whElJSUvTp48eY2NAADAzqMABgAgb/3ud7/b60c/+tFVRUVFrWwjYs2aNXHzzTfHpEmTora21kIAtkJtbW289NJL8c4770Tfvn2jtLQ073dSWFhYNnz48C/26dNn4UMPPbTMpwQAAHYOBTAAAHnp1ltv3f+b3/zmfxYWFjbP913kcrl4/vnn4/rrr4/ly5f7cAB8BitXroxp06ZFRUVFdOvWLTKZTF7vo6CgIDto0KBDBw0atOiBBx54xycEAAB2vC0VwJmex8Z+H/WF+pURa17ym6wAACTTww8//KXDDjvsXzKZTN6/rPGDDz6I22+/Pd544w0fDIDtbMCAAfGtb30r2rRpk/e7yOVyjVOmTPn1yJEjH/LJAACAHavN3jVR1OGjv6YABgAgdV555ZXTPve5z30r3/fQ0NAQjz32WDz++ONRV1fngwGwg2Sz2Tj66KPjC1/4QhQUFOT9Pl5//fU79tprr9/7ZAAAwI6jAAYAIC9ks9nMyy+/fFafPn2Oz/ddvPvuu3HbbbfFe++954MBsJN069YtvvOd70S3bt3yfhdLliy5f5999rmypqam0ScDAAC2PwUwAACpV1paWjBr1qyzevfufVw+7yGXy8WTTz4ZDz74oLt+AXaBbDYbxxxzTBxxxBF5fzfw0qVLHxg6dOjlSmAAANj+FMAAAKRar169mk2ePHlsu3btDsrnPaxcuTJuueWWePvtt30oAHaxnj17ximnnBIdOnTI6z2sXr16yiGHHPIvS5Ys2exTAQAA28+WCuDCyoHR9aO+0FgVUbMia3sAADRpQ4cOLXvqqacub9Omzf75uoNcLhfPPPNMXH/99bF27VofCoAmYP369TFlypQoKSmJnj17RiaTycs9NG/evPtJJ500ZPLkyc+sWLHCoykAAGA7KetcHwXlH/01BTAAAIk1ZMiQ0kceeeSKVq1a7Z2vO6iuro7bb789nnjiiWhs9IRNgKaksbEx5s+fH++//34MGDAgstn8/DlLaWlpp6997WuDn3rqqadXrlxZ75MBAACfnQIYAIDUOfTQQ1s8+OCDv2/ZsuUe+bqDOXPmxNVXX+2RzwBN3PLly+OFF16Ijh075u0joUtLSzudcMIJ+7/00ktPv/3227U+FQAA8NkogAEASJVhw4Y1v++++37TsmXLQfl4/vr6+hg/fnz88Y9/jNpaP0MHSILNmzfHiy++GJs3b47ddtstCgoK8m4HxcXFbY866qg9n3vuuaeXL1/ucdAAAPAZKIABAEiNI488snLcuHG/b9GixcB8PP97770XV111VcyZM8eHASCBFi1aFC+//HL069cvWrRokXfnLykp6XDcccftP2fOnGcWLVq0yScCAAC2jQIYAIBUOPLIIyvvvPPO35aXl++Wj+d/+umn48Ybb4wPP/zQhwEgwf7yl7/ECy+8ECUlJdGrV6+8O3+zZs3aHHXUUfspgQEAYNspgAEASLxjjz227W233faH5s2b98m3s1dVVcXNN98cTz31VDQ2NvowAKRAY2NjzJ8/P5YtWxYDBgyIZs2a5dX5mzVr1uaYY4458M0333xm4cKFNT4RAACwdRTAAAAk2qGHHtritttuuzofy9+33347rrnmmli8eLEPAkAKvf/++/HKK69Enz59orKyMq/Ons1mK4888sh9Zs6c+dTSpUs3+zQAAMCnpwAGACCxjjjiiJb33nvvteXl5f3y6dy5XC4mTZoUN998c1RVVfkgAKRYVVVVTJ06NbLZbPTp0ycymUzenL24uLjtV7/61c+/8sorTy1evLjWpwEAAD4dBTAAAIl06KGHtrj33nt/l2/lb3V1ddx0000xefLkyOVyPggAeSCXy8WCBQvi3Xffjd133z2y2fz5mUyzZs1aH3300fvNmDHjSXcCAwDAp6MABgAgcYYOHVo2fvz4qysqKgbk07mXLVsWV111lUc+A+SplStXxiuvvBKf+9znoqKiIm/O3axZszZHH3300GeeeebJFStW1PkkAADAlimAAQBIlCFDhpQ++uij17Rs2XL3fDr31KlT49prr42NGzf6EADksaqqqpg+fXq0bds2unTpkjfnLikpaT9q1KihTz755JMrV66s90kAAICPt6UCuMB6AABoSjp16pSdMGHCv1dWVu6RL2dubGyMcePGxR133BF1dW56AiCitrY2br755hg/fnw0NjbmzbkrKyv3mDBhwr9369bNXQkAALCNFMAAADQZrVq1Kpw+ffolbdq02T9fzlxdXR2/+93vYtKkSd73C8DfyeVy8fjjj8fvf//7qK6uzptzt2nTZv8pU6Zc0qpVq0KfAgAA2HoKYAAAmoSKioqC2bNnX9KuXbuD8uXMS5cujYsuuijmz5/vAwDAx3r11VfjoosuiqVLl+bNmdu1a3fQ7Nmz/72iosLPrgAAYCu5iAYAoEmYOXPmz9q1a3dIvpz35ZdfjiuuuCLWrVsnfAA+0bp16+KKK66Il19+OW/O3K5du4Nnzpz5M+kDAMDWUQADALDLvfjii2N69OgxKh/Omsvl4oEHHogbbrghamtrhQ/Ap1ZbWxs33HBDPPDAA3nz2oAePXqMevHFF8dIHwAAPj0FMAAAu9SkSZO+NnDgwFPy4ax1dXVx8803x8SJE73vF4BtksvlYuLEiXHLLbdEXV1dXpx54MCBJ0+aNOlr0gcAgE9HAQwAwC7z6KOPHnXggQeekw9nXbduXfz617+OWbNmCR6Az2zmzJnx61//Ol9eJZA58MADz3n00UePkjwAAHyywsqB0fWjvtBYFVGzImtDAADsEDfeeOO+Rx999EWZTKYw7Wddvnx5XHXVVbFy5UrBA7DdbNiwIWbPnh0DBw6MioqKtB8307179/179uz56sMPP7xc+gAA5LuyzvVRUP7RX1MAAwCw011xxRV7fPe7372qoKCgWdrPOmfOnPjtb38bGzduFDwA2111dXVMmzYtOnfuHB07dkz1WTOZTOHuu+9+eJs2bV6aNGnSKukDAJDPFMAAADQZZ5xxRvef/exnvy0sLCxP+1knTJgQd999d9TX1wsegB2moaEhXnrppchms9G3b99UnzWTyRTttddeB/3lL395dubMmRukDwBAvlIAAwDQJBx00EEVf/jDH64pLi7ulOZz5nK5eOCBB+Kxxx4TOgA77c+eBQsWRF1dXfTv3z8ymUxqz1pQUFBywAEHDJs+ffqkpUuXbpY+AAD5aEsFcIH1AACwMwwaNKj0vvvuu7qsrKxXms9ZV1cX1113XUyaNEnoAOx0EydOjOuvvz7q6upSfc6ysrJef/rTn67u379/idQBAODvKYABANjhKioqCh577LGLKyoqBqb5nNXV1XHNNdfE7NmzhQ7ALvPKK6/ElVdeGVVVVak+Z4sWLQZOnDhxbEVFhZ9vAQDA33CBDADADjdz5syftW3b9sA0n3HdunVx2WWXxRtvvCFwAHa5xYsXx2WXXRZr165N9TnbtWt34MyZM38mcQAA+P8UwAAA7FBPPvnkqB49eoxK8xlXrVoVV1xxRSxfvlzgADQZK1asiCuuuCJWrlyZ6nP26NFj1KRJk0ZJHAAA/lth5cDo+lFfaKyKqFmRtSEAALbZjTfeuO+XvvSlCzOZTGp/8fDdd9+NK6+8MtatWydwAJqc6urqmDVrVvTv3z8qKytTe85u3boN79mz57yHH37Yb2MBAJAXyjrXR0H5R39NAQwAwA5x3nnn9T311FOvLigoKE7rGV977bW45pprorq6WuAANFmbN2+OGTNmRI8ePaJ9+/apPGMmkykYNGjQIYWFhVOee+45v5UFAEDqKYABANipjjrqqFb/8R//8YdmzZq1SusZX3755bj++uujrq5O4AA0eQ0NDfHSSy9Fp06dolOnTqk8Y0FBQXbYsGGfnz9//qQ33nhjk9QBAEizLRXA3gEMAMB21a1bt+wNN9zwnyUlJR3TesYpU6bEjTfeGPX19QIHIDHq6+vjxhtvjKlTp6b2jCUlJZ1uuOGG/+jWrZu7GgAAyFsKYAAAtqunn376XyorK/dI6/kmTZoUd955ZzQ2NgobgMRpbGyMO+64I5588snUnrGysnLw008//UtpAwCQrxTAAABsN88///w3unTp8k9pPd/EiRNj3LhxkcvlhA1AYuVyubj//vtTXQJ36dLlS88+++yJ0gYAIB95BzAAANvFTTfdNPzII488L5PJZNJ4vsceeyzGjx8vaABS47XXXotmzZpF3759U3m+zp0779urV695Dz/88DJpAwCQNlt6B7ACGACAz+wXv/hF7x/+8IdXFxQUNEvj+R544IF45JFHBA1A6ixYsCDq6upiwIABqTtbJpPJDBo06ODGxsbnpk6dul7aAACkiQIYAIAd5oADDqj43e9+99tmzZq1TeP5xo0bF5MmTRI0AKm1aNGi2Lx5cwwcODB1ZysoKMjut99+w5577rnH33vvvc3SBgAgLbZUAHsHMAAA2yybzWbuvPPOfyktLe2exvNNmDBB+QtAXpg0aVI89NBDqTxbaWlpj3vuuedfstlsRtIAAOQDBTAAANvs+eef/06HDh0OTePZHn744Xj44YeFDEDeeOSRR+LPf/5zKs/WoUOHw5599tlvSxkAgHygAAYAYJvcd999hw8ePPjUNJ7t/vvvjwkTJggZgLzz2GOPxX333ZfKs+25554/+NOf/nSYlAEASDvvAAYAYKudccYZ3ceMGXN5QUFBcdrONnHixHjkkUeEDEDeWrx4cWSz2ejbt2/ajpbp06fPvn/5y18mz5w5c4OkAQBIsi29A1gBDADAVhk2bFjzG2+88Q/NmjVrl7azPfroo6l99CUAbI2FCxdGUVFR9OvXL1XnKigoKD7wwAP3e/LJJx9dsWJFnaQBAEiqLRXAHgENAMBWuffee39ZWlraPW3nevzxx+PBBx8UMAD8jz//+c8xceLE1J2rtLS0x3333fdLCQMAkFYKYAAAPrVJkyaN6tSp0xEpPFeMHz9ewADwD8aPHx+TJ09O3bk6der0hUmTJn1VwgAApJFHQAMA8Kmcd955fU888cR/z2QyRWk618yZM+Puu+8WMAB8jNdeey06duwYnTt3TtW5unbtuk9BQcHzzz333DopAwCQNN4BDADAZ3LEEUe0vOKKK67NZrOVaTrXyy+/HDfffHPkcjkhA8DHyOVyMXv27OjSpUt06tQpNefKZDJF++yzz/CpU6c+9u67726WNAAASeIdwAAAbLNsNpu55ZZb/q2kpKRjms61YMGCuPnmm6OxsVHIAPAJGhsb4+abb44333wzVecqLS3tcvfdd5+fzWYzUgYAIC0UwAAAbNGkSZO+3rZt2wPTdKZly5bFDTfcEPX19QIGgE+prq4urr322li+fHmqztWuXbsDH3/88VESBgAgLTwCGgCAj3XZZZcN+upXvzo2k8mk5hcH33///bjyyiujqqpKwACwlerq6uLll1+OIUOGRHl5eWrO1aVLl31LS0unPvPMM2ukDABAEngENAAAW61///4lJ5988q8ymUxRWs60YcOG+P3vfx8bN24UMABso40bN8bvfve7VP15WlBQkP3hD394ft++fYslDABA4q9vrQAAgI/y4IMPnl1WVtYrLeeprq6O3/zmN7Fq1SrhAsBntGrVqrjyyiujuro6NWcqKyvr8/DDD58lXQAAkk4BDADA/zF+/Pgju3XrdnRazlNfX5/KdxYCwK60fPnyuO6666K+vj41Z+rRo8dXx40bd4R0AQBIMgUwAAB/53vf+16nI4444py0nCeXy8Vtt90Wb7zxhnABYDt7/fXX47bbbotcLpeaMx155JHnfvvb3+4oXQAAkkoBDADA/6qoqCi4+OKLLywsLCxPy5nGjx8fs2bNEi4A7CCzZs2Khx56KDXnKSwsrPj1r399QUVFhZ+bAQCQSC5kAQD4XxMnThxdWVk5OC3nef7552PixImCBYAd7LHHHosXXnghNeeprKzc89FHHz1RsgAAJFFh5cDo+lFfaKyKqFmRtSEAgDxxwQUX7DZq1KgLM5lMYRrO8+qrr8Ytt9ySqkdSAkBT/7O3d+/e0a5du1Scp2PHjkNzudxzU6ZMWSddAACamrLO9VHwMc/wcwcwAADRt2/f4h//+McXZzKZVPwG4HvvvRc33HBDNDY2ChcAdpKGhoa47rrrYtmyZak4T0FBQfbss88e27dv32LpAgCQqGtZKwAAYPz48T8qKyvrkYazbNiwIX7/+99HbW2tYAFgJ9u0aVP8/ve/j40bN6biPGVlZb3GjRs3RrIAACSJAhgAIM/ddNNNw/v06XN8Gs5SX18f1157baxdu1awALCLrFmzJq699tqor69PxXn69ev3jd///vdDJQsAQFIogAEA8thBBx1Uceyxx/5rRGTScJ477rgjFi9eLFgA2MUWLVoUd955Z1qOU/CNb3zj34YNG9ZcsgAAJOIC1goAAPLXzTfffFZxcXG7NJxl4sSJMX36dKECQBMxbdq0mDRpUirOUlJS0unOO+88Q6oAACSBAhgAIE/913/914FdunT5UhrO8tprr8Wf//xnoQJAEzN+/PhYsGBBKs7SrVu3o2+66abhUgUAoKlTAAMA5KEvfelLlV/5yld+lYazrFixIq6//vpobGwULAA0MY2NjXHdddfFihUr0nCczHHHHfergw46qEKyAAA0ZQpgAIA8dPXVV5+ezWYrk36OmpqauPbaa2PTpk1CBYAmatOmTXHttddGTU1N4s+SzWbb3njjjT+RKgAATZkCGAAgz9x6663Du3Tp8uWknyOXy8Utt9wSK1euFCoANHErV66MW2+9NXK5XOLP4lHQAAA0dQpgAIA8MnTo0LKvfvWrv0jDWSZMmBBz584VKgAkxJw5c+Kxxx5LxVlGjRr1i6FDh5ZJFQCApkgBDACQR+64444fFRcXd0z6OV5++eV45JFHBAoACfPQQw+l4he4SkpKOt5xxx0/lCgAAE2RAhgAIE9cfvnlu/fs2XNU0s/xwQcfxB133JGKR0gCQL7J5XJx2223xZo1axJ/lp49ex57+eWX7y5VAACaGgUwAEAe6NatW/a73/3uv2YymURf/9XX18cNN9wQ1dXVQgWAhKqqqoobb7wx6uvrE32OTCZT8N3vfvdX3bp1y0oVAICmRAEMAJAHxo8ff0pZWVmvpJ/jnnvuiaVLlwoUABJuyZIlcd999yX+HGVlZT3Hjx9/ikQBAGhKFMAAACn385//vOeAAQNGJ/0c06dPjylTpggUAFJi8uTJMWPGjMSfY8CAAaN//vOf95QoAABNhQIYACDFstls5qyzzjo3k8kk+tGEK1asiLvvvlugAJAyd911V6xYsSLRZ8hkMtmzzjrr3Gw2m5EoAABNgQIYACDFxo0b98XKysq9knyG2trauOGGG6K2tlagAJAyf/1zfvPmzYk+R2Vl5V7jxo0bKVEAAJoCBTAAQEoNHz68/OCDDz4t6ee4//77Y/ny5QIFgJRavnx5jBs3LvHnGDFixI+HDRvWXKIAAOxqCmAAgJS69dZbT8tms22TfIYZM2bEc889J0wASLnJkyfHzJkzE32G4uLitrfffvtp0gQAYFdTAAMApNBVV121R48ePb6S5DOsXLky7rrrLmECQJ64++6744MPPkj0GXr27PnVK664Yg9pAgCwKymAAQBSprS0tOAb3/jGT5N8rdfY2Bi333679/4CQB6pqamJ2267LRobG5N8jIJvfvObZ5aWlvqZGwAAu+6i1AoAANJlwoQJX6uoqBiQ5DOMHz8+Fi1aJEwAyDNvvvlmPPjgg4k+Q4sWLQY9+OCDx0gTAIBdRQEMAJAiRx55ZOWwYcN+kOQzzJ07N5544glhAkCemjhxYixYsCDRZxg+fPiPjjjiiJbSBABgV1AAAwCkyBVXXHFyUVFRRVLnr6qqijvvvDNyuZwwASBP5XK5uP3226O6ujqxZygqKmrxm9/85mRpAgCwKyiAAQBS4vzzz+/Xu3fv45J8httvvz0+/PBDYQJAnlu3bl3cfvvtiT5D7969jz///PP7SRMAgJ1NAQwAkALZbDZz6qmn/jyTyST2+m769OkxZ84cYQIAERExe/bsmDFjRmLnz2QyBaeeeurPs9lsRpoAAOxMCmAAgBT44x//eERlZeXgpM6/du3auPfeewUJAPyde+65J9atW5fY+SsrKwf/6U9/+oIkAQDYmRTAAAAJ17dv3+JDDjnkR0k+w9133x01NTXCBAD+Tk1NTdx9992JPsPBBx/8o759+xZLEwCAnUUBDACQcHfdddc3S0pKOiV1/smTJ8e8efMECQB8pLlz58azzz6b2PlLSko63nPPPd+SJAAAO4sCGAAgwb70pS9VDhw48KSkzr9mzZoYP368IAGALXrggQdizZo1iZ2/f//+Jx111FGtJAkAwM6gAAYASLArrrji1MLCwvIkzp7L5eK2226LTZs2CRIA2KJNmzbFbbfdFrlcLpHzFxYWll1++eU/kCQAADuDAhgAIKF+8Ytf9O7evftXkjr/s88+G2+88YYgAYBP5Y033ojnn38+sfN369bt6F/96ld9JAkAwI6mAAYASKgf/vCHP8pkMom8nvvggw/igQceECIAsFXGjRsX69atS+TsmUym4NRTT/2xFAEA2NEUwAAACXTdddcNa9eu3YFJnD2Xy8Udd9wRtbW1ggQAtsqmTZvizjvvTOz8bdq02f+mm27aT5IAAOxICmAAgIQpLS0t+NrXvnZ6Uud/4YUXYuHChYIEALbJq6++GjNmzEjs/Mccc8zpFRUVfiYHAMAO42ITACBhbr/99oMrKip2S+LsGzZsiHHjxgkRAPhM7r///qiqqkrk7OXl5X3/67/+6wgpAgCwoyiAAQASpKKiouCwww47Nanz33vvvYn9YS0A0HRs2LAh7r///sTOf9BBB/1zq1atCiUJAMCOoAAGAEiQ+++//+iysrKeSZx9zpw58dJLLwkRANguXnjhhViwYEEiZy8tLe32xz/+8StSBABgR1AAAwAkRN++fYv33Xfff07i7LW1tXHvvfcKEQDYru6+++6oq6tL5Oz77bffKf379y+RIgAA25sCGAAgIW6++eZRxcXFbZM4+yOPPBJr164VIgCwXa1atSoee+yxRM6ezWbb3njjjV+TIgAA25sCGAAgAYYOHVq21157fSeJs7/33nvxxBNPCBEA2CEmTpwYK1asSOTsQ4YM+c7QoUPLpAgAwPakAAYASIBrr732xKKiosqkzZ3L5eKee+6JxsZGIQIAO0R9fX3cddddkcvlEjd7UVFR5bXXXnuCFAEA2J4UwAAATdwBBxxQMWDAgG8kcfYZM2bEW2+9JUQAYId6880348UXX0zk7AMGDPjG8OHDy6UIAMD2ogAGAGjirrrqqhOKiooqkjb3pk2b4oEHHhAgALBT3H///VFbW5u4uYuKilpcffXV7gIGAGC7UQADADRhBx10UEX//v0Teffvww8/HB9++KEQAYCdYv369TFhwoREzj5w4MBvHHDAARVSBABge1AAAwA0Yf/5n/95bGFhYfOkzb1q1aqYPHmyAAGAnerpp5+O1atXJ27uwsLC8ssuu2yUBAEA2B4UwAAATdQBBxxQMWjQoNFJnP3uu++O+vp6IQIAO1V9fX3cddddiZx99913/+bQoUPLpAgAwGelAAYAaKIuv/zyYwsLC8uTNvfcuXNjwYIFAgQAdokFCxbE3LlzEzd3UVFRi9/97ndflyAAAJ+VAhgAoAkaOnRo2aBBgxL37t+6urr405/+JEAAYJf605/+FHV1dYmbe/fdd//mkCFDSiUIAMBnoQAGAGiCfvOb33ylqKioZdLmfu655xL53j0AIF1Wr14dzz33XOLmLioqann11VcfLUEAAD4LBTAAQBPTq1evZoMHD/5m0uaurq6ORx55RIAAQJPwyCOPRHV1deLmHjJkyLe6deuWlSAAANtKAQwA0MTcdNNNxxQXF7dN2twTJkyIqqoqAQIATUJVVVUifzmtuLi43a233uouYAAAtpkCGACgCWnVqlXhXnvtdVLS5l61alU8++yzAgQAmpTJkyfHqlWrEjf30KFDR7dq1apQggAAbAsFMABAE3LLLbccXlJS0jlpcz/44INRX18vQACgSamvr48HH3wwcXOXlJR0vummmw6VIAAA20IBDADQRGSz2cwBBxzw7aTNvWjRonjppZcECAA0SS+99FIsXrw4cXOPGDHiO9lsNiNBAAC2lgIYAKCJuOaaa/YuLy/vm7S5H3roocjlcgIEAJqkXC6XyLuAy8vL+1111VV7SRAAgK2lAAYAaCK+8pWvfDdpM8+bNy8WLlwoPACgSVu4cGG8+uqrrg8BAMgLCmAAgCbgsssuG1RZWblPkmbO5XIxfvx44QEAifDAAw8k7qklrVu33veSSy7pLz0AALaGAhgAoAkYNWrUCUmbefbs2bFs2TLhAQCJsGzZsnjllVcSN/cJJ5xwovQAANgaCmAAgF3sn//5nzt37NjxiCTN3NjYGA888IDwAIBEGT9+fDQ0NCRq5k6dOn1h9OjRHaQHAMCnpQAGANjFfvSjH30tk8kk6rps2rRpsWrVKuEBAImyatWqeOGFFxI1cyaTKfzpT386SnoAAHxaCmAAgF1o0KBBpX369Plqkmaur6+PCRMmCA8ASKQJEyZEXV1dombu27fvV/r27VssPQAAPg0FMADALnTZZZcdXlRUVJGkmadOnRpr164VHgCQSOvXr48pU6YkauaioqLK3/zmN0dIDwCAT0MBDACwi2Sz2cy+++57UpJmrqurc/cvAJB4jz76aOLuAt5///1PymazGekBAPBJFMAAALvI1VdfPbSsrKx3kmaeMmVKbNiwQXgAQKJt2LAhnn/++UTNXFZW1ueqq67aS3oAAHwSBTAAwC7y5S9/+bgkzVtfXx8TJ04UHACQCo8//nji7gL+0pe+dLzkAAD4JApgAIBdYPTo0R3atm07IkkzT5s2LdatWyc8ACAVPvzww5g+fXqiZm7fvv2I0aNHd5AeAABbogAGANgFfvrTn47KZDKFSZm3vr4+HnnkEcEBAKnyyCOPRH19fWLmzWQyhT/96U+/JjkAALZEAQwAsJN16tQp26dPn6OTNLO7fwGANFq3bl1MmzYtUTP36dPnmE6dOmWlBwDAx1EAAwDsZFddddUB2Wy2dVLmbWxsjEmTJgmOVOvYsWN06OCJmgD5aNKkSdHY2JiYebPZbOurrrrqAMkBAPBxFMAAADvZiBEjvp6keV988cVYtWqV4Ei1Ll26xIUXXhinnXZadO3a1UIA8siqVavipZdecj0JAEBqKIABAHaiM844o3tlZeXeSZk3l8vFxIkTBUdeyGQyMXjw4PjVr34VY8aMcUcwQB55/PHHI5fLJWbeysrKvc8444zukgMA4KMogAEAdqJTTjnlqxGRScq8CxYsiPfee09w5JVMJhN77713XHjhhTFmzJho3769pQCk3HvvvRcLFy5M1B9X/3NdCQAA/4cCGABgJ+nVq1ezXr16fTlJM3v3L/nsr0XwBRdcECeffHK0bdvWUgBSLGnXPb169fpyr169mkkOAIB/pAAGANhJrrjiioOLiopaJmXeBN4JAztEYWFhDB8+PC688MIYPXp0VFZWWgpACi1YsCCWLVuWmHmLiopaXnnllYdIDgCAf6QABgDYSYYPH/6VJM2btHfhwY5WVFQUI0aMiEsuuSRGjx4dLVu2tBSAFMnlcvH4448naub99tvvK5IDAOAfKYABAHaC0aNHd6isrByalHnXrl0bL7/8suDgI/y1CL744ovjhBNOiBYtWlgKQEq89NJLsW7dusTMW1lZudfo0aM7SA4AgL+lAAYA2AlOP/30o5J07fXMM89EQ0OD4GALiouL47DDDouxY8fGqFGjoqyszFIAEq6hoSGeeeaZJI1c8D/XmQAA8P8vEq0AAGDHymazmX79+n05KfPW1tbGlClTBAefUnFxcYwcOTIuvfTSGDVqVJSWlloKQII9//zzUVtbm5h5+/Xr9+VsNpuRHAAAf6UABgDYwX7zm9/sWVJS0jkp886YMSOqq6sFB1uppKQkRo4cGZdcckkcffTRUVJSYikACVRdXR0zZ85M0p8/na+44orBkgMA4K8UwAAAO9gXvvCFLyVl1lwuF08//bTQ4DNo3rx5HHXUUXHJJZfEyJEjI5vNWgpAwjz11FORy+USM++RRx75ZakBAPBXCmAAgB1oyJAhpZ07dz4iKfO+/vrrsWLFCsHBdlBeXh6jRo2KSy+9VBEMkDArVqyI119/PTHzdunS5fD+/ft79AQAABGhAAYA2KHGjh17aGFhYWJeCOruX9j+KioqYtSoUXHxxRfH4YcfHkVFRZYC4LpouyosLGz+H//xHwdLDQCACAUwAMAOteeeex6ZlFnXrl0b8+bNExrsIK1atYrjjz8+LrroohgxYkQUFPh2DKApmzdvXqxZsyYx8+61115HSg0AgAgFMADADnPMMce0bt269b5Jmfe5556LxsZGwcEO1qZNmxg9enRcfPHFimCAJqyxsTGee+65JP35MvyYY45pLTkAAPykAQBgBznzzDMPz2Qyibje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FpafffbZvaQFAJA+CmAAgE9p//3375+EOV9//XVhAXmjvLw8Ro0aFf/+7/8eI0eOjGw2aymA67FP6fOf//xAaQEApI8CGADgU+rRo8fuTX3G2traePvtt4UF5J2KiooYNWpUXHzxxXH44Yc3+XdvAum2ePHiRLySo1evXoOkBQCQPgpgAIBPqXXr1k3+DoklS5ZEQ0ODsIC81apVqzj++OPj4osvjhEjRkRBgW97gZ2voaEhlixZ0uTnbNOmjQIYACCFfCcMAPApDBkypLR58+a9m/qcb775prAAIqJ169YxevToGDt2rCIYcF32MZo3b95n0KBBpdICAEgX3wEDAHwKp556av9MJtPkr53eeustYQH8jTZt2sTo0aPjvPPOi+HDhyuCAddlfyOTyRT84Ac/+Jy0AADSxXe+AACfwuDBg5v84/Hq6+tj0aJFwgL4CJ06dYqTTz45/u3f/i323nvvyGQylgLsUIsXL07Eqzn23HPPgdICAEgXBTAAwKfQpUuXAU19xnfeeSfq6uqEBbAFnTt3jjFjxiiCgR2utrY23n333SRc53oPMABAyiiAAQA+hZYtW/Zv6jN6/DPAp9elS5cYM2ZMnHvuuTF48GALAfL2+iwJ17kAAGwdBTAAwCcYPnx4eUlJSeemPqfHPwNsvV69esVpp50W55xzTvTvrwMB8u/6rLS0tPPw4cPLpQUAkB4KYACAT/Ctb31rt4ho8s8IXbx4sbAAtlGfPn3irLPOinPOOSd22203CwG2i4T8gl7m29/+dj9pAQCkhwIYAOAT7L777k2+CVi7dm1s2LBBWACfUZ8+feLss8+OM888M3r27GkhwGfy4Ycfxrp165r8nAMHDlQAAwCkSJEVAABsWadOnZr8D8TefvttQQFsRwMGDIgBAwbEggULYvz48bF06VJLAbb5Oq1Vq1audwEA2GkUwAAAn6CyslIBDJCnBgwYEP3794958+bFQw89FO+++66lAFtlyZIlsddeezX1613PvgcASBEFMADAFnTq1CnbvHnzXk19ziVLlggLYAfJZDIxePDg2GOPPeLll1+OBx98MFauXGkxQGqu05o3b967Xbt2RatXr66XGABA8nkHMADAFowZM6ZnJpPJNuUZGxsbPZoUYCfIZDKx9957x4UXXhhjxoyJ9u3bWwrwiZYuXRqNjY1NesaCgoLsqaee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k8nE7NmzY+LEibFmzRoNAXif/VNSzJo161kTAwBongTAAAC70O233/7KOeecszU/P78022sdMGBAtG/f3tWu0My9+uqrMWnSpFi1apVmALyPjh07xgEHHJCIWhsbG6u/8Y1v/NXUAACaJwEwAMAutHLlyob169fP6tat2+hsrzWVSsXhhx8ekyZNMjhohubMmROTJ0+OJUuWaAbAh3D44YdHKpVKRK3r16+fVVFR0WhqAADNU54WAADsWq+++mpirts77LDDDAyamTfffDP+/d//PX7yk58IfwE+pFQqFSNGjEhMva+88sozpgYA0Hw5AQwAsIvddNNNz5166qnV+fn5rbO91m7dukX//v1j4cKFBgc5btmyZfHYY4/F/PnzNQPgIzrggAOic+fOiai1sbFxy4033jjL1AAAmi8BMADALrZy5cqG8vLyGT179vx0Euo9+uijBcCQw5YvXx7jxo0T/AJ8wv1SUpSXlz9TXl7eYGoAAM2XABgAYDeYMWPGUxdccEEiAuAhQ4ZE69ato7q62uAgh6xcuTImTJgQc+fOjUwmoyEAH1ObNm3i0EMPTUy9zz777FOmBgDQvPkGMADAbvDVr371lYaGhk1JqLWgoCCOOOIIQ4McsW7duvj5z38ed955Z8yZM0f4C/AJjRw5MvLz8xNRa0NDw8abbrrpVVMDAGjenAAGANgNKisrm1atWjW9T58+5ySh3qOPPjqefPJJQREk2Pr16+Oxxx6L2bNn+3cZYBdJpVIxatSoxNS7cuXKadXV1WmTAwBo3pwABgDYTaZNm5aY6/c6duwYAwYMMDRIoA0bNsSvf/3r+Nd//dd49dVXhb8Au9CAAQOiY8eOian36aefftLUAAAQAAMA7CZf+9rX5tTX11ckpd6jjjrK0CBBqqqq4v77749vf/vb8eKLL0ZTU5OmAOxiRx55ZGJqra+vX/eNb3zjdVMDAMAV0AAAu0ltbW16xYoVT++///6fT0K9hx56aLRt2zaqqqoMD7LYli1bYsqUKfHcc8/F9u3bNQRgN2nbtm0MGTIkMfUuX778qdraWtc/AwDgBDAAwO70xz/+cUJSas3Pz4/jjjvO0CBL1dTUxKOPPhq33XZb/OUvfxH+Auxmxx57bOTn5yel3Myvf/3rCaYGAECEABgAYLe66667llZXV89PSr1HH310tGjRwuAgi7wd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qATAAABZ4umnn968fPnyxF3xN3r06GjXrp0BAgBZqUOHDnH88ccnru5ly5ZNmD59+hYTBADgoxIAAwBkkbvvvvtPmUymKUk1FxYWxumnn254AEBWOvPMMxP3yYpMJtN41113/dH0AAD4OATAAABZ5Be/+MWatWvXTkta3UcccUT06tXLAAGArNK7d+847LDDEld3eXn5X+6///51JggAwMchAAYAyDIPP/zwn5JWcyqVijPPPNPwAICsMmbMmEilUomr+8EHH/yT6QEA8HEJgAEAsszXv/71NzZs2DAraXUPHDgwDj74YAMEALLCoEGDYsCAAYmru6KiYuatt966wAQBAPi4BMAAAFlo3Lhxv01i3WPGjIm8PFtMAGDvysvLizFjxiSy9j//+c+/NUEAAD7RflgLAACyz/XXXz+nqqrqr0mru1evXnHUUUcZIACwVx1zzDHRvXv3xNW9adOmV2666aa5JggAwCchAAYAyFJ/+tOf7k1i3WPGjInS0lIDBAD2ijZt2sRZZ52VyNofeOCBe00QAIBPSgAMAJClbrrpprlJPAVcXFwcZ555pgECAHvFWWedFS1btkxc3Zs2bXrl5ptvnmeCAAB8UgJgAIAsNm7cuF8lse5Ro0ZF7969DRAA2KP69OkTI0eOTGTtjz322K9MEACAXUEADACQxcaOHTu7qqrqb0mrO5VKxfnnnx+pVMoQAYA9tv/4/Oc/n8j9R2Vl5d+uueaav5kiAAC7ggAYACDLTZ069bdJrLtv374xZMgQAwQA9ojDDjsssTeQTJ48+TcmCADAriIABgDIcpdeeumLVVVVryax9s9//vNRXFxsiADAblVaWhrnn39+Imuvqqr66+WXX/6SKQIAsKsIgAEAEuChhx76WRLrLisri9NPP90AAYDd6qyzzoqSkpIklp753e9+91MTBABgVxIAAwAkwA033DB3w4YNs5JY+3HHHRd9+vQxRABgt+jbt28cddRRiay9oqJi1te//vU3TBEAgF1JAAwAkBA///nPfxoR6aTVnUql4vOf/3zk5dl6AgC7Vn5+flx00UWRSqWSWH76F7/4xX+bIgAAu5q3cAAACXHHHXe8tW7duulJrL13795xzDHHGCIAsEudcMIJ0b1790TWXl5e/pc77rjjLVMEAGBXEwADACTI3XfffW8mk2lKYu1nnXVWtG3b1hAB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onv37vEv//IvccABBzSrdWcymaYnnnji9s997nPPeAoAAODDEQADAJBYDz/88NJjjjlmY+/evY+KiGZzFKq0tDSGDx8eq1evjvXr13sQAHLcwIED45prrol27do1t6VnZsyY8YOzzjprqqcAAAA+PAEwAACJdv/99795zDHHVO6zzz5HRDMKgVu0aBGHHXZYtGzZMhYuXBjpdNrDAJBjCgoK4pxzzonzzz8/WrRo0dyWn37uuefuOuWUUyZ4EgAA4KMRAAMAkHi///3v5w8bNmxF3759j2lO10GnUqno27dvDB06NBYvXhxbtmzxMADkiJ49e8YNN9wQgwcPblbf+434x7XPU6ZM+fbpp58+2ZMAAAAfnQAYAICc8OCDDy4ZNmzYin79+jWrEDgionXr1nHEEUdEfX19LF261MMAkGCpVCpOOOGEuOKKK6JNmzbNbv07wt9vnXPOOX/xNAAAwMcjAAYAIGc89NBDS4YNG7a8X79+xza3EDg/Pz8OPvjg6NWrV8yfPz8aGho8EAAJU1JSEpdffnmccMIJkZ+f3+zWn8lkGp944olvffazn53maQAAgI9PAAwAQE556KGHlo4cOXJdnz59RqWa252ZEdG1a9cYNmxYLFu2LCorKz0QAAnRt2/fuO6662K//fZrluvPZDLpp59++rvnnHPO054GAAD4ZATAAADknD/96U+LDj300KX7779/s7sOOiKiuLg4jjzyyCgpKYk333wz0um0hwIgSxUUFMRnP/vZuPDCC6OkpKRZ9iCdTjc88sgjt5x//vnTPREAAPDJCYABAMhJDz/88NId3wQelUqlmt09mqlUKvr06RMHH3xwLFy4MLZt2+ahAMgynTt3jrFjx8bQoUOjGV5aERH/CH+feOKJ2y+88MLnPBEAALBrCIABAMhZDz300JIePXq8NmjQoGPz8vJaNMcetG3bNkaNGhVNTU2xZMkSDwVAFkilUjF69Oi48soro0OHDs22D01NTdt++9vf/stll132oqcCAAB2HQEwAAA5bdKkSeXdu3efM3jw4GYbAufn58eAAQOiV69esWDBgti+fbsHA2Avad26dVx66aVx/PHHR35+frPtQ2NjY/WvfvWrf7nuuute81QAAMCuJQAGACDnTZ48eW1jY+OMI4444uiCgoKS5tqHrl27xqhRo2Lbtm2xcuVKDwbAHpRKpWLUqFExduzY6NWrV7PuRX19/fo77rjjK9/61rcWejIAAGDXEwADANAsPP/881UbNmx45rjjjjuqsLCwrLn2obCwMAYNGhT77bdfLF68OGpraz0cALtZ+/bt44orrogTTzwxCgub9/uU2tralTfffPPVP/nJT1Z7MgAAYPcQAAMA0Gz87W9/27p27doZJ5xwwsjCwsK2zbkXnTp1ipEjR0Z1dbXTwAC70ciRI+Pqq6+OHj16NPte1NTULL/hhhuu/e1vf7vOkwEAALuPABgAgGbltdde2zpv3rynTznllKFFRUWdmnMvCgsL49BDD4399tsvFi1a5DQwwC709qnfk08+udmf+o2I2Lx587yLL774unHjxm30dAAAwO71fgFwat9zYsTOftC4LmLjq610DwCAxOrVq1fhs88++69du3Y9QTciGhoaYurUqTF58uRobGzUEICPqaCgIE499dQYPXq04HeH8vLyp4499tjvrly5skE3AABg9+swrDYKuuz8ZwJgAAByWuvWrfNeeumlm/fdd9+zdeMfVq9eHffff38sWbJEMwA+ov322y8uuugi1z2/w8KFC38/fPjwnzY0NGR0AwAA9gwBMAAAzd7zzz9/8aGHHnp1RKR0IyKTycTMmTPjz3/+c9TV1WkIwAcoKSmJ8847L0aMGBGplL9Kdki//PLL9xx77LEPagUAAOxZ7xcA+wYwAADNwn333Tfn+OOP39yrV6/DQwgcqVQqevfuHcOHD49169ZFRUWFhwTgPRxyyCExduzY6N+/v/B3h0wm0/jMM8/828knnzxONwAAYM97v28AC4ABAGg2fve7370xePDgJf369Ts6lUrl60hEcXFxjBgxInr06BFLly6N2tpaTQHYoUOHDvGFL3whzjzzzCguLtaQHZqammoeeOCBWz73uc9N1w0AANg7BMAAALDDww8/vKygoOC54cOHH1FQUFCqI//QrVu3OO6446K0tDQWL14cTU1NmgI0Wy1btoxzzjknLr300ujevbuGvENtbe2K22677arbbrvtDd0AAIC9RwAMAADv8Oyzz25avHjx0yeddNKQoqKiTjryD3l5edGnT58YOXJkbN26NVatWqUpQLNz+OGHx1e+8pUYMGBA5OXlacg7VFVV/e3CCy+8/oEHHvDdAAAA2MsEwAAA8C7z58+vefbZZ58+44wz+hcX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OigOOOCAKCoq0pQs0djYuGXmzJk/PvPMMyc2NDS4XgAAAPjQBMAAAJADjjzyyNY/+9nPrujbt++5EZGnI9mluro6Fi5cGPPnz4958+ZFZWWlprBXtGvXLg455JAYMGBA9O/fP1q39nsjWSj91ltv/fmqq676xaxZs6q1AwAA+KgEwAAAkEN++ctfjhgzZsyNrVq16q0b2SmdTsfKlStj0aJFsXDhwli8eHFs27ZNY9gtSkpKol+/ftG/f//Yf//9o1evXpGX53dEslVNTc3yRx999EdXXnnlK7oBAAB8XAJgAADIMd26dSt8+OGHPzd48ODL8vPzbdyzXCaTiTVr1sTChQtj0aJFsWjRotiyZYvG8LGUlZVF//79/xn6du/ePVKplMZkuaampprXXnvtV2PGjHmgoqKiUUcAAIBPQgAMAAA56rjjjiv7r//6r8tdC508mzdvjuXLl8eKFSti+fLlsXjx4qipqdEY/pfi4uLo169f9O7dO/bZZ5/Yd999o6ysTGMSJJPJpJcsWfLn66677pfTp0/3mx8AAMAuIQAGAIAc99Of/nTIueeee3NpaWlf3UimxsbGWLlyZSxdujSWLVsWy5cvj3Xr1kUmk9GcZiKVSkWXLl1in332iT59+kSfPn2iV69eUVBQoDkJtXXr1sUPPvjgj6699tq/6wYAALArCYABAKAZaNeuXf64cePOGTp06BUFBQWtdST56uvrY+XKlf88KbxixYpYu3ZtpNNpzUm4vLy86Nq1a+yzzz7//KdXr17RsmVLzckBjY2NW/7617/+4pxzznm0srKySUcAAIBdTQAMAADNyIknntjmnnvuuXzfffcdk0qlHB3MMdu3b481a9bEmjVrYu3atbF27dooLy+PDRs2CIazUF5eXnTs2DG6desWXbt2jW7dukW3bt2iR48eUVhYqEE5JpPJNC5ZsuRR1z0DAAC7mwAYAACaoa9+9av7Xnfdddd16NDhCN3IfY2Njf8MhNetWxfr1q2LioqKWLduXWzbtk2DdrPS0tLo3LnzP//p0qVLdO3aNbp27eoK52Ziw4YNM//rv/7rxz/60Y+W6wYAALC7CYABAKAZ++UvfznirLPOuq64uNj3gZupmpqaWL9+/T//qaioiMrKyqisrIxNmzZFY2OjJn2AgoKCaN++fbRr1y7at28fHTt2jC5dukSnTp2ic+fOUVxcrEnN1NatW98aP378PVdcccXLugEAAOwpAmAAAGjm2rVrl//ggw+eOWLEiCsLCwvb6gjvtHnz5n+GwZs2bYrKysqorq6OLVu2xJYtW6K6ujqqq6sjk8nk3NpTqVS0bt06WrduHWVlZdGmTZsoLS39X2Fvu3btok2bNh4U/peGhobKl1566efnnHPO+OrqavevAwAAe5QAGAAAiIiIoUOHFt97770XHHjggRfk5+c7ssiHlk6n/xkEV1dXR01Nzfv+k8lkora2NtLpdNTX10dTU1PU1dXt0u8U5+XlRcuWLSM/Pz+KiooiLy8vWrVqFalUKoqLi3f6T0lJSbRq1eqfgW9paWnk5eUZMB9aU1NTzYIFC/745S9/+Y+zZ8+u0REAAGBvEAADAAD/y2mnndb2rrvuurRPnz5n5+XlFeoIe9LbgfDbtm/f/r7XUBcUFESLFi3++b/fDnxhT8pkMg1LliwZd8stt/xq0qRJVToCAADsTQJgAABgp0477bS2d95554X777//5wTBAP9XJpNpWLhw4QO33nrrHwS/AABAtni/ADi/7UHRc2c/SG+LqC33/gcAAHLZokWL6u69995X0un0swcddFCnkpKS3roC8A8VFRUz/7//7/+77aKLLpq6aNGiOh0BAACyRXH3xsgr3fnPBMAAAEDMnDmz8u67736qqalpWr9+/Ypbt27dN5VKpXQGaG4ymUx6zZo1U+65555/Peeccx6cOXNmpa4AAADZRgAMAAB8KDNnzqz88Y9//Gw6nZ4uCAaak7eD37vvvvtfzz///McEvwAAQDYTAAMAAB+JIBhoLgS/AABAEgmAAQCAj+XtILisrOyFvn37diwuLu4VEYJgIBdkKioqnrv33nu/PWbMmEcEvwAAQJK8XwCc2vecGLGzHzSui9j4aivdAwAA/unqq6/u8ZWvfOX8Pn36nJWXl9dCR4CkSafT9UuXLh3/X//1Xw/84he/WKMjAABAEnUYVhsFXXb+MwEwAADwkZ1xxhntb7/99rMPPPDA8/Pz81vrCJDtmpqaqhcsWPDgd77znUcmTpzotC8AAJBoAmAAAGC3GD58eMkPf/jDzwwePPjioqKijjoCZJv6+voNr7322u9vvPHGx2fPnl2jIwAAQC4QAAMAALvV0KFDi++5556zDjnkkPOKioq66giwt9XV1a19/fXXH7z++uvHC34BAIBcIwAGAAD2iFatWuXdc889w0455ZTzO3bseJSOAHtYZsOGDbOmTJny4PXXX/9qbW1tWksAAIBcJAAGAAD2uH/913/tf/7555/dq1ev0/Ly8lroCLC7pNPp+pUrV05+4IEHHvnOd76zSEcAAIBcJwAGAAD2mjPOOKP97bfffvYBBxzw2YKCgjY6AuwqjY2NVW+++eafv/e97z06YcKETToCAAA0FwJgAABgrxs+fHjJ97///dGDBg0aU1paur+OAB9XdXX1wtdee+3Rr371q1Nfe+21Wh0BAACaGwEwAACQVb761a/ue8EFF3y6b9++ZxUUFLTWEeCDNDY2bnnrrbfG/+EPf5j4ox/9aLmOAAAAzZkAGAAAyEpDhw4t/sEPfnDy4MGDz27dunV/HQHerbq6+s2XX375weuuu+7ppUuXbtcRAAAAATAAAJDlCgsLU3ffffeQ0aNHn9G1a9fj8vLyinQFmq90Ol1XXl4+bcqUKROuvfbav+sIAADA/yYABgAAEqNPnz4t/v3f/33UyJEjz2rfvv2nIiKlK9AsZDZt2vTXF1544bGvfe1rzzntCwAA8N4EwAAAQCJddNFFXa6++uqTDzzwwLNbtmzZTUcg99TV1a1ZsGDBuJ/+9KdP3n///et0BAAA4IMJgAEAgETr1q1b4d13333k4YcffmqHDh2OyMvLK9QVSK50Ot2wcePGWbNmzZp8/fXXz6qoqGjUFQAAgA9PAAwAAOSMo48+uvWtt956/CGHHHJKu3btBkdEnq5AIqQrKytfmzdv3uQ777xz+owZM6q1BAAA4OMRAAMAADnpuOOOK/vGN75x/CGHHHJa27ZtB4bvBUO2yVRVVc2dN2/epO9///vTpk+fvkVLAAAAPjkBMAAAkPNuu+22vmedddZJffr0Oa5Vq1a9dQT2ntra2uXLly+f/uijjz51xx13vKUjAAAAu5YAGAAAaFa+9KUvdbv44ouP7t+//wlOBsMekamqqpq7cOHCv/z+97+fcd9995VrCQAAwO4jAAYAAJqtSy65pOtll112jDAYdrl0VVXVvIULF/7lV7/61bO/+93v1moJAADAniEABgAAiIirr766x/nnnz9q//33P7JNmzZDUqlUga7Ah5fJZBoqKyv/vnjx4uf+9Kc/zbr33ntX6woAAMCeJwAGAAB4l379+hV97WtfGzRy5MhRPXv2PLaoqKizrsD/VV9fv37VqlXPvPDCC8/9+7//+5zFixfX6woAAMDeJQAGAAB4H61bt8678847Bx599NFHde/efURpaen+4apomq/M1q1bF69Zs+bF5557btY3v/nNOdXV1WltAQAAyB4CYAAAgI9g8ODBrcaOHXvI8OHDD+vevfvw1q1bHxACYXJXprq6+s01a9a88sorr7z8k5/8ZN5rr71Wqy0AAADZSwAMAADwCVx//fX7nHHGGYf169dvePv27Yfm5+e31hWSrLGxsXrjxo2vvvXWWy+PHz/+lR//+McrdQUAACA5BMAAAAC70Je//OUe55xzzvA+ffoM7tix45CioqKuukI2q6+vX7t27doXFy9ePGfixImv3Xvvvat1BQAAILkEwAAAALvRl7/85R6f+cxnBvfr129Qly5dDm/ZsqVAmL2qrq5u7bp16wS+AAAAOUoADAAAsIe0atUq75prrtnn2GOPPXi//fY7uH379oeUlpb2TaVS+brDbpKuqalZtnHjxnlvvfXW3GeffXbef/3Xfy2vra1Naw0AAEBuEgADAADsRQceeGDLq6+++oAhQ4Yc3LNnz4Pbtm17sGuj+biampqqq6qqXi8vL583Z86ceb/85S/nvfjii1t1BgAAoPkQAAMAAGSZoUOHFn/xi1/cf9CgQQf26NHjwHbt2h3YqlWr3qlUKk932CFdU1OzvLKycsHq1asXzJkzZ8Gf//znJTNmzKjWGgAAgOZNAAwAAJAAxx13XNkFF1xw4MEHH3xA165dDywtLd23pKRkn1QqVag7uS2TyTRs27ZtRXV19dJ169YtfOONNxZOmDBh4YQJEzbpDgAAAO8mAAYAAEiw8847r+OJJ57Yp3///vt16dKlT5s2bfZr3bp1v/z8/GLdSZampqaa6urqxZs3b16ybt26pQsXLlzy9NNPL33ooYc26A4AAAAflgAYAAAgx7Rr1y7/kksu6TFkyJCe++67b89OnTr1Kisr61VcXNyzZcuW3VKpVL4u7R2ZTKaprq6uvKamZtWWLVtWVlRUrFy6dOnK2bNnr7r//vvXVFZWNukSAAAAn4QAGAAAoBnp1KlTwec+97luQ4cO7bnPPvv0aNeuXafWrVt3Li4u7tqyZcvORUVFnfLy8lro1MeTTqe319fXr6+rq6uoqalZW11dvb6y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AACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoMY3JP//9K8My551lzpAk293a7QAAAAAAAAD8iIw3r+SL7TpPxuSt4/ibJJuz20QDBgAAAAAAAHhzrJPp6NvHYcyyjLl7dJTPbl/Jp6sPLufSsM+5ec7q5YOrF0OeP/SVaAAAAAAAAIA3weH7u6zfm79dWDIMSw6225w785vsx3XyzasOby5ssz69c4sAAAAAAAAAr9n69C6bC9sT93a7rKdnORin5Otxynzi1JQcfiwCAwAAAAAAALxO69O7HH68TaaT98cp85R8vbp3Nfszv8q0LHn7xMF1sjk/ZzUPmZ/MmWefhAYAAAAAAAD4oayPdjn7223Gn7x6ZrXPnetX8mBKkpv3cufDd/Pufn5FL56SzcVtNheT3dNt8tQlAwAAAAAAAHyv1sm0ySv/9XtsNWZ3I/lHkgzHi7/4XY7WYz5yiwAAAAAAAAA/Ivtcv/3nPEyS1fHa42t5+vNLyX7JoRsCAAAAAAAAePPt1/nbV3/KvePn1Xc371/NYxEYAAAAAAAA4M0yTHk2rvNo2WdzvHZqzN9v/SF3vju3evng/at5fPDLPDu1yuGyZHSVAAAAAAAAAK/XOGe4ueSvZ4e8M8xZbVe5ceuPufvy3Oqkw4+v5emDX+fuuTlLhhwsEYIBAAAAAAAAXpclGR8OuXP0TR4cPM/9z/+SRyfNDf/1TZezOp/87KdjzizJZkhO7edMy/w/nAUAAAAAAADg/zaMWcZkP8/ZLsmLacr2/MV8+cnvs/tP5/4FmLjAq1ifcioAAAAASUVORK5CYII='; /** * PptxGenJS: Utility Methods */ /** * Translates any type of `x`/`y`/`w`/`h` prop to EMU * - guaranteed to return a result regardless of undefined, null, etc. (0) * - {number} - 12800 (EMU) * - {number} - 0.5 (inches) * - {string} - "75%" * @param {number|string} size - numeric ("5.5") or percentage ("90%") * @param {'X' | 'Y'} xyDir - direction * @param {PresLayout} layout - presentation layout * @returns {number} calculated size */ function getSmartParseNumber(size, xyDir, layout) { // FIRST: Convert string numeric value if reqd if (typeof size === 'string' && !isNaN(Number(size))) size = Number(size); // CASE 1: Number in inches // Assume any number less than 100 is inches if (typeof size === 'number' && size < 100) return inch2Emu(size); // CASE 2: Number is already converted to something other than inches // Assume any number greater than 100 sure isnt inches! Just return it (assume value is EMU already). if (typeof size === 'number' && size >= 100) return size; // CASE 3: Percentage (ex: '50%') if (typeof size === 'string' && size.includes('%')) { if (xyDir && xyDir === 'X') return Math.round((parseFloat(size) / 100) * layout.width); if (xyDir && xyDir === 'Y') return Math.round((parseFloat(size) / 100) * layout.height); // Default: Assume width (x/cx) return Math.round((parseFloat(size) / 100) * layout.width); } // LAST: Default value return 0; } /** * Basic UUID Generator Adapted * @link https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript#answer-2117523 * @param {string} uuidFormat - UUID format * @returns {string} UUID */ function getUuid(uuidFormat) { return uuidFormat.replace(/[xy]/g, function (c) { var r = (Math.random() * 16) | 0; var v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); } /** * Replace special XML characters with HTML-encoded strings * @param {string} xml - XML string to encode * @returns {string} escaped XML */ function encodeXmlEntities(xml) { // NOTE: Dont use short-circuit eval here as value c/b "0" (zero) etc.! if (typeof xml === 'undefined' || xml == null) return ''; return xml.toString().replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); } /** * Convert inches into EMU * @param {number|string} inches - as string or number * @returns {number} EMU value */ function inch2Emu(inches) { // NOTE: Provide Caller Safety: Numbers may get conv<->conv during flight, so be kind and do some simple checks to ensure inches were passed // Any value over 100 damn sure isnt inches, so lets assume its in EMU already, therefore, just return the same value if (typeof inches === 'number' && inches > 100) return inches; if (typeof inches === 'string') inches = Number(inches.replace(/in*/gi, '')); return Math.round(EMU * inches); } /** * Convert `pt` into points (using `ONEPT`) * @param {number|string} pt * @returns {number} value in points (`ONEPT`) */ function valToPts(pt) { var points = Number(pt) || 0; return isNaN(points) ? 0 : Math.round(points * ONEPT); } /** * Convert degrees (0..360) to PowerPoint `rot` value * @param {number} d degrees * @returns {number} calculated `rot` value */ function convertRotationDegrees(d) { d = d || 0; return Math.round((d > 360 ? d - 360 : d) * 60000); } /** * Converts component value to hex value * @param {number} c - component color * @returns {string} hex string */ function componentToHex(c) { var hex = c.toString(16); return hex.length === 1 ? '0' + hex : hex; } /** * Converts RGB colors from css selectors to Hex for Presentation colors * @param {number} r - red value * @param {number} g - green value * @param {number} b - blue value * @returns {string} XML string */ function rgbToHex(r, g, b) { return (componentToHex(r) + componentToHex(g) + componentToHex(b)).toUpperCase(); } /** TODO: FUTURE: TODO-4.0: * @date 2022-04-10 * @tldr this s/b a private method with all current calls switched to `genXmlColorSelection()` * @desc lots of code calls this method * @example [gen-charts.tx] `strXml += '' + createColorElement(seriesColor, ``) + ''` * Thi sis wrong. We s/b calling `genXmlColorSelection()` instead as it returns `BLAH`!! */ /** * Create either a `a:schemeClr` - (scheme color) or `a:srgbClr` (hexa representation). * @param {string|SCHEME_COLORS} colorStr - hexa representation (eg. "FFFF00") or a scheme color constant (eg. pptx.SchemeColor.ACCENT1) * @param {string} innerElements - additional elements that adjust the color and are enclosed by the color element * @returns {string} XML string */ function createColorElement(colorStr, innerElements) { var colorVal = (colorStr || '').replace('#', ''); if (!REGEX_HEX_COLOR.test(colorVal) && colorVal !== SchemeColor.background1 && colorVal !== SchemeColor.background2 && colorVal !== SchemeColor.text1 && colorVal !== SchemeColor.text2 && colorVal !== SchemeColor.accent1 && colorVal !== SchemeColor.accent2 && colorVal !== SchemeColor.accent3 && colorVal !== SchemeColor.accent4 && colorVal !== SchemeColor.accent5 && colorVal !== SchemeColor.accent6) { console.warn("\"".concat(colorVal, "\" is not a valid scheme color or hex RGB! \"").concat(DEF_FONT_COLOR, "\" used instead. Only provide 6-digit RGB or 'pptx.SchemeColor' values!")); colorVal = DEF_FONT_COLOR; } var tagName = REGEX_HEX_COLOR.test(colorVal) ? 'srgbClr' : 'schemeClr'; var colorAttr = 'val="' + (REGEX_HEX_COLOR.test(colorVal) ? colorVal.toUpperCase() : colorVal) + '"'; return innerElements ? "").concat(innerElements, "") : ""); } /** * Creates `a:glow` element * @param {TextGlowProps} options glow properties * @param {TextGlowProps} defaults defaults for unspecified properties in `opts` * @see http://officeopenxml.com/drwSp-effects.php * { size: 8, color: 'FFFFFF', opacity: 0.75 }; */ function createGlowElement(options, defaults) { var strXml = ''; var opts = __assign(__assign({}, defaults), options); var size = Math.round(opts.size * ONEPT); var color = opts.color; var opacity = Math.round(opts.opacity * 100000); strXml += ""); strXml += createColorElement(color, "")); strXml += ''; return strXml; } /** * Create color selection * @param {Color | ShapeFillProps | ShapeLineProps} props fill props * @returns XML string */ function genXmlColorSelection(props) { var fillType = 'solid'; var colorVal = ''; var internalElements = ''; var outText = ''; if (props) { if (typeof props === 'string') colorVal = props; else { if (props.type) fillType = props.type; if (props.color) colorVal = props.color; if (props.alpha) internalElements += ""); // DEPRECATED: @deprecated v3.3.0 if (props.transparency) internalElements += ""); } switch (fillType) { case 'solid': outText += "".concat(createColorElement(colorVal, internalElements), ""); break; default: // @note need a statement as having only "break" is removed by rollup, then tiggers "no-default" js-linter outText += ''; break; } } return outText; } /** * Get a new rel ID (rId) for charts, media, etc. * @param {PresSlide} target - the slide to use * @returns {number} count of all current rels plus 1 for the caller to use as its "rId" */ function getNewRelId(target) { return target._rels.length + target._relsChart.length + target._relsMedia.length + 1; } /** * Checks shadow options passed by user and performs corrections if needed. * @param {ShadowProps} ShadowProps - shadow options */ function correctShadowOptions(ShadowProps) { if (!ShadowProps || typeof ShadowProps !== 'object') { // console.warn("`shadow` options must be an object. Ex: `{shadow: {type:'none'}}`") return; } // OPT: `type` if (ShadowProps.type !== 'outer' && ShadowProps.type !== 'inner' && ShadowProps.type !== 'none') { console.warn('Warning: shadow.type options are `outer`, `inner` or `none`.'); ShadowProps.type = 'outer'; } // OPT: `angle` if (ShadowProps.angle) { // A: REALITY-CHECK if (isNaN(Number(ShadowProps.angle)) || ShadowProps.angle < 0 || ShadowProps.angle > 359) { console.warn('Warning: shadow.angle can only be 0-359'); ShadowProps.angle = 270; } // B: ROBUST: Cast any type of valid arg to int: '12', 12.3, etc. -> 12 ShadowProps.angle = Math.round(Number(ShadowProps.angle)); } // OPT: `opacity` if (ShadowProps.opacity) { // A: REALITY-CHECK if (isNaN(Number(ShadowProps.opacity)) || ShadowProps.opacity < 0 || ShadowProps.opacity > 1) { console.warn('Warning: shadow.opacity can only be 0-1'); ShadowProps.opacity = 0.75; } // B: ROBUST: Cast any type of valid arg to int: '12', 12.3, etc. -> 12 ShadowProps.opacity = Number(ShadowProps.opacity); } // OPT: `color` if (ShadowProps.color) { // INCORRECT FORMAT if (ShadowProps.color.startsWith('#')) { console.warn('Warning: shadow.color should not include hash (#) character, , e.g. "FF0000"'); ShadowProps.color = ShadowProps.color.replace('#', ''); } } return ShadowProps; } /** * PptxGenJS: Table Generation */ /** * Break cell text into lines based upon table column width (e.g.: Magic Happens Here(tm)) * @param {TableCell} cell - table cell * @param {number} colWidth - table column width (inches) * @return {TableRow[]} - cell's text objects grouped into lines */ function parseTextToLines(cell, colWidth, verbose) { var _a, _b; // FYI: CPL = Width / (font-size / font-constant) // FYI: CHAR:2.3, colWidth:10, fontSize:12 => CPL=138, (actual chars per line in PPT)=145 [14.5 CPI] // FYI: CHAR:2.3, colWidth:7 , fontSize:12 => CPL= 97, (actual chars per line in PPT)=100 [14.3 CPI] // FYI: CHAR:2.3, colWidth:9 , fontSize:16 => CPL= 96, (actual chars per line in PPT)=84 [ 9.3 CPI] var FOCO = 2.3 + (((_a = cell.options) === null || _a === void 0 ? void 0 : _a.autoPageCharWeight) ? cell.options.autoPageCharWeight : 0); // Character Constant var CPL = Math.floor((colWidth / ONEPT) * EMU) / ((((_b = cell.options) === null || _b === void 0 ? void 0 : _b.fontSize) ? cell.options.fontSize : DEF_FONT_SIZE) / FOCO); // Chars-Per-Line var parsedLines = []; var inputCells = []; var inputLines1 = []; var inputLines2 = []; /* if (cell.options && cell.options.autoPageCharWeight) { let CHR1 = 2.3 + (cell.options && cell.options.autoPageCharWeight ? cell.options.autoPageCharWeight : 0) // Character Constant let CPL1 = ((colWidth / ONEPT) * EMU) / ((cell.options && cell.options.fontSize ? cell.options.fontSize : DEF_FONT_SIZE) / CHR1) // Chars-Per-Line console.log(`cell.options.autoPageCharWeight: '${cell.options.autoPageCharWeight}' => CPL: ${CPL1}`) let CHR2 = 2.3 + 0 let CPL2 = ((colWidth / ONEPT) * EMU) / ((cell.options && cell.options.fontSize ? cell.options.fontSize : DEF_FONT_SIZE) / CHR2) // Chars-Per-Line console.log(`cell.options.autoPageCharWeight: '0' => CPL: ${CPL2}`) } */ /** * EX INPUTS: `cell.text` * - string....: "Account Name Column" * - object....: { text:"Account Name Column" } * - object[]..: [{ text:"Account Name", options:{ bold:true } }, { text:" Column" }] * - object[]..: [{ text:"Account Name", options:{ breakLine:true } }, { text:"Input" }] */ /** * EX OUTPUTS: * - string....: [{ text:"Account Name Column" }] * - object....: [{ text:"Account Name Column" }] * - object[]..: [{ text:"Account Name", options:{ breakLine:true } }, { text:"Input" }] * - object[]..: [{ text:"Account Name", options:{ breakLine:true } }, { text:"Input" }] */ // STEP 1: Ensure inputCells is an array of TableCells if (cell.text && cell.text.toString().trim().length === 0) { // Allow a single space/whitespace as cell text (user-requested feature) inputCells.push({ _type: SLIDE_OBJECT_TYPES.tablecell, text: ' ' }); } else if (typeof cell.text === 'number' || typeof cell.text === 'string') { inputCells.push({ _type: SLIDE_OBJECT_TYPES.tablecell, text: (cell.text || '').toString().trim() }); } else if (Array.isArray(cell.text)) { inputCells = cell.text; } if (verbose) { console.log('[1/4] inputCells'); inputCells.forEach(function (cell, idx) { return console.log("[1/4] [".concat(idx + 1, "] cell: ").concat(JSON.stringify(cell))); }); // console.log('...............................................\n\n') } // STEP 2: Group table cells into lines based on "\n" or `breakLine` prop /** * - EX: `[{ text:"Input Output" }, { text:"Extra" }]` == 1 line * - EX: `[{ text:"Input" }, { text:"Output", options:{ breakLine:true } }]` == 1 line * - EX: `[{ text:"Input\nOutput" }]` == 2 lines * - EX: `[{ text:"Input", options:{ breakLine:true } }, { text:"Output" }]` == 2 lines */ var newLine = []; inputCells.forEach(function (cell) { var _a; // (this is always true, we just constructed them above, but we need to tell typescript b/c type is still string||Cell[]) if (typeof cell.text === 'string') { if (cell.text.split('\n').length > 1) { cell.text.split('\n').forEach(function (textLine) { newLine.push({ _type: SLIDE_OBJECT_TYPES.tablecell, text: textLine, options: __assign(__assign({}, cell.options), { breakLine: true }), }); }); } else { newLine.push({ _type: SLIDE_OBJECT_TYPES.tablecell, text: cell.text.trim(), options: cell.options, }); } if ((_a = cell.options) === null || _a === void 0 ? void 0 : _a.breakLine) { if (verbose) console.log("inputCells: new line > ".concat(JSON.stringify(newLine))); inputLines1.push(newLine); newLine = []; } } // Flush buffer if (newLine.length > 0) { inputLines1.push(newLine); newLine = []; } }); if (verbose) { console.log("[2/4] inputLines1 (".concat(inputLines1.length, ")")); inputLines1.forEach(function (line, idx) { return console.log("[2/4] [".concat(idx + 1, "] line: ").concat(JSON.stringify(line))); }); // console.log('...............................................\n\n') } // STEP 3: Tokenize every text object into words (then it's really easy to assemble lines below without having to break text, add its `options`, etc.) inputLines1.forEach(function (line) { line.forEach(function (cell) { var lineCells = []; var cellTextStr = String(cell.text); // force convert to string (compiled JS is better with this than a cast) var lineWords = cellTextStr.split(' '); lineWords.forEach(function (word, idx) { var cellProps = __assign({}, cell.options); // IMPORTANT: Handle `breakLine` prop - we cannot apply to each word - only apply to very last word! if (cellProps === null || cellProps === void 0 ? void 0 : cellProps.breakLine) cellProps.breakLine = idx + 1 === lineWords.length; lineCells.push({ _type: SLIDE_OBJECT_TYPES.tablecell, text: word + (idx + 1 < lineWords.length ? ' ' : ''), options: cellProps }); }); inputLines2.push(lineCells); }); }); if (verbose) { console.log("[3/4] inputLines2 (".concat(inputLines2.length, ")")); inputLines2.forEach(function (line) { return console.log("[3/4] line: ".concat(JSON.stringify(line))); }); // console.log('...............................................\n\n') } // STEP 4: Group cells/words into lines based upon space consumed by word letters inputLines2.forEach(function (line) { var lineCells = []; var strCurrLine = ''; line.forEach(function (word) { // A: create new line when horizontal space is exhausted if (strCurrLine.length + word.text.length > CPL) { // if (verbose) console.log(`STEP 4: New line added: (${strCurrLine.length} + ${word.text.length} > ${CPL})`); parsedLines.push(lineCells); lineCells = []; strCurrLine = ''; } // B: add current word to line cells lineCells.push(word); // C: add current word to `strCurrLine` which we use to keep track of line's char length strCurrLine += word.text.toString(); }); // Flush buffer: Only create a line when there's text to avoid empty row if (lineCells.length > 0) parsedLines.push(lineCells); }); if (verbose) { console.log("[4/4] parsedLines (".concat(parsedLines.length, ")")); parsedLines.forEach(function (line, idx) { return console.log("[4/4] [Line ".concat(idx + 1, "]:\n").concat(JSON.stringify(line))); }); console.log('...............................................\n\n'); } // Done: return parsedLines; } /** * Takes an array of table rows and breaks into an array of slides, which contain the calculated amount of table rows that fit on that slide * @param {TableCell[][]} tableRows - table rows * @param {TableToSlidesProps} tableProps - table2slides properties * @param {PresLayout} presLayout - presentation layout * @param {SlideLayout} masterSlide - master slide * @return {TableRowSlide[]} array of table rows */ function getSlidesForTableRows(tableRows, tableProps, presLayout, masterSlide) { if (tableRows === void 0) { tableRows = []; } if (tableProps === void 0) { tableProps = {}; } var arrInchMargins = DEF_SLIDE_MARGIN_IN; var emuSlideTabW = EMU * 1; var emuSlideTabH = EMU * 1; var emuTabCurrH = 0; var numCols = 0; var tableRowSlides = []; var tablePropX = getSmartParseNumber(tableProps.x, 'X', presLayout); var tablePropY = getSmartParseNumber(tableProps.y, 'Y', presLayout); var tablePropW = getSmartParseNumber(tableProps.w, 'X', presLayout); var tablePropH = getSmartParseNumber(tableProps.h, 'Y', presLayout); var tableCalcW = tablePropW; function calcSlideTabH() { var emuStartY = 0; if (tableRowSlides.length === 0) emuStartY = tablePropY || inch2Emu(arrInchMargins[0]); if (tableRowSlides.length > 0) emuStartY = inch2Emu(tableProps.autoPageSlideStartY || tableProps.newSlideStartY || arrInchMargins[0]); emuSlideTabH = (tablePropH || presLayout.height) - emuStartY - inch2Emu(arrInchMargins[2]); // console.log(`| startY .......................................... = ${(emuStartY / EMU).toFixed(1)}`) // console.log(`| emuSlideTabH .................................... = ${(emuSlideTabH / EMU).toFixed(1)}`) if (tableRowSlides.length > 1) { // D: RULE: Use margins for starting point after the initial Slide, not `opt.y` (ISSUE #43, ISSUE #47, ISSUE #48) if (typeof tableProps.autoPageSlideStartY === 'number') { emuSlideTabH = (tablePropH || presLayout.height) - inch2Emu(tableProps.autoPageSlideStartY + arrInchMargins[2]); } else if (typeof tableProps.newSlideStartY === 'number') { // @deprecated v3.3.0 emuSlideTabH = (tablePropH || presLayout.height) - inch2Emu(tableProps.newSlideStartY + arrInchMargins[2]); } else if (tablePropY) { emuSlideTabH = (tablePropH || presLayout.height) - inch2Emu((tablePropY / EMU < arrInchMargins[0] ? tablePropY / EMU : arrInchMargins[0]) + arrInchMargins[2]); // Use whichever is greater: area between margins or the table H provided (dont shrink usable area - the whole point of over-riding Y on paging is to *increase* usable space) if (emuSlideTabH < tablePropH) emuSlideTabH = tablePropH; } } } if (tableProps.verbose) { console.log('[[VERBOSE MODE]]'); console.log('|-- TABLE PROPS --------------------------------------------------------|'); console.log("| presLayout.width ................................ = ".concat((presLayout.width / EMU).toFixed(1))); console.log("| presLayout.height ............................... = ".concat((presLayout.height / EMU).toFixed(1))); console.log("| tableProps.x .................................... = ".concat(typeof tableProps.x === 'number' ? (tableProps.x / EMU).toFixed(1) : tableProps.x)); console.log("| tableProps.y .................................... = ".concat(typeof tableProps.y === 'number' ? (tableProps.y / EMU).toFixed(1) : tableProps.y)); console.log("| tableProps.w .................................... = ".concat(typeof tableProps.w === 'number' ? (tableProps.w / EMU).toFixed(1) : tableProps.w)); console.log("| tableProps.h .................................... = ".concat(typeof tableProps.h === 'number' ? (tableProps.h / EMU).toFixed(1) : tableProps.h)); console.log("| tableProps.slideMargin .......................... = ".concat(tableProps.slideMargin ? String(tableProps.slideMargin) : '')); console.log("| tableProps.margin ............................... = ".concat(String(tableProps.margin))); console.log("| tableProps.colW ................................. = ".concat(String(tableProps.colW))); console.log("| tableProps.autoPageSlideStartY .................. = ".concat(tableProps.autoPageSlideStartY)); console.log("| tableProps.autoPageCharWeight ................... = ".concat(tableProps.autoPageCharWeight)); console.log('|-- CALCULATIONS -------------------------------------------------------|'); console.log("| tablePropX ...................................... = ".concat(tablePropX / EMU)); console.log("| tablePropY ...................................... = ".concat(tablePropY / EMU)); console.log("| tablePropW ...................................... = ".concat(tablePropW / EMU)); console.log("| tablePropH ...................................... = ".concat(tablePropH / EMU)); console.log("| tableCalcW ...................................... = ".concat(tableCalcW / EMU)); } // STEP 1: Calculate margins { // Important: Use default size as zero cell margin is causing our tables to be too large and touch bottom of slide! if (!tableProps.slideMargin && tableProps.slideMargin !== 0) tableProps.slideMargin = DEF_SLIDE_MARGIN_IN[0]; if (masterSlide && typeof masterSlide._margin !== 'undefined') { if (Array.isArray(masterSlide._margin)) arrInchMargins = masterSlide._margin; else if (!isNaN(Number(masterSlide._margin))) { arrInchMargins = [Number(masterSlide._margin), Number(masterSlide._margin), Number(masterSlide._margin), Number(masterSlide._margin)]; } } else if (tableProps.slideMargin || tableProps.slideMargin === 0) { if (Array.isArray(tableProps.slideMargin)) arrInchMargins = tableProps.slideMargin; else if (!isNaN(tableProps.slideMargin)) arrInchMargins = [tableProps.slideMargin, tableProps.slideMargin, tableProps.slideMargin, tableProps.slideMargin]; } if (tableProps.verbose) console.log("| arrInchMargins .................................. = [".concat(arrInchMargins.join(', '), "]")); } // STEP 2: Calculate number of columns { // NOTE: Cells may have a colspan, so merely taking the length of the [0] (or any other) row is not // ....: sufficient to determine column count. Therefore, check each cell for a colspan and total cols as reqd var firstRow = tableRows[0] || []; firstRow.forEach(function (cell) { if (!cell) cell = { _type: SLIDE_OBJECT_TYPES.tablecell }; var cellOpts = cell.options || null; numCols += Number((cellOpts === null || cellOpts === void 0 ? void 0 : cellOpts.colspan) ? cellOpts.colspan : 1); }); if (tableProps.verbose) console.log("| numCols ......................................... = ".concat(numCols)); } // STEP 3: Calculate width using tableProps.colW if possible if (!tablePropW && tableProps.colW) { tableCalcW = Array.isArray(tableProps.colW) ? tableProps.colW.reduce(function (p, n) { return p + n; }) * EMU : tableProps.colW * numCols || 0; if (tableProps.verbose) console.log("| tableCalcW ...................................... = ".concat(tableCalcW / EMU)); } // STEP 4: Calculate usable width now that total usable space is known (`emuSlideTabW`) { emuSlideTabW = tableCalcW || inch2Emu((tablePropX ? tablePropX / EMU : arrInchMargins[1]) + arrInchMargins[3]); if (tableProps.verbose) console.log("| emuSlideTabW .................................... = ".concat((emuSlideTabW / EMU).toFixed(1))); } // STEP 5: Calculate column widths if not provided (emuSlideTabW will be used below to determine lines-per-col) if (!tableProps.colW || !Array.isArray(tableProps.colW)) { if (tableProps.colW && !isNaN(Number(tableProps.colW))) { var arrColW_1 = []; var firstRow = tableRows[0] || []; firstRow.forEach(function () { return arrColW_1.push(tableProps.colW); }); tableProps.colW = []; arrColW_1.forEach(function (val) { if (Array.isArray(tableProps.colW)) tableProps.colW.push(val); }); } else { // No column widths provided? Then distribute cols. tableProps.colW = []; for (var iCol = 0; iCol < numCols; iCol++) { tableProps.colW.push(emuSlideTabW / EMU / numCols); } } } // STEP 6: **MAIN** Iterate over rows, add table content, create new slides as rows overflow var newTableRowSlide = { rows: [] }; tableRows.forEach(function (row, iRow) { // A: Row variables var rowCellLines = []; var maxCellMarTopEmu = 0; var maxCellMarBtmEmu = 0; // B: Create new row in data model, calc `maxCellMar*` var currTableRow = []; row.forEach(function (cell) { var _a, _b, _c, _d; currTableRow.push({ _type: SLIDE_OBJECT_TYPES.tablecell, text: [], options: cell.options, }); /** FUTURE: DEPRECATED: * - Backwards-Compat: Oops! Discovered we were still using points for cell margin before v3.8.0 (UGH!) * - We cant introduce a breaking change before v4.0, so... */ if (cell.options.margin && cell.options.margin[0] >= 1) { if (((_a = cell.options) === null || _a === void 0 ? void 0 : _a.margin) && cell.options.margin[0] && valToPts(cell.options.margin[0]) > maxCellMarTopEmu) maxCellMarTopEmu = valToPts(cell.options.margin[0]); else if ((tableProps === null || tableProps === void 0 ? void 0 : tableProps.margin) && tableProps.margin[0] && valToPts(tableProps.margin[0]) > maxCellMarTopEmu) maxCellMarTopEmu = valToPts(tableProps.margin[0]); if (((_b = cell.options) === null || _b === void 0 ? void 0 : _b.margin) && cell.options.margin[2] && valToPts(cell.options.margin[2]) > maxCellMarBtmEmu) maxCellMarBtmEmu = valToPts(cell.options.margin[2]); else if ((tableProps === null || tableProps === void 0 ? void 0 : tableProps.margin) && tableProps.margin[2] && valToPts(tableProps.margin[2]) > maxCellMarBtmEmu) maxCellMarBtmEmu = valToPts(tableProps.margin[2]); } else { if (((_c = cell.options) === null || _c === void 0 ? void 0 : _c.margin) && cell.options.margin[0] && inch2Emu(cell.options.margin[0]) > maxCellMarTopEmu) maxCellMarTopEmu = inch2Emu(cell.options.margin[0]); else if ((tableProps === null || tableProps === void 0 ? void 0 : tableProps.margin) && tableProps.margin[0] && inch2Emu(tableProps.margin[0]) > maxCellMarTopEmu) maxCellMarTopEmu = inch2Emu(tableProps.margin[0]); if (((_d = cell.options) === null || _d === void 0 ? void 0 : _d.margin) && cell.options.margin[2] && inch2Emu(cell.options.margin[2]) > maxCellMarBtmEmu) maxCellMarBtmEmu = inch2Emu(cell.options.margin[2]); else if ((tableProps === null || tableProps === void 0 ? void 0 : tableProps.margin) && tableProps.margin[2] && inch2Emu(tableProps.margin[2]) > maxCellMarBtmEmu) maxCellMarBtmEmu = inch2Emu(tableProps.margin[2]); } }); // C: Calc usable vertical space/table height. Set default value first, adjust below when necessary. calcSlideTabH(); emuTabCurrH += maxCellMarTopEmu + maxCellMarBtmEmu; // Start row height with margins if (tableProps.verbose && iRow === 0) console.log("| SLIDE [".concat(tableRowSlides.length, "]: emuSlideTabH ...... = ").concat((emuSlideTabH / EMU).toFixed(1), " ")); // D: --==[[ BUILD DATA SET ]]==-- (iterate over cells: split text into lines[], set `lineHeight`) row.forEach(function (cell, iCell) { var _a; var newCell = { _type: SLIDE_OBJECT_TYPES.tablecell, _lines: null, _lineHeight: inch2Emu(((((_a = cell.options) === null || _a === void 0 ? void 0 : _a.fontSize) ? cell.options.fontSize : tableProps.fontSize ? tableProps.fontSize : DEF_FONT_SIZE) * (LINEH_MODIFIER + (tableProps.autoPageLineWeight ? tableProps.autoPageLineWeight : 0))) / 100), text: [], options: cell.options, }; // E-1: Exempt cells with `rowspan` from increasing lineHeight (or we could create a new slide when unecessary!) if (newCell.options.rowspan) newCell._lineHeight = 0; // E-2: The parseTextToLines method uses `autoPageCharWeight`, so inherit from table options newCell.options.autoPageCharWeight = tableProps.autoPageCharWeight ? tableProps.autoPageCharWeight : null; // E-3: **MAIN** Parse cell contents into lines based upon col width, font, etc var totalColW = tableProps.colW[iCell]; if (cell.options.colspan && Array.isArray(tableProps.colW)) { totalColW = tableProps.colW.filter(function (_cell, idx) { return idx >= iCell && idx < idx + cell.options.colspan; }).reduce(function (prev, curr) { return prev + curr; }); } // E-4: Create lines based upon available column width newCell._lines = parseTextToLines(cell, totalColW, false); // E-5: Add cell to array rowCellLines.push(newCell); }); /** E: --==[[ PAGE DATA SET ]]==-- * Add text one-line-a-time to this row's cells until: lines are exhausted OR table height limit is hit * * Design: * - Building cells L-to-R/loop style wont work as one could be 100 lines and another 1 line * - Therefore, build the whole row, one-line-at-a-time, across each table columns * - Then, when the vertical size limit is hit is by any of the cells, make a new slide and continue adding any remaining lines * * Implementation: * - `rowCellLines` is an array of cells, one for each column in the table, with each cell containing an array of lines * * Sample Data: * - `rowCellLines` ..: [ TableCell, TableCell, TableCell ] * - `TableCell` .....: { _type: 'tablecell', _lines: TableCell[], _lineHeight: 10 } * - `_lines` ........: [ {_type: 'tablecell', text: 'cell-1,line-1', options: {…}}, {_type: 'tablecell', text: 'cell-1,line-2', options: {…}} } * - `_lines` is TableCell[] (the 1-N words in the line) * { * _lines: [{ text:'cell-1,line-1' }, { text:'cell-1,line-2' }], // TOTAL-CELL-HEIGHT = 2 * _lines: [{ text:'cell-2,line-1' }, { text:'cell-2,line-2' }], // TOTAL-CELL-HEIGHT = 2 * _lines: [{ text:'cell-3,line-1' }, { text:'cell-3,line-2' }, { text:'cell-3,line-3' }, { text:'cell-3,line-4' }], // TOTAL-CELL-HEIGHT = 4 * } * * Example: 2 rows, with the firstrow overflowing onto a new slide * SLIDE 1: * |--------|--------|--------|--------| * | line-1 | line-1 | line-1 | line-1 | * | | | line-2 | | * | | | line-3 | | * |--------|--------|--------|--------| * * SLIDE 2: * |--------|--------|--------|--------| * | | | line-4 | | * |--------|--------|--------|--------| * | line-1 | line-1 | line-1 | line-1 | * |--------|--------|--------|--------| */ if (tableProps.verbose) console.log("\n| SLIDE [".concat(tableRowSlides.length, "]: ROW [").concat(iRow, "]: START...")); var currCellIdx = 0; var emuLineMaxH = 0; var isDone = false; while (!isDone) { var srcCell = rowCellLines[currCellIdx]; var tgtCell = currTableRow[currCellIdx]; // NOTE: may be redefined below (a new row may be created, thus changing this value) // 1: calc emuLineMaxH rowCellLines.forEach(function (cell) { if (cell._lineHeight >= emuLineMaxH) emuLineMaxH = cell._lineHeight; }); // 2: create a new slide if there is insufficient room for the current row if (emuTabCurrH + emuLineMaxH > emuSlideTabH) { if (tableProps.verbose) { console.log('\n|-----------------------------------------------------------------------|'); // prettier-ignore console.log("|-- NEW SLIDE CREATED (currTabH+currLineH > maxH) => ".concat((emuTabCurrH / EMU).toFixed(2), " + ").concat((srcCell._lineHeight / EMU).toFixed(2), " > ").concat(emuSlideTabH / EMU)); console.log('|-----------------------------------------------------------------------|\n\n'); } // A: add current row slide or it will be lost (only if it has rows and text) if (currTableRow.length > 0 && currTableRow.map(function (cell) { return cell.text.length; }).reduce(function (p, n) { return p + n; }) > 0) newTableRowSlide.rows.push(currTableRow); // B: add current slide to Slides array tableRowSlides.push(newTableRowSlide); // C: reset working/curr slide to hold rows as they're created var newRows = []; newTableRowSlide = { rows: newRows }; // D: reset working/curr row currTableRow = []; row.forEach(function (cell) { return currTableRow.push({ _type: SLIDE_OBJECT_TYPES.tablecell, text: [], options: cell.options }); }); // E: Calc usable vertical space/table height now as we may still be in the same row and code above ("C: Calc usable vertical space/table height.") calc may now be invalid calcSlideTabH(); emuTabCurrH += maxCellMarTopEmu + maxCellMarBtmEmu; // Start row height with margins if (tableProps.verbose) console.log("| SLIDE [".concat(tableRowSlides.length, "]: emuSlideTabH ...... = ").concat((emuSlideTabH / EMU).toFixed(1), " ")); // F: reset current table height for this new Slide emuTabCurrH = 0; // G: handle repeat headers option /or/ Add new empty row to continue current lines into if ((tableProps.addHeaderToEach || tableProps.autoPageRepeatHeader) && tableProps._arrObjTabHeadRows) { tableProps._arrObjTabHeadRows.forEach(function (row) { var newHeadRow = []; var maxLineHeight = 0; row.forEach(function (cell) { newHeadRow.push(cell); if (cell._lineHeight > maxLineHeight) maxLineHeight = cell._lineHeight; }); newTableRowSlide.rows.push(newHeadRow); emuTabCurrH += maxLineHeight; // TODO: what about margins? dont we need to include cell margin in line height? }); } // WIP: NEW: TEST THIS!! tgtCell = currTableRow[currCellIdx]; } // 3: set array of words that comprise this line var currLine = srcCell._lines.shift(); // 4: create new line by adding all words from curr line (or add empty if there are no words to avoid "needs repair" issue triggered when cells have null content) if (Array.isArray(tgtCell.text)) { if (currLine) tgtCell.text = tgtCell.text.concat(currLine); else if (tgtCell.text.length === 0) tgtCell.text = tgtCell.text.concat({ _type: SLIDE_OBJECT_TYPES.tablecell, text: '' }); // IMPORTANT: ^^^ add empty if there are no words to avoid "needs repair" issue triggered when cells have null content } // 5: increase table height by the curr line height (if we're on the last column) if (currCellIdx === rowCellLines.length - 1) emuTabCurrH += emuLineMaxH; // 6: advance column/cell index (or circle back to first one to continue adding lines) currCellIdx = currCellIdx < rowCellLines.length - 1 ? currCellIdx + 1 : 0; // 7: done? var brent = rowCellLines.map(function (cell) { return cell._lines.length; }).reduce(function (prev, next) { return prev + next; }); if (brent === 0) isDone = true; } // F: Flush/capture row buffer before it resets at the top of this loop if (currTableRow.length > 0) newTableRowSlide.rows.push(currTableRow); if (tableProps.verbose) { console.log("- SLIDE [".concat(tableRowSlides.length, "]: ROW [").concat(iRow, "]: ...COMPLETE ...... emuTabCurrH = ").concat((emuTabCurrH / EMU).toFixed(2), " ( emuSlideTabH = ").concat((emuSlideTabH / EMU).toFixed(2), " )")); } }); // STEP 7: Flush buffer / add final slide tableRowSlides.push(newTableRowSlide); if (tableProps.verbose) { console.log('\n|================================================|'); console.log("| FINAL: tableRowSlides.length = ".concat(tableRowSlides.length)); tableRowSlides.forEach(function (slide) { return console.log(slide); }); console.log('|================================================|\n\n'); } // LAST: return tableRowSlides; } /** * Reproduces an HTML table as a PowerPoint table - including column widths, style, etc. - creates 1 or more slides as needed * @param {PptxGenJS} pptx - pptxgenjs instance * @param {string} tabEleId - HTMLElementID of the table * @param {ITableToSlidesOpts} options - array of options (e.g.: tabsize) * @param {SlideLayout} masterSlide - masterSlide */ function genTableToSlides(pptx, tabEleId, options, masterSlide) { if (options === void 0) { options = {}; } var opts = options || {}; opts.slideMargin = opts.slideMargin || opts.slideMargin === 0 ? opts.slideMargin : 0.5; var emuSlideTabW = opts.w || pptx.presLayout.width; var arrObjTabHeadRows = []; var arrObjTabBodyRows = []; var arrObjTabFootRows = []; var arrColW = []; var arrTabColW = []; var arrInchMargins = [0.5, 0.5, 0.5, 0.5]; // TRBL-style var intTabW = 0; // REALITY-CHECK: if (!document.getElementById(tabEleId)) throw new Error('tableToSlides: Table ID "' + tabEleId + '" does not exist!'); // STEP 1: Set margins if (masterSlide === null || masterSlide === void 0 ? void 0 : masterSlide._margin) { if (Array.isArray(masterSlide._margin)) arrInchMargins = masterSlide._margin; else if (!isNaN(masterSlide._margin)) arrInchMargins = [masterSlide._margin, masterSlide._margin, masterSlide._margin, masterSlide._margin]; opts.slideMargin = arrInchMargins; } else if (opts === null || opts === void 0 ? void 0 : opts.slideMargin) { if (Array.isArray(opts.slideMargin)) arrInchMargins = opts.slideMargin; else if (!isNaN(opts.slideMargin)) arrInchMargins = [opts.slideMargin, opts.slideMargin, opts.slideMargin, opts.slideMargin]; } emuSlideTabW = (opts.w ? inch2Emu(opts.w) : pptx.presLayout.width) - inch2Emu(arrInchMargins[1] + arrInchMargins[3]); if (opts.verbose) { console.log('[[VERBOSE MODE]]'); console.log('|-- `tableToSlides` ----------------------------------------------------|'); console.log("| tableProps.h .................................... = ".concat(opts.h)); console.log("| tableProps.w .................................... = ".concat(opts.w)); console.log("| pptx.presLayout.width ........................... = ".concat((pptx.presLayout.width / EMU).toFixed(1))); console.log("| pptx.presLayout.height .......................... = ".concat((pptx.presLayout.height / EMU).toFixed(1))); console.log("| emuSlideTabW .................................... = ".concat((emuSlideTabW / EMU).toFixed(1))); } // STEP 2: Grab table col widths - just find the first availble row, either thead/tbody/tfoot, others may have colspans, who cares, we only need col widths from 1 var firstRowCells = document.querySelectorAll("#".concat(tabEleId, " tr:first-child th")); if (firstRowCells.length === 0) firstRowCells = document.querySelectorAll("#".concat(tabEleId, " tr:first-child td")); firstRowCells.forEach(function (cell) { if (cell.getAttribute('colspan')) { // Guesstimate (divide evenly) col widths // NOTE: both j$query and vanilla selectors return {0} when table is not visible) for (var idxc = 0; idxc < Number(cell.getAttribute('colspan')); idxc++) { arrTabColW.push(Math.round(cell.offsetWidth / Number(cell.getAttribute('colspan')))); } } else { arrTabColW.push(cell.offsetWidth); } }); arrTabColW.forEach(function (colW) { intTabW += colW; }); // STEP 3: Calc/Set column widths by using same column width percent from HTML table arrTabColW.forEach(function (colW, idxW) { var intCalcWidth = Number(((Number(emuSlideTabW) * ((colW / intTabW) * 100)) / 100 / EMU).toFixed(2)); var intMinWidth = 0; var colSelectorMin = document.querySelector("#".concat(tabEleId, " thead tr:first-child th:nth-child(").concat(idxW + 1, ")")); if (colSelectorMin) intMinWidth = Number(colSelectorMin.getAttribute('data-pptx-min-width')); var colSelectorSet = document.querySelector("#".concat(tabEleId, " thead tr:first-child th:nth-child(").concat(idxW + 1, ")")); if (colSelectorSet) intMinWidth = Number(colSelectorSet.getAttribute('data-pptx-width')); arrColW.push((intMinWidth > intCalcWidth ? intMinWidth : intCalcWidth)); }); if (opts.verbose) { console.log("| arrColW ......................................... = [".concat(arrColW.join(', '), "]")); } // STEP 4: Iterate over each table element and create data arrays (text and opts) // NOTE: We create 3 arrays instead of one so we can loop over body then show header/footer rows on first and last page var tableParts = ['thead', 'tbody', 'tfoot']; tableParts.forEach(function (part) { document.querySelectorAll("#".concat(tabEleId, " ").concat(part, " tr")).forEach(function (row) { var arrObjTabCells = []; Array.from(row.cells).forEach(function (cell) { // A: Get RGB text/bkgd colors var arrRGB1 = window.getComputedStyle(cell).getPropertyValue('color').replace(/\s+/gi, '').replace('rgba(', '').replace('rgb(', '').replace(')', '').split(','); var arrRGB2 = window .getComputedStyle(cell) .getPropertyValue('background-color') .replace(/\s+/gi, '') .replace('rgba(', '') .replace('rgb(', '') .replace(')', '') .split(','); if ( // NOTE: (ISSUE#57): Default for unstyled tables is black bkgd, so use white instead window.getComputedStyle(cell).getPropertyValue('background-color') === 'rgba(0, 0, 0, 0)' || window.getComputedStyle(cell).getPropertyValue('transparent')) { arrRGB2 = ['255', '255', '255']; } // B: Create option object var cellOpts = { align: null, bold: !!(window.getComputedStyle(cell).getPropertyValue('font-weight') === 'bold' || Number(window.getComputedStyle(cell).getPropertyValue('font-weight')) >= 500), border: null, color: rgbToHex(Number(arrRGB1[0]), Number(arrRGB1[1]), Number(arrRGB1[2])), fill: { color: rgbToHex(Number(arrRGB2[0]), Number(arrRGB2[1]), Number(arrRGB2[2])) }, fontFace: (window.getComputedStyle(cell).getPropertyValue('font-family') || '').split(',')[0].replace(/"/g, '').replace('inherit', '').replace('initial', '') || null, fontSize: Number(window.getComputedStyle(cell).getPropertyValue('font-size').replace(/[a-z]/gi, '')), margin: null, colspan: Number(cell.getAttribute('colspan')) || null, rowspan: Number(cell.getAttribute('rowspan')) || null, valign: null, }; if (['left', 'center', 'right', 'start', 'end'].includes(window.getComputedStyle(cell).getPropertyValue('text-align'))) { var align = window.getComputedStyle(cell).getPropertyValue('text-align').replace('start', 'left').replace('end', 'right'); cellOpts.align = align === 'center' ? 'center' : align === 'left' ? 'left' : align === 'right' ? 'right' : null; } if (['top', 'middle', 'bottom'].includes(window.getComputedStyle(cell).getPropertyValue('vertical-align'))) { var valign = window.getComputedStyle(cell).getPropertyValue('vertical-align'); cellOpts.valign = valign === 'top' ? 'top' : valign === 'middle' ? 'middle' : valign === 'bottom' ? 'bottom' : null; } // C: Add padding [margin] (if any) // NOTE: Margins translate: px->pt 1:1 (e.g.: a 20px padded cell looks the same in PPTX as 20pt Text Inset/Padding) if (window.getComputedStyle(cell).getPropertyValue('padding-left')) { cellOpts.margin = [0, 0, 0, 0]; var sidesPad = ['padding-top', 'padding-right', 'padding-bottom', 'padding-left']; sidesPad.forEach(function (val, idxs) { cellOpts.margin[idxs] = Math.round(Number(window.getComputedStyle(cell).getPropertyValue(val).replace(/\D/gi, ''))); }); } // D: Add border (if any) if (window.getComputedStyle(cell).getPropertyValue('border-top-width') || window.getComputedStyle(cell).getPropertyValue('border-right-width') || window.getComputedStyle(cell).getPropertyValue('border-bottom-width') || window.getComputedStyle(cell).getPropertyValue('border-left-width')) { cellOpts.border = [null, null, null, null]; var sidesBor = ['top', 'right', 'bottom', 'left']; sidesBor.forEach(function (val, idxb) { var intBorderW = Math.round(Number(window .getComputedStyle(cell) .getPropertyValue('border-' + val + '-width') .replace('px', ''))); var arrRGB = []; arrRGB = window .getComputedStyle(cell) .getPropertyValue('border-' + val + '-color') .replace(/\s+/gi, '') .replace('rgba(', '') .replace('rgb(', '') .replace(')', '') .split(','); var strBorderC = rgbToHex(Number(arrRGB[0]), Number(arrRGB[1]), Number(arrRGB[2])); cellOpts.border[idxb] = { pt: intBorderW, color: strBorderC }; }); } // LAST: Add cell arrObjTabCells.push({ _type: SLIDE_OBJECT_TYPES.tablecell, text: cell.innerText, options: cellOpts, }); }); switch (part) { case 'thead': arrObjTabHeadRows.push(arrObjTabCells); break; case 'tbody': arrObjTabBodyRows.push(arrObjTabCells); break; case 'tfoot': arrObjTabFootRows.push(arrObjTabCells); break; default: console.log("table parsing: unexpected table part: ".concat(part)); break; } }); }); // STEP 5: Break table into Slides as needed // Pass head-rows as there is an option to add to each table and the parse func needs this data to fulfill that option opts._arrObjTabHeadRows = arrObjTabHeadRows || null; opts.colW = arrColW; getSlidesForTableRows(__spreadArray(__spreadArray(__spreadArray([], arrObjTabHeadRows, true), arrObjTabBodyRows, true), arrObjTabFootRows, true), opts, pptx.presLayout, masterSlide).forEach(function (slide, idxTr) { // A: Create new Slide var newSlide = pptx.addSlide({ masterName: opts.masterSlideName || null }); // B: DESIGN: Reset `y` to startY or margin after first Slide (ISSUE#43, ISSUE#47, ISSUE#48) if (idxTr === 0) opts.y = opts.y || arrInchMargins[0]; if (idxTr > 0) opts.y = opts.autoPageSlideStartY || opts.newSlideStartY || arrInchMargins[0]; if (opts.verbose) console.log("| opts.autoPageSlideStartY: ".concat(opts.autoPageSlideStartY, " / arrInchMargins[0]: ").concat(arrInchMargins[0], " => opts.y = ").concat(opts.y)); // C: Add table to Slide newSlide.addTable(slide.rows, { x: opts.x || arrInchMargins[3], y: opts.y, w: Number(emuSlideTabW) / EMU, colW: arrColW, autoPage: false }); // D: Add any additional objects if (opts.addImage) { opts.addImage.options = opts.addImage.options || {}; if (!opts.addImage.image || (!opts.addImage.image.path && !opts.addImage.image.data)) { console.warn('Warning: tableToSlides.addImage requires either `path` or `data`'); } else { newSlide.addImage({ path: opts.addImage.image.path, data: opts.addImage.image.data, x: opts.addImage.options.x, y: opts.addImage.options.y, w: opts.addImage.options.w, h: opts.addImage.options.h, }); } } if (opts.addShape) newSlide.addShape(opts.addShape.shapeName, opts.addShape.options || {}); if (opts.addTable) newSlide.addTable(opts.addTable.rows, opts.addTable.options || {}); if (opts.addText) newSlide.addText(opts.addText.text, opts.addText.options || {}); }); } /** * PptxGenJS: Slide Object Generators */ /** counter for included charts (used for index in their filenames) */ var _chartCounter = 0; /** * Transforms a slide definition to a slide object that is then passed to the XML transformation process. * @param {SlideMasterProps} props - slide definition * @param {PresSlide|SlideLayout} target - empty slide object that should be updated by the passed definition */ function createSlideMaster(props, target) { // STEP 1: Add background if either the slide or layout has background props // if (props.background || target.background) addBackgroundDefinition(props.background, target) if (props.bkgd) target.bkgd = props.bkgd; // DEPRECATED: (remove in v4.0.0) // STEP 2: Add all Slide Master objects in the order they were given if (props.objects && Array.isArray(props.objects) && props.objects.length > 0) { props.objects.forEach(function (object, idx) { var key = Object.keys(object)[0]; var tgt = target; if (MASTER_OBJECTS[key] && key === 'chart') addChartDefinition(tgt, object[key].type, object[key].data, object[key].opts); else if (MASTER_OBJECTS[key] && key === 'image') addImageDefinition(tgt, object[key]); else if (MASTER_OBJECTS[key] && key === 'line') addShapeDefinition(tgt, SHAPE_TYPE.LINE, object[key]); else if (MASTER_OBJECTS[key] && key === 'rect') addShapeDefinition(tgt, SHAPE_TYPE.RECTANGLE, object[key]); else if (MASTER_OBJECTS[key] && key === 'text') addTextDefinition(tgt, [{ text: object[key].text }], object[key].options, false); else if (MASTER_OBJECTS[key] && key === 'placeholder') { // TODO: 20180820: Check for existing `name`? object[key].options.placeholder = object[key].options.name; delete object[key].options.name; // remap name for earier handling internally object[key].options._placeholderType = object[key].options.type; delete object[key].options.type; // remap name for earier handling internally object[key].options._placeholderIdx = 100 + idx; addTextDefinition(tgt, [{ text: object[key].text }], object[key].options, true); // TODO: ISSUE#599 - only text is suported now (add more below) // else if (object[key].image) addImageDefinition(tgt, object[key].image) /* 20200120: So... image placeholders go into the "slideLayoutN.xml" file and addImage doesnt do this yet... */ } }); } // STEP 3: Add Slide Numbers (NOTE: Do this last so numbers are not covered by objects!) if (props.slideNumber && typeof props.slideNumber === 'object') target._slideNumberProps = props.slideNumber; } /** * Generate the chart based on input data. * OOXML Chart Spec: ISO/IEC 29500-1:2016(E) * * @param {CHART_NAME | IChartMulti[]} `type` should belong to: 'column', 'pie' * @param {[]} `data` a JSON object with follow the following format * @param {IChartOptsLib} `opt` chart options * @param {PresSlide} `target` slide object that the chart will be added to * @return {object} chart object * { * title: 'eSurvey chart', * data: [ * { * name: 'Income', * labels: ['2005', '2006', '2007', '2008', '2009'], * values: [23.5, 26.2, 30.1, 29.5, 24.6] * }, * { * name: 'Expense', * labels: ['2005', '2006', '2007', '2008', '2009'], * values: [18.1, 22.8, 23.9, 25.1, 25] * } * ] * } */ function addChartDefinition(target, type, data, opt) { var _a; function correctGridLineOptions(glOpts) { if (!glOpts || glOpts.style === 'none') return; if (glOpts.size !== undefined && (isNaN(Number(glOpts.size)) || glOpts.size <= 0)) { console.warn('Warning: chart.gridLine.size must be greater than 0.'); delete glOpts.size; // delete prop to used defaults } if (glOpts.style && !['solid', 'dash', 'dot'].includes(glOpts.style)) { console.warn('Warning: chart.gridLine.style options: `solid`, `dash`, `dot`.'); delete glOpts.style; } if (glOpts.cap && !['flat', 'square', 'round'].includes(glOpts.cap)) { console.warn('Warning: chart.gridLine.cap options: `flat`, `square`, `round`.'); delete glOpts.cap; } } var chartId = ++_chartCounter; var resultObject = { _type: null, text: null, options: null, chartRid: null, }; // DESIGN: `type` can an object (ex: `pptx.charts.DOUGHNUT`) or an array of chart objects // EX: addChartDefinition([ { type:pptx.charts.BAR, data:{name:'', labels:[], values[]} }, {} ]) // Multi-Type Charts var tmpOpt = null; var tmpData = []; if (Array.isArray(type)) { // For multi-type charts there needs to be data for each type, // as well as a single data source for non-series operations. // The data is indexed below to keep the data in order when segmented // into types. type.forEach(function (obj) { tmpData = tmpData.concat(obj.data); }); tmpOpt = data || opt; } else { tmpData = data; tmpOpt = opt; } tmpData.forEach(function (item, i) { item._dataIndex = i; // Converts the 'labels' array from string[] to string[][] (or the respective primitive type), if needed if (item.labels !== undefined && !Array.isArray(item.labels[0])) { item.labels = [item.labels]; } }); var options = tmpOpt && typeof tmpOpt === 'object' ? tmpOpt : {}; // STEP 1: TODO: check for reqd fields, correct type, etc // `type` exists in CHART_TYPE // Array.isArray(data) /* if ( Array.isArray(rel.data) && rel.data.length > 0 && typeof rel.data[0] === 'object' && rel.data[0].labels && Array.isArray(rel.data[0].labels) && rel.data[0].values && Array.isArray(rel.data[0].values) ) { obj = rel.data[0]; } else { console.warn("USAGE: addChart( 'pie', [ {name:'Sales', labels:['Jan','Feb'], values:[10,20]} ], {x:1, y:1} )"); return; } */ // STEP 2: Set default options/decode user options // A: Core options._type = type; options.x = typeof options.x !== 'undefined' && options.x != null && !isNaN(Number(options.x)) ? options.x : 1; options.y = typeof options.y !== 'undefined' && options.y != null && !isNaN(Number(options.y)) ? options.y : 1; options.w = options.w || '50%'; options.h = options.h || '50%'; options.objectName = options.objectName ? encodeXmlEntities(options.objectName) : "Chart ".concat(target._slideObjects.filter(function (obj) { return obj._type === SLIDE_OBJECT_TYPES.chart; }).length); // B: Options: misc if (!['bar', 'col'].includes(options.barDir || '')) options.barDir = 'col'; // barGrouping: "21.2.3.17 ST_Grouping (Grouping)" // barGrouping must be handled before data label validation as it can affect valid label positioning if (options._type === CHART_TYPE.AREA) { if (!['stacked', 'standard', 'percentStacked'].includes(options.barGrouping || '')) options.barGrouping = 'standard'; } if (options._type === CHART_TYPE.BAR) { if (!['clustered', 'stacked', 'percentStacked'].includes(options.barGrouping || '')) options.barGrouping = 'clustered'; } if (options._type === CHART_TYPE.BAR3D) { if (!['clustered', 'stacked', 'standard', 'percentStacked'].includes(options.barGrouping || '')) options.barGrouping = 'standard'; } if ((_a = options.barGrouping) === null || _a === void 0 ? void 0 : _a.includes('tacked')) { if (!options.barGapWidthPct) options.barGapWidthPct = 50; } // Clean up and validate data label positions // REFERENCE: https://docs.microsoft.com/en-us/openspecs/office_standards/ms-oi29500/e2b1697c-7adc-463d-9081-3daef72f656f?redirectedfrom=MSDN if (options.dataLabelPosition) { if (options._type === CHART_TYPE.AREA || options._type === CHART_TYPE.BAR3D || options._type === CHART_TYPE.DOUGHNUT || options._type === CHART_TYPE.RADAR) { delete options.dataLabelPosition; } if (options._type === CHART_TYPE.PIE) { if (!['bestFit', 'ctr', 'inEnd', 'outEnd'].includes(options.dataLabelPosition)) delete options.dataLabelPosition; } if (options._type === CHART_TYPE.BUBBLE || options._type === CHART_TYPE.BUBBLE3D || options._type === CHART_TYPE.LINE || options._type === CHART_TYPE.SCATTER) { if (!['b', 'ctr', 'l', 'r', 't'].includes(options.dataLabelPosition)) delete options.dataLabelPosition; } if (options._type === CHART_TYPE.BAR) { if (!['stacked', 'percentStacked'].includes(options.barGrouping || '')) { if (!['ctr', 'inBase', 'inEnd'].includes(options.dataLabelPosition)) delete options.dataLabelPosition; } if (!['clustered'].includes(options.barGrouping || '')) { if (!['ctr', 'inBase', 'inEnd', 'outEnd'].includes(options.dataLabelPosition)) delete options.dataLabelPosition; } } } options.dataLabelBkgrdColors = options.dataLabelBkgrdColors || !options.dataLabelBkgrdColors ? options.dataLabelBkgrdColors : false; if (!['b', 'l', 'r', 't', 'tr'].includes(options.legendPos || '')) options.legendPos = 'r'; // 3D bar: ST_Shape if (!['cone', 'coneToMax', 'box', 'cylinder', 'pyramid', 'pyramidToMax'].includes(options.bar3DShape || '')) options.bar3DShape = 'box'; // lineDataSymbol: http://www.datypic.com/sc/ooxml/a-val-32.html // Spec has [plus,star,x] however neither PPT2013 nor PPT-Online support them if (!['circle', 'dash', 'diamond', 'dot', 'none', 'square', 'triangle'].includes(options.lineDataSymbol || '')) options.lineDataSymbol = 'circle'; if (!['gap', 'span'].includes(options.displayBlanksAs || '')) options.displayBlanksAs = 'span'; if (!['standard', 'marker', 'filled'].includes(options.radarStyle || '')) options.radarStyle = 'standard'; options.lineDataSymbolSize = options.lineDataSymbolSize && !isNaN(options.lineDataSymbolSize) ? options.lineDataSymbolSize : 6; options.lineDataSymbolLineSize = options.lineDataSymbolLineSize && !isNaN(options.lineDataSymbolLineSize) ? valToPts(options.lineDataSymbolLineSize) : valToPts(0.75); // `layout` allows the override of PPT defaults to maximize space if (options.layout) { ['x', 'y', 'w', 'h'].forEach(function (key) { var val = options.layout[key]; if (isNaN(Number(val)) || val < 0 || val > 1) { console.warn('Warning: chart.layout.' + key + ' can only be 0-1'); // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete options.layout[key]; // remove invalid value so that default will be used } }); } // Set gridline defaults options.catGridLine = options.catGridLine || (options._type === CHART_TYPE.SCATTER ? { color: 'D9D9D9', size: 1 } : { style: 'none' }); options.valGridLine = options.valGridLine || (options._type === CHART_TYPE.SCATTER ? { color: 'D9D9D9', size: 1 } : {}); options.serGridLine = options.serGridLine || (options._type === CHART_TYPE.SCATTER ? { color: 'D9D9D9', size: 1 } : { style: 'none' }); correctGridLineOptions(options.catGridLine); correctGridLineOptions(options.valGridLine); correctGridLineOptions(options.serGridLine); correctShadowOptions(options.shadow); // C: Options: plotArea options.showDataTable = options.showDataTable || !options.showDataTable ? options.showDataTable : false; options.showDataTableHorzBorder = options.showDataTableHorzBorder || !options.showDataTableHorzBorder ? options.showDataTableHorzBorder : true; options.showDataTableVertBorder = options.showDataTableVertBorder || !options.showDataTableVertBorder ? options.showDataTableVertBorder : true; options.showDataTableOutline = options.showDataTableOutline || !options.showDataTableOutline ? options.showDataTableOutline : true; options.showDataTableKeys = options.showDataTableKeys || !options.showDataTableKeys ? options.showDataTableKeys : true; options.showLabel = options.showLabel || !options.showLabel ? options.showLabel : false; options.showLegend = options.showLegend || !options.showLegend ? options.showLegend : false; options.showPercent = options.showPercent || !options.showPercent ? options.showPercent : true; options.showTitle = options.showTitle || !options.showTitle ? options.showTitle : false; options.showValue = options.showValue || !options.showValue ? options.showValue : false; options.showLeaderLines = options.showLeaderLines || !options.showLeaderLines ? options.showLeaderLines : false; options.catAxisLineShow = typeof options.catAxisLineShow !== 'undefined' ? options.catAxisLineShow : true; options.valAxisLineShow = typeof options.valAxisLineShow !== 'undefined' ? options.valAxisLineShow : true; options.serAxisLineShow = typeof options.serAxisLineShow !== 'undefined' ? options.serAxisLineShow : true; options.v3DRotX = !isNaN(options.v3DRotX) && options.v3DRotX >= -90 && options.v3DRotX <= 90 ? options.v3DRotX : 30; options.v3DRotY = !isNaN(options.v3DRotY) && options.v3DRotY >= 0 && options.v3DRotY <= 360 ? options.v3DRotY : 30; options.v3DRAngAx = options.v3DRAngAx || !options.v3DRAngAx ? options.v3DRAngAx : true; options.v3DPerspective = !isNaN(options.v3DPerspective) && options.v3DPerspective >= 0 && options.v3DPerspective <= 240 ? options.v3DPerspective : 30; // D: Options: chart options.barGapWidthPct = !isNaN(options.barGapWidthPct) && options.barGapWidthPct >= 0 && options.barGapWidthPct <= 1000 ? options.barGapWidthPct : 150; options.barGapDepthPct = !isNaN(options.barGapDepthPct) && options.barGapDepthPct >= 0 && options.barGapDepthPct <= 1000 ? options.barGapDepthPct : 150; options.chartColors = Array.isArray(options.chartColors) ? options.chartColors : options._type === CHART_TYPE.PIE || options._type === CHART_TYPE.DOUGHNUT ? PIECHART_COLORS : BARCHART_COLORS; options.chartColorsOpacity = options.chartColorsOpacity && !isNaN(options.chartColorsOpacity) ? options.chartColorsOpacity : null; // DEPRECATED: v3.11.0 - use `plotArea.border` vvv options.border = options.border && typeof options.border === 'object' ? options.border : null; if (options.border && (!options.border.pt || isNaN(options.border.pt))) options.border.pt = DEF_CHART_BORDER.pt; if (options.border && (!options.border.color || typeof options.border.color !== 'string')) options.border.color = DEF_CHART_BORDER.color; // DEPRECATED: (remove above in v4.0) ^^^ options.plotArea = options.plotArea || {}; options.plotArea.border = options.plotArea.border && typeof options.plotArea.border === 'object' ? options.plotArea.border : null; if (options.plotArea.border && (!options.plotArea.border.pt || isNaN(options.plotArea.border.pt))) options.plotArea.border.pt = DEF_CHART_BORDER.pt; if (options.plotArea.border && (!options.plotArea.border.color || typeof options.plotArea.border.color !== 'string')) { options.plotArea.border.color = DEF_CHART_BORDER.color; } if (options.border) options.plotArea.border = options.border; // @deprecated [[remove in v4.0]] options.plotArea.fill = options.plotArea.fill || { color: null, transparency: null }; if (options.fill) options.plotArea.fill.color = options.fill; // @deprecated [[remove in v4.0]] // options.chartArea = options.chartArea || {}; options.chartArea.border = options.chartArea.border && typeof options.chartArea.border === 'object' ? options.chartArea.border : null; if (options.chartArea.border) { options.chartArea.border = { color: options.chartArea.border.color || DEF_CHART_BORDER.color, pt: options.chartArea.border.pt || DEF_CHART_BORDER.pt, }; } options.chartArea.roundedCorners = typeof options.chartArea.roundedCorners === 'boolean' ? options.chartArea.roundedCorners : true; // options.dataBorder = options.dataBorder && typeof options.dataBorder === 'object' ? options.dataBorder : null; if (options.dataBorder && (!options.dataBorder.pt || isNaN(options.dataBorder.pt))) options.dataBorder.pt = 0.75; if (options.dataBorder && (!options.dataBorder.color || typeof options.dataBorder.color !== 'string' || options.dataBorder.color.length !== 6)) { options.dataBorder.color = 'F9F9F9'; } // if (!options.dataLabelFormatCode && options._type === CHART_TYPE.SCATTER) options.dataLabelFormatCode = 'General'; if (!options.dataLabelFormatCode && (options._type === CHART_TYPE.PIE || options._type === CHART_TYPE.DOUGHNUT)) { options.dataLabelFormatCode = options.showPercent ? '0%' : 'General'; } options.dataLabelFormatCode = options.dataLabelFormatCode && typeof options.dataLabelFormatCode === 'string' ? options.dataLabelFormatCode : '#,##0'; // // Set default format for Scatter chart labels to custom string if not defined if (!options.dataLabelFormatScatter && options._type === CHART_TYPE.SCATTER) options.dataLabelFormatScatter = 'custom'; // options.lineSize = typeof options.lineSize === 'number' ? options.lineSize : 2; options.valAxisMajorUnit = typeof options.valAxisMajorUnit === 'number' ? options.valAxisMajorUnit : null; if (options._type === CHART_TYPE.AREA || options._type === CHART_TYPE.BAR || options._type === CHART_TYPE.BAR3D || options._type === CHART_TYPE.LINE) { options.catAxisMultiLevelLabels = !!options.catAxisMultiLevelLabels; } else { delete options.catAxisMultiLevelLabels; } // STEP 4: Set props resultObject._type = 'chart'; resultObject.options = options; resultObject.chartRid = getNewRelId(target); // STEP 5: Add this chart to this Slide Rels (rId/rels count spans all slides! Count all images to get next rId) target._relsChart.push({ rId: getNewRelId(target), data: tmpData, opts: options, type: options._type, globalId: chartId, fileName: "chart".concat(chartId, ".xml"), Target: "/ppt/charts/chart".concat(chartId, ".xml"), }); target._slideObjects.push(resultObject); return resultObject; } /** * Adds an image object to a slide definition. * This method can be called with only two args (opt, target) - this is supposed to be the only way in future. * @param {ImageProps} `opt` - object containing `path`/`data`, `x`, `y`, etc. * @param {PresSlide} `target` - slide that the image should be added to (if not specified as the 2nd arg) * @note: Remote images (eg: "http://whatev.com/blah"/from web and/or remote server arent supported yet - we'd need to create an , load it, then send to canvas * @see: https://stackoverflow.com/questions/164181/how-to-fetch-a-remote-image-to-display-in-a-canvas) */ function addImageDefinition(target, opt) { var newObject = { _type: null, text: null, options: null, image: null, imageRid: null, hyperlink: null, }; // FIRST: Set vars for this image (object param replaces positional args in 1.1.0) var intPosX = opt.x || 0; var intPosY = opt.y || 0; var intWidth = opt.w || 0; var intHeight = opt.h || 0; var sizing = opt.sizing || null; var objHyperlink = opt.hyperlink || ''; var strImageData = opt.data || ''; var strImagePath = opt.path || ''; var imageRelId = getNewRelId(target); var objectName = opt.objectName ? encodeXmlEntities(opt.objectName) : "Image ".concat(target._slideObjects.filter(function (obj) { return obj._type === SLIDE_OBJECT_TYPES.image; }).length); // REALITY-CHECK: if (!strImagePath && !strImageData) { console.error('ERROR: addImage() requires either \'data\' or \'path\' parameter!'); return null; } else if (strImagePath && typeof strImagePath !== 'string') { console.error("ERROR: addImage() 'path' should be a string, ex: {path:'/img/sample.png'} - you sent ".concat(String(strImagePath))); return null; } else if (strImageData && typeof strImageData !== 'string') { console.error("ERROR: addImage() 'data' should be a string, ex: {data:'image/png;base64,NMP[...]'} - you sent ".concat(String(strImageData))); return null; } else if (strImageData && typeof strImageData === 'string' && !strImageData.toLowerCase().includes('base64,')) { console.error('ERROR: Image `data` value lacks a base64 header! Ex: \'image/png;base64,NMP[...]\')'); return null; } // STEP 1: Set extension // NOTE: Split to address URLs with params (eg: `path/brent.jpg?someParam=true`) var strImgExtn = (strImagePath .substring(strImagePath.lastIndexOf('/') + 1) .split('?')[0] .split('.') .pop() .split('#')[0] || 'png').toLowerCase(); // However, pre-encoded images can be whatever mime-type they want (and good for them!) if (strImageData && /image\/(\w+);/.exec(strImageData) && /image\/(\w+);/.exec(strImageData).length > 0) { strImgExtn = /image\/(\w+);/.exec(strImageData)[1]; } else if (strImageData === null || strImageData === void 0 ? void 0 : strImageData.toLowerCase().includes('image/svg+xml')) { strImgExtn = 'svg'; } // STEP 2: Set type/path newObject._type = SLIDE_OBJECT_TYPES.image; newObject.image = strImagePath || 'preencoded.png'; // STEP 3: Set image properties & options // FIXME: Measure actual image when no intWidth/intHeight params passed // ....: This is an async process: we need to make getSizeFromImage use callback, then set H/W... // if ( !intWidth || !intHeight ) { var imgObj = getSizeFromImage(strImagePath); newObject.options = { x: intPosX || 0, y: intPosY || 0, w: intWidth || 1, h: intHeight || 1, altText: opt.altText || '', rounding: typeof opt.rounding === 'boolean' ? opt.rounding : false, sizing: sizing, placeholder: opt.placeholder, rotate: opt.rotate || 0, flipV: opt.flipV || false, flipH: opt.flipH || false, transparency: opt.transparency || 0, objectName: objectName, shadow: correctShadowOptions(opt.shadow), }; // STEP 4: Add this image to this Slide Rels (rId/rels count spans all slides! Count all images to get next rId) if (strImgExtn === 'svg') { // SVG files consume *TWO* rId's: (a png version and the svg image) // // target._relsMedia.push({ path: strImagePath || strImageData + 'png', type: 'image/png', extn: 'png', data: strImageData || '', rId: imageRelId, Target: "../media/image-".concat(target._slideNum, "-").concat(target._relsMedia.length + 1, ".png"), isSvgPng: true, svgSize: { w: getSmartParseNumber(newObject.options.w, 'X', target._presLayout), h: getSmartParseNumber(newObject.options.h, 'Y', target._presLayout) }, }); newObject.imageRid = imageRelId; target._relsMedia.push({ path: strImagePath || strImageData, type: 'image/svg+xml', extn: strImgExtn, data: strImageData || '', rId: imageRelId + 1, Target: "../media/image-".concat(target._slideNum, "-").concat(target._relsMedia.length + 1, ".").concat(strImgExtn), }); newObject.imageRid = imageRelId + 1; } else { // PERF: Duplicate media should reuse existing `Target` value and not create an additional copy var dupeItem = target._relsMedia.filter(function (item) { return item.path && item.path === strImagePath && item.type === 'image/' + strImgExtn && !item.isDuplicate; })[0]; target._relsMedia.push({ path: strImagePath || 'preencoded.' + strImgExtn, type: 'image/' + strImgExtn, extn: strImgExtn, data: strImageData || '', rId: imageRelId, isDuplicate: !!(dupeItem === null || dupeItem === void 0 ? void 0 : dupeItem.Target), Target: (dupeItem === null || dupeItem === void 0 ? void 0 : dupeItem.Target) ? dupeItem.Target : "../media/image-".concat(target._slideNum, "-").concat(target._relsMedia.length + 1, ".").concat(strImgExtn), }); newObject.imageRid = imageRelId; } // STEP 5: Hyperlink support if (typeof objHyperlink === 'object') { if (!objHyperlink.url && !objHyperlink.slide) throw new Error('ERROR: `hyperlink` option requires either: `url` or `slide`'); else { imageRelId++; target._rels.push({ type: SLIDE_OBJECT_TYPES.hyperlink, data: objHyperlink.slide ? 'slide' : 'dummy', rId: imageRelId, Target: objHyperlink.url || objHyperlink.slide.toString(), }); objHyperlink._rId = imageRelId; newObject.hyperlink = objHyperlink; } } // STEP 6: Add object to slide target._slideObjects.push(newObject); } /** * Adds a media object to a slide definition. * @param {PresSlide} `target` - slide object that the media will be added to * @param {MediaProps} `opt` - media options */ function addMediaDefinition(target, opt) { var intPosX = opt.x || 0; var intPosY = opt.y || 0; var intSizeX = opt.w || 2; var intSizeY = opt.h || 2; var strData = opt.data || ''; var strLink = opt.link || ''; var strPath = opt.path || ''; var strType = opt.type || 'audio'; var strExtn = ''; var strCover = opt.cover || IMG_PLAYBTN; var objectName = opt.objectName ? encodeXmlEntities(opt.objectName) : "Media ".concat(target._slideObjects.filter(function (obj) { return obj._type === SLIDE_OBJECT_TYPES.media; }).length); var slideData = { _type: SLIDE_OBJECT_TYPES.media }; // STEP 1: REALITY-CHECK if (!strPath && !strData && strType !== 'online') { throw new Error('addMedia() error: either `data` or `path` are required!'); } else if (strData && !strData.toLowerCase().includes('base64,')) { throw new Error('addMedia() error: `data` value lacks a base64 header! Ex: \'video/mpeg;base64,NMP[...]\')'); } else if (strCover && !strCover.toLowerCase().includes('base64,')) { throw new Error('addMedia() error: `cover` value lacks a base64 header! Ex: \'data:image/png;base64,iV[...]\')'); } // Online Video: requires `link` if (strType === 'online' && !strLink) { throw new Error('addMedia() error: online videos require `link` value'); } // FIXME: 20190707 // strType = strData ? strData.split(';')[0].split('/')[0] : strType strExtn = opt.extn || (strData ? strData.split(';')[0].split('/')[1] : strPath.split('.').pop()) || 'mp3'; // STEP 2: Set type, media slideData.mtype = strType; slideData.media = strPath || 'preencoded.mov'; slideData.options = {}; // STEP 3: Set media properties & options slideData.options.x = intPosX; slideData.options.y = intPosY; slideData.options.w = intSizeX; slideData.options.h = intSizeY; slideData.options.objectName = objectName; // STEP 4: Add this media to this Slide Rels (rId/rels count spans all slides! Count all media to get next rId) /** * NOTE: * - rId starts at 2 (hence the intRels+1 below) as slideLayout.xml is rId=1! * * NOTE: * - Audio/Video files consume *TWO* rId's: * * */ if (strType === 'online') { var relId1 = getNewRelId(target); // A: Add video target._relsMedia.push({ path: strPath || 'preencoded' + strExtn, data: 'dummy', type: 'online', extn: strExtn, rId: relId1, Target: strLink, }); slideData.mediaRid = relId1; // B: Add cover (preview/overlay) image target._relsMedia.push({ path: 'preencoded.png', data: strCover, type: 'image/png', extn: 'png', rId: getNewRelId(target), Target: "../media/image-".concat(target._slideNum, "-").concat(target._relsMedia.length + 1, ".png"), }); } else { // PERF: Duplicate media should reuse existing `Target` value and not create an additional copy var dupeItem = target._relsMedia.filter(function (item) { return item.path && item.path === strPath && item.type === strType + '/' + strExtn && !item.isDuplicate; })[0]; // A: "relationships/video" var relId1 = getNewRelId(target); target._relsMedia.push({ path: strPath || 'preencoded' + strExtn, type: strType + '/' + strExtn, extn: strExtn, data: strData || '', rId: relId1, isDuplicate: !!(dupeItem === null || dupeItem === void 0 ? void 0 : dupeItem.Target), Target: (dupeItem === null || dupeItem === void 0 ? void 0 : dupeItem.Target) ? dupeItem.Target : "../media/media-".concat(target._slideNum, "-").concat(target._relsMedia.length + 1, ".").concat(strExtn), }); slideData.mediaRid = relId1; // B: "relationships/media" target._relsMedia.push({ path: strPath || 'preencoded' + strExtn, type: strType + '/' + strExtn, extn: strExtn, data: strData || '', rId: getNewRelId(target), isDuplicate: !!(dupeItem === null || dupeItem === void 0 ? void 0 : dupeItem.Target), Target: (dupeItem === null || dupeItem === void 0 ? void 0 : dupeItem.Target) ? dupeItem.Target : "../media/media-".concat(target._slideNum, "-").concat(target._relsMedia.length + 0, ".").concat(strExtn), }); // C: Add cover (preview/overlay) image target._relsMedia.push({ path: 'preencoded.png', type: 'image/png', extn: 'png', data: strCover, rId: getNewRelId(target), Target: "../media/image-".concat(target._slideNum, "-").concat(target._relsMedia.length + 1, ".png"), }); } // LAST target._slideObjects.push(slideData); } /** * Adds Notes to a slide. * @param {PresSlide} `target` slide object * @param {string} `notes` * @since 2.3.0 */ function addNotesDefinition(target, notes) { target._slideObjects.push({ _type: SLIDE_OBJECT_TYPES.notes, text: [{ text: notes }], }); } /** * Adds a shape object to a slide definition. * @param {PresSlide} target slide object that the shape should be added to * @param {SHAPE_NAME} shapeName shape name * @param {ShapeProps} opts shape options */ function addShapeDefinition(target, shapeName, opts) { var options = typeof opts === 'object' ? opts : {}; options.line = options.line || { type: 'none' }; var newObject = { _type: SLIDE_OBJECT_TYPES.text, shape: shapeName || SHAPE_TYPE.RECTANGLE, options: options, text: null, }; // Reality check if (!shapeName) throw new Error('Missing/Invalid shape parameter! Example: `addShape(pptxgen.shapes.LINE, {x:1, y:1, w:1, h:1});`'); // 1: ShapeLineProps defaults var newLineOpts = { type: options.line.type || 'solid', color: options.line.color || DEF_SHAPE_LINE_COLOR, transparency: options.line.transparency || 0, width: options.line.width || 1, dashType: options.line.dashType || 'solid', beginArrowType: options.line.beginArrowType || null, endArrowType: options.line.endArrowType || null, }; if (typeof options.line === 'object' && options.line.type !== 'none') options.line = newLineOpts; // 2: Set options defaults options.x = options.x || (options.x === 0 ? 0 : 1); options.y = options.y || (options.y === 0 ? 0 : 1); options.w = options.w || (options.w === 0 ? 0 : 1); options.h = options.h || (options.h === 0 ? 0 : 1); options.objectName = options.objectName ? encodeXmlEntities(options.objectName) : "Shape ".concat(target._slideObjects.filter(function (obj) { return obj._type === SLIDE_OBJECT_TYPES.text; }).length); // 3: Handle line (lots of deprecated opts) if (typeof options.line === 'string') { var tmpOpts = newLineOpts; tmpOpts.color = String(options.line); // @deprecated `options.line` string (was line color) options.line = tmpOpts; } if (typeof options.lineSize === 'number') options.line.width = options.lineSize; // @deprecated (part of `ShapeLineProps` now) if (typeof options.lineDash === 'string') options.line.dashType = options.lineDash; // @deprecated (part of `ShapeLineProps` now) if (typeof options.lineHead === 'string') options.line.beginArrowType = options.lineHead; // @deprecated (part of `ShapeLineProps` now) if (typeof options.lineTail === 'string') options.line.endArrowType = options.lineTail; // @deprecated (part of `ShapeLineProps` now) // 4: Create hyperlink rels createHyperlinkRels(target, newObject); // LAST: Add object to slide target._slideObjects.push(newObject); } /** * Adds a table object to a slide definition. * @param {PresSlide} target - slide object that the table should be added to * @param {TableRow[]} tableRows - table data * @param {TableProps} options - table options * @param {SlideLayout} slideLayout - Slide layout * @param {PresLayout} presLayout - Presentation layout * @param {Function} addSlide - method * @param {Function} getSlide - method */ function addTableDefinition(target, tableRows, options, slideLayout, presLayout, addSlide, getSlide) { var slides = [target]; // Create array of Slides as more may be added by auto-paging var opt = options && typeof options === 'object' ? options : {}; opt.objectName = opt.objectName ? encodeXmlEntities(opt.objectName) : "Table ".concat(target._slideObjects.filter(function (obj) { return obj._type === SLIDE_OBJECT_TYPES.table; }).length); // STEP 1: REALITY-CHECK { // A: check for empty if (tableRows === null || tableRows.length === 0 || !Array.isArray(tableRows)) { throw new Error('addTable: Array expected! EX: \'slide.addTable( [rows], {options} );\' (https://gitbrent.github.io/PptxGenJS/docs/api-tables.html)'); } // B: check for non-well-formatted array (ex: rows=['a','b'] instead of [['a','b']]) if (!tableRows[0] || !Array.isArray(tableRows[0])) { throw new Error('addTable: \'rows\' should be an array of cells! EX: \'slide.addTable( [ [\'A\'], [\'B\'], {text:\'C\',options:{align:\'center\'}} ] );\' (https://gitbrent.github.io/PptxGenJS/docs/api-tables.html)'); } // TODO: FUTURE: This is wacky and wont function right (shows .w value when there is none from demo.js?!) 20191219 /* if (opt.w && opt.colW) { console.warn('addTable: please use either `colW` or `w` - not both (table will use `colW` and ignore `w`)') console.log(`${opt.w} ${opt.colW}`) } */ } // STEP 2: Transform `tableRows` into well-formatted TableCell's // tableRows can be object or plain text array: `[{text:'cell 1'}, {text:'cell 2', options:{color:'ff0000'}}]` | `["cell 1", "cell 2"]` var arrRows = []; tableRows.forEach(function (row) { var newRow = []; if (Array.isArray(row)) { row.forEach(function (cell) { // A: var newCell = { _type: SLIDE_OBJECT_TYPES.tablecell, text: '', options: typeof cell === 'object' && cell.options ? cell.options : {}, }; // B: if (typeof cell === 'string' || typeof cell === 'number') newCell.text = cell.toString(); else if (cell.text) { // Cell can contain complex text type, or string, or number if (typeof cell.text === 'string' || typeof cell.text === 'number') newCell.text = cell.text.toString(); else if (cell.text) newCell.text = cell.text; // Capture options if (cell.options && typeof cell.options === 'object') newCell.options = cell.options; } // C: Set cell borders newCell.options.border = newCell.options.border || opt.border || [{ type: 'none' }, { type: 'none' }, { type: 'none' }, { type: 'none' }]; var cellBorder = newCell.options.border; // CASE 1: border interface is: BorderOptions | [BorderOptions, BorderOptions, BorderOptions, BorderOptions] if (!Array.isArray(cellBorder) && typeof cellBorder === 'object') newCell.options.border = [cellBorder, cellBorder, cellBorder, cellBorder]; // Handle: [null, null, {type:'solid'}, null] if (!newCell.options.border[0]) newCell.options.border[0] = { type: 'none' }; if (!newCell.options.border[1]) newCell.options.border[1] = { type: 'none' }; if (!newCell.options.border[2]) newCell.options.border[2] = { type: 'none' }; if (!newCell.options.border[3]) newCell.options.border[3] = { type: 'none' }; // set complete BorderOptions for all sides var arrSides = [0, 1, 2, 3]; arrSides.forEach(function (idx) { newCell.options.border[idx] = { type: newCell.options.border[idx].type || DEF_CELL_BORDER.type, color: newCell.options.border[idx].color || DEF_CELL_BORDER.color, pt: typeof newCell.options.border[idx].pt === 'number' ? newCell.options.border[idx].pt : DEF_CELL_BORDER.pt, }; }); // LAST: newRow.push(newCell); }); } else { console.log('addTable: tableRows has a bad row. A row should be an array of cells. You provided:'); console.log(row); } arrRows.push(newRow); }); // STEP 3: Set options opt.x = getSmartParseNumber(opt.x || (opt.x === 0 ? 0 : EMU / 2), 'X', presLayout); opt.y = getSmartParseNumber(opt.y || (opt.y === 0 ? 0 : EMU / 2), 'Y', presLayout); if (opt.h) opt.h = getSmartParseNumber(opt.h, 'Y', presLayout); // NOTE: Dont set default `h` - leaving it null triggers auto-rowH in `makeXMLSlide()` opt.fontSize = opt.fontSize || DEF_FONT_SIZE; opt.margin = opt.margin === 0 || opt.margin ? opt.margin : DEF_CELL_MARGIN_IN; if (typeof opt.margin === 'number') opt.margin = [Number(opt.margin), Number(opt.margin), Number(opt.margin), Number(opt.margin)]; if (!opt.color) opt.color = opt.color || DEF_FONT_COLOR; // Set default color if needed (table option > inherit from Slide > default to black) if (typeof opt.border === 'string') { console.warn('addTable `border` option must be an object. Ex: `{border: {type:\'none\'}}`'); opt.border = null; } else if (Array.isArray(opt.border)) { [0, 1, 2, 3].forEach(function (idx) { opt.border[idx] = opt.border[idx] ? { type: opt.border[idx].type || DEF_CELL_BORDER.type, color: opt.border[idx].color || DEF_CELL_BORDER.color, pt: opt.border[idx].pt || DEF_CELL_BORDER.pt } : { type: 'none' }; }); } opt.autoPage = typeof opt.autoPage === 'boolean' ? opt.autoPage : false; opt.autoPageRepeatHeader = typeof opt.autoPageRepeatHeader === 'boolean' ? opt.autoPageRepeatHeader : false; opt.autoPageHeaderRows = typeof opt.autoPageHeaderRows !== 'undefined' && !isNaN(Number(opt.autoPageHeaderRows)) ? Number(opt.autoPageHeaderRows) : 1; opt.autoPageLineWeight = typeof opt.autoPageLineWeight !== 'undefined' && !isNaN(Number(opt.autoPageLineWeight)) ? Number(opt.autoPageLineWeight) : 0; if (opt.autoPageLineWeight) { if (opt.autoPageLineWeight > 1) opt.autoPageLineWeight = 1; else if (opt.autoPageLineWeight < -1) opt.autoPageLineWeight = -1; } // autoPage ^^^ // Set/Calc table width // Get slide margins - start with default values, then adjust if master or slide margins exist var arrTableMargin = DEF_SLIDE_MARGIN_IN; // Case 1: Master margins if (slideLayout && typeof slideLayout._margin !== 'undefined') { if (Array.isArray(slideLayout._margin)) arrTableMargin = slideLayout._margin; else if (!isNaN(Number(slideLayout._margin))) { arrTableMargin = [Number(slideLayout._margin), Number(slideLayout._margin), Number(slideLayout._margin), Number(slideLayout._margin)]; } } // Case 2: Table margins /* FIXME: add `_margin` option to slide options else if ( addNewSlide._margin ) { if ( Array.isArray(addNewSlide._margin) ) arrTableMargin = addNewSlide._margin; else if ( !isNaN(Number(addNewSlide._margin)) ) arrTableMargin = [Number(addNewSlide._margin), Number(addNewSlide._margin), Number(addNewSlide._margin), Number(addNewSlide._margin)]; } */ /** * Calc table width depending upon what data we have - several scenarios exist (including bad data, eg: colW doesnt match col count) * The API does not require a `w` value, but XML generation does, hence, code to calc a width below using colW value(s) */ if (opt.colW) { var firstRowColCnt = arrRows[0].reduce(function (totalLen, c) { var _a; if (((_a = c === null || c === void 0 ? void 0 : c.options) === null || _a === void 0 ? void 0 : _a.colspan) && typeof c.options.colspan === 'number') { totalLen += c.options.colspan; } else { totalLen += 1; } return totalLen; }, 0); if (typeof opt.colW === 'string' || typeof opt.colW === 'number') { // Ex: `colW = 3` or `colW = '3'` opt.w = Math.floor(Number(opt.colW) * firstRowColCnt); opt.colW = null; // IMPORTANT: Unset `colW` so table is created using `opt.w`, which will evenly divide cols } else if (opt.colW && Array.isArray(opt.colW) && opt.colW.length === 1 && firstRowColCnt > 1) { // Ex: `colW=[3]` but with >1 cols (same as above, user is saying "use this width for all") opt.w = Math.floor(Number(opt.colW) * firstRowColCnt); opt.colW = null; // IMPORTANT: Unset `colW` so table is created using `opt.w`, which will evenly divide cols } else if (opt.colW && Array.isArray(opt.colW) && opt.colW.length !== firstRowColCnt) { // Err: Mismatched colW and cols count console.warn('addTable: mismatch: (colW.length != data.length) Therefore, defaulting to evenly distributed col widths.'); opt.colW = null; } } else if (opt.w) { opt.w = getSmartParseNumber(opt.w, 'X', presLayout); } else { opt.w = Math.floor(presLayout._sizeW / EMU - arrTableMargin[1] - arrTableMargin[3]); } // STEP 4: Convert units to EMU now (we use different logic in makeSlide->table - smartCalc is not used) if (opt.x && opt.x < 20) opt.x = inch2Emu(opt.x); if (opt.y && opt.y < 20) opt.y = inch2Emu(opt.y); if (opt.w && opt.w < 20) opt.w = inch2Emu(opt.w); if (opt.h && opt.h < 20) opt.h = inch2Emu(opt.h); // STEP 5: Loop over cells: transform each to ITableCell; check to see whether to unset `autoPage` while here arrRows.forEach(function (row) { row.forEach(function (cell, idy) { // A: Transform cell data if needed /* Table rows can be an object or plain text - transform into object when needed // EX: var arrTabRows1 = [ [ { text:'A1\nA2', options:{rowspan:2, fill:'99FFCC'} } ] ,[ 'B2', 'C2', 'D2', 'E2' ] ] */ if (typeof cell === 'number' || typeof cell === 'string') { // Grab table formatting `opts` to use here so text style/format inherits as it should row[idy] = { _type: SLIDE_OBJECT_TYPES.tablecell, text: String(row[idy]), options: opt }; } else if (typeof cell === 'object') { // ARG0: `text` if (typeof cell.text === 'number') row[idy].text = row[idy].text.toString(); else if (typeof cell.text === 'undefined' || cell.text === null) row[idy].text = ''; // ARG1: `options`: ensure options exists row[idy].options = cell.options || {}; // Set type to tabelcell row[idy]._type = SLIDE_OBJECT_TYPES.tablecell; } // B: Check for fine-grained formatting, disable auto-page when found // Since genXmlTextBody already checks for text array ( text:[{},..{}] ) we're done! // Text in individual cells will be formatted as they are added by calls to genXmlTextBody within table builder // if (cell.text && Array.isArray(cell.text)) opt.autoPage = false // TODO: FIXME: WIP: 20210807: We cant do this anymore }); }); // If autoPage = true, we need to return references to newly created slides if any var newAutoPagedSlides = []; // STEP 6: Auto-Paging: (via {options} and used internally) // (used internally by `tableToSlides()` to not engage recursion - we've already paged the table data, just add this one) if (opt && !opt.autoPage) { // Create hyperlink rels (IMPORTANT: Wait until table has been shredded across Slides or all rels will end-up on Slide 1!) createHyperlinkRels(target, arrRows); // Add slideObjects (NOTE: Use `extend` to avoid mutation) target._slideObjects.push({ _type: SLIDE_OBJECT_TYPES.table, arrTabRows: arrRows, options: Object.assign({}, opt), }); } else { if (opt.autoPageRepeatHeader) opt._arrObjTabHeadRows = arrRows.filter(function (_row, idx) { return idx < opt.autoPageHeaderRows; }); // Loop over rows and create 1-N tables as needed (ISSUE#21) getSlidesForTableRows(arrRows, opt, presLayout, slideLayout).forEach(function (slide, idx) { // A: Create new Slide when needed, otherwise, use existing (NOTE: More than 1 table can be on a Slide, so we will go up AND down the Slide chain) if (!getSlide(target._slideNum + idx)) slides.push(addSlide({ masterName: (slideLayout === null || slideLayout === void 0 ? void 0 : slideLayout._name) || null })); // B: Reset opt.y to `option`/`margin` after first Slide (ISSUE#43, ISSUE#47, ISSUE#48) if (idx > 0) opt.y = inch2Emu(opt.autoPageSlideStartY || opt.newSlideStartY || arrTableMargin[0]); // C: Add this table to new Slide { var newSlide = getSlide(target._slideNum + idx); opt.autoPage = false; // Create hyperlink rels (IMPORTANT: Wait until table has been shredded across Slides or all rels will end-up on Slide 1!) createHyperlinkRels(newSlide, slide.rows); // Add rows to new slide newSlide.addTable(slide.rows, Object.assign({}, opt)); // Add reference to the new slide so it can be returned, but don't add the first one because the user already has a reference to that one. if (idx > 0) newAutoPagedSlides.push(newSlide); } }); } return newAutoPagedSlides; } /** * Adds a text object to a slide definition. * @param {PresSlide} target - slide object that the text should be added to * @param {string|TextProps[]} text text string or object * @param {TextPropsOptions} opts text options * @param {boolean} isPlaceholder whether this a placeholder object * @since: 1.0.0 */ function addTextDefinition(target, text, opts, isPlaceholder) { var newObject = { _type: isPlaceholder ? SLIDE_OBJECT_TYPES.placeholder : SLIDE_OBJECT_TYPES.text, shape: (opts === null || opts === void 0 ? void 0 : opts.shape) || SHAPE_TYPE.RECTANGLE, text: !text || text.length === 0 ? [{ text: '', options: null }] : text, options: opts || {}, }; function cleanOpts(itemOpts) { // STEP 1: Set some options { // A.1: Color (placeholders should inherit their colors or override them, so don't default them) if (!itemOpts.placeholder) { itemOpts.color = itemOpts.color || newObject.options.color || target.color || DEF_FONT_COLOR; } // A.2: Placeholder should inherit their bullets or override them, so don't default them if (itemOpts.placeholder || isPlaceholder) { itemOpts.bullet = itemOpts.bullet || false; } // A.3: Text targeting a placeholder need to inherit the placeholders options (eg: margin, valign, etc.) (Issue #640) if (itemOpts.placeholder && target._slideLayout && target._slideLayout._slideObjects) { var placeHold = target._slideLayout._slideObjects.filter(function (item) { return item._type === 'placeholder' && item.options && item.options.placeholder && item.options.placeholder === itemOpts.placeholder; })[0]; if (placeHold === null || placeHold === void 0 ? void 0 : placeHold.options) itemOpts = __assign(__assign({}, itemOpts), placeHold.options); } // A.4: Other options itemOpts.objectName = itemOpts.objectName ? encodeXmlEntities(itemOpts.objectName) : "Text ".concat(target._slideObjects.filter(function (obj) { return obj._type === SLIDE_OBJECT_TYPES.text; }).length); // B: if (itemOpts.shape === SHAPE_TYPE.LINE) { // ShapeLineProps defaults var newLineOpts = { type: itemOpts.line.type || 'solid', color: itemOpts.line.color || DEF_SHAPE_LINE_COLOR, transparency: itemOpts.line.transparency || 0, width: itemOpts.line.width || 1, dashType: itemOpts.line.dashType || 'solid', beginArrowType: itemOpts.line.beginArrowType || null, endArrowType: itemOpts.line.endArrowType || null, }; if (typeof itemOpts.line === 'object') itemOpts.line = newLineOpts; // 3: Handle line (lots of deprecated opts) if (typeof itemOpts.line === 'string') { var tmpOpts = newLineOpts; if (typeof itemOpts.line === 'string') tmpOpts.color = itemOpts.line; // @deprecated [remove in v4.0] // tmpOpts.color = itemOpts.line!.toString() // @deprecated `itemOpts.line`:[string] (was line color) itemOpts.line = tmpOpts; } if (typeof itemOpts.lineSize === 'number') itemOpts.line.width = itemOpts.lineSize; // @deprecated (part of `ShapeLineProps` now) if (typeof itemOpts.lineDash === 'string') itemOpts.line.dashType = itemOpts.lineDash; // @deprecated (part of `ShapeLineProps` now) if (typeof itemOpts.lineHead === 'string') itemOpts.line.beginArrowType = itemOpts.lineHead; // @deprecated (part of `ShapeLineProps` now) if (typeof itemOpts.lineTail === 'string') itemOpts.line.endArrowType = itemOpts.lineTail; // @deprecated (part of `ShapeLineProps` now) } // C: Line opts itemOpts.line = itemOpts.line || {}; itemOpts.lineSpacing = itemOpts.lineSpacing && !isNaN(itemOpts.lineSpacing) ? itemOpts.lineSpacing : null; itemOpts.lineSpacingMultiple = itemOpts.lineSpacingMultiple && !isNaN(itemOpts.lineSpacingMultiple) ? itemOpts.lineSpacingMultiple : null; // D: Transform text options to bodyProperties as thats how we build XML itemOpts._bodyProp = itemOpts._bodyProp || {}; itemOpts._bodyProp.autoFit = itemOpts.autoFit || false; // DEPRECATED: (3.3.0) If true, shape will collapse to text size (Fit To shape) itemOpts._bodyProp.anchor = !itemOpts.placeholder ? TEXT_VALIGN.ctr : null; // VALS: [t,ctr,b] itemOpts._bodyProp.vert = itemOpts.vert || null; // VALS: [eaVert,horz,mongolianVert,vert,vert270,wordArtVert,wordArtVertRtl] itemOpts._bodyProp.wrap = typeof itemOpts.wrap === 'boolean' ? itemOpts.wrap : true; // E: Inset // @deprecated 3.10.0 (`inset` - use `margin`) if ((itemOpts.inset && !isNaN(Number(itemOpts.inset))) || itemOpts.inset === 0) { itemOpts._bodyProp.lIns = inch2Emu(itemOpts.inset); itemOpts._bodyProp.rIns = inch2Emu(itemOpts.inset); itemOpts._bodyProp.tIns = inch2Emu(itemOpts.inset); itemOpts._bodyProp.bIns = inch2Emu(itemOpts.inset); } // F: Transform @deprecated props if (typeof itemOpts.underline === 'boolean' && itemOpts.underline === true) itemOpts.underline = { style: 'sng' }; } // STEP 2: Transform `align`/`valign` to XML values, store in _bodyProp for XML gen { if ((itemOpts.align || '').toLowerCase().indexOf('c') === 0) itemOpts._bodyProp.align = TEXT_HALIGN.center; else if ((itemOpts.align || '').toLowerCase().indexOf('l') === 0) itemOpts._bodyProp.align = TEXT_HALIGN.left; else if ((itemOpts.align || '').toLowerCase().indexOf('r') === 0) itemOpts._bodyProp.align = TEXT_HALIGN.right; else if ((itemOpts.align || '').toLowerCase().indexOf('j') === 0) itemOpts._bodyProp.align = TEXT_HALIGN.justify; if ((itemOpts.valign || '').toLowerCase().indexOf('b') === 0) itemOpts._bodyProp.anchor = TEXT_VALIGN.b; else if ((itemOpts.valign || '').toLowerCase().indexOf('m') === 0) itemOpts._bodyProp.anchor = TEXT_VALIGN.ctr; else if ((itemOpts.valign || '').toLowerCase().indexOf('t') === 0) itemOpts._bodyProp.anchor = TEXT_VALIGN.t; } // STEP 3: ROBUST: Set rational values for some shadow props if needed correctShadowOptions(itemOpts.shadow); return itemOpts; } // STEP 1: Create/Clean object options newObject.options = cleanOpts(newObject.options); // STEP 2: Create/Clean text options newObject.text.forEach(function (item) { return (item.options = cleanOpts(item.options || {})); }); // STEP 3: Create hyperlinks createHyperlinkRels(target, newObject.text || ''); // LAST: Add object to Slide target._slideObjects.push(newObject); } /** * Adds placeholder objects to slide * @param {PresSlide} slide - slide object containing layouts */ function addPlaceholdersToSlideLayouts(slide) { // Add all placeholders on this Slide that dont already exist (slide._slideLayout._slideObjects || []).forEach(function (slideLayoutObj) { if (slideLayoutObj._type === SLIDE_OBJECT_TYPES.placeholder) { // A: Search for this placeholder on Slide before we add // NOTE: Check to ensure a placeholder does not already exist on the Slide // They are created when they have been populated with text (ex: `slide.addText('Hi', { placeholder:'title' });`) if (slide._slideObjects.filter(function (slideObj) { return slideObj.options && slideObj.options.placeholder === slideLayoutObj.options.placeholder; }).length === 0) { addTextDefinition(slide, [{ text: '' }], slideLayoutObj.options, false); } } }); } /* -------------------------------------------------------------------------------- */ /** * Adds a background image or color to a slide definition. * @param {BackgroundProps} props - color string or an object with image definition * @param {PresSlide} target - slide object that the background is set to */ function addBackgroundDefinition(props, target) { var _a; // A: @deprecated if (target.bkgd) { if (!target.background) target.background = {}; if (typeof target.bkgd === 'string') target.background.color = target.bkgd; else { if (target.bkgd.data) target.background.data = target.bkgd.data; if (target.bkgd.path) target.background.path = target.bkgd.path; if (target.bkgd.src) target.background.path = target.bkgd.src; // @deprecated (drop in 4.x) } } if ((_a = target.background) === null || _a === void 0 ? void 0 : _a.fill) target.background.color = target.background.fill; // B: Handle media if (props && (props.path || props.data)) { // Allow the use of only the data key (`path` isnt reqd) props.path = props.path || 'preencoded.png'; var strImgExtn = (props.path.split('.').pop() || 'png').split('?')[0]; // Handle "blah.jpg?width=540" etc. if (strImgExtn === 'jpg') strImgExtn = 'jpeg'; // base64-encoded jpg's come out as "data:image/jpeg;base64,/9j/[...]", so correct exttnesion to avoid content warnings at PPT startup target._relsMedia = target._relsMedia || []; var intRels = target._relsMedia.length + 1; // NOTE: `Target` cannot have spaces (eg:"Slide 1-image-1.jpg") or a "presentation is corrupt" warning comes up target._relsMedia.push({ path: props.path, type: SLIDE_OBJECT_TYPES.image, extn: strImgExtn, data: props.data || null, rId: intRels, Target: "../media/".concat((target._name || '').replace(/\s+/gi, '-'), "-image-").concat(target._relsMedia.length + 1, ".").concat(strImgExtn), }); target._bkgdImgRid = intRels; } } /** * Parses text/text-objects from `addText()` and `addTable()` methods; creates 'hyperlink'-type Slide Rels for each hyperlink found * @param {PresSlide} target - slide object that any hyperlinks will be be added to * @param {number | string | TextProps | TextProps[] | ITableCell[][]} text - text to parse */ function createHyperlinkRels(target, text) { var textObjs = []; // Only text objects can have hyperlinks, bail when text param is plain text if (typeof text === 'string' || typeof text === 'number') return; // IMPORTANT: "else if" Array.isArray must come before typeof===object! Otherwise, code will exhaust recursion! else if (Array.isArray(text)) textObjs = text; else if (typeof text === 'object') textObjs = [text]; textObjs.forEach(function (text) { // `text` can be an array of other `text` objects (table cell word-level formatting), continue parsing using recursion if (Array.isArray(text)) { createHyperlinkRels(target, text); } else if (Array.isArray(text.text)) { // this handles TableCells with hyperlinks createHyperlinkRels(target, text.text); } else if (text && typeof text === 'object' && text.options && text.options.hyperlink && !text.options.hyperlink._rId) { if (typeof text.options.hyperlink !== 'object') console.log('ERROR: text `hyperlink` option should be an object. Ex: `hyperlink: {url:\'https://github.com\'}` '); else if (!text.options.hyperlink.url && !text.options.hyperlink.slide) console.log('ERROR: \'hyperlink requires either: `url` or `slide`\''); else { var relId = getNewRelId(target); target._rels.push({ type: SLIDE_OBJECT_TYPES.hyperlink, data: text.options.hyperlink.slide ? 'slide' : 'dummy', rId: relId, Target: encodeXmlEntities(text.options.hyperlink.url) || text.options.hyperlink.slide.toString(), }); text.options.hyperlink._rId = relId; } } }); } /** * PptxGenJS: Slide Class */ var Slide = /** @class */ (function () { function Slide(params) { var _a; this.addSlide = params.addSlide; this.getSlide = params.getSlide; this._name = "Slide ".concat(params.slideNumber); this._presLayout = params.presLayout; this._rId = params.slideRId; this._rels = []; this._relsChart = []; this._relsMedia = []; this._setSlideNum = params.setSlideNum; this._slideId = params.slideId; this._slideLayout = params.slideLayout || null; this._slideNum = params.slideNumber; this._slideObjects = []; /** NOTE: Slide Numbers: In order for Slide Numbers to function they need to be in all 3 files: master/layout/slide * `defineSlideMaster` and `addNewSlide.slideNumber` will add {slideNumber} to `this.masterSlide` and `this.slideLayouts` * so, lastly, add to the Slide now. */ this._slideNumberProps = ((_a = this._slideLayout) === null || _a === void 0 ? void 0 : _a._slideNumberProps) ? this._slideLayout._slideNumberProps : null; } Object.defineProperty(Slide.prototype, "bkgd", { get: function () { return this._bkgd; }, set: function (value) { this._bkgd = value; if (!this._background || !this._background.color) { if (!this._background) this._background = {}; if (typeof value === 'string') this._background.color = value; } }, enumerable: false, configurable: true }); Object.defineProperty(Slide.prototype, "background", { get: function () { return this._background; }, set: function (props) { this._background = props; // Add background (image data/path must be captured before `exportPresentation()` is called) if (props) addBackgroundDefinition(props, this); }, enumerable: false, configurable: true }); Object.defineProperty(Slide.prototype, "color", { get: function () { return this._color; }, set: function (value) { this._color = value; }, enumerable: false, configurable: true }); Object.defineProperty(Slide.prototype, "hidden", { get: function () { return this._hidden; }, set: function (value) { this._hidden = value; }, enumerable: false, configurable: true }); Object.defineProperty(Slide.prototype, "slideNumber", { get: function () { return this._slideNumberProps; }, /** * @type {SlideNumberProps} */ set: function (value) { // NOTE: Slide Numbers: In order for Slide Numbers to function they need to be in all 3 files: master/layout/slide this._slideNumberProps = value; this._setSlideNum(value); }, enumerable: false, configurable: true }); Object.defineProperty(Slide.prototype, "newAutoPagedSlides", { get: function () { return this._newAutoPagedSlides; }, enumerable: false, configurable: true }); /** * Add chart to Slide * @param {CHART_NAME|IChartMulti[]} type - chart type * @param {object[]} data - data object * @param {IChartOpts} options - chart options * @return {Slide} this Slide */ Slide.prototype.addChart = function (type, data, options) { // FUTURE: TODO-VERSION-4: Remove first arg - only take data and opts, with "type" required on opts // Set `_type` on IChartOptsLib as its what is used as object is passed around var optionsWithType = options || {}; optionsWithType._type = type; addChartDefinition(this, type, data, options); return this; }; /** * Add image to Slide * @param {ImageProps} options - image options * @return {Slide} this Slide */ Slide.prototype.addImage = function (options) { addImageDefinition(this, options); return this; }; /** * Add media (audio/video) to Slide * @param {MediaProps} options - media options * @return {Slide} this Slide */ Slide.prototype.addMedia = function (options) { addMediaDefinition(this, options); return this; }; /** * Add speaker notes to Slide * @docs https://gitbrent.github.io/PptxGenJS/docs/speaker-notes.html * @param {string} notes - notes to add to slide * @return {Slide} this Slide */ Slide.prototype.addNotes = function (notes) { addNotesDefinition(this, notes); return this; }; /** * Add shape to Slide * @param {SHAPE_NAME} shapeName - shape name * @param {ShapeProps} options - shape options * @return {Slide} this Slide */ Slide.prototype.addShape = function (shapeName, options) { // NOTE: As of v3.1.0,