From b95f3607fc35b157da082e196911172733bfcb20 Mon Sep 17 00:00:00 2001 From: shanialbeck Date: Tue, 16 May 2023 10:55:39 +0300 Subject: [PATCH 1/7] add dateTime format to Grid Data interfaces --- src/GridParser.ts | 31 +++++++++++++++++++++++++++++-- src/constants.ts | 37 +++++++++++++++++++++++++++++++++++-- src/types.ts | 3 +++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/GridParser.ts b/src/GridParser.ts index c8990d8..3574ca1 100644 --- a/src/GridParser.ts +++ b/src/GridParser.ts @@ -1,9 +1,10 @@ -import { GridNotFoundErr, headerNotFoundErr, invalidDataTypeErr, invalidValueInColumnErr } from "./constants"; +import { dateFormats, GridNotFoundErr, headerNotFoundErr, invalidDataTypeErr, invalidFormatTypeErr, invalidMissingFormatFromDateTimeErr, invalidValueInColumnErr, dateFormatsRegex, milliSecPerDay, numberOfDaysTillExcelBeginYear, monthsbeforeLeap } from "./constants"; import { ColumnMetadata, dataTypes, Grid, TableData } from "./types"; -export default class GridParser { +export class GridParser { public parseToTableData(initialDataGrid: Grid): TableData | undefined { if (!initialDataGrid) { + return undefined; } @@ -38,6 +39,13 @@ export default class GridParser { } } + if (dataType == dataTypes.dateTime) { + if (dateFormatsRegex[columnMetadata[colIndex].format!].test(cellValue.toString())) { + throw new Error(invalidValueInColumnErr); + } + rowData[prop] = this.convertToExcelDate(cellValue.toString()); + } + row.push(rowData[prop].toString()); colIndex++; } @@ -47,6 +55,16 @@ export default class GridParser { return tableData; } + private convertToExcelDate(dateStr: string) { + const [month, day, year, hour, minute] = dateStr.split(/[\/: ]/); + const date = new Date(Date.UTC(parseInt(year), parseInt(month) - 1, parseInt(day), parseInt(hour), parseInt(minute), 0,0)).getTime(); + // Excel incorrectly assumes that the year 1900 is a leap year. This is a workaround for that + if (parseInt(year) == 1900 && parseInt(month) <= monthsbeforeLeap) { + return ((date + numberOfDaysTillExcelBeginYear*milliSecPerDay) / (milliSecPerDay)) - 1; + } + return (date + numberOfDaysTillExcelBeginYear*milliSecPerDay) / (milliSecPerDay); + } + private validateGridHeader(data: Grid) { const headerData: ColumnMetadata[] = data.Header; if (!headerData) { @@ -57,6 +75,15 @@ export default class GridParser { if (!(headerData[prop].type in dataTypes)) { throw new Error(invalidDataTypeErr); } + + if (headerData[prop].type == dataTypes.dateTime && headerData[prop].format == undefined) { + throw new Error(invalidMissingFormatFromDateTimeErr); + } + + if (headerData[prop].format != undefined && !(headerData[prop].format! in dateFormats)) { + throw new Error(invalidFormatTypeErr); + } + } } } diff --git a/src/constants.ts b/src/constants.ts index 469e390..d5cb34e 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -12,6 +12,7 @@ export const pivotCachesPath = "xl/pivotCache/"; export const section1mPath = "Formulas/Section1.m"; export const docPropsCoreXmlPath = "docProps/core.xml"; export const docPropsRootElement = "cp:coreProperties"; +export const stylesXmlPath = "xl/styles.xml"; export const sharedStringsNotFoundErr = "SharedStrings were not found in template"; export const connectionsNotFoundErr = "Connections were not found in template"; @@ -28,6 +29,9 @@ export const GridNotFoundErr = "Invalid JSON file, grid data is missing"; export const invalidValueInColumnErr = "Invalid cell value in column"; export const headerNotFoundErr = "Invalid JSON file, header is missing"; export const invalidDataTypeErr = "Invalid JSON file, invalid data type"; +export const invalidFormatTypeErr = "Invalid JSON file, invalid format type"; +export const stylesNotFoundErr = "Styles were not found in template"; +export const invalidMissingFormatFromDateTimeErr = "Invalid JSON file, missing format from dateTime"; export const blobFileType = "blob"; export const uint8ArrayType = "uint8array"; @@ -66,7 +70,12 @@ export const element = { queryTableRefresh: "queryTableRefresh", sheetData: "sheetData", row: "row", - dimension: "dimension" + dimension: "dimension", + differentialFormats: "dxfs", + differentialFormat: "dxf", + numberFormat: "numFmt", + cellFormats: "cellXfs", + cellFormat: "xf" } export const elementAttributes = { @@ -96,9 +105,18 @@ export const elementAttributes = { nextId: "nextId", row: "r", spans: "spans", - x14acDyDescent: "x14ac:dyDescent" + x14acDyDescent: "x14ac:dyDescent", + numberFormatId: "numFmtId", + formatCode: "formatCode", + dataDiffFormatId: "dataDxfId", + fontId: "fontId", + fillId: "fillId", + borderId: "borderId", + formatId: "xfId", + applyNumberFormat: "applyNumberFormat" }; + export const elementAttributesValues = { connectionName: (queryName: string) => `Query - ${queryName}`, connectionDescription: (queryName: string) => `Connection to the '${queryName}' query in the workbook.`, @@ -108,10 +126,25 @@ export const elementAttributesValues = { } +export const milliSecPerDay = 86400000; +//This contains the number of days between 01/01/1970 and 01/01/1900 +export const numberOfDaysTillExcelBeginYear = 25569; +export const monthsbeforeLeap = 2; +export const beginYear = 1900; export const defaults = { queryName: "Query1", }; +export const dateFormatsRegex: { [key: string]: RegExp } = { + "m/d/yyyy h:mm": /^([1-9]|0[1-9]|1[0-2])\/([1-9]|[012][0-9]|3[01])\/\d{4} ([01]\d|2[0-3]):([0-5]\d)$/, + 'm/d/yyyy\\ h:mm': /^([1-9]|0[1-9]|1[0-2])\/([1-9]|[012][0-9]|3[01])\/\d{4} ([01]\d|2[0-3]):([0-5]\d)$/ +}; + +export const dateFormats: { [key: string]: number } = { + "m/d/yyyy h:mm": 27, + 'm/d/yyyy\\ h:mm': 27 +}; + export const URLS = { PQ: [ "http://schemas.microsoft.com/DataMashup", diff --git a/src/types.ts b/src/types.ts index 1a0fc03..da2b346 100644 --- a/src/types.ts +++ b/src/types.ts @@ -31,6 +31,7 @@ export interface TableData { export interface ColumnMetadata { name: string; type: number; + format?: string; } export interface Grid { @@ -47,8 +48,10 @@ export enum dataTypes { string = 1, number = 2, boolean = 3, + dateTime = 4 } + export enum docPropsModifiableElements { title = "dc:title", subject = "dc:subject", From 84317fce9b6a340cb307244af18549b2364b89b9 Mon Sep 17 00:00:00 2001 From: shanialbeck Date: Tue, 16 May 2023 10:57:46 +0300 Subject: [PATCH 2/7] update workbook to contain datetime format --- src/TableDataParserFactory.ts | 2 +- src/utils/documentUtils.ts | 3 ++ src/workbookManager.ts | 62 +++++++++++++++++++++++++++++++++-- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/TableDataParserFactory.ts b/src/TableDataParserFactory.ts index 8ee9dd0..dd57d9f 100644 --- a/src/TableDataParserFactory.ts +++ b/src/TableDataParserFactory.ts @@ -1,4 +1,4 @@ -import GridParser from "./GridParser"; +import {GridParser} from "./GridParser"; import { TableDataParser } from "./types"; export default class TableDataParserFactory { diff --git a/src/utils/documentUtils.ts b/src/utils/documentUtils.ts index 00302b5..7547eee 100644 --- a/src/utils/documentUtils.ts +++ b/src/utils/documentUtils.ts @@ -67,6 +67,9 @@ const updateCellData = (dataType: number, data: string, cell: Element, cellData: case dataTypes.number: cell.setAttribute("t", "1"); break; + case dataTypes.dateTime: + cell.setAttribute("s", "1"); + break; case dataTypes.boolean: cell.setAttribute("t", "b"); break; diff --git a/src/workbookManager.ts b/src/workbookManager.ts index b6c3d02..32c55be 100644 --- a/src/workbookManager.ts +++ b/src/workbookManager.ts @@ -16,6 +16,9 @@ import { templateWithInitialDataErr, queryTableNotFoundErr, tableNotFoundErr, + stylesXmlPath, + stylesNotFoundErr, + dateFormats, } from "./constants"; import { DocProps, @@ -164,14 +167,26 @@ export class WorkbookManager { const newTable: string = await this.updateTablesInitialData(tableXmlString, tableData); zip.file(tableXmlPath, newTable); - const workbookXmlString = await zip.file(workbookXmlPath)?.async(textResultType); + const workbookXmlString: string | undefined = await zip.file(workbookXmlPath)?.async(textResultType); if (workbookXmlString === undefined) { throw new Error(sheetsNotFoundErr); } - const newWorkbook:string = await this.updateWorkbookInitialData(workbookXmlString, tableData); + const newWorkbook: string = await this.updateWorkbookInitialData(workbookXmlString, tableData); zip.file(workbookXmlPath, newWorkbook); + + const styleXmlString: string | undefined = await zip.file(stylesXmlPath)?.async(textResultType); + if (styleXmlString === undefined) { + throw new Error(sheetsNotFoundErr); + } + + const newStyles: string | undefined = await this.updateStylesFormat(styleXmlString, tableData); + if (styleXmlString === undefined) { + throw new Error(stylesNotFoundErr); + } + zip.file(stylesXmlPath, newStyles); } + private async updateTablesInitialData(tableXmlString: string, tableData: TableData) { const parser: DOMParser = new DOMParser(); @@ -179,12 +194,17 @@ export class WorkbookManager { const tableDoc: Document = parser.parseFromString(tableXmlString, xmlTextResultType); const tableColumns: Element = tableDoc.getElementsByTagName(element.tableColumns)[0]; tableColumns.textContent = ""; + var diffFormatId = 0; tableData.columnMetadata.forEach((col: ColumnMetadata, columnIndex: number) => { const tableColumn: Element = tableDoc.createElementNS(tableDoc.documentElement.namespaceURI, element.tableColumn); tableColumn.setAttribute(elementAttributes.id, (columnIndex + 1).toString()); tableColumn.setAttribute(elementAttributes.uniqueName, (columnIndex + 1).toString()); tableColumn.setAttribute(elementAttributes.name, col.name); tableColumn.setAttribute(elementAttributes.queryTableFieldId, (columnIndex + 1).toString()); + if (col.format !== undefined) { + tableColumn.setAttribute(elementAttributes.dataDiffFormatId, diffFormatId.toString()); + diffFormatId++; + } tableColumns.appendChild(tableColumn); }); @@ -224,6 +244,44 @@ export class WorkbookManager { return newSerializer.serializeToString(workbookDoc); } + private async updateStylesFormat(stylesXmlString: string, tableData: TableData) { + const newParser: DOMParser = new DOMParser(); + const newSerializer: XMLSerializer = new XMLSerializer(); + const stylesDoc: Document = newParser.parseFromString(stylesXmlString, xmlTextResultType); + const differentialFormats: Element = stylesDoc.getElementsByTagName(element.differentialFormats)[0]; + differentialFormats.textContent = ""; + differentialFormats.setAttribute(elementAttributes.count, "0"); + tableData.columnMetadata.forEach((col: ColumnMetadata) => { + if (col.format !== undefined) { + // Add new diffrential format to styles + const diffFormat: Element = stylesDoc.createElementNS(stylesDoc.documentElement.namespaceURI, element.differentialFormat); + const numberFormat: Element = stylesDoc.createElementNS(stylesDoc.documentElement.namespaceURI, element.numberFormat); + numberFormat.setAttribute(elementAttributes.numberFormatId, dateFormats[col.format].toString()); + numberFormat.setAttribute(elementAttributes.formatCode, col.format); + diffFormat.appendChild(numberFormat); + differentialFormats.appendChild(diffFormat); + // Increment format count + const formatCount = Number.parseInt(differentialFormats.getAttribute(elementAttributes.count)!); + differentialFormats.setAttribute(elementAttributes.count, (formatCount + 1).toString()); + } + // Date: Tue, 16 May 2023 10:58:57 +0300 Subject: [PATCH 3/7] add date conversion testing --- src/index.ts | 1 + tests/GridParser.test.ts | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/GridParser.test.ts diff --git a/src/index.ts b/src/index.ts index e76661a..da6b37c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,3 +4,4 @@ export { WorkbookManager } from "./workbookManager"; export type { QueryInfo } from "./types"; export type {ArrayReader} from "././utils/arrayUtils"; +export { GridParser } from "./GridParser"; diff --git a/tests/GridParser.test.ts b/tests/GridParser.test.ts new file mode 100644 index 0000000..c0a6cc6 --- /dev/null +++ b/tests/GridParser.test.ts @@ -0,0 +1,18 @@ +import workbookTemplate from "../src/workbookTemplate"; +import { GridParser } from "../src/GridParser"; + + +describe("Grid Parser tests", () => { + const gridParser = new GridParser() as any; + + test("Connection XML attributes contain new query name", async () => { + const RandomExcelDate = gridParser.convertToExcelDate("5/4/2023 00:00"); + expect(RandomExcelDate).toEqual(45050); + const FirstExcelDate = gridParser.convertToExcelDate("1/1/1900 00:00"); + expect(FirstExcelDate).toEqual(1); + }) + + + + +}); \ No newline at end of file From 9112f8ff538abf8fa86eb7967487fd036f45d416 Mon Sep 17 00:00:00 2001 From: shanialbeck Date: Tue, 16 May 2023 11:25:30 +0300 Subject: [PATCH 4/7] remove comments and invalid date formats --- src/constants.ts | 6 ++---- src/workbookManager.ts | 23 +++++++++++------------ 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index d5cb34e..f31178e 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -136,13 +136,11 @@ export const defaults = { }; export const dateFormatsRegex: { [key: string]: RegExp } = { - "m/d/yyyy h:mm": /^([1-9]|0[1-9]|1[0-2])\/([1-9]|[012][0-9]|3[01])\/\d{4} ([01]\d|2[0-3]):([0-5]\d)$/, - 'm/d/yyyy\\ h:mm': /^([1-9]|0[1-9]|1[0-2])\/([1-9]|[012][0-9]|3[01])\/\d{4} ([01]\d|2[0-3]):([0-5]\d)$/ + "m/d/yyyy h:mm": /^([1-9]|0[1-9]|1[0-2])\/([1-9]|[012][0-9]|3[01])\/\d{4} ([01]\d|2[0-3]):([0-5]\d)$/ }; export const dateFormats: { [key: string]: number } = { - "m/d/yyyy h:mm": 27, - 'm/d/yyyy\\ h:mm': 27 + "m/d/yyyy h:mm": 27 }; export const URLS = { diff --git a/src/workbookManager.ts b/src/workbookManager.ts index 32c55be..0481d7e 100644 --- a/src/workbookManager.ts +++ b/src/workbookManager.ts @@ -264,18 +264,17 @@ export class WorkbookManager { const formatCount = Number.parseInt(differentialFormats.getAttribute(elementAttributes.count)!); differentialFormats.setAttribute(elementAttributes.count, (formatCount + 1).toString()); } - // Date: Tue, 16 May 2023 11:49:16 +0300 Subject: [PATCH 5/7] fix bug in cell formatting --- src/constants.ts | 6 +++--- src/workbookManager.ts | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index f31178e..03c1d64 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -122,8 +122,8 @@ export const elementAttributesValues = { connectionDescription: (queryName: string) => `Connection to the '${queryName}' query in the workbook.`, connection: (queryName: string) => `Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=${queryName};`, connectionCommand: (queryName: string) => `SELECT * FROM [${queryName}]`, - tableResultType: () => "sTable" - + tableResultType: () => "sTable", + cellNumberFormatId: (numberFormatId: number) => "0" } export const milliSecPerDay = 86400000; @@ -140,7 +140,7 @@ export const dateFormatsRegex: { [key: string]: RegExp } = { }; export const dateFormats: { [key: string]: number } = { - "m/d/yyyy h:mm": 27 + "m/d/yyyy h:mm": 22 }; export const URLS = { diff --git a/src/workbookManager.ts b/src/workbookManager.ts index 0481d7e..2c994c0 100644 --- a/src/workbookManager.ts +++ b/src/workbookManager.ts @@ -263,18 +263,18 @@ export class WorkbookManager { // Increment format count const formatCount = Number.parseInt(differentialFormats.getAttribute(elementAttributes.count)!); differentialFormats.setAttribute(elementAttributes.count, (formatCount + 1).toString()); - } - const cellFormats: Element = stylesDoc.getElementsByTagName(element.cellFormats)[0]; - const cellFormat: Element = stylesDoc.createElementNS(stylesDoc.documentElement.namespaceURI, element.cellFormat); - cellFormat.setAttribute(elementAttributes.numberFormatId, "22"); - cellFormat.setAttribute(elementAttributes.fontId, "0"); - cellFormat.setAttribute(elementAttributes.fillId, "0"); - cellFormat.setAttribute(elementAttributes.borderId, "0"); - cellFormat.setAttribute(elementAttributes.formatId, "0"); - cellFormat.setAttribute(elementAttributes.applyNumberFormat, "1"); - cellFormats.appendChild(cellFormat); - const cellformatCount = Number.parseInt(cellFormats.getAttribute(elementAttributes.count)!); - cellFormats.setAttribute(elementAttributes.count, (cellformatCount + 1).toString()); + const cellFormats: Element = stylesDoc.getElementsByTagName(element.cellFormats)[0]; + const cellFormat: Element = stylesDoc.createElementNS(stylesDoc.documentElement.namespaceURI, element.cellFormat); + cellFormat.setAttribute(elementAttributes.numberFormatId, dateFormats[col.format].toString()); + cellFormat.setAttribute(elementAttributes.fontId, "0"); + cellFormat.setAttribute(elementAttributes.fillId, "0"); + cellFormat.setAttribute(elementAttributes.borderId, "0"); + cellFormat.setAttribute(elementAttributes.formatId, "0"); + cellFormat.setAttribute(elementAttributes.applyNumberFormat, "1"); + cellFormats.appendChild(cellFormat); + const cellformatCount = Number.parseInt(cellFormats.getAttribute(elementAttributes.count)!); + cellFormats.setAttribute(elementAttributes.count, (cellformatCount + 1).toString()); + } }); From 13724b6be1800a4144078f038b0de3c3959e97c7 Mon Sep 17 00:00:00 2001 From: shanialbeck Date: Tue, 16 May 2023 17:30:13 +0300 Subject: [PATCH 6/7] remove unused constant variable --- src/constants.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 03c1d64..5261a8d 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -122,8 +122,7 @@ export const elementAttributesValues = { connectionDescription: (queryName: string) => `Connection to the '${queryName}' query in the workbook.`, connection: (queryName: string) => `Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=${queryName};`, connectionCommand: (queryName: string) => `SELECT * FROM [${queryName}]`, - tableResultType: () => "sTable", - cellNumberFormatId: (numberFormatId: number) => "0" + tableResultType: () => "sTable" } export const milliSecPerDay = 86400000; From 74c57906bf7ccdcebde32a59b00a614f8eb51695 Mon Sep 17 00:00:00 2001 From: roben Date: Sun, 11 Jun 2023 09:50:51 +0300 Subject: [PATCH 7/7] 1. added autodetect (-1) that makes updateCellData to look at the data and create the relevant type of cell, currently excluding dates (applied as strings and commented out) 2. Added a blank table1 template to be used by new scenario 3. Added generateTableWorkbook public API 4. scoped queryTable related updates in initial data to Query scenario, currently with a parameter. 5. small fixes - vars into lets and consts 6. added missing xr3:uid to column xmls, without it - file is corrupted on open (repair works, but not a good experience) 7. changed tsconfig to not generate sourceMaps as we are not publishing sources, resulting in issues when publishing consuming web apps. 8. version is now 2.1.10-beta --- package-lock.json | 17 ++- package.json | 3 +- src/types.ts | 6 +- src/utils/documentUtils.ts | 46 ++++--- src/workbookManager.ts | 270 ++++++++++++++++++++++++------------- src/workbookTemplate.ts | 2 + tsconfig.json | 2 +- 7 files changed, 232 insertions(+), 114 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7143f4b..48e8cec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@microsoft/connected-workbooks", - "version": "1.0.0", + "version": "2.1.2-beta", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@microsoft/connected-workbooks", - "version": "1.0.0", + "version": "2.1.2-beta", "license": "MIT", "dependencies": { "base64-js": "^1.5.1", @@ -20,6 +20,7 @@ "@types/base64-js": "^1.3.0", "@types/jest": "^26.0.24", "@types/jszip": "^3.4.1", + "@types/uuid": "^9.0.2", "@typescript-eslint/eslint-plugin": "^4.28.2", "@typescript-eslint/parser": "^4.28.2", "babel-jest": "^27.0.6", @@ -4274,6 +4275,12 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "node_modules/@types/uuid": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.2.tgz", + "integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==", + "dev": true + }, "node_modules/@types/yargs": { "version": "16.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", @@ -12552,6 +12559,12 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "@types/uuid": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.2.tgz", + "integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==", + "dev": true + }, "@types/yargs": { "version": "16.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", diff --git a/package.json b/package.json index 8ae9161..5c0edee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/connected-workbooks", - "version": "1.0.0", + "version": "2.1.10-beta", "description": "Use this library to generate Excel workbooks with a custom Mashup Query loaded to the grid, to be used by applications for 'Export to Excel' features to allow refreshable workbooks", "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -40,6 +40,7 @@ "@types/base64-js": "^1.3.0", "@types/jest": "^26.0.24", "@types/jszip": "^3.4.1", + "@types/uuid": "^9.0.2", "@typescript-eslint/eslint-plugin": "^4.28.2", "@typescript-eslint/parser": "^4.28.2", "babel-jest": "^27.0.6", diff --git a/src/types.ts b/src/types.ts index da2b346..1be6c44 100644 --- a/src/types.ts +++ b/src/types.ts @@ -36,7 +36,7 @@ export interface ColumnMetadata { export interface Grid { Header: ColumnMetadata[]; - GridData: (string|number|boolean)[][]; + GridData: (string | number | boolean)[][]; } export interface TableDataParser { @@ -44,14 +44,14 @@ export interface TableDataParser { } export enum dataTypes { + autodetect = -1, null = 0, string = 1, number = 2, boolean = 3, - dateTime = 4 + dateTime = 4, } - export enum docPropsModifiableElements { title = "dc:title", subject = "dc:subject", diff --git a/src/utils/documentUtils.ts b/src/utils/documentUtils.ts index 7547eee..05df538 100644 --- a/src/utils/documentUtils.ts +++ b/src/utils/documentUtils.ts @@ -55,26 +55,42 @@ const createCellElement = (doc: Document, colIndex: number, rowIndex: number, da const cellData: Element = doc.createElementNS(doc.documentElement.namespaceURI, "v"); updateCellData(dataType, data, cell, cellData); cell.appendChild(cellData); - + return cell; }; const updateCellData = (dataType: number, data: string, cell: Element, cellData: Element) => { - switch(dataType) { - case dataTypes.string: - cell.setAttribute("t", "str"); - break; - case dataTypes.number: - cell.setAttribute("t", "1"); - break; - case dataTypes.dateTime: - cell.setAttribute("s", "1"); - break; - case dataTypes.boolean: - cell.setAttribute("t", "b"); - break; + if (dataType == dataTypes.autodetect) { + dataType = isNaN(Number(data)) ? dataTypes.string : dataTypes.number; + if (dataType == dataTypes.string) { + if (data.toLowerCase() == "true" || data.toLowerCase() == "false") { + dataType = dataTypes.boolean; + } /* else if (!isNaN(Date.parse(data))) { + dataType = dataTypes.dateTime; + }*/ + } + } + switch (dataType) { + case dataTypes.string: + cell.setAttribute("t", "str"); + break; + case dataTypes.number: + cell.setAttribute("t", "1"); + break; + case dataTypes.dateTime: + cell.setAttribute("s", "1"); + break; + case dataTypes.boolean: + cell.setAttribute("t", "b"); + break; } cellData.textContent = data; }; -export default { createOrUpdateProperty, getDocPropsProperties, getCellReference, createCell: createCellElement, getTableReference }; +export default { + createOrUpdateProperty, + getDocPropsProperties, + getCellReference, + createCell: createCellElement, + getTableReference, +}; diff --git a/src/workbookManager.ts b/src/workbookManager.ts index 2c994c0..9ff1b75 100644 --- a/src/workbookManager.ts +++ b/src/workbookManager.ts @@ -5,11 +5,32 @@ import JSZip from "jszip"; import { pqUtils, documentUtils } from "./utils"; import WorkbookTemplate from "./workbookTemplate"; import MashupHandler from "./mashupDocumentParser"; +import { v4 } from "uuid"; import { connectionsXmlPath, queryTablesPath, pivotCachesPath, - docPropsCoreXmlPath, defaults, sharedStringsXmlPath, sheetsXmlPath, emptyQueryMashupErr, blobFileType, application, base64NotFoundErr, textResultType, connectionsNotFoundErr, sharedStringsNotFoundErr, sheetsNotFoundErr, trueValue, falseValue, xmlTextResultType, element, elementAttributes, elementAttributesValues, pivotCachesPathPrefix, emptyValue, queryAndPivotTableNotFoundErr, + docPropsCoreXmlPath, + defaults, + sharedStringsXmlPath, + sheetsXmlPath, + emptyQueryMashupErr, + blobFileType, + application, + base64NotFoundErr, + textResultType, + connectionsNotFoundErr, + sharedStringsNotFoundErr, + sheetsNotFoundErr, + trueValue, + falseValue, + xmlTextResultType, + element, + elementAttributes, + elementAttributesValues, + pivotCachesPathPrefix, + emptyValue, + queryAndPivotTableNotFoundErr, queryTableXmlPath, tableXmlPath, workbookXmlPath, @@ -36,6 +57,23 @@ import TableDataParserFactory from "./TableDataParserFactory"; export class WorkbookManager { private mashupHandler: MashupHandler = new MashupHandler(); + async generateTableWorkbook(initialDataGrid: Grid, docProps?: DocProps): Promise { + const zip: JSZip = await JSZip.loadAsync(WorkbookTemplate.SIMPLE_BLANK_TABLE1_TEMPLATE, { base64: true }); + const tableData: TableData | undefined = await this.parseInitialDataGrid(initialDataGrid); + if (tableData === undefined) { + throw new Error(tableNotFoundErr); + } + + await this.updateDocProps(zip, docProps); + if (tableData) { + await this.addInitialData(zip, tableData); + } + + return await zip.generateAsync({ + type: blobFileType, + mimeType: application, + }); + } async generateSingleQueryWorkbook( query: QueryInfo, initialDataGrid?: Grid, @@ -58,8 +96,8 @@ export class WorkbookManager { throw new Error(templateWithInitialDataErr); } - const tableData: TableData|undefined = await this.parseInitialDataGrid(initialDataGrid); - + const tableData: TableData | undefined = await this.parseInitialDataGrid(initialDataGrid); + return await this.generateSingleQueryWorkbookFromZip(zip, query, docProps, tableData); } @@ -69,12 +107,11 @@ export class WorkbookManager { } const parser: TableDataParser = TableDataParserFactory.createParser(initialDataGrid); - const tableData: TableData|undefined = parser.parseToTableData(initialDataGrid); - + const tableData: TableData | undefined = parser.parseToTableData(initialDataGrid); + return tableData; } - private async generateSingleQueryWorkbookFromZip( zip: JSZip, query: QueryInfo, @@ -89,7 +126,7 @@ export class WorkbookManager { await this.updateSingleQueryAttributes(zip, query.queryName, query.refreshOnOpen); await this.updateDocProps(zip, docProps); if (tableData) { - await this.addSingleQueryInitialData(zip, tableData); + await this.addInitialData(zip, tableData, true); } return await zip.generateAsync({ @@ -99,7 +136,7 @@ export class WorkbookManager { } private async updatePowerQueryDocument(zip: JSZip, queryName: string, queryMashup: string) { - const old_base64: string|undefined = await pqUtils.getBase64(zip); + const old_base64: string | undefined = await pqUtils.getBase64(zip); if (!old_base64) { throw new Error(base64NotFoundErr); @@ -113,9 +150,9 @@ export class WorkbookManager { const { doc, properties } = await documentUtils.getDocPropsProperties(zip); //set auto updated elements - const docPropsAutoUpdatedElementsArr: ("created" | "modified")[] = Object.keys(docPropsAutoUpdatedElements) as Array< - keyof typeof docPropsAutoUpdatedElements - >; + const docPropsAutoUpdatedElementsArr: ("created" | "modified")[] = Object.keys( + docPropsAutoUpdatedElements + ) as Array; const nowTime: string = new Date().toISOString(); @@ -142,7 +179,7 @@ export class WorkbookManager { zip.file(docPropsCoreXmlPath, newDoc); } - private async addSingleQueryInitialData(zip: JSZip, tableData: TableData) { + private async addInitialData(zip: JSZip, tableData: TableData, updateQueryTable = false) { const sheetsXmlString: string | undefined = await zip.file(sheetsXmlPath)?.async(textResultType); if (sheetsXmlString === undefined) { throw new Error(sheetsNotFoundErr); @@ -151,13 +188,24 @@ export class WorkbookManager { const newSheet: string = await this.updateSheetsInitialData(sheetsXmlString, tableData); zip.file(sheetsXmlPath, newSheet); - const queryTableXmlString: string | undefined = await zip.file(queryTableXmlPath)?.async(textResultType); - if (queryTableXmlString === undefined) { - throw new Error(queryTableNotFoundErr); - } + if (updateQueryTable) { + const queryTableXmlString: string | undefined = await zip.file(queryTableXmlPath)?.async(textResultType); + if (queryTableXmlString === undefined) { + throw new Error(queryTableNotFoundErr); + } + + const newQueryTable: string = await this.updateQueryTablesInitialData(queryTableXmlString, tableData); + zip.file(queryTableXmlPath, newQueryTable); - const newQueryTable: string = await this.updateQueryTablesInitialData(queryTableXmlString, tableData); - zip.file(queryTableXmlPath, newQueryTable); + // update defined name + const workbookXmlString: string | undefined = await zip.file(workbookXmlPath)?.async(textResultType); + if (workbookXmlString === undefined) { + throw new Error(sheetsNotFoundErr); + } + + const newWorkbook: string = await this.updateWorkbookInitialData(workbookXmlString, tableData); + zip.file(workbookXmlPath, newWorkbook); + } const tableXmlString: string | undefined = await zip.file(tableXmlPath)?.async(textResultType); if (tableXmlString === undefined) { @@ -167,14 +215,6 @@ export class WorkbookManager { const newTable: string = await this.updateTablesInitialData(tableXmlString, tableData); zip.file(tableXmlPath, newTable); - const workbookXmlString: string | undefined = await zip.file(workbookXmlPath)?.async(textResultType); - if (workbookXmlString === undefined) { - throw new Error(sheetsNotFoundErr); - } - - const newWorkbook: string = await this.updateWorkbookInitialData(workbookXmlString, tableData); - zip.file(workbookXmlPath, newWorkbook); - const styleXmlString: string | undefined = await zip.file(stylesXmlPath)?.async(textResultType); if (styleXmlString === undefined) { throw new Error(sheetsNotFoundErr); @@ -186,21 +226,26 @@ export class WorkbookManager { } zip.file(stylesXmlPath, newStyles); } - - private async updateTablesInitialData(tableXmlString: string, tableData: TableData) { + private async updateTablesInitialData(tableXmlString: string, tableData: TableData, updateQueryTable = false) { const parser: DOMParser = new DOMParser(); const serializer: XMLSerializer = new XMLSerializer(); const tableDoc: Document = parser.parseFromString(tableXmlString, xmlTextResultType); const tableColumns: Element = tableDoc.getElementsByTagName(element.tableColumns)[0]; tableColumns.textContent = ""; - var diffFormatId = 0; + let diffFormatId = 0; tableData.columnMetadata.forEach((col: ColumnMetadata, columnIndex: number) => { - const tableColumn: Element = tableDoc.createElementNS(tableDoc.documentElement.namespaceURI, element.tableColumn); + const tableColumn: Element = tableDoc.createElementNS( + tableDoc.documentElement.namespaceURI, + element.tableColumn + ); tableColumn.setAttribute(elementAttributes.id, (columnIndex + 1).toString()); - tableColumn.setAttribute(elementAttributes.uniqueName, (columnIndex + 1).toString()); + if (updateQueryTable) { + tableColumn.setAttribute(elementAttributes.uniqueName, (columnIndex + 1).toString()); + tableColumn.setAttribute(elementAttributes.queryTableFieldId, (columnIndex + 1).toString()); + } + tableColumn.setAttribute("xr3:uid", "{" + v4().toUpperCase() + "}"); tableColumn.setAttribute(elementAttributes.name, col.name); - tableColumn.setAttribute(elementAttributes.queryTableFieldId, (columnIndex + 1).toString()); if (col.format !== undefined) { tableColumn.setAttribute(elementAttributes.dataDiffFormatId, diffFormatId.toString()); diffFormatId++; @@ -227,7 +272,7 @@ export class WorkbookManager { tableData.data.length + 1 )}`.replace("$", "") ); - + return serializer.serializeToString(tableDoc); } @@ -235,12 +280,12 @@ export class WorkbookManager { const newParser: DOMParser = new DOMParser(); const newSerializer: XMLSerializer = new XMLSerializer(); const workbookDoc: Document = newParser.parseFromString(workbookXmlString, xmlTextResultType); - var definedName: Element = workbookDoc.getElementsByTagName(element.definedName)[0]; + const definedName: Element = workbookDoc.getElementsByTagName(element.definedName)[0]; const prefix = queryName === undefined ? defaults.queryName : queryName; definedName.textContent = prefix + `!$A$1:$${documentUtils.getCellReference(tableData.columnMetadata.length - 1, tableData.data.length + 1)}`; - + return newSerializer.serializeToString(workbookDoc); } @@ -254,8 +299,14 @@ export class WorkbookManager { tableData.columnMetadata.forEach((col: ColumnMetadata) => { if (col.format !== undefined) { // Add new diffrential format to styles - const diffFormat: Element = stylesDoc.createElementNS(stylesDoc.documentElement.namespaceURI, element.differentialFormat); - const numberFormat: Element = stylesDoc.createElementNS(stylesDoc.documentElement.namespaceURI, element.numberFormat); + const diffFormat: Element = stylesDoc.createElementNS( + stylesDoc.documentElement.namespaceURI, + element.differentialFormat + ); + const numberFormat: Element = stylesDoc.createElementNS( + stylesDoc.documentElement.namespaceURI, + element.numberFormat + ); numberFormat.setAttribute(elementAttributes.numberFormatId, dateFormats[col.format].toString()); numberFormat.setAttribute(elementAttributes.formatCode, col.format); diffFormat.appendChild(numberFormat); @@ -264,7 +315,10 @@ export class WorkbookManager { const formatCount = Number.parseInt(differentialFormats.getAttribute(elementAttributes.count)!); differentialFormats.setAttribute(elementAttributes.count, (formatCount + 1).toString()); const cellFormats: Element = stylesDoc.getElementsByTagName(element.cellFormats)[0]; - const cellFormat: Element = stylesDoc.createElementNS(stylesDoc.documentElement.namespaceURI, element.cellFormat); + const cellFormat: Element = stylesDoc.createElementNS( + stylesDoc.documentElement.namespaceURI, + element.cellFormat + ); cellFormat.setAttribute(elementAttributes.numberFormatId, dateFormats[col.format].toString()); cellFormat.setAttribute(elementAttributes.fontId, "0"); cellFormat.setAttribute(elementAttributes.fillId, "0"); @@ -274,9 +328,8 @@ export class WorkbookManager { cellFormats.appendChild(cellFormat); const cellformatCount = Number.parseInt(cellFormats.getAttribute(elementAttributes.count)!); cellFormats.setAttribute(elementAttributes.count, (cellformatCount + 1).toString()); - } + } }); - return newSerializer.serializeToString(stylesDoc); } @@ -301,7 +354,7 @@ export class WorkbookManager { queryTableDoc .getElementsByTagName(element.queryTableRefresh)[0] .setAttribute(elementAttributes.nextId, (tableData.columnMetadata.length + 1).toString()); - + return serializer.serializeToString(queryTableDoc); } @@ -311,7 +364,7 @@ export class WorkbookManager { const sheetsDoc: Document = parser.parseFromString(sheetsXmlString, xmlTextResultType); const sheetData: Element = sheetsDoc.getElementsByTagName(element.sheetData)[0]; sheetData.textContent = ""; - var rowIndex: number = 0; + let rowIndex = 0; const columnRow: Element = sheetsDoc.createElementNS(sheetsDoc.documentElement.namespaceURI, element.row); columnRow.setAttribute(elementAttributes.row, (rowIndex + 1).toString()); columnRow.setAttribute(elementAttributes.spans, "1:" + tableData.columnMetadata.length); @@ -343,41 +396,51 @@ export class WorkbookManager { sheetsDoc .getElementsByTagName(element.dimension)[0] - .setAttribute(elementAttributes.reference, documentUtils.getTableReference(tableData.data[0].length - 1, tableData.data.length)); - + .setAttribute( + elementAttributes.reference, + documentUtils.getTableReference(tableData.data[0].length - 1, tableData.data.length) + ); + return serializer.serializeToString(sheetsDoc); } private async updateSingleQueryAttributes(zip: JSZip, queryName: string, refreshOnOpen: boolean) { // Update connections - const connectionsXmlString: string|undefined = await zip.file(connectionsXmlPath)?.async(textResultType); + const connectionsXmlString: string | undefined = await zip.file(connectionsXmlPath)?.async(textResultType); if (connectionsXmlString === undefined) { throw new Error(connectionsNotFoundErr); - } - - const {connectionId, connectionXmlFileString } = await this.updateConnections(connectionsXmlString, queryName, refreshOnOpen); - zip.file(connectionsXmlPath, connectionXmlFileString ); - + } + + const { connectionId, connectionXmlFileString } = await this.updateConnections( + connectionsXmlString, + queryName, + refreshOnOpen + ); + zip.file(connectionsXmlPath, connectionXmlFileString); + // Update sharedStrings - const sharedStringsXmlString: string|undefined = await zip.file(sharedStringsXmlPath)?.async(textResultType); + const sharedStringsXmlString: string | undefined = await zip.file(sharedStringsXmlPath)?.async(textResultType); if (sharedStringsXmlString === undefined) { throw new Error(sharedStringsNotFoundErr); } - - const {sharedStringIndex, newSharedStrings} = await this.updateSharedStrings(sharedStringsXmlString, queryName); + + const { sharedStringIndex, newSharedStrings } = await this.updateSharedStrings( + sharedStringsXmlString, + queryName + ); zip.file(sharedStringsXmlPath, newSharedStrings); - + // Update sheet - const sheetsXmlString: string|undefined = await zip.file(sheetsXmlPath)?.async(textResultType); + const sheetsXmlString: string | undefined = await zip.file(sheetsXmlPath)?.async(textResultType); if (sheetsXmlString === undefined) { throw new Error(sheetsNotFoundErr); } const worksheetString: string = await this.updateWorksheet(sheetsXmlString, sharedStringIndex.toString()); zip.file(sheetsXmlPath, worksheetString); - + // Update tables - await this.updatePivotTablesandQueryTables(zip, queryName, refreshOnOpen, connectionId!); + await this.updatePivotTablesandQueryTables(zip, queryName, refreshOnOpen, connectionId!); } private async updateConnections(connectionsXmlString: string, queryName: string, refreshOnOpen: boolean) { @@ -385,23 +448,28 @@ export class WorkbookManager { const serializer: XMLSerializer = new XMLSerializer(); const refreshOnLoadValue: string = refreshOnOpen ? trueValue : falseValue; const connectionsDoc: Document = parser.parseFromString(connectionsXmlString, xmlTextResultType); - const connectionsProperties: HTMLCollectionOf = connectionsDoc.getElementsByTagName(element.databaseProperties); + const connectionsProperties: HTMLCollectionOf = connectionsDoc.getElementsByTagName( + element.databaseProperties + ); const dbPr: Element = connectionsProperties[0]; dbPr.setAttribute(elementAttributes.refreshOnLoad, refreshOnLoadValue); - + // Update query details to match queryName dbPr.parentElement?.setAttribute(elementAttributes.name, elementAttributesValues.connectionName(queryName)); - dbPr.parentElement?.setAttribute(elementAttributes.description, elementAttributesValues.connectionDescription(queryName)); + dbPr.parentElement?.setAttribute( + elementAttributes.description, + elementAttributesValues.connectionDescription(queryName) + ); dbPr.setAttribute(elementAttributes.connection, elementAttributesValues.connection(queryName)); - dbPr.setAttribute(elementAttributes.command,elementAttributesValues.connectionCommand(queryName)); + dbPr.setAttribute(elementAttributes.command, elementAttributesValues.connectionCommand(queryName)); const connectionId: string | null | undefined = dbPr.parentElement?.getAttribute(elementAttributes.id); - const connectionXmlFileString: string = serializer.serializeToString(connectionsDoc); + const connectionXmlFileString: string = serializer.serializeToString(connectionsDoc); if (connectionId === null) { throw new Error(connectionsNotFoundErr); } - return {connectionId, connectionXmlFileString}; + return { connectionId, connectionXmlFileString }; } private async updateSharedStrings(sharedStringsXmlString: string, queryName: string) { @@ -411,10 +479,10 @@ export class WorkbookManager { const sharedStringsTable: Element = sharedStringsDoc.getElementsByTagName(element.sharedStringTable)[0]; if (!sharedStringsTable) { throw new Error(sharedStringsNotFoundErr); - } + } const textElementCollection: HTMLCollectionOf = sharedStringsDoc.getElementsByTagName(element.text); - let textElement: Element|null = null; + let textElement: Element | null = null; let sharedStringIndex: number = textElementCollection.length; if (textElementCollection && textElementCollection.length) { for (let i = 0; i < textElementCollection.length; i++) { @@ -422,47 +490,58 @@ export class WorkbookManager { textElement = textElementCollection[i]; sharedStringIndex = i + 1; break; - } + } } } - if (textElement === null) { + if (textElement === null) { if (sharedStringsDoc.documentElement.namespaceURI) { - textElement = sharedStringsDoc.createElementNS(sharedStringsDoc.documentElement.namespaceURI, element.text); + textElement = sharedStringsDoc.createElementNS( + sharedStringsDoc.documentElement.namespaceURI, + element.text + ); textElement.textContent = queryName; - const siElement: Element = sharedStringsDoc.createElementNS(sharedStringsDoc.documentElement.namespaceURI, element.sharedStringItem); + const siElement: Element = sharedStringsDoc.createElementNS( + sharedStringsDoc.documentElement.namespaceURI, + element.sharedStringItem + ); siElement.appendChild(textElement); sharedStringsDoc.getElementsByTagName(element.sharedStringTable)[0].appendChild(siElement); } - const value: string|null = sharedStringsTable.getAttribute(elementAttributes.count); + const value: string | null = sharedStringsTable.getAttribute(elementAttributes.count); if (value) { - sharedStringsTable.setAttribute(elementAttributes.count, (parseInt(value)+1).toString()); + sharedStringsTable.setAttribute(elementAttributes.count, (parseInt(value) + 1).toString()); } - const uniqueValue: string|null = sharedStringsTable.getAttribute(elementAttributes.uniqueCount); + const uniqueValue: string | null = sharedStringsTable.getAttribute(elementAttributes.uniqueCount); if (uniqueValue) { - sharedStringsTable.setAttribute(elementAttributes.uniqueCount, (parseInt(uniqueValue)+1).toString()); + sharedStringsTable.setAttribute(elementAttributes.uniqueCount, (parseInt(uniqueValue) + 1).toString()); } } const newSharedStrings: string = serializer.serializeToString(sharedStringsDoc); - - return {sharedStringIndex, newSharedStrings}; -} - + + return { sharedStringIndex, newSharedStrings }; + } + private async updateWorksheet(sheetsXmlString: string, sharedStringIndex: string) { const parser: DOMParser = new DOMParser(); const serializer: XMLSerializer = new XMLSerializer(); const sheetsDoc: Document = parser.parseFromString(sheetsXmlString, xmlTextResultType); sheetsDoc.getElementsByTagName(element.cellValue)[0].innerHTML = sharedStringIndex.toString(); const newSheet: string = serializer.serializeToString(sheetsDoc); - + return newSheet; } - private async updatePivotTablesandQueryTables(zip: JSZip, queryName: string, refreshOnOpen: boolean, connectionId: string) { + private async updatePivotTablesandQueryTables( + zip: JSZip, + queryName: string, + refreshOnOpen: boolean, + connectionId: string + ) { // Find Query Table - let found: boolean = false; + let found = false; const queryTablePromises: Promise<{ path: string; queryTableXmlString: string; @@ -479,16 +558,20 @@ export class WorkbookManager { })() ); }); - + (await Promise.all(queryTablePromises)).forEach(({ path, queryTableXmlString }) => { - const {isQueryTableUpdated, newQueryTable} = this.updateQueryTable(queryTableXmlString, connectionId, refreshOnOpen); + const { isQueryTableUpdated, newQueryTable } = this.updateQueryTable( + queryTableXmlString, + connectionId, + refreshOnOpen + ); zip.file(queryTablesPath + path, newQueryTable); if (isQueryTableUpdated) { found = true; } }); if (found) { - return; + return; } // Find Pivot Table @@ -512,7 +595,11 @@ export class WorkbookManager { } }); (await Promise.all(pivotCachePromises)).forEach(({ path, pivotCacheXmlString }) => { - const {isPivotTableUpdated, newPivotTable} = this.updatePivotTable(pivotCacheXmlString, connectionId, refreshOnOpen); + const { isPivotTableUpdated, newPivotTable } = this.updatePivotTable( + pivotCacheXmlString, + connectionId, + refreshOnOpen + ); zip.file(pivotCachesPath + path, newPivotTable); if (isPivotTableUpdated) { found = true; @@ -525,29 +612,29 @@ export class WorkbookManager { private updateQueryTable(tableXmlString: string, connectionId: string, refreshOnOpen: boolean) { const refreshOnLoadValue: string = refreshOnOpen ? trueValue : falseValue; - let isQueryTableUpdated: boolean = false; + let isQueryTableUpdated = false; const parser: DOMParser = new DOMParser(); const serializer: XMLSerializer = new XMLSerializer(); const queryTableDoc: Document = parser.parseFromString(tableXmlString, xmlTextResultType); const queryTable: Element = queryTableDoc.getElementsByTagName(element.queryTable)[0]; - var newQueryTable: string = emptyValue; + let newQueryTable = emptyValue; if (queryTable.getAttribute(elementAttributes.connectionId) == connectionId) { queryTable.setAttribute(elementAttributes.refreshOnLoad, refreshOnLoadValue); newQueryTable = serializer.serializeToString(queryTableDoc); isQueryTableUpdated = true; } - return {isQueryTableUpdated, newQueryTable}; + return { isQueryTableUpdated, newQueryTable }; } private updatePivotTable(tableXmlString: string, connectionId: string, refreshOnOpen: boolean) { const refreshOnLoadValue: string = refreshOnOpen ? trueValue : falseValue; - let isPivotTableUpdated: boolean = false; + let isPivotTableUpdated = false; const parser: DOMParser = new DOMParser(); const serializer: XMLSerializer = new XMLSerializer(); const pivotCacheDoc: Document = parser.parseFromString(tableXmlString, xmlTextResultType); let cacheSource: Element = pivotCacheDoc.getElementsByTagName(element.cacheSource)[0]; - var newPivotTable: string = emptyValue; + let newPivotTable = emptyValue; if (cacheSource.getAttribute(elementAttributes.connectionId) == connectionId) { cacheSource = cacheSource.parentElement!; cacheSource.setAttribute(elementAttributes.refreshOnLoad, refreshOnLoadValue); @@ -555,7 +642,6 @@ export class WorkbookManager { isPivotTableUpdated = true; } - return {isPivotTableUpdated, newPivotTable}; + return { isPivotTableUpdated, newPivotTable }; } - -} +} diff --git a/src/workbookTemplate.ts b/src/workbookTemplate.ts index f05374e..152f2c1 100644 --- a/src/workbookTemplate.ts +++ b/src/workbookTemplate.ts @@ -2,6 +2,8 @@ // Licensed under the MIT license. export default class WorkbookTemplate { + public static readonly SIMPLE_BLANK_TABLE1_TEMPLATE = + "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"; public static readonly SIMPLE_QUERY_WORKBOOK_TEMPLATE = "UEsDBAoAAAAAAAAAIQCHQG94swcAALMHAAATAAAAW0NvbnRlbnRfVHlwZXNdLnhtbDw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04IiBzdGFuZGFsb25lPSJ5ZXMiPz4NCjxUeXBlcyB4bWxucz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL3BhY2thZ2UvMjAwNi9jb250ZW50LXR5cGVzIj48RGVmYXVsdCBFeHRlbnNpb249InJlbHMiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtcGFja2FnZS5yZWxhdGlvbnNoaXBzK3htbCIvPjxEZWZhdWx0IEV4dGVuc2lvbj0ieG1sIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24veG1sIi8+PE92ZXJyaWRlIFBhcnROYW1lPSIveGwvd29ya2Jvb2sueG1sIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24vdm5kLm9wZW54bWxmb3JtYXRzLW9mZmljZWRvY3VtZW50LnNwcmVhZHNoZWV0bWwuc2hlZXQubWFpbit4bWwiLz48T3ZlcnJpZGUgUGFydE5hbWU9Ii94bC93b3Jrc2hlZXRzL3NoZWV0MS54bWwiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQuc3ByZWFkc2hlZXRtbC53b3Jrc2hlZXQreG1sIi8+PE92ZXJyaWRlIFBhcnROYW1lPSIveGwvd29ya3NoZWV0cy9zaGVldDIueG1sIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24vdm5kLm9wZW54bWxmb3JtYXRzLW9mZmljZWRvY3VtZW50LnNwcmVhZHNoZWV0bWwud29ya3NoZWV0K3htbCIvPjxPdmVycmlkZSBQYXJ0TmFtZT0iL3hsL3RoZW1lL3RoZW1lMS54bWwiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQudGhlbWUreG1sIi8+PE92ZXJyaWRlIFBhcnROYW1lPSIveGwvY29ubmVjdGlvbnMueG1sIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24vdm5kLm9wZW54bWxmb3JtYXRzLW9mZmljZWRvY3VtZW50LnNwcmVhZHNoZWV0bWwuY29ubmVjdGlvbnMreG1sIi8+PE92ZXJyaWRlIFBhcnROYW1lPSIveGwvc3R5bGVzLnhtbCIgQ29udGVudFR5cGU9ImFwcGxpY2F0aW9uL3ZuZC5vcGVueG1sZm9ybWF0cy1vZmZpY2Vkb2N1bWVudC5zcHJlYWRzaGVldG1sLnN0eWxlcyt4bWwiLz48T3ZlcnJpZGUgUGFydE5hbWU9Ii94bC9zaGFyZWRTdHJpbmdzLnhtbCIgQ29udGVudFR5cGU9ImFwcGxpY2F0aW9uL3ZuZC5vcGVueG1sZm9ybWF0cy1vZmZpY2Vkb2N1bWVudC5zcHJlYWRzaGVldG1sLnNoYXJlZFN0cmluZ3MreG1sIi8+PE92ZXJyaWRlIFBhcnROYW1lPSIveGwvdGFibGVzL3RhYmxlMS54bWwiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQuc3ByZWFkc2hlZXRtbC50YWJsZSt4bWwiLz48T3ZlcnJpZGUgUGFydE5hbWU9Ii94bC9xdWVyeVRhYmxlcy9xdWVyeVRhYmxlMS54bWwiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQuc3ByZWFkc2hlZXRtbC5xdWVyeVRhYmxlK3htbCIvPjxPdmVycmlkZSBQYXJ0TmFtZT0iL2N1c3RvbVhtbC9pdGVtUHJvcHMxLnhtbCIgQ29udGVudFR5cGU9ImFwcGxpY2F0aW9uL3ZuZC5vcGVueG1sZm9ybWF0cy1vZmZpY2Vkb2N1bWVudC5jdXN0b21YbWxQcm9wZXJ0aWVzK3htbCIvPjxPdmVycmlkZSBQYXJ0TmFtZT0iL2N1c3RvbVhtbC9pdGVtUHJvcHMyLnhtbCIgQ29udGVudFR5cGU9ImFwcGxpY2F0aW9uL3ZuZC5vcGVueG1sZm9ybWF0cy1vZmZpY2Vkb2N1bWVudC5jdXN0b21YbWxQcm9wZXJ0aWVzK3htbCIvPjxPdmVycmlkZSBQYXJ0TmFtZT0iL2RvY1Byb3BzL2NvcmUueG1sIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24vdm5kLm9wZW54bWxmb3JtYXRzLXBhY2thZ2UuY29yZS1wcm9wZXJ0aWVzK3htbCIvPjxPdmVycmlkZSBQYXJ0TmFtZT0iL2RvY1Byb3BzL2FwcC54bWwiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQuZXh0ZW5kZWQtcHJvcGVydGllcyt4bWwiLz48L1R5cGVzPlBLAwQKAAAAAAAAACEAtVUwI0wCAABMAgAACwAAAF9yZWxzLy5yZWxzPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/Pg0KPFJlbGF0aW9uc2hpcHMgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9wYWNrYWdlLzIwMDYvcmVsYXRpb25zaGlwcyI+PFJlbGF0aW9uc2hpcCBJZD0icklkMyIgVHlwZT0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvcmVsYXRpb25zaGlwcy9leHRlbmRlZC1wcm9wZXJ0aWVzIiBUYXJnZXQ9ImRvY1Byb3BzL2FwcC54bWwiLz48UmVsYXRpb25zaGlwIElkPSJySWQyIiBUeXBlPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvcGFja2FnZS8yMDA2L3JlbGF0aW9uc2hpcHMvbWV0YWRhdGEvY29yZS1wcm9wZXJ0aWVzIiBUYXJnZXQ9ImRvY1Byb3BzL2NvcmUueG1sIi8+PFJlbGF0aW9uc2hpcCBJZD0icklkMSIgVHlwZT0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvcmVsYXRpb25zaGlwcy9vZmZpY2VEb2N1bWVudCIgVGFyZ2V0PSJ4bC93b3JrYm9vay54bWwiLz48L1JlbGF0aW9uc2hpcHM+UEsDBAoAAAAAAAAAIQA0fsZl/ggAAP4IAAAPAAAAeGwvd29ya2Jvb2sueG1sPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/Pg0KPHdvcmtib29rIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvc3ByZWFkc2hlZXRtbC8yMDA2L21haW4iIHhtbG5zOnI9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZpY2VEb2N1bWVudC8yMDA2L3JlbGF0aW9uc2hpcHMiIHhtbG5zOm1jPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvbWFya3VwLWNvbXBhdGliaWxpdHkvMjAwNiIgbWM6SWdub3JhYmxlPSJ4MTUgeHIgeHI2IHhyMTAgeHIyIiB4bWxuczp4MTU9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAxMC8xMS9tYWluIiB4bWxuczp4cj0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9vZmZpY2Uvc3ByZWFkc2hlZXRtbC8yMDE0L3JldmlzaW9uIiB4bWxuczp4cjY9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAxNi9yZXZpc2lvbjYiIHhtbG5zOnhyMTA9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAxNi9yZXZpc2lvbjEwIiB4bWxuczp4cjI9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAxNS9yZXZpc2lvbjIiPjxmaWxlVmVyc2lvbiBhcHBOYW1lPSJ4bCIgbGFzdEVkaXRlZD0iNyIgbG93ZXN0RWRpdGVkPSI3IiBydXBCdWlsZD0iMjQ3MjkiLz48d29ya2Jvb2tQciBjb2RlTmFtZT0iVGhpc1dvcmtib29rIiBkZWZhdWx0VGhlbWVWZXJzaW9uPSIxNjY5MjUiLz48bWM6QWx0ZXJuYXRlQ29udGVudCB4bWxuczptYz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL21hcmt1cC1jb21wYXRpYmlsaXR5LzIwMDYiPjxtYzpDaG9pY2UgUmVxdWlyZXM9IngxNSI+PHgxNWFjOmFic1BhdGggdXJsPSJDOlxVc2Vyc1x2LWFobWFkc2JlaWhcRGVza3RvcFwiIHhtbG5zOngxNWFjPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL29mZmljZS9zcHJlYWRzaGVldG1sLzIwMTAvMTEvYWMiLz48L21jOkNob2ljZT48L21jOkFsdGVybmF0ZUNvbnRlbnQ+PHhyOnJldmlzaW9uUHRyIHJldklETGFzdFNhdmU9IjAiIGRvY3VtZW50SWQ9IjEzX25jcjoxX3s5M0VGMjAxQy03ODU2LTRCNjAtOTRENC02NUREQjhGM0YxNkF9IiB4cjY6Y29hdXRoVmVyc2lvbkxhc3Q9IjQ3IiB4cjY6Y29hdXRoVmVyc2lvbk1heD0iNDciIHhyMTA6dWlkTGFzdFNhdmU9InswMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB9Ii8+PGJvb2tWaWV3cz48d29ya2Jvb2tWaWV3IHhXaW5kb3c9IjI4NjgwIiB5V2luZG93PSItMTIwIiB3aW5kb3dXaWR0aD0iMjkwNDAiIHdpbmRvd0hlaWdodD0iMTU5OTAiIHhyMjp1aWQ9IntEQjkxNUNCOS04REQ5LTQ5MkEtQTQ3MS1DNjFFNjEyMDAxMTN9Ii8+PC9ib29rVmlld3M+PHNoZWV0cz48c2hlZXQgbmFtZT0iUXVlcnkxIiBzaGVldElkPSIyIiByOmlkPSJySWQxIi8+PHNoZWV0IG5hbWU9IlNoZWV0MSIgc2hlZXRJZD0iMSIgcjppZD0icklkMiIvPjwvc2hlZXRzPjxkZWZpbmVkTmFtZXM+PGRlZmluZWROYW1lIG5hbWU9IkV4dGVybmFsRGF0YV8xIiBsb2NhbFNoZWV0SWQ9IjAiIGhpZGRlbj0iMSI+UXVlcnkxISRBJDE6JEEkMjwvZGVmaW5lZE5hbWU+PC9kZWZpbmVkTmFtZXM+PGNhbGNQciBjYWxjSWQ9IjE5MTAyOSIvPjxleHRMc3Q+PGV4dCB1cmk9InsxNDBBNzA5NC0wRTM1LTQ4OTItODQzMi1DNEQyRTU3RURFQjV9IiB4bWxuczp4MTU9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAxMC8xMS9tYWluIj48eDE1Ondvcmtib29rUHIgY2hhcnRUcmFja2luZ1JlZkJhc2U9IjEiLz48L2V4dD48ZXh0IHVyaT0ie0I1OEIwMzkyLTRGMUYtNDE5MC1CQjY0LTVERjM1NzFEQ0U1Rn0iIHhtbG5zOnhjYWxjZj0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9vZmZpY2Uvc3ByZWFkc2hlZXRtbC8yMDE4L2NhbGNmZWF0dXJlcyI+PHhjYWxjZjpjYWxjRmVhdHVyZXM+PHhjYWxjZjpmZWF0dXJlIG5hbWU9Im1pY3Jvc29mdC5jb206UkQiLz48eGNhbGNmOmZlYXR1cmUgbmFtZT0ibWljcm9zb2Z0LmNvbTpGViIvPjx4Y2FsY2Y6ZmVhdHVyZSBuYW1lPSJtaWNyb3NvZnQuY29tOkxFVF9XRiIvPjx4Y2FsY2Y6ZmVhdHVyZSBuYW1lPSJtaWNyb3NvZnQuY29tOkxBTUJEQV9XRiIvPjwveGNhbGNmOmNhbGNGZWF0dXJlcz48L2V4dD48L2V4dExzdD48L3dvcmtib29rPlBLAwQKAAAAAAAAACEAhuCs6+wEAADsBAAAGgAAAHhsL19yZWxzL3dvcmtib29rLnhtbC5yZWxzPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/Pg0KPFJlbGF0aW9uc2hpcHMgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9wYWNrYWdlLzIwMDYvcmVsYXRpb25zaGlwcyI+PFJlbGF0aW9uc2hpcCBJZD0icklkOCIgVHlwZT0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvcmVsYXRpb25zaGlwcy9jdXN0b21YbWwiIFRhcmdldD0iLi4vY3VzdG9tWG1sL2l0ZW0yLnhtbCIvPjxSZWxhdGlvbnNoaXAgSWQ9InJJZDMiIFR5cGU9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZpY2VEb2N1bWVudC8yMDA2L3JlbGF0aW9uc2hpcHMvdGhlbWUiIFRhcmdldD0idGhlbWUvdGhlbWUxLnhtbCIvPjxSZWxhdGlvbnNoaXAgSWQ9InJJZDciIFR5cGU9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZpY2VEb2N1bWVudC8yMDA2L3JlbGF0aW9uc2hpcHMvY3VzdG9tWG1sIiBUYXJnZXQ9Ii4uL2N1c3RvbVhtbC9pdGVtMS54bWwiLz48UmVsYXRpb25zaGlwIElkPSJySWQyIiBUeXBlPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9yZWxhdGlvbnNoaXBzL3dvcmtzaGVldCIgVGFyZ2V0PSJ3b3Jrc2hlZXRzL3NoZWV0Mi54bWwiLz48UmVsYXRpb25zaGlwIElkPSJySWQxIiBUeXBlPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9yZWxhdGlvbnNoaXBzL3dvcmtzaGVldCIgVGFyZ2V0PSJ3b3Jrc2hlZXRzL3NoZWV0MS54bWwiLz48UmVsYXRpb25zaGlwIElkPSJySWQ2IiBUeXBlPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9yZWxhdGlvbnNoaXBzL3NoYXJlZFN0cmluZ3MiIFRhcmdldD0ic2hhcmVkU3RyaW5ncy54bWwiLz48UmVsYXRpb25zaGlwIElkPSJySWQ1IiBUeXBlPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9yZWxhdGlvbnNoaXBzL3N0eWxlcyIgVGFyZ2V0PSJzdHlsZXMueG1sIi8+PFJlbGF0aW9uc2hpcCBJZD0icklkNCIgVHlwZT0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvcmVsYXRpb25zaGlwcy9jb25uZWN0aW9ucyIgVGFyZ2V0PSJjb25uZWN0aW9ucy54bWwiLz48L1JlbGF0aW9uc2hpcHM+UEsDBAoAAAAAAAAAIQC9v4Zi+QQAAPkEAAAYAAAAeGwvd29ya3NoZWV0cy9zaGVldDEueG1sPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/Pg0KPHdvcmtzaGVldCB4bWxucz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL3NwcmVhZHNoZWV0bWwvMjAwNi9tYWluIiB4bWxuczpyPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9yZWxhdGlvbnNoaXBzIiB4bWxuczptYz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL21hcmt1cC1jb21wYXRpYmlsaXR5LzIwMDYiIG1jOklnbm9yYWJsZT0ieDE0YWMgeHIgeHIyIHhyMyIgeG1sbnM6eDE0YWM9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAwOS85L2FjIiB4bWxuczp4cj0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9vZmZpY2Uvc3ByZWFkc2hlZXRtbC8yMDE0L3JldmlzaW9uIiB4bWxuczp4cjI9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAxNS9yZXZpc2lvbjIiIHhtbG5zOnhyMz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9vZmZpY2Uvc3ByZWFkc2hlZXRtbC8yMDE2L3JldmlzaW9uMyIgeHI6dWlkPSJ7RURGMDEzOEUtRDIxNi00Q0QxLThFRkEtMTM5NkExQkI0NDc4fSI+PHNoZWV0UHIgY29kZU5hbWU9IlNoZWV0MSIvPjxkaW1lbnNpb24gcmVmPSJBMTpBMiIvPjxzaGVldFZpZXdzPjxzaGVldFZpZXcgdGFiU2VsZWN0ZWQ9IjEiIHdvcmtib29rVmlld0lkPSIwIi8+PC9zaGVldFZpZXdzPjxzaGVldEZvcm1hdFByIGRlZmF1bHRSb3dIZWlnaHQ9IjE0LjQiIHgxNGFjOmR5RGVzY2VudD0iMC4zIi8+PGNvbHM+PGNvbCBtaW49IjEiIG1heD0iMSIgd2lkdGg9IjkuNjY0MDYyNSIgYmVzdEZpdD0iMSIgY3VzdG9tV2lkdGg9IjEiLz48L2NvbHM+PHNoZWV0RGF0YT48cm93IHI9IjEiIHNwYW5zPSIxOjEiIHgxNGFjOmR5RGVzY2VudD0iMC4zIj48YyByPSJBMSIgdD0icyI+PHY+MDwvdj48L2M+PC9yb3c+PHJvdyByPSIyIiBzcGFucz0iMToxIiB4MTRhYzpkeURlc2NlbnQ9IjAuMyI+PGMgcj0iQTIiIHQ9InMiPjx2PjE8L3Y+PC9jPjwvcm93Pjwvc2hlZXREYXRhPjxwYWdlTWFyZ2lucyBsZWZ0PSIwLjciIHJpZ2h0PSIwLjciIHRvcD0iMC43NSIgYm90dG9tPSIwLjc1IiBoZWFkZXI9IjAuMyIgZm9vdGVyPSIwLjMiLz48dGFibGVQYXJ0cyBjb3VudD0iMSI+PHRhYmxlUGFydCByOmlkPSJySWQxIi8+PC90YWJsZVBhcnRzPjwvd29ya3NoZWV0PlBLAwQKAAAAAAAAACEAOnp/VrEDAACxAwAAGAAAAHhsL3dvcmtzaGVldHMvc2hlZXQyLnhtbDw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04IiBzdGFuZGFsb25lPSJ5ZXMiPz4NCjx3b3Jrc2hlZXQgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9zcHJlYWRzaGVldG1sLzIwMDYvbWFpbiIgeG1sbnM6cj0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvcmVsYXRpb25zaGlwcyIgeG1sbnM6bWM9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9tYXJrdXAtY29tcGF0aWJpbGl0eS8yMDA2IiBtYzpJZ25vcmFibGU9IngxNGFjIHhyIHhyMiB4cjMiIHhtbG5zOngxNGFjPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL29mZmljZS9zcHJlYWRzaGVldG1sLzIwMDkvOS9hYyIgeG1sbnM6eHI9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAxNC9yZXZpc2lvbiIgeG1sbnM6eHIyPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL29mZmljZS9zcHJlYWRzaGVldG1sLzIwMTUvcmV2aXNpb24yIiB4bWxuczp4cjM9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAxNi9yZXZpc2lvbjMiIHhyOnVpZD0iezA1MzFEOEMwLURFRUItNDMxMy05RTA2LTM1NzAxOTA0Mzk1N30iPjxzaGVldFByIGNvZGVOYW1lPSJTaGVldDIiLz48ZGltZW5zaW9uIHJlZj0iQTEiLz48c2hlZXRWaWV3cz48c2hlZXRWaWV3IHdvcmtib29rVmlld0lkPSIwIi8+PC9zaGVldFZpZXdzPjxzaGVldEZvcm1hdFByIGRlZmF1bHRSb3dIZWlnaHQ9IjE0LjQiIHgxNGFjOmR5RGVzY2VudD0iMC4zIi8+PHNoZWV0RGF0YS8+PHBhZ2VNYXJnaW5zIGxlZnQ9IjAuNyIgcmlnaHQ9IjAuNyIgdG9wPSIwLjc1IiBib3R0b209IjAuNzUiIGhlYWRlcj0iMC4zIiBmb290ZXI9IjAuMyIvPjwvd29ya3NoZWV0PlBLAwQKAAAAAAAAACEAwRcQvsYgAADGIAAAEwAAAHhsL3RoZW1lL3RoZW1lMS54bWw8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJVVEYtOCIgc3RhbmRhbG9uZT0ieWVzIj8+DQo8YTp0aGVtZSB4bWxuczphPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvZHJhd2luZ21sLzIwMDYvbWFpbiIgbmFtZT0iT2ZmaWNlIFRoZW1lIj48YTp0aGVtZUVsZW1lbnRzPjxhOmNsclNjaGVtZSBuYW1lPSJPZmZpY2UiPjxhOmRrMT48YTpzeXNDbHIgdmFsPSJ3aW5kb3dUZXh0IiBsYXN0Q2xyPSIwMDAwMDAiLz48L2E6ZGsxPjxhOmx0MT48YTpzeXNDbHIgdmFsPSJ3aW5kb3ciIGxhc3RDbHI9IkZGRkZGRiIvPjwvYTpsdDE+PGE6ZGsyPjxhOnNyZ2JDbHIgdmFsPSI0NDU0NkEiLz48L2E6ZGsyPjxhOmx0Mj48YTpzcmdiQ2xyIHZhbD0iRTdFNkU2Ii8+PC9hOmx0Mj48YTphY2NlbnQxPjxhOnNyZ2JDbHIgdmFsPSI0NDcyQzQiLz48L2E6YWNjZW50MT48YTphY2NlbnQyPjxhOnNyZ2JDbHIgdmFsPSJFRDdEMzEiLz48L2E6YWNjZW50Mj48YTphY2NlbnQzPjxhOnNyZ2JDbHIgdmFsPSJBNUE1QTUiLz48L2E6YWNjZW50Mz48YTphY2NlbnQ0PjxhOnNyZ2JDbHIgdmFsPSJGRkMwMDAiLz48L2E6YWNjZW50ND48YTphY2NlbnQ1PjxhOnNyZ2JDbHIgdmFsPSI1QjlCRDUiLz48L2E6YWNjZW50NT48YTphY2NlbnQ2PjxhOnNyZ2JDbHIgdmFsPSI3MEFENDciLz48L2E6YWNjZW50Nj48YTpobGluaz48YTpzcmdiQ2xyIHZhbD0iMDU2M0MxIi8+PC9hOmhsaW5rPjxhOmZvbEhsaW5rPjxhOnNyZ2JDbHIgdmFsPSI5NTRGNzIiLz48L2E6Zm9sSGxpbms+PC9hOmNsclNjaGVtZT48YTpmb250U2NoZW1lIG5hbWU9Ik9mZmljZSI+PGE6bWFqb3JGb250PjxhOmxhdGluIHR5cGVmYWNlPSJDYWxpYnJpIExpZ2h0IiBwYW5vc2U9IjAyMEYwMzAyMDIwMjA0MDMwMjA0Ii8+PGE6ZWEgdHlwZWZhY2U9IiIvPjxhOmNzIHR5cGVmYWNlPSIiLz48YTpmb250IHNjcmlwdD0iSnBhbiIgdHlwZWZhY2U9Iua4uOOCtOOCt+ODg+OCryBMaWdodCIvPjxhOmZvbnQgc2NyaXB0PSJIYW5nIiB0eXBlZmFjZT0i66eR7J2AIOqzoOuUlSIvPjxhOmZvbnQgc2NyaXB0PSJIYW5zIiB0eXBlZmFjZT0i562J57q/IExpZ2h0Ii8+PGE6Zm9udCBzY3JpcHQ9IkhhbnQiIHR5cGVmYWNlPSLmlrDntLDmmI7pq5QiLz48YTpmb250IHNjcmlwdD0iQXJhYiIgdHlwZWZhY2U9IlRpbWVzIE5ldyBSb21hbiIvPjxhOmZvbnQgc2NyaXB0PSJIZWJyIiB0eXBlZmFjZT0iVGltZXMgTmV3IFJvbWFuIi8+PGE6Zm9udCBzY3JpcHQ9IlRoYWkiIHR5cGVmYWNlPSJUYWhvbWEiLz48YTpmb250IHNjcmlwdD0iRXRoaSIgdHlwZWZhY2U9Ik55YWxhIi8+PGE6Zm9udCBzY3JpcHQ9IkJlbmciIHR5cGVmYWNlPSJWcmluZGEiLz48YTpmb250IHNjcmlwdD0iR3VqciIgdHlwZWZhY2U9IlNocnV0aSIvPjxhOmZvbnQgc2NyaXB0PSJLaG1yIiB0eXBlZmFjZT0iTW9vbEJvcmFuIi8+PGE6Zm9udCBzY3JpcHQ9IktuZGEiIHR5cGVmYWNlPSJUdW5nYSIvPjxhOmZvbnQgc2NyaXB0PSJHdXJ1IiB0eXBlZmFjZT0iUmFhdmkiLz48YTpmb250IHNjcmlwdD0iQ2FucyIgdHlwZWZhY2U9IkV1cGhlbWlhIi8+PGE6Zm9udCBzY3JpcHQ9IkNoZXIiIHR5cGVmYWNlPSJQbGFudGFnZW5ldCBDaGVyb2tlZSIvPjxhOmZvbnQgc2NyaXB0PSJZaWlpIiB0eXBlZmFjZT0iTWljcm9zb2Z0IFlpIEJhaXRpIi8+PGE6Zm9udCBzY3JpcHQ9IlRpYnQiIHR5cGVmYWNlPSJNaWNyb3NvZnQgSGltYWxheWEiLz48YTpmb250IHNjcmlwdD0iVGhhYSIgdHlwZWZhY2U9Ik1WIEJvbGkiLz48YTpmb250IHNjcmlwdD0iRGV2YSIgdHlwZWZhY2U9Ik1hbmdhbCIvPjxhOmZvbnQgc2NyaXB0PSJUZWx1IiB0eXBlZmFjZT0iR2F1dGFtaSIvPjxhOmZvbnQgc2NyaXB0PSJUYW1sIiB0eXBlZmFjZT0iTGF0aGEiLz48YTpmb250IHNjcmlwdD0iU3lyYyIgdHlwZWZhY2U9IkVzdHJhbmdlbG8gRWRlc3NhIi8+PGE6Zm9udCBzY3JpcHQ9Ik9yeWEiIHR5cGVmYWNlPSJLYWxpbmdhIi8+PGE6Zm9udCBzY3JpcHQ9Ik1seW0iIHR5cGVmYWNlPSJLYXJ0aWthIi8+PGE6Zm9udCBzY3JpcHQ9Ikxhb28iIHR5cGVmYWNlPSJEb2tDaGFtcGEiLz48YTpmb250IHNjcmlwdD0iU2luaCIgdHlwZWZhY2U9Iklza29vbGEgUG90YSIvPjxhOmZvbnQgc2NyaXB0PSJNb25nIiB0eXBlZmFjZT0iTW9uZ29saWFuIEJhaXRpIi8+PGE6Zm9udCBzY3JpcHQ9IlZpZXQiIHR5cGVmYWNlPSJUaW1lcyBOZXcgUm9tYW4iLz48YTpmb250IHNjcmlwdD0iVWlnaCIgdHlwZWZhY2U9Ik1pY3Jvc29mdCBVaWdodXIiLz48YTpmb250IHNjcmlwdD0iR2VvciIgdHlwZWZhY2U9IlN5bGZhZW4iLz48YTpmb250IHNjcmlwdD0iQXJtbiIgdHlwZWZhY2U9IkFyaWFsIi8+PGE6Zm9udCBzY3JpcHQ9IkJ1Z2kiIHR5cGVmYWNlPSJMZWVsYXdhZGVlIFVJIi8+PGE6Zm9udCBzY3JpcHQ9IkJvcG8iIHR5cGVmYWNlPSJNaWNyb3NvZnQgSmhlbmdIZWkiLz48YTpmb250IHNjcmlwdD0iSmF2YSIgdHlwZWZhY2U9IkphdmFuZXNlIFRleHQiLz48YTpmb250IHNjcmlwdD0iTGlzdSIgdHlwZWZhY2U9IlNlZ29lIFVJIi8+PGE6Zm9udCBzY3JpcHQ9Ik15bXIiIHR5cGVmYWNlPSJNeWFubWFyIFRleHQiLz48YTpmb250IHNjcmlwdD0iTmtvbyIgdHlwZWZhY2U9IkVicmltYSIvPjxhOmZvbnQgc2NyaXB0PSJPbGNrIiB0eXBlZmFjZT0iTmlybWFsYSBVSSIvPjxhOmZvbnQgc2NyaXB0PSJPc21hIiB0eXBlZmFjZT0iRWJyaW1hIi8+PGE6Zm9udCBzY3JpcHQ9IlBoYWciIHR5cGVmYWNlPSJQaGFnc3BhIi8+PGE6Zm9udCBzY3JpcHQ9IlN5cm4iIHR5cGVmYWNlPSJFc3RyYW5nZWxvIEVkZXNzYSIvPjxhOmZvbnQgc2NyaXB0PSJTeXJqIiB0eXBlZmFjZT0iRXN0cmFuZ2VsbyBFZGVzc2EiLz48YTpmb250IHNjcmlwdD0iU3lyZSIgdHlwZWZhY2U9IkVzdHJhbmdlbG8gRWRlc3NhIi8+PGE6Zm9udCBzY3JpcHQ9IlNvcmEiIHR5cGVmYWNlPSJOaXJtYWxhIFVJIi8+PGE6Zm9udCBzY3JpcHQ9IlRhbGUiIHR5cGVmYWNlPSJNaWNyb3NvZnQgVGFpIExlIi8+PGE6Zm9udCBzY3JpcHQ9IlRhbHUiIHR5cGVmYWNlPSJNaWNyb3NvZnQgTmV3IFRhaSBMdWUiLz48YTpmb250IHNjcmlwdD0iVGZuZyIgdHlwZWZhY2U9IkVicmltYSIvPjwvYTptYWpvckZvbnQ+PGE6bWlub3JGb250PjxhOmxhdGluIHR5cGVmYWNlPSJDYWxpYnJpIiBwYW5vc2U9IjAyMEYwNTAyMDIwMjA0MDMwMjA0Ii8+PGE6ZWEgdHlwZWZhY2U9IiIvPjxhOmNzIHR5cGVmYWNlPSIiLz48YTpmb250IHNjcmlwdD0iSnBhbiIgdHlwZWZhY2U9Iua4uOOCtOOCt+ODg+OCryIvPjxhOmZvbnQgc2NyaXB0PSJIYW5nIiB0eXBlZmFjZT0i66eR7J2AIOqzoOuUlSIvPjxhOmZvbnQgc2NyaXB0PSJIYW5zIiB0eXBlZmFjZT0i562J57q/Ii8+PGE6Zm9udCBzY3JpcHQ9IkhhbnQiIHR5cGVmYWNlPSLmlrDntLDmmI7pq5QiLz48YTpmb250IHNjcmlwdD0iQXJhYiIgdHlwZWZhY2U9IkFyaWFsIi8+PGE6Zm9udCBzY3JpcHQ9IkhlYnIiIHR5cGVmYWNlPSJBcmlhbCIvPjxhOmZvbnQgc2NyaXB0PSJUaGFpIiB0eXBlZmFjZT0iVGFob21hIi8+PGE6Zm9udCBzY3JpcHQ9IkV0aGkiIHR5cGVmYWNlPSJOeWFsYSIvPjxhOmZvbnQgc2NyaXB0PSJCZW5nIiB0eXBlZmFjZT0iVnJpbmRhIi8+PGE6Zm9udCBzY3JpcHQ9Ikd1anIiIHR5cGVmYWNlPSJTaHJ1dGkiLz48YTpmb250IHNjcmlwdD0iS2htciIgdHlwZWZhY2U9IkRhdW5QZW5oIi8+PGE6Zm9udCBzY3JpcHQ9IktuZGEiIHR5cGVmYWNlPSJUdW5nYSIvPjxhOmZvbnQgc2NyaXB0PSJHdXJ1IiB0eXBlZmFjZT0iUmFhdmkiLz48YTpmb250IHNjcmlwdD0iQ2FucyIgdHlwZWZhY2U9IkV1cGhlbWlhIi8+PGE6Zm9udCBzY3JpcHQ9IkNoZXIiIHR5cGVmYWNlPSJQbGFudGFnZW5ldCBDaGVyb2tlZSIvPjxhOmZvbnQgc2NyaXB0PSJZaWlpIiB0eXBlZmFjZT0iTWljcm9zb2Z0IFlpIEJhaXRpIi8+PGE6Zm9udCBzY3JpcHQ9IlRpYnQiIHR5cGVmYWNlPSJNaWNyb3NvZnQgSGltYWxheWEiLz48YTpmb250IHNjcmlwdD0iVGhhYSIgdHlwZWZhY2U9Ik1WIEJvbGkiLz48YTpmb250IHNjcmlwdD0iRGV2YSIgdHlwZWZhY2U9Ik1hbmdhbCIvPjxhOmZvbnQgc2NyaXB0PSJUZWx1IiB0eXBlZmFjZT0iR2F1dGFtaSIvPjxhOmZvbnQgc2NyaXB0PSJUYW1sIiB0eXBlZmFjZT0iTGF0aGEiLz48YTpmb250IHNjcmlwdD0iU3lyYyIgdHlwZWZhY2U9IkVzdHJhbmdlbG8gRWRlc3NhIi8+PGE6Zm9udCBzY3JpcHQ9Ik9yeWEiIHR5cGVmYWNlPSJLYWxpbmdhIi8+PGE6Zm9udCBzY3JpcHQ9Ik1seW0iIHR5cGVmYWNlPSJLYXJ0aWthIi8+PGE6Zm9udCBzY3JpcHQ9Ikxhb28iIHR5cGVmYWNlPSJEb2tDaGFtcGEiLz48YTpmb250IHNjcmlwdD0iU2luaCIgdHlwZWZhY2U9Iklza29vbGEgUG90YSIvPjxhOmZvbnQgc2NyaXB0PSJNb25nIiB0eXBlZmFjZT0iTW9uZ29saWFuIEJhaXRpIi8+PGE6Zm9udCBzY3JpcHQ9IlZpZXQiIHR5cGVmYWNlPSJBcmlhbCIvPjxhOmZvbnQgc2NyaXB0PSJVaWdoIiB0eXBlZmFjZT0iTWljcm9zb2Z0IFVpZ2h1ciIvPjxhOmZvbnQgc2NyaXB0PSJHZW9yIiB0eXBlZmFjZT0iU3lsZmFlbiIvPjxhOmZvbnQgc2NyaXB0PSJBcm1uIiB0eXBlZmFjZT0iQXJpYWwiLz48YTpmb250IHNjcmlwdD0iQnVnaSIgdHlwZWZhY2U9IkxlZWxhd2FkZWUgVUkiLz48YTpmb250IHNjcmlwdD0iQm9wbyIgdHlwZWZhY2U9Ik1pY3Jvc29mdCBKaGVuZ0hlaSIvPjxhOmZvbnQgc2NyaXB0PSJKYXZhIiB0eXBlZmFjZT0iSmF2YW5lc2UgVGV4dCIvPjxhOmZvbnQgc2NyaXB0PSJMaXN1IiB0eXBlZmFjZT0iU2Vnb2UgVUkiLz48YTpmb250IHNjcmlwdD0iTXltciIgdHlwZWZhY2U9Ik15YW5tYXIgVGV4dCIvPjxhOmZvbnQgc2NyaXB0PSJOa29vIiB0eXBlZmFjZT0iRWJyaW1hIi8+PGE6Zm9udCBzY3JpcHQ9Ik9sY2siIHR5cGVmYWNlPSJOaXJtYWxhIFVJIi8+PGE6Zm9udCBzY3JpcHQ9Ik9zbWEiIHR5cGVmYWNlPSJFYnJpbWEiLz48YTpmb250IHNjcmlwdD0iUGhhZyIgdHlwZWZhY2U9IlBoYWdzcGEiLz48YTpmb250IHNjcmlwdD0iU3lybiIgdHlwZWZhY2U9IkVzdHJhbmdlbG8gRWRlc3NhIi8+PGE6Zm9udCBzY3JpcHQ9IlN5cmoiIHR5cGVmYWNlPSJFc3RyYW5nZWxvIEVkZXNzYSIvPjxhOmZvbnQgc2NyaXB0PSJTeXJlIiB0eXBlZmFjZT0iRXN0cmFuZ2VsbyBFZGVzc2EiLz48YTpmb250IHNjcmlwdD0iU29yYSIgdHlwZWZhY2U9Ik5pcm1hbGEgVUkiLz48YTpmb250IHNjcmlwdD0iVGFsZSIgdHlwZWZhY2U9Ik1pY3Jvc29mdCBUYWkgTGUiLz48YTpmb250IHNjcmlwdD0iVGFsdSIgdHlwZWZhY2U9Ik1pY3Jvc29mdCBOZXcgVGFpIEx1ZSIvPjxhOmZvbnQgc2NyaXB0PSJUZm5nIiB0eXBlZmFjZT0iRWJyaW1hIi8+PC9hOm1pbm9yRm9udD48L2E6Zm9udFNjaGVtZT48YTpmbXRTY2hlbWUgbmFtZT0iT2ZmaWNlIj48YTpmaWxsU3R5bGVMc3Q+PGE6c29saWRGaWxsPjxhOnNjaGVtZUNsciB2YWw9InBoQ2xyIi8+PC9hOnNvbGlkRmlsbD48YTpncmFkRmlsbCByb3RXaXRoU2hhcGU9IjEiPjxhOmdzTHN0PjxhOmdzIHBvcz0iMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOmx1bU1vZCB2YWw9IjExMDAwMCIvPjxhOnNhdE1vZCB2YWw9IjEwNTAwMCIvPjxhOnRpbnQgdmFsPSI2NzAwMCIvPjwvYTpzY2hlbWVDbHI+PC9hOmdzPjxhOmdzIHBvcz0iNTAwMDAiPjxhOnNjaGVtZUNsciB2YWw9InBoQ2xyIj48YTpsdW1Nb2QgdmFsPSIxMDUwMDAiLz48YTpzYXRNb2QgdmFsPSIxMDMwMDAiLz48YTp0aW50IHZhbD0iNzMwMDAiLz48L2E6c2NoZW1lQ2xyPjwvYTpncz48YTpncyBwb3M9IjEwMDAwMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOmx1bU1vZCB2YWw9IjEwNTAwMCIvPjxhOnNhdE1vZCB2YWw9IjEwOTAwMCIvPjxhOnRpbnQgdmFsPSI4MTAwMCIvPjwvYTpzY2hlbWVDbHI+PC9hOmdzPjwvYTpnc0xzdD48YTpsaW4gYW5nPSI1NDAwMDAwIiBzY2FsZWQ9IjAiLz48L2E6Z3JhZEZpbGw+PGE6Z3JhZEZpbGwgcm90V2l0aFNoYXBlPSIxIj48YTpnc0xzdD48YTpncyBwb3M9IjAiPjxhOnNjaGVtZUNsciB2YWw9InBoQ2xyIj48YTpzYXRNb2QgdmFsPSIxMDMwMDAiLz48YTpsdW1Nb2QgdmFsPSIxMDIwMDAiLz48YTp0aW50IHZhbD0iOTQwMDAiLz48L2E6c2NoZW1lQ2xyPjwvYTpncz48YTpncyBwb3M9IjUwMDAwIj48YTpzY2hlbWVDbHIgdmFsPSJwaENsciI+PGE6c2F0TW9kIHZhbD0iMTEwMDAwIi8+PGE6bHVtTW9kIHZhbD0iMTAwMDAwIi8+PGE6c2hhZGUgdmFsPSIxMDAwMDAiLz48L2E6c2NoZW1lQ2xyPjwvYTpncz48YTpncyBwb3M9IjEwMDAwMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOmx1bU1vZCB2YWw9Ijk5MDAwIi8+PGE6c2F0TW9kIHZhbD0iMTIwMDAwIi8+PGE6c2hhZGUgdmFsPSI3ODAwMCIvPjwvYTpzY2hlbWVDbHI+PC9hOmdzPjwvYTpnc0xzdD48YTpsaW4gYW5nPSI1NDAwMDAwIiBzY2FsZWQ9IjAiLz48L2E6Z3JhZEZpbGw+PC9hOmZpbGxTdHlsZUxzdD48YTpsblN0eWxlTHN0PjxhOmxuIHc9IjYzNTAiIGNhcD0iZmxhdCIgY21wZD0ic25nIiBhbGduPSJjdHIiPjxhOnNvbGlkRmlsbD48YTpzY2hlbWVDbHIgdmFsPSJwaENsciIvPjwvYTpzb2xpZEZpbGw+PGE6cHJzdERhc2ggdmFsPSJzb2xpZCIvPjxhOm1pdGVyIGxpbT0iODAwMDAwIi8+PC9hOmxuPjxhOmxuIHc9IjEyNzAwIiBjYXA9ImZsYXQiIGNtcGQ9InNuZyIgYWxnbj0iY3RyIj48YTpzb2xpZEZpbGw+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiLz48L2E6c29saWRGaWxsPjxhOnByc3REYXNoIHZhbD0ic29saWQiLz48YTptaXRlciBsaW09IjgwMDAwMCIvPjwvYTpsbj48YTpsbiB3PSIxOTA1MCIgY2FwPSJmbGF0IiBjbXBkPSJzbmciIGFsZ249ImN0ciI+PGE6c29saWRGaWxsPjxhOnNjaGVtZUNsciB2YWw9InBoQ2xyIi8+PC9hOnNvbGlkRmlsbD48YTpwcnN0RGFzaCB2YWw9InNvbGlkIi8+PGE6bWl0ZXIgbGltPSI4MDAwMDAiLz48L2E6bG4+PC9hOmxuU3R5bGVMc3Q+PGE6ZWZmZWN0U3R5bGVMc3Q+PGE6ZWZmZWN0U3R5bGU+PGE6ZWZmZWN0THN0Lz48L2E6ZWZmZWN0U3R5bGU+PGE6ZWZmZWN0U3R5bGU+PGE6ZWZmZWN0THN0Lz48L2E6ZWZmZWN0U3R5bGU+PGE6ZWZmZWN0U3R5bGU+PGE6ZWZmZWN0THN0PjxhOm91dGVyU2hkdyBibHVyUmFkPSI1NzE1MCIgZGlzdD0iMTkwNTAiIGRpcj0iNTQwMDAwMCIgYWxnbj0iY3RyIiByb3RXaXRoU2hhcGU9IjAiPjxhOnNyZ2JDbHIgdmFsPSIwMDAwMDAiPjxhOmFscGhhIHZhbD0iNjMwMDAiLz48L2E6c3JnYkNscj48L2E6b3V0ZXJTaGR3PjwvYTplZmZlY3RMc3Q+PC9hOmVmZmVjdFN0eWxlPjwvYTplZmZlY3RTdHlsZUxzdD48YTpiZ0ZpbGxTdHlsZUxzdD48YTpzb2xpZEZpbGw+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiLz48L2E6c29saWRGaWxsPjxhOnNvbGlkRmlsbD48YTpzY2hlbWVDbHIgdmFsPSJwaENsciI+PGE6dGludCB2YWw9Ijk1MDAwIi8+PGE6c2F0TW9kIHZhbD0iMTcwMDAwIi8+PC9hOnNjaGVtZUNscj48L2E6c29saWRGaWxsPjxhOmdyYWRGaWxsIHJvdFdpdGhTaGFwZT0iMSI+PGE6Z3NMc3Q+PGE6Z3MgcG9zPSIwIj48YTpzY2hlbWVDbHIgdmFsPSJwaENsciI+PGE6dGludCB2YWw9IjkzMDAwIi8+PGE6c2F0TW9kIHZhbD0iMTUwMDAwIi8+PGE6c2hhZGUgdmFsPSI5ODAwMCIvPjxhOmx1bU1vZCB2YWw9IjEwMjAwMCIvPjwvYTpzY2hlbWVDbHI+PC9hOmdzPjxhOmdzIHBvcz0iNTAwMDAiPjxhOnNjaGVtZUNsciB2YWw9InBoQ2xyIj48YTp0aW50IHZhbD0iOTgwMDAiLz48YTpzYXRNb2QgdmFsPSIxMzAwMDAiLz48YTpzaGFkZSB2YWw9IjkwMDAwIi8+PGE6bHVtTW9kIHZhbD0iMTAzMDAwIi8+PC9hOnNjaGVtZUNscj48L2E6Z3M+PGE6Z3MgcG9zPSIxMDAwMDAiPjxhOnNjaGVtZUNsciB2YWw9InBoQ2xyIj48YTpzaGFkZSB2YWw9IjYzMDAwIi8+PGE6c2F0TW9kIHZhbD0iMTIwMDAwIi8+PC9hOnNjaGVtZUNscj48L2E6Z3M+PC9hOmdzTHN0PjxhOmxpbiBhbmc9IjU0MDAwMDAiIHNjYWxlZD0iMCIvPjwvYTpncmFkRmlsbD48L2E6YmdGaWxsU3R5bGVMc3Q+PC9hOmZtdFNjaGVtZT48L2E6dGhlbWVFbGVtZW50cz48YTpvYmplY3REZWZhdWx0cy8+PGE6ZXh0cmFDbHJTY2hlbWVMc3QvPjxhOmV4dExzdD48YTpleHQgdXJpPSJ7MDVBNEMyNUMtMDg1RS00MzQwLTg1QTMtQTU1MzFFNTEwREIyfSI+PHRobTE1OnRoZW1lRmFtaWx5IHhtbG5zOnRobTE1PSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL29mZmljZS90aGVtZW1sLzIwMTIvbWFpbiIgbmFtZT0iT2ZmaWNlIFRoZW1lIiBpZD0iezYyRjkzOUI2LTkzQUYtNERCOC05QzZCLUQ2QzdERkRDNTg5Rn0iIHZpZD0iezRBM0M0NkU4LTYxQ0MtNDYwMy1BNTg5LTc0MjJBNDdBOEU0QX0iLz48L2E6ZXh0PjwvYTpleHRMc3Q+PC9hOnRoZW1lPlBLAwQKAAAAAAAAACEAY7SZLI4GAACOBgAADQAAAHhsL3N0eWxlcy54bWw8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJVVEYtOCIgc3RhbmRhbG9uZT0ieWVzIj8+DQo8c3R5bGVTaGVldCB4bWxucz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL3NwcmVhZHNoZWV0bWwvMjAwNi9tYWluIiB4bWxuczptYz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL21hcmt1cC1jb21wYXRpYmlsaXR5LzIwMDYiIG1jOklnbm9yYWJsZT0ieDE0YWMgeDE2cjIgeHIiIHhtbG5zOngxNGFjPSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL29mZmljZS9zcHJlYWRzaGVldG1sLzIwMDkvOS9hYyIgeG1sbnM6eDE2cjI9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAxNS8wMi9tYWluIiB4bWxuczp4cj0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9vZmZpY2Uvc3ByZWFkc2hlZXRtbC8yMDE0L3JldmlzaW9uIj48Zm9udHMgY291bnQ9IjEiIHgxNGFjOmtub3duRm9udHM9IjEiPjxmb250PjxzeiB2YWw9IjExIi8+PGNvbG9yIHRoZW1lPSIxIi8+PG5hbWUgdmFsPSJDYWxpYnJpIi8+PGZhbWlseSB2YWw9IjIiLz48c2NoZW1lIHZhbD0ibWlub3IiLz48L2ZvbnQ+PC9mb250cz48ZmlsbHMgY291bnQ9IjIiPjxmaWxsPjxwYXR0ZXJuRmlsbCBwYXR0ZXJuVHlwZT0ibm9uZSIvPjwvZmlsbD48ZmlsbD48cGF0dGVybkZpbGwgcGF0dGVyblR5cGU9ImdyYXkxMjUiLz48L2ZpbGw+PC9maWxscz48Ym9yZGVycyBjb3VudD0iMSI+PGJvcmRlcj48bGVmdC8+PHJpZ2h0Lz48dG9wLz48Ym90dG9tLz48ZGlhZ29uYWwvPjwvYm9yZGVyPjwvYm9yZGVycz48Y2VsbFN0eWxlWGZzIGNvdW50PSIxIj48eGYgbnVtRm10SWQ9IjAiIGZvbnRJZD0iMCIgZmlsbElkPSIwIiBib3JkZXJJZD0iMCIvPjwvY2VsbFN0eWxlWGZzPjxjZWxsWGZzIGNvdW50PSIxIj48eGYgbnVtRm10SWQ9IjAiIGZvbnRJZD0iMCIgZmlsbElkPSIwIiBib3JkZXJJZD0iMCIgeGZJZD0iMCIvPjwvY2VsbFhmcz48Y2VsbFN0eWxlcyBjb3VudD0iMSI+PGNlbGxTdHlsZSBuYW1lPSJOb3JtYWwiIHhmSWQ9IjAiIGJ1aWx0aW5JZD0iMCIvPjwvY2VsbFN0eWxlcz48ZHhmcyBjb3VudD0iMSI+PGR4Zj48bnVtRm10IG51bUZtdElkPSIwIiBmb3JtYXRDb2RlPSJHZW5lcmFsIi8+PC9keGY+PC9keGZzPjx0YWJsZVN0eWxlcyBjb3VudD0iMCIgZGVmYXVsdFRhYmxlU3R5bGU9IlRhYmxlU3R5bGVNZWRpdW0yIiBkZWZhdWx0UGl2b3RTdHlsZT0iUGl2b3RTdHlsZUxpZ2h0MTYiLz48ZXh0THN0PjxleHQgdXJpPSJ7RUI3OURFRjItODBCOC00M2U1LTk1QkQtNTRDQkRERjkwMjBDfSIgeG1sbnM6eDE0PSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL29mZmljZS9zcHJlYWRzaGVldG1sLzIwMDkvOS9tYWluIj48eDE0OnNsaWNlclN0eWxlcyBkZWZhdWx0U2xpY2VyU3R5bGU9IlNsaWNlclN0eWxlTGlnaHQxIi8+PC9leHQ+PGV4dCB1cmk9Ins5MjYwQTUxMC1GMzAxLTQ2YTgtODYzNS1GNTEyRDY0QkU1RjV9IiB4bWxuczp4MTU9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAxMC8xMS9tYWluIj48eDE1OnRpbWVsaW5lU3R5bGVzIGRlZmF1bHRUaW1lbGluZVN0eWxlPSJUaW1lU2xpY2VyU3R5bGVMaWdodDEiLz48L2V4dD48L2V4dExzdD48L3N0eWxlU2hlZXQ+UEsDBAoAAAAAAAAAIQAYUb/kwwAAAMMAAAAUAAAAeGwvc2hhcmVkU3RyaW5ncy54bWw8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJVVEYtOCIgc3RhbmRhbG9uZT0ieWVzIj8+DQo8c3N0IHhtbG5zPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvc3ByZWFkc2hlZXRtbC8yMDA2L21haW4iIGNvdW50PSIyIiB1bmlxdWVDb3VudD0iMiI+PHNpPjx0PlF1ZXJ5MTwvdD48L3NpPjxzaT48dC8+PC9zaT48L3NzdD5QSwMECgAAAAAAAAAhAKic9QAlAQAAJQEAACMAAAB4bC93b3Jrc2hlZXRzL19yZWxzL3NoZWV0MS54bWwucmVsczw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04IiBzdGFuZGFsb25lPSJ5ZXMiPz4NCjxSZWxhdGlvbnNoaXBzIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvcGFja2FnZS8yMDA2L3JlbGF0aW9uc2hpcHMiPjxSZWxhdGlvbnNoaXAgSWQ9InJJZDEiIFR5cGU9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZpY2VEb2N1bWVudC8yMDA2L3JlbGF0aW9uc2hpcHMvdGFibGUiIFRhcmdldD0iLi4vdGFibGVzL3RhYmxlMS54bWwiLz48L1JlbGF0aW9uc2hpcHM+UEsDBAoAAAAAAAAAIQDrCENUzwIAAM8CAAASAAAAeGwvY29ubmVjdGlvbnMueG1sPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/Pg0KPGNvbm5lY3Rpb25zIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvc3ByZWFkc2hlZXRtbC8yMDA2L21haW4iIHhtbG5zOm1jPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvbWFya3VwLWNvbXBhdGliaWxpdHkvMjAwNiIgbWM6SWdub3JhYmxlPSJ4cjE2IiB4bWxuczp4cjE2PSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL29mZmljZS9zcHJlYWRzaGVldG1sLzIwMTcvcmV2aXNpb24xNiI+PGNvbm5lY3Rpb24gaWQ9IjEiIHhyMTY6dWlkPSJ7ODZCQTc4NEMtNjY0MC00OTg5LUE4NUUtRUI0OTY2QjlFNzQxfSIga2VlcEFsaXZlPSIxIiBuYW1lPSJRdWVyeSAtIFF1ZXJ5MSIgZGVzY3JpcHRpb249IkNvbm5lY3Rpb24gdG8gdGhlICdRdWVyeTEnIHF1ZXJ5IGluIHRoZSB3b3JrYm9vay4iIHR5cGU9IjUiIHJlZnJlc2hlZFZlcnNpb249IjciIGJhY2tncm91bmQ9IjEiIHNhdmVEYXRhPSIxIj48ZGJQciBjb25uZWN0aW9uPSJQcm92aWRlcj1NaWNyb3NvZnQuTWFzaHVwLk9sZURiLjE7RGF0YSBTb3VyY2U9JFdvcmtib29rJDtMb2NhdGlvbj1RdWVyeTE7RXh0ZW5kZWQgUHJvcGVydGllcz0mcXVvdDsmcXVvdDsiIGNvbW1hbmQ9IlNFTEVDVCAqIEZST00gW1F1ZXJ5MV0iLz48L2Nvbm5lY3Rpb24+PC9jb25uZWN0aW9ucz5QSwMECgAAAAAAAAAhAHQHJ6CAAwAAgAMAABQAAAB4bC90YWJsZXMvdGFibGUxLnhtbDw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04IiBzdGFuZGFsb25lPSJ5ZXMiPz4NCjx0YWJsZSB4bWxucz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL3NwcmVhZHNoZWV0bWwvMjAwNi9tYWluIiB4bWxuczptYz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL21hcmt1cC1jb21wYXRpYmlsaXR5LzIwMDYiIG1jOklnbm9yYWJsZT0ieHIgeHIzIiB4bWxuczp4cj0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9vZmZpY2Uvc3ByZWFkc2hlZXRtbC8yMDE0L3JldmlzaW9uIiB4bWxuczp4cjM9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAxNi9yZXZpc2lvbjMiIGlkPSIxIiB4cjp1aWQ9IntEODUzOUNGNi0wNEU1LTQ2NEQtOTk1MC01QTM2QzVBMUZDRkV9IiBuYW1lPSJRdWVyeTEiIGRpc3BsYXlOYW1lPSJRdWVyeTEiIHJlZj0iQTE6QTIiIHRhYmxlVHlwZT0icXVlcnlUYWJsZSIgdG90YWxzUm93U2hvd249IjAiPjxhdXRvRmlsdGVyIHJlZj0iQTE6QTIiIHhyOnVpZD0ie0Q4NTM5Q0Y2LTA0RTUtNDY0RC05OTUwLTVBMzZDNUExRkNGRX0iLz48dGFibGVDb2x1bW5zIGNvdW50PSIxIj48dGFibGVDb2x1bW4gaWQ9IjEiIHhyMzp1aWQ9IntEMTA4NDg1OC04QUU1LTQ3MjgtQTlCRS1GRTc4ODIxQ0RGRkZ9IiB1bmlxdWVOYW1lPSIxIiBuYW1lPSJRdWVyeTEiIHF1ZXJ5VGFibGVGaWVsZElkPSIxIiBkYXRhRHhmSWQ9IjAiLz48L3RhYmxlQ29sdW1ucz48dGFibGVTdHlsZUluZm8gbmFtZT0iVGFibGVTdHlsZU1lZGl1bTciIHNob3dGaXJzdENvbHVtbj0iMCIgc2hvd0xhc3RDb2x1bW49IjAiIHNob3dSb3dTdHJpcGVzPSIxIiBzaG93Q29sdW1uU3RyaXBlcz0iMCIvPjwvdGFibGU+UEsDBAoAAAAAAAAAIQAObTbG1AIAANQCAAAeAAAAeGwvcXVlcnlUYWJsZXMvcXVlcnlUYWJsZTEueG1sPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/Pg0KPHF1ZXJ5VGFibGUgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9zcHJlYWRzaGVldG1sLzIwMDYvbWFpbiIgeG1sbnM6bWM9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9tYXJrdXAtY29tcGF0aWJpbGl0eS8yMDA2IiBtYzpJZ25vcmFibGU9InhyMTYiIHhtbG5zOnhyMTY9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vb2ZmaWNlL3NwcmVhZHNoZWV0bWwvMjAxNy9yZXZpc2lvbjE2IiBuYW1lPSJFeHRlcm5hbERhdGFfMSIgY29ubmVjdGlvbklkPSIxIiB4cjE2OnVpZD0iezI0QzE3Qjg5LTNDRDMtNEFBNS1CODRGLTlGRjVGMzUyNDVEN30iIGF1dG9Gb3JtYXRJZD0iMTYiIGFwcGx5TnVtYmVyRm9ybWF0cz0iMCIgYXBwbHlCb3JkZXJGb3JtYXRzPSIwIiBhcHBseUZvbnRGb3JtYXRzPSIwIiBhcHBseVBhdHRlcm5Gb3JtYXRzPSIwIiBhcHBseUFsaWdubWVudEZvcm1hdHM9IjAiIGFwcGx5V2lkdGhIZWlnaHRGb3JtYXRzPSIwIj48cXVlcnlUYWJsZVJlZnJlc2ggbmV4dElkPSIyIj48cXVlcnlUYWJsZUZpZWxkcyBjb3VudD0iMSI+PHF1ZXJ5VGFibGVGaWVsZCBpZD0iMSIgbmFtZT0iUXVlcnkxIiB0YWJsZUNvbHVtbklkPSIxIi8+PC9xdWVyeVRhYmxlRmllbGRzPjwvcXVlcnlUYWJsZVJlZnJlc2g+PC9xdWVyeVRhYmxlPlBLAwQKAAAAAAAAACEApT60BHIiAAByIgAAEwAAAGN1c3RvbVhtbC9pdGVtMS54bWz//jwAPwB4AG0AbAAgAHYAZQByAHMAaQBvAG4APQAiADEALgAwACIAIABlAG4AYwBvAGQAaQBuAGcAPQAiAHUAdABmAC0AMQA2ACIAPwA+ADwARABhAHQAYQBNAGEAcwBoAHUAcAAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAYQB0AGEATQBhAHMAaAB1AHAAIgA+AEEAQQBBAEEAQQBEADgARABBAEEAQgBRAFMAdwBNAEUARgBBAEEAQwBBAEEAZwBBAE4ARwA4AGsAVgBKAHkASwBsAEYAKwBpAEEAQQBBAEEAOQBRAEEAQQBBAEIASQBBAEgAQQBCAEQAYgAyADUAbQBhAFcAYwB2AFUARwBGAGoAYQAyAEYAbgBaAFMANQA0AGIAVwB3AGcAbwBoAGcAQQBLAEsAQQBVAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAaABZACsAeABEAG8ASQB3AEYARQBWAC8AaABYAFMAbgBMAFgAVQBSADgAaQBpAEQAcQB5AFEAbQBSAE8AUABhAFEATQBWAEcAZQBCAGgAYQBMAFAALwBtADQAQwBmADUAQwAyAEkAVQBkAFgATwA4ADUANQA3AGgAMwB2AHYAMQBCAHQAbgBZAE4AcwBGAEYAOQA5AFoAMABtAEoASwBJAGMAaABKAG8ATABMAHYASwBZAEoAMgBTAHcAUgAzAEMASgBjAGsAawBiAEYAUgA1AFUAcgBVAE8ASgBoAGwAdABNAHQAbwBxAEoAVQBmAG4AegBnAGwAagAzAG4AdgBxAEYANwBUAHIAYQB5AFkANABqADkAZwArAFgAeABmAGwAVQBiAGUASwBmAEcAVAB6AFgAdwA0AE4AVwBxAGUAdwAxAEUAVABDADcAagBWAEcAQwBoAHIASABWAEgAQgBCAE8AYgBDAFoAUQBXADcAdwAyADQAdABwADcAcgBQADkAZwBiAEEAYQBHAGoAZgAwAFcAbQBvAE0AdAB3AFcAdwBPAFEASgA3AFgANQBBAFAAVQBFAHMARABCAEIAUQBBAEEAZwBBAEkAQQBEAFIAdgBKAEYAUQBQAHkAdQBtAHIAcABBAEEAQQBBAE8AawBBAEEAQQBBAFQAQQBCAHcAQQBXADAATgB2AGIAbgBSAGwAYgBuAFIAZgBWAEgAbAB3AFoAWABOAGQATABuAGgAdABiAEMAQwBpAEcAQQBBAG8AbwBCAFEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQgB0AGoAawBzAE8AdwBqAEEATQBSAEsAOABTAGUAWgArADYAcwBFAEEASQBOAFcAVQBCADMASQBBAEwAUgBNAEgAOQBpAE8AYQBqAHgAawBYAGgAYgBDAHcANABFAGwAYwBnAGIAWABlAEkAcABXAGYAbQBlAGUAYgB6AGUAbABmAEgAWgBBAGYAeABvAEQASAAyADMAaQBuAFkARgBDAFUASQBjAHMAYgBmAGUAdABjAHEAbQBMAGkAUgBlAHoAagBXADEAZgBVAFoASwBJAG8AYwBkAFYARgBCAHgAeAB3AE8AaQBOAEYAMABaAEgAVQBzAGYAQwBDAFgAbgBjAGEAUABWAG4ATQArAHgAeABhAEQATgBuAGYAZABFAG0ANwBMAGMAbwBmAEcATwB5AGIASABrAHUAYwBmAFUARgBkAG4AYQB2AFEAMABzAEwAaQBrAEwASwArADEARwBRAGQAeABXAG4ATgB6AGwAUQBLAG0AeABMAGoASQArAEoAZQB3AFAAMwBrAGQAdwB0AEEAYgB6AGQAbgBFAEoARwAyAFUAZABpAEYAeABHAFYANQAvAEEAVgBCAEwAQQB3AFEAVQBBAEEASQBBAEMAQQBBADAAYgB5AFIAVQBQAGYAYwAvAFcAagBzAEEAQQBBAEIASwBBAEEAQQBBAEUAdwBBAGMAQQBFAFoAdgBjAG0AMQAxAGIARwBGAHoATAAxAE4AbABZADMAUgBwAGIAMgA0AHgATABtADAAZwBvAGgAZwBBAEsASwBBAFUAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBLADAANQBOAEwAcwBuAE0AegAxAE0ASQBoAHQAQwBHADEAcgB4AGMAdgBGAHoARgBHAFkAbABGAHEAUwBrAEsAZwBhAFcAcABSAFoAVwBHAEMAcgBZAEsATwBhAGsAbAB2AEYAdwBLAFEAQgBDAGMAWAAxAHEAVQBuAEEAbwBVAFUAVgBMAGkANQBjAHIATQBRAHgAYQAwAEIAZwBCAFEAUwB3AEUAQwBMAFEAQQBVAEEAQQBJAEEAQwBBAEEAMABiAHkAUgBVAG4ASQBxAFUAWAA2AEkAQQBBAEEARAAxAEEAQQBBAEEARQBnAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAUQAyADkAdQBaAG0AbABuAEwAMQBCAGgAWQAyAHQAaABaADIAVQB1AGUARwAxAHMAVQBFAHMAQgBBAGkAMABBAEYAQQBBAEMAQQBBAGcAQQBOAEcAOABrAFYAQQAvAEsANgBhAHUAawBBAEEAQQBBADYAUQBBAEEAQQBCAE0AQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBADcAZwBBAEEAQQBGAHQARABiADIANQAwAFoAVwA1ADAAWAAxAFIANQBjAEcAVgB6AFgAUwA1ADQAYgBXAHgAUQBTAHcARQBDAEwAUQBBAFUAQQBBAEkAQQBDAEEAQQAwAGIAeQBSAFUAUABmAGMALwBXAGoAcwBBAEEAQQBCAEsAQQBBAEEAQQBFAHcAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBEAGYAQQBRAEEAQQBSAG0AOQB5AGIAWABWAHMAWQBYAE0AdgBVADIAVgBqAGQARwBsAHYAYgBqAEUAdQBiAFYAQgBMAEIAUQBZAEEAQQBBAEEAQQBBAHcAQQBEAEEATQBJAEEAQQBBAEIAbgBBAGcAQQBBAEEAQQBBAFEAQQBRAEEAQQA3ADcAdQAvAFAARAA5ADQAYgBXAHcAZwBkAG0AVgB5AGMAMgBsAHYAYgBqADAAaQBNAFMANAB3AEkAaQBCAGwAYgBtAE4AdgBaAEcAbAB1AFoAegAwAGkAZABYAFIAbQBMAFQAZwBpAFAAegA0ADgAVQBHAFYAeQBiAFcAbAB6AGMAMgBsAHYAYgBrAHgAcABjADMAUQBnAGUARwAxAHMAYgBuAE0ANgBlAEgATgBrAFAAUwBKAG8AZABIAFIAdwBPAGkAOAB2AGQAMwBkADMATABuAGMAegBMAG0AOQB5AFoAeQA4AHkATQBEAEEAeABMADEAaABOAFQARgBOAGoAYQBHAFYAdABZAFMASQBnAGUARwAxAHMAYgBuAE0ANgBlAEgATgBwAFAAUwBKAG8AZABIAFIAdwBPAGkAOAB2AGQAMwBkADMATABuAGMAegBMAG0AOQB5AFoAeQA4AHkATQBEAEEAeABMADEAaABOAFQARgBOAGoAYQBHAFYAdABZAFMAMQBwAGIAbgBOADAAWQBXADUAagBaAFMASQArAFAARQBOAGgAYgBrAFYAMgBZAFcAeAAxAFkAWABSAGwAUgBuAFYAMABkAFgASgBsAFUARwBGAGoAYQAyAEYAbgBaAFgATQArAFoAbQBGAHMAYwAyAFUAOABMADAATgBoAGIAawBWADIAWQBXAHgAMQBZAFgAUgBsAFIAbgBWADAAZABYAEoAbABVAEcARgBqAGEAMgBGAG4AWgBYAE0AKwBQAEUAWgBwAGMAbQBWADMAWQBXAHgAcwBSAFcANQBoAFkAbQB4AGwAWgBEADUAMABjAG4AVgBsAFAAQwA5AEcAYQBYAEoAbABkADIARgBzAGIARQBWAHUAWQBXAEoAcwBaAFcAUQArAFAAQwA5AFEAWgBYAEoAdABhAFgATgB6AGEAVwA5AHUAVABHAGwAegBkAEQANQBYAEIAdwBBAEEAQQBBAEEAQQBBAEQAVQBIAEEAQQBEAHYAdQA3ADgAOABQADMAaAB0AGIAQwBCADIAWgBYAEoAegBhAFcAOQB1AFAAUwBJAHgATABqAEEAaQBJAEcAVgB1AFkAMgA5AGsAYQBXADUAbgBQAFMASgAxAGQARwBZAHQATwBDAEkALwBQAGoAeABNAGIAMgBOAGgAYgBGAEIAaABZADIAdABoAFoAMgBWAE4AWgBYAFIAaABaAEcARgAwAFkAVQBaAHAAYgBHAFUAZwBlAEcAMQBzAGIAbgBNADYAZQBIAE4AawBQAFMASgBvAGQASABSAHcATwBpADgAdgBkADMAZAAzAEwAbgBjAHoATABtADkAeQBaAHkAOAB5AE0ARABBAHgATAAxAGgATgBUAEYATgBqAGEARwBWAHQAWQBTAEkAZwBlAEcAMQBzAGIAbgBNADYAZQBIAE4AcABQAFMASgBvAGQASABSAHcATwBpADgAdgBkADMAZAAzAEwAbgBjAHoATABtADkAeQBaAHkAOAB5AE0ARABBAHgATAAxAGgATgBUAEYATgBqAGEARwBWAHQAWQBTADEAcABiAG4ATgAwAFkAVwA1AGoAWgBTAEkAKwBQAEUAbAAwAFoAVwAxAHoAUABqAHgASgBkAEcAVgB0AFAAagB4AEoAZABHAFYAdABUAEcAOQBqAFkAWABSAHAAYgAyADQAKwBQAEUAbAAwAFoAVwAxAFUAZQBYAEIAbABQAGsARgBzAGIARQBaAHYAYwBtADEAMQBiAEcARgB6AFAAQwA5AEoAZABHAFYAdABWAEgAbAB3AFoAVAA0ADgAUwBYAFIAbABiAFYAQgBoAGQARwBnAGcATAB6ADQAOABMADAAbAAwAFoAVwAxAE0AYgAyAE4AaABkAEcAbAB2AGIAagA0ADgAVQAzAFIAaABZAG0AeABsAFIAVwA1ADAAYwBtAGwAbABjAHkAQQB2AFAAagB3AHYAUwBYAFIAbABiAFQANAA4AFMAWABSAGwAYgBUADQAOABTAFgAUgBsAGIAVQB4AHYAWQAyAEYAMABhAFcAOQB1AFAAagB4AEoAZABHAFYAdABWAEgAbAB3AFoAVAA1AEcAYgAzAEoAdABkAFcAeABoAFAAQwA5AEoAZABHAFYAdABWAEgAbAB3AFoAVAA0ADgAUwBYAFIAbABiAFYAQgBoAGQARwBnACsAVQAyAFYAagBkAEcAbAB2AGIAagBFAHYAVQBYAFYAbABjAG4AawB4AFAAQwA5AEoAZABHAFYAdABVAEcARgAwAGEARAA0ADgATAAwAGwAMABaAFcAMQBNAGIAMgBOAGgAZABHAGwAdgBiAGoANAA4AFUAMwBSAGgAWQBtAHgAbABSAFcANQAwAGMAbQBsAGwAYwB6ADQAOABSAFcANQAwAGMAbgBrAGcAVgBIAGwAdwBaAFQAMABpAFMAWABOAFEAYwBtAGwAMgBZAFgAUgBsAEkAaQBCAFcAWQBXAHgAMQBaAFQAMABpAGIARABBAGkASQBDADgAKwBQAEUAVgB1AGQASABKADUASQBGAFIANQBjAEcAVQA5AEkAawBaAHAAYgBHAHgARgBiAG0ARgBpAGIARwBWAGsASQBpAEIAVwBZAFcAeAAxAFoAVAAwAGkAYgBEAEUAaQBJAEMAOAArAFAARQBWAHUAZABIAEoANQBJAEYAUgA1AGMARwBVADkASQBrAFoAcABiAEcAeABQAFkAbQBwAGwAWQAzAFIAVQBlAFgAQgBsAEkAaQBCAFcAWQBXAHgAMQBaAFQAMABpAGMAMQBSAGgAWQBtAHgAbABJAGkAQQB2AFAAagB4AEYAYgBuAFIAeQBlAFMAQgBVAGUAWABCAGwAUABTAEoARwBhAFcAeABzAFYARwA5AEUAWQBYAFIAaABUAFcAOQBrAFoAVwB4AEYAYgBtAEYAaQBiAEcAVgBrAEkAaQBCAFcAWQBXAHgAMQBaAFQAMABpAGIARABBAGkASQBDADgAKwBQAEUAVgB1AGQASABKADUASQBGAFIANQBjAEcAVQA5AEkAawBKADEAWgBtAFoAbABjAGsANQBsAGUASABSAFMAWgBXAFoAeQBaAFgATgBvAEkAaQBCAFcAWQBXAHgAMQBaAFQAMABpAGIARABFAGkASQBDADgAKwBQAEUAVgB1AGQASABKADUASQBGAFIANQBjAEcAVQA5AEkAbABKAGwAYwAzAFYAcwBkAEYAUgA1AGMARwBVAGkASQBGAFoAaABiAEgAVgBsAFAAUwBKAHoAVgBHAFYANABkAEMASQBnAEwAegA0ADgAUgBXADUAMABjAG4AawBnAFYASABsAHcAWgBUADAAaQBUAG0ARgB0AFoAVgBWAHcAWgBHAEYAMABaAFcAUgBCAFoAbgBSAGwAYwBrAFoAcABiAEcAdwBpAEkARgBaAGgAYgBIAFYAbABQAFMASgBzAE0AQwBJAGcATAB6ADQAOABSAFcANQAwAGMAbgBrAGcAVgBIAGwAdwBaAFQAMABpAFQAbQBGADIAYQBXAGQAaABkAEcAbAB2AGIAbABOADAAWgBYAEIATwBZAFcAMQBsAEkAaQBCAFcAWQBXAHgAMQBaAFQAMABpAGMAMAA1AGgAZABtAGwAbgBZAFgAUgBwAGIAMgA0AGkASQBDADgAKwBQAEUAVgB1AGQASABKADUASQBGAFIANQBjAEcAVQA5AEkAawBaAHAAYgBHAHgAVQBZAFgASgBuAFoAWABRAGkASQBGAFoAaABiAEgAVgBsAFAAUwBKAHoAVQBYAFYAbABjAG4AawB4AEkAaQBBAHYAUABqAHgARgBiAG4AUgB5AGUAUwBCAFUAZQBYAEIAbABQAFMASgBHAGEAVwB4AHMAWgBXAFIARABiADIAMQB3AGIARwBWADAAWgBWAEoAbABjADMAVgBzAGQARgBSAHYAVgAyADkAeQBhADMATgBvAFoAVwBWADAASQBpAEIAVwBZAFcAeAAxAFoAVAAwAGkAYgBEAEUAaQBJAEMAOAArAFAARQBWAHUAZABIAEoANQBJAEYAUgA1AGMARwBVADkASQBrAEYAawBaAEcAVgBrAFYARwA5AEUAWQBYAFIAaABUAFcAOQBrAFoAVwB3AGkASQBGAFoAaABiAEgAVgBsAFAAUwBKAHMATQBDAEkAZwBMAHoANAA4AFIAVwA1ADAAYwBuAGsAZwBWAEgAbAB3AFoAVAAwAGkAUgBtAGwAcwBiAEUATgB2AGQAVwA1ADAASQBpAEIAVwBZAFcAeAAxAFoAVAAwAGkAYgBEAEUAaQBJAEMAOAArAFAARQBWAHUAZABIAEoANQBJAEYAUgA1AGMARwBVADkASQBrAFoAcABiAEcAeABGAGMAbgBKAHYAYwBrAE4AdgBaAEcAVQBpAEkARgBaAGgAYgBIAFYAbABQAFMASgB6AFYAVwA1AHIAYgBtADkAMwBiAGkASQBnAEwAegA0ADgAUgBXADUAMABjAG4AawBnAFYASABsAHcAWgBUADAAaQBSAG0AbABzAGIARQBWAHkAYwBtADkAeQBRADIAOQAxAGIAbgBRAGkASQBGAFoAaABiAEgAVgBsAFAAUwBKAHMATQBDAEkAZwBMAHoANAA4AFIAVwA1ADAAYwBuAGsAZwBWAEgAbAB3AFoAVAAwAGkAUgBtAGwAcwBiAEUAeABoAGMAMwBSAFYAYwBHAFIAaABkAEcAVgBrAEkAaQBCAFcAWQBXAHgAMQBaAFQAMABpAFoARABJAHcATQBqAEkAdABNAEQARQB0AE0ARABSAFUATQBUAE0ANgBOAFQAYwA2AE4ARABFAHUATgBEAEkANABOAGoAZwAzAE4AbABvAGkASQBDADgAKwBQAEUAVgB1AGQASABKADUASQBGAFIANQBjAEcAVQA5AEkAawBaAHAAYgBHAHgARABiADIAeAAxAGIAVwA1AFUAZQBYAEIAbABjAHkASQBnAFYAbQBGAHMAZABXAFUAOQBJAG4ATgBDAFoAegAwADkASQBpAEEAdgBQAGoAeABGAGIAbgBSAHkAZQBTAEIAVQBlAFgAQgBsAFAAUwBKAEcAYQBXAHgAcwBRADIAOQBzAGQAVwAxAHUAVABtAEYAdABaAFgATQBpAEkARgBaAGgAYgBIAFYAbABQAFMASgB6AFcAeQBaAHgAZABXADkAMABPADEARgAxAFoAWABKADUATQBTAFoAeABkAFcAOQAwAE8AMQAwAGkASQBDADgAKwBQAEUAVgB1AGQASABKADUASQBGAFIANQBjAEcAVQA5AEkAawBaAHAAYgBHAHgAVABkAEcARgAwAGQAWABNAGkASQBGAFoAaABiAEgAVgBsAFAAUwBKAHoAUQAyADkAdABjAEcAeABsAGQARwBVAGkASQBDADgAKwBQAEUAVgB1AGQASABKADUASQBGAFIANQBjAEcAVQA5AEkAbABKAGwAYgBHAEYAMABhAFcAOQB1AGMAMgBoAHAAYwBFAGwAdQBaAG0AOQBEAGIAMgA1ADAAWQBXAGwAdQBaAFgASQBpAEkARgBaAGgAYgBIAFYAbABQAFMASgB6AGUAeQBaAHgAZABXADkAMABPADIATgB2AGIASABWAHQAYgBrAE4AdgBkAFcANQAwAEoAbgBGADEAYgAzAFEANwBPAGoARQBzAEoAbgBGADEAYgAzAFEANwBhADIAVgA1AFEAMgA5AHMAZABXADEAdQBUAG0ARgB0AFoAWABNAG0AYwBYAFYAdgBkAEQAcwA2AFcAMQAwAHMASgBuAEYAMQBiADMAUQA3AGMAWABWAGwAYwBuAGwAUwBaAFcAeABoAGQARwBsAHYAYgBuAE4AbwBhAFgAQgB6AEoAbgBGADEAYgAzAFEANwBPAGwAdABkAEwAQwBaAHgAZABXADkAMABPADIATgB2AGIASABWAHQAYgBrAGwAawBaAFcANQAwAGEAWABSAHAAWgBYAE0AbQBjAFgAVgB2AGQARABzADYAVwB5AFoAeABkAFcAOQAwAE8AMQBOAGwAWQAzAFIAcABiADIANAB4AEwAMQBGADEAWgBYAEoANQBNAFMAOQBCAGQAWABSAHYAVQBtAFYAdABiADMAWgBsAFoARQBOAHYAYgBIAFYAdABiAG4ATQB4AEwAbgB0AFIAZABXAFYAeQBlAFQARQBzAE0ASAAwAG0AYwBYAFYAdgBkAEQAdABkAEwAQwBaAHgAZABXADkAMABPADAATgB2AGIASABWAHQAYgBrAE4AdgBkAFcANQAwAEoAbgBGADEAYgAzAFEANwBPAGoARQBzAEoAbgBGADEAYgAzAFEANwBTADIAVgA1AFEAMgA5AHMAZABXADEAdQBUAG0ARgB0AFoAWABNAG0AYwBYAFYAdgBkAEQAcwA2AFcAMQAwAHMASgBuAEYAMQBiADMAUQA3AFEAMgA5AHMAZABXADEAdQBTAFcAUgBsAGIAbgBSAHAAZABHAGwAbABjAHkAWgB4AGQAVwA5ADAATwB6AHAAYgBKAG4ARgAxAGIAMwBRADcAVQAyAFYAagBkAEcAbAB2AGIAagBFAHYAVQBYAFYAbABjAG4AawB4AEwAMABGADEAZABHADkAUwBaAFcAMQB2AGQAbQBWAGsAUQAyADkAcwBkAFcAMQB1AGMAegBFAHUAZQAxAEYAMQBaAFgASgA1AE0AUwB3AHcAZgBTAFoAeABkAFcAOQAwAE8AMQAwAHMASgBuAEYAMQBiADMAUQA3AFUAbQBWAHMAWQBYAFIAcABiADIANQB6AGEARwBsAHcAUwBXADUAbQBiAHkAWgB4AGQAVwA5ADAATwB6AHAAYgBYAFgAMABpAEkAQwA4ACsAUABDADkAVABkAEcARgBpAGIARwBWAEYAYgBuAFIAeQBhAFcAVgB6AFAAagB3AHYAUwBYAFIAbABiAFQANAA4AFMAWABSAGwAYgBUADQAOABTAFgAUgBsAGIAVQB4AHYAWQAyAEYAMABhAFcAOQB1AFAAagB4AEoAZABHAFYAdABWAEgAbAB3AFoAVAA1AEcAYgAzAEoAdABkAFcAeABoAFAAQwA5AEoAZABHAFYAdABWAEgAbAB3AFoAVAA0ADgAUwBYAFIAbABiAFYAQgBoAGQARwBnACsAVQAyAFYAagBkAEcAbAB2AGIAagBFAHYAVQBYAFYAbABjAG4AawB4AEwAMQBOAHYAZABYAEoAagBaAFQAdwB2AFMAWABSAGwAYgBWAEIAaABkAEcAZwArAFAAQwA5AEoAZABHAFYAdABUAEcAOQBqAFkAWABSAHAAYgAyADQAKwBQAEYATgAwAFkAVwBKAHMAWgBVAFYAdQBkAEgASgBwAFoAWABNAGcATAB6ADQAOABMADAAbAAwAFoAVwAwACsAUABDADkASgBkAEcAVgB0AGMAegA0ADgATAAwAHgAdgBZADIARgBzAFUARwBGAGoAYQAyAEYAbgBaAFUAMQBsAGQARwBGAGsAWQBYAFIAaABSAG0AbABzAFoAVAA0AFcAQQBBAEEAQQBVAEUAcwBGAEIAZwBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEAQQBBAEEATgBvAEEAQQBBAEEAQgBBAEEAQQBBADAASQB5AGQAMwB3AEUAVgAwAFIARwBNAGUAZwBEAEEAVAA4AEsAWAA2AHcARQBBAEEAQQBCAHMANgBwAEoAUwByAHYAeQBCAFIAbwBsAEQAVABFAGMAWQA5AGIAcgArAEEAQQBBAEEAQQBBAEkAQQBBAEEAQQBBAEEAQQBOAG0AQQBBAEQAQQBBAEEAQQBBAEUAQQBBAEEAQQBNADIAQQBCAHEAcgBrAFUASABXAEwASQBqAHUAdABtAHcAVAA4AGEAUwB3AEEAQQBBAEEAQQBCAEkAQQBBAEEASwBBAEEAQQBBAEEAUQBBAEEAQQBBAEIAKwArADQAcABrADIAYwAzADgAbgBsACsAQgA4AEMAUQAxAHgAUQA4AGwAQQBBAEEAQQBDAEQAVABnAGcAVgBUAFgAZABjAGUAaQAxAGQAQQA0AFEAcABTADIARQBNADMAagA5AHoARAB4AHUATABSAE8AegBQAGMARgArAFYAbABEADMAVABPAEgAdQBjAGQAVQBpAGwAbgBmAFYARwBpAEYAZwBSAGoANgBvAEQAcABoAGEAdABFAFQAdwBjAHcAZwBrAFAAKwB4AFgAQgA0AFQAaQB4AGIAWQB2AEQAcAA5ADAAeQBuADcAYQBqAEYARgBiAFYAQgBIADQAMQBzAHgASwArAEUAeABRAEEAQQBBAEQAbgBVAHcAUABqADgAbwBaAEQATwBjAHMAYQBDAEEAbABaADIAQwBsAG8AOABWAFEATQBtAHcAPQA9ADwALwBEAGEAdABhAE0AYQBzAGgAdQBwAD4AUEsDBAoAAAAAAAAAIQBNi82aOgEAADoBAAAYAAAAY3VzdG9tWG1sL2l0ZW1Qcm9wczEueG1sPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8ZHM6ZGF0YXN0b3JlSXRlbSBkczppdGVtSUQ9Ins3NzhEMUZFOS0yNDVFLTQ2NzUtODY1OS03QTRBOUJFNkJCRTB9IiB4bWxuczpkcz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvY3VzdG9tWG1sIj48ZHM6c2NoZW1hUmVmcz48ZHM6c2NoZW1hUmVmIGRzOnVyaT0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9EYXRhTWFzaHVwIi8+PC9kczpzY2hlbWFSZWZzPjwvZHM6ZGF0YXN0b3JlSXRlbT5QSwMECgAAAAAAAAAhAFqxufOUAAAAlAAAABMAAABjdXN0b21YbWwvaXRlbTIueG1sPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48Q29ubmVjdGVkV29ya2Jvb2sgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vQ29ubmVjdGVkV29ya2Jvb2siIHZlcnNpb249IjEuMC4wIj48L0Nvbm5lY3RlZFdvcmtib29rPlBLAwQKAAAAAAAAACEAFSe/CUEBAABBAQAAGAAAAGN1c3RvbVhtbC9pdGVtUHJvcHMyLnhtbDw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04IiBzdGFuZGFsb25lPSJubyI/Pg0KPGRzOmRhdGFzdG9yZUl0ZW0gZHM6aXRlbUlEPSJ7MEIzODRDM0MtRTFENC00MDFCLThDRjQtNjI4NTk0OUQ3NjcxfSIgeG1sbnM6ZHM9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZpY2VEb2N1bWVudC8yMDA2L2N1c3RvbVhtbCI+PGRzOnNjaGVtYVJlZnM+PGRzOnNjaGVtYVJlZiBkczp1cmk9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vQ29ubmVjdGVkV29ya2Jvb2siLz48L2RzOnNjaGVtYVJlZnM+PC9kczpkYXRhc3RvcmVJdGVtPlBLAwQKAAAAAADRcCRUfrdlns8CAADPAgAAEQAAAGRvY1Byb3BzL2NvcmUueG1sPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxjcDpjb3JlUHJvcGVydGllcyB4bWxuczpjcD0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL3BhY2thZ2UvMjAwNi9tZXRhZGF0YS9jb3JlLXByb3BlcnRpZXMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6ZGN0ZXJtcz0iaHR0cDovL3B1cmwub3JnL2RjL3Rlcm1zLyIgeG1sbnM6ZGNtaXR5cGU9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS8iIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiPjxkYzpjcmVhdG9yPkBtaWNyb3NvZnQvY29ubmVjdGVkLXdvcmtib29rczwvZGM6Y3JlYXRvcj48Y3A6bGFzdE1vZGlmaWVkQnk+QG1pY3Jvc29mdC9jb25uZWN0ZWQtd29ya2Jvb2tzPC9jcDpsYXN0TW9kaWZpZWRCeT48ZGN0ZXJtczpjcmVhdGVkIHhzaTp0eXBlPSJkY3Rlcm1zOlczQ0RURiI+MjAyMi0wMS0wNFQxNDowNjozNC45NTdaPC9kY3Rlcm1zOmNyZWF0ZWQ+PGRjdGVybXM6bW9kaWZpZWQgeHNpOnR5cGU9ImRjdGVybXM6VzNDRFRGIj4yMDIyLTAxLTA0VDE0OjA2OjM0Ljk1N1o8L2RjdGVybXM6bW9kaWZpZWQ+PGRjOnRpdGxlPkBtaWNyb3NvZnQvY29ubmVjdGVkLXdvcmtib29rcyB3b3JrYm9vazwvZGM6dGl0bGU+PC9jcDpjb3JlUHJvcGVydGllcz5QSwMECgAAAAAAAAAhANz31OcsAwAALAMAABAAAABkb2NQcm9wcy9hcHAueG1sPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/Pg0KPFByb3BlcnRpZXMgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZpY2VEb2N1bWVudC8yMDA2L2V4dGVuZGVkLXByb3BlcnRpZXMiIHhtbG5zOnZ0PSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9kb2NQcm9wc1ZUeXBlcyI+PEFwcGxpY2F0aW9uPk1pY3Jvc29mdCBFeGNlbDwvQXBwbGljYXRpb24+PERvY1NlY3VyaXR5PjA8L0RvY1NlY3VyaXR5PjxTY2FsZUNyb3A+ZmFsc2U8L1NjYWxlQ3JvcD48SGVhZGluZ1BhaXJzPjx2dDp2ZWN0b3Igc2l6ZT0iMiIgYmFzZVR5cGU9InZhcmlhbnQiPjx2dDp2YXJpYW50Pjx2dDpscHN0cj5Xb3Jrc2hlZXRzPC92dDpscHN0cj48L3Z0OnZhcmlhbnQ+PHZ0OnZhcmlhbnQ+PHZ0Omk0PjI8L3Z0Omk0PjwvdnQ6dmFyaWFudD48L3Z0OnZlY3Rvcj48L0hlYWRpbmdQYWlycz48VGl0bGVzT2ZQYXJ0cz48dnQ6dmVjdG9yIHNpemU9IjIiIGJhc2VUeXBlPSJscHN0ciI+PHZ0Omxwc3RyPlF1ZXJ5MTwvdnQ6bHBzdHI+PHZ0Omxwc3RyPlNoZWV0MTwvdnQ6bHBzdHI+PC92dDp2ZWN0b3I+PC9UaXRsZXNPZlBhcnRzPjxDb21wYW55PjwvQ29tcGFueT48TGlua3NVcFRvRGF0ZT5mYWxzZTwvTGlua3NVcFRvRGF0ZT48U2hhcmVkRG9jPmZhbHNlPC9TaGFyZWREb2M+PEh5cGVybGlua3NDaGFuZ2VkPmZhbHNlPC9IeXBlcmxpbmtzQ2hhbmdlZD48QXBwVmVyc2lvbj4xNi4wMzAwPC9BcHBWZXJzaW9uPjwvUHJvcGVydGllcz5QSwMECgAAAAAAAAAhAPzFE/40AQAANAEAAB8AAAB4bC90YWJsZXMvX3JlbHMvdGFibGUxLnhtbC5yZWxzPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/Pg0KPFJlbGF0aW9uc2hpcHMgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9wYWNrYWdlLzIwMDYvcmVsYXRpb25zaGlwcyI+PFJlbGF0aW9uc2hpcCBJZD0icklkMSIgVHlwZT0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvcmVsYXRpb25zaGlwcy9xdWVyeVRhYmxlIiBUYXJnZXQ9Ii4uL3F1ZXJ5VGFibGVzL3F1ZXJ5VGFibGUxLnhtbCIvPjwvUmVsYXRpb25zaGlwcz5QSwMECgAAAAAAAAAhAHQ/OXooAQAAKAEAAB4AAABjdXN0b21YbWwvX3JlbHMvaXRlbTEueG1sLnJlbHM8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJVVEYtOCIgc3RhbmRhbG9uZT0ieWVzIj8+DQo8UmVsYXRpb25zaGlwcyB4bWxucz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL3BhY2thZ2UvMjAwNi9yZWxhdGlvbnNoaXBzIj48UmVsYXRpb25zaGlwIElkPSJySWQxIiBUeXBlPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9yZWxhdGlvbnNoaXBzL2N1c3RvbVhtbFByb3BzIiBUYXJnZXQ9Iml0ZW1Qcm9wczEueG1sIi8+PC9SZWxhdGlvbnNoaXBzPlBLAwQKAAAAAAAAACEAXJYnIigBAAAoAQAAHgAAAGN1c3RvbVhtbC9fcmVscy9pdGVtMi54bWwucmVsczw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04IiBzdGFuZGFsb25lPSJ5ZXMiPz4NCjxSZWxhdGlvbnNoaXBzIHhtbG5zPSJodHRwOi8v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"; } diff --git a/tsconfig.json b/tsconfig.json index b60d7f3..6dbfc45 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,7 @@ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ "declaration": true /* Generates corresponding '.d.ts' file. */, // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - "sourceMap": true /* Generates corresponding '.map' file. */, + "sourceMap": false /* Generates corresponding '.map' file. */, // "outFile": "./", /* Concatenate and emit output to single file. */ "outDir": "./dist" /* Redirect output structure to the directory. */, // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */