diff --git a/.gitignore b/.gitignore
index 32b9cc9..37a4804 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/example/node_modules
/node_modules
+*xlsx*
diff --git a/Readme.md b/Readme.md
index 089a6d8..1a9e9e3 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1,19 +1,22 @@
# excel-export #
-A simple node.js module for exporting data set to Excel xlsx file.
+A simple js module for exporting data set to Excel xlsx file, it works in node and in the browser.
## Using excel-export ##
-Setup configs object before passing it into the execute method. If generating multiple sheets, configs object can be an array of worksheet configuration. Or passing in a worksheet configuration to generate single worksheet xlsx file. Within a worksheet configuration uses **name** attribute to specify worksheet name. **cols** is an array for column definition. Column definition should have caption and type properties while width property is not required. The unit for width property is character. **beforeCellWrite** callback is optional. beforeCellWrite is invoked with row, cell data and option object (eOpt detail later) parameters. The return value from beforeCellWrite is what get written into the cell. Supported valid types are string, date, bool and number. **rows** is the data to be exported. It is an Array of Array (row). Each row should be the same length as cols. Styling is optional. However, if you want to style your spreadsheet, a valid excel styles xml file is needed. An easy way to get a styles xml file is to unzip an existing xlsx file which has the desired styles and copy out the styles.xml file. Use **stylesXmlFile** property of configuartion object to specify the relative path and file name of the xml file. Google for "spreadsheetml style" to learn more detail on styling spreadsheet. eOpt in beforeCellWrite callback contains rowNum for current row number. eOpt.styleIndex should be a valid zero based index from cellXfs tag of the selected styles xml file. eOpt.cellType is default to the type value specified in column definition. However, in some scenario you might want to change it for different format.
+Setup configs object before passing it into the execute method. If generating multiple sheets, configs object can be an array of worksheet configuration. Or passing in a worksheet configuration to generate single worksheet xlsx file. Within a worksheet configuration uses **name** attribute to specify worksheet name. **cols** is an array for column definition. Column definition should have caption and type properties while width property is not required. The unit for width property is character. **beforeCellWrite** callback is optional. beforeCellWrite is invoked with row, cell data and option object (eOpt detail later) parameters. The return value from beforeCellWrite is what get written into the cell. Supported valid types are string, date, bool and number. **rows** is the data to be exported. It is an Array of Array (row). Each row should be the same length as cols. Styling is optional. However, if you want to style your spreadsheet, a valid excel styles xml file is needed. An easy way to get a styles xml file is to unzip an existing xlsx file which has the desired styles and copy out the styles.xml file. Use **stylesXml**
+property of configuration object to specify the content of the xml file. Google for "spreadsheetml style" to learn more detail on styling spreadsheet. eOpt in beforeCellWrite callback contains rowNum for current row number. eOpt.styleIndex should be a valid zero based index from cellXfs tag of the selected styles xml file. eOpt.cellType is default to the type value specified in column definition. However, in some scenario you might want to change it for different format.
var express = require('express');
var nodeExcel = require('excel-export');
var app = express();
+ var fs = require('fs')
app.get('/Excel', function(req, res){
var conf ={};
- conf.stylesXmlFile = "styles.xml";
+ var xmlFile = fs.readFileSync("styles.xml")
+ conf.stylesXml = xmlFile
conf.name = "mysheet";
conf.cols = [{
caption:'string',
@@ -62,3 +65,14 @@ Setup configs object before passing it into the execute method. If generating mu
app.listen(3000);
console.log('Listening on port 3000');
+
+Easiest way to use it in the browser is using buffer. Do npm install buffer
+
+ var Buffer = require('buffer/').Buffer
+ // ... same as previous example
+ var result = nodeExcel.execute(conf)
+ var blob = new Blob([new Buffer(result, 'binary')], {type: 'application/vnd.openxmlformats'})
+ saveAs(blob, 'excel.xlsx')
+
+### Disclaimer ###
+This package is based in the [original](https://github.com/functionscope/Node-Excel-Export) but ported to support browser and avoid global side effects.
\ No newline at end of file
diff --git a/example/app.js b/example/app.js
index bd5aa5d..74455c1 100644
--- a/example/app.js
+++ b/example/app.js
@@ -1,86 +1,86 @@
var express = require('express'),
- nodeExcel = require('excel-export'),
- uuid = require('node-uuid'),
- app = express();
+ nodeExcel = require('excel-export'),
+ uuid = require('node-uuid'),
+ app = express()
-app.get('/Large', function(req, res){
- var conf ={};
- conf.cols = [];
- for (i = 0; i < 100; i++){
+app.get('/Large', function (req, res) {
+ var conf = {}
+ conf.cols = []
+ for (i = 0; i < 100; i++) {
conf.cols.push({
- caption:'string ' + i,
- captionStyleIndex: 1,
- type:'string'
- });
+ caption: 'string ' + i,
+ captionStyleIndex: 1,
+ type: 'string'
+ })
}
- conf.rows = [];
- for (j = 0; j < 1000; j++){
- var row = [];
- for (k = 0; k < 100; k++){
- row.push(uuid.v4());
- }
- conf.rows.push(row);
- conf.rows.push(row);
+ conf.rows = []
+ for (j = 0; j < 1000; j++) {
+ var row = []
+ for (k = 0; k < 100; k++) {
+ row.push(uuid.v4())
+ }
+ conf.rows.push(row)
+ conf.rows.push(row)
}
- var result = nodeExcel.execute(conf);
- res.setHeader('Content-Type', 'application/vnd.openxmlformats');
- res.setHeader("Content-Disposition", "attachment; filename=" + "Large.xlsx");
- res.end(result, 'binary');
+ var result = nodeExcel.execute(conf)
+ res.setHeader('Content-Type', 'application/vnd.openxmlformats')
+ res.setHeader('Content-Disposition', 'attachment; filename=' + 'Large.xlsx')
+ res.end(result, 'binary')
+})
-});
-
-app.get('/Excel', function(req, res){
- var conf ={};
- // uncomment it for style example
+app.get('/Excel', function (req, res) {
+ var conf = {}
+ // uncomment it for style example
// conf.stylesXmlFile = "styles.xml";
- conf.cols = [{
- caption:'string',
- captionStyleIndex: 1,
- type:'string',
- beforeCellWrite:function(row, cellData){
- return cellData.toUpperCase();
- }
- , width:15
- },{
- caption:'date',
- type:'date',
- beforeCellWrite:function(){
- var originDate = new Date(Date.UTC(1899,11,30));
- return function(row, cellData, eOpt){
- // uncomment it for style example
+ conf.cols = [{
+ caption: 'string',
+ captionStyleIndex: 1,
+ type: 'string',
+ beforeCellWrite: function (row, cellData) {
+ return cellData.toUpperCase()
+ },
+ width: 15
+ }, {
+ caption: 'date',
+ type: 'date',
+ beforeCellWrite: (function () {
+ var originDate = new Date(Date.UTC(1899, 11, 30))
+ return function (row, cellData, eOpt) {
+ // uncomment it for style example
// if (eOpt.rowNum%2){
// eOpt.styleIndex = 1;
- // }
+ // }
// else{
// eOpt.styleIndex = 2;
// }
- if (cellData === null){
- eOpt.cellType = 'string';
- return 'N/A';
- } else
- return (cellData - originDate) / (24 * 60 * 60 * 1000);
- }
- }()
- , width:20.85
- },{
- caption:'bool',
- type:'bool'
- },{
- caption:'number',
- type:'number',
- width:30
- }];
- conf.rows = [
+ if (cellData === null) {
+ eOpt.cellType = 'string'
+ return 'N/A'
+ } else {
+ return (cellData - originDate) / (24 * 60 * 60 * 1000)
+ }
+ }
+ }()),
+ width: 20.85
+ }, {
+ caption: 'bool',
+ type: 'bool'
+ }, {
+ caption: 'number',
+ type: 'number',
+ width: 30
+ }]
+ conf.rows = [
['pi', new Date(Date.UTC(2013, 4, 1)), true, 3.14159],
- ["e", new Date(2012, 4, 1), false, 2.7182],
+ ['e', new Date(2012, 4, 1), false, 2.7182],
["M&M<>'", new Date(Date.UTC(2013, 6, 9)), false, 1.61803],
- ["null date", null, true, 1.414]
- ];
- var result = nodeExcel.execute(conf);
- res.setHeader('Content-Type', 'application/vnd.openxmlformats');
- res.setHeader("Content-Disposition", "attachment; filename=" + "Report.xlsx");
- res.end(result, 'binary');
-});
+ ['null date', null, true, 1.414]
+ ]
+ var result = nodeExcel.execute(conf)
+ res.setHeader('Content-Type', 'application/vnd.openxmlformats')
+ res.setHeader('Content-Disposition', 'attachment; filename=' + 'Report.xlsx')
+ res.end(result, 'binary')
+})
-app.listen(3000);
-console.log('Listening on port 3000');
\ No newline at end of file
+app.listen(3000)
+console.log('Listening on port 3000')
diff --git a/index.js b/index.js
index ea2dbc4..1032f80 100644
--- a/index.js
+++ b/index.js
@@ -1,123 +1,104 @@
-require('node-zip');
-var fs = require('fs'),
-Sheet = require('./sheet'),
-SortedMap = require('collections/sorted-map');
+// TODO update jszip to 3.x
+var JSZip = require('jszip')
+var Sheet = require('./sheet')
-Date.prototype.getJulian = function() {
- return Math.floor((this / 86400000) - (this.getTimezoneOffset() / 1440) + 2440587.5);
-};
-
-Date.prototype.oaDate = function() {
- return (this - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
-};
-
-var templateXLSX = "UEsDBAoAAAAAABN7eUK9Z10uNQQAADUEAAATAAAAW0NvbnRlbnRfVHlwZXNdLnhtbO+7vzw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi04Ij8+PFR5cGVzIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvcGFja2FnZS8yMDA2L2NvbnRlbnQtdHlwZXMiPjxEZWZhdWx0IEV4dGVuc2lvbj0ieG1sIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24vdm5kLm9wZW54bWxmb3JtYXRzLW9mZmljZWRvY3VtZW50LnNwcmVhZHNoZWV0bWwuc2hlZXQubWFpbit4bWwiIC8+PERlZmF1bHQgRXh0ZW5zaW9uPSJyZWxzIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24vdm5kLm9wZW54bWxmb3JtYXRzLXBhY2thZ2UucmVsYXRpb25zaGlwcyt4bWwiIC8+PERlZmF1bHQgRXh0ZW5zaW9uPSJwc21kY3AiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtcGFja2FnZS5jb3JlLXByb3BlcnRpZXMreG1sIiAvPjxPdmVycmlkZSBQYXJ0TmFtZT0iL2RvY1Byb3BzL2FwcC54bWwiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQuZXh0ZW5kZWQtcHJvcGVydGllcyt4bWwiIC8+PE92ZXJyaWRlIFBhcnROYW1lPSIveGwvc2hhcmVkU3RyaW5ncy54bWwiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQuc3ByZWFkc2hlZXRtbC5zaGFyZWRTdHJpbmdzK3htbCIgLz48T3ZlcnJpZGUgUGFydE5hbWU9Ii94bC9zdHlsZXMueG1sIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24vdm5kLm9wZW54bWxmb3JtYXRzLW9mZmljZWRvY3VtZW50LnNwcmVhZHNoZWV0bWwuc3R5bGVzK3htbCIgLz48T3ZlcnJpZGUgUGFydE5hbWU9Ii94bC93b3Jrc2hlZXRzL3NoZWV0LnhtbCIgQ29udGVudFR5cGU9ImFwcGxpY2F0aW9uL3ZuZC5vcGVueG1sZm9ybWF0cy1vZmZpY2Vkb2N1bWVudC5zcHJlYWRzaGVldG1sLndvcmtzaGVldCt4bWwiIC8+PE92ZXJyaWRlIFBhcnROYW1lPSIveGwvdGhlbWUvdGhlbWUueG1sIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24vdm5kLm9wZW54bWxmb3JtYXRzLW9mZmljZWRvY3VtZW50LnRoZW1lK3htbCIgLz48L1R5cGVzPlBLAwQKAAAAAACLdTlIAAAAAAAAAAAAAAAABgAAAF9yZWxzL1BLAwQKAAAAAAATe3lCdJmAA5wCAACcAgAACwAAAF9yZWxzLy5yZWxz77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48UmVsYXRpb25zaGlwcyB4bWxucz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL3BhY2thZ2UvMjAwNi9yZWxhdGlvbnNoaXBzIj48UmVsYXRpb25zaGlwIFR5cGU9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZpY2VEb2N1bWVudC8yMDA2L3JlbGF0aW9uc2hpcHMvb2ZmaWNlRG9jdW1lbnQiIFRhcmdldD0iL3hsL3dvcmtib29rLnhtbCIgSWQ9IlI0YWEyMmIzMWExYTc0MjkxIiAvPjxSZWxhdGlvbnNoaXAgVHlwZT0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvcmVsYXRpb25zaGlwcy9leHRlbmRlZC1wcm9wZXJ0aWVzIiBUYXJnZXQ9Ii9kb2NQcm9wcy9hcHAueG1sIiBJZD0icklkMSIgLz48UmVsYXRpb25zaGlwIFR5cGU9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9wYWNrYWdlLzIwMDYvcmVsYXRpb25zaGlwcy9tZXRhZGF0YS9jb3JlLXByb3BlcnRpZXMiIFRhcmdldD0iL3BhY2thZ2Uvc2VydmljZXMvbWV0YWRhdGEvY29yZS1wcm9wZXJ0aWVzL2VjZmRkMzE0M2YyMTQ4OTA5NWE0NGM3MTExNWI3MjNiLnBzbWRjcCIgSWQ9IlJlZjQ4N2MzZTBjNzQ0YTg3IiAvPjwvUmVsYXRpb25zaGlwcz5QSwMECgAAAAAAi3U5SAAAAAAAAAAAAAAAAAkAAABkb2NQcm9wcy9QSwMECgAAAAAAE3t5Qu9e3149AwAAPQMAABAAAABkb2NQcm9wcy9hcHAueG1s77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48YXA6UHJvcGVydGllcyB4bWxuczp2dD0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvZG9jUHJvcHNWVHlwZXMiIHhtbG5zOmFwPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9leHRlbmRlZC1wcm9wZXJ0aWVzIj48YXA6QXBwbGljYXRpb24+TWljcm9zb2Z0IEV4Y2VsPC9hcDpBcHBsaWNhdGlvbj48YXA6RG9jU2VjdXJpdHk+MDwvYXA6RG9jU2VjdXJpdHk+PGFwOlNjYWxlQ3JvcD5mYWxzZTwvYXA6U2NhbGVDcm9wPjxhcDpIZWFkaW5nUGFpcnM+PHZ0OnZlY3RvciBiYXNlVHlwZT0idmFyaWFudCIgc2l6ZT0iNCI+PHZ0OnZhcmlhbnQ+PHZ0Omxwc3RyPldvcmtzaGVldHM8L3Z0Omxwc3RyPjwvdnQ6dmFyaWFudD48dnQ6dmFyaWFudD48dnQ6aTQ+MTwvdnQ6aTQ+PC92dDp2YXJpYW50Pjx2dDp2YXJpYW50Pjx2dDpscHN0cj5OYW1lZCBSYW5nZXM8L3Z0Omxwc3RyPjwvdnQ6dmFyaWFudD48dnQ6dmFyaWFudD48dnQ6aTQ+MjwvdnQ6aTQ+PC92dDp2YXJpYW50PjwvdnQ6dmVjdG9yPjwvYXA6SGVhZGluZ1BhaXJzPjxhcDpUaXRsZXNPZlBhcnRzPjx2dDp2ZWN0b3IgYmFzZVR5cGU9Imxwc3RyIiBzaXplPSIzIj48dnQ6bHBzdHI+U2hlZXQgMTwvdnQ6bHBzdHI+PHZ0Omxwc3RyPlNoZWV0IDEhUHJpbnRfQXJlYTwvdnQ6bHBzdHI+PHZ0Omxwc3RyPlNoZWV0IDEhUHJpbnRfVGl0bGVzPC92dDpscHN0cj48L3Z0OnZlY3Rvcj48L2FwOlRpdGxlc09mUGFydHM+PC9hcDpQcm9wZXJ0aWVzPlBLAwQKAAAAAACLdTlIAAAAAAAAAAAAAAAACAAAAHBhY2thZ2UvUEsDBAoAAAAAAMWFeUIAAAAAAAAAAAAAAAARAAAAcGFja2FnZS9zZXJ2aWNlcy9QSwMECgAAAAAAxYV5QgAAAAAAAAAAAAAAABoAAABwYWNrYWdlL3NlcnZpY2VzL21ldGFkYXRhL1BLAwQKAAAAAADFhXlCAAAAAAAAAAAAAAAAKgAAAHBhY2thZ2Uvc2VydmljZXMvbWV0YWRhdGEvY29yZS1wcm9wZXJ0aWVzL1BLAwQKAAAAAAATe3lCc4c2yNoBAADaAQAAUQAAAHBhY2thZ2Uvc2VydmljZXMvbWV0YWRhdGEvY29yZS1wcm9wZXJ0aWVzL2VjZmRkMzE0M2YyMTQ4OTA5NWE0NGM3MTExNWI3MjNiLnBzbWRjcO+7vzw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi04Ij8+PGNvcmVQcm9wZXJ0aWVzIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6ZGN0ZXJtcz0iaHR0cDovL3B1cmwub3JnL2RjL3Rlcm1zLyIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9wYWNrYWdlLzIwMDYvbWV0YWRhdGEvY29yZS1wcm9wZXJ0aWVzIj48ZGN0ZXJtczpjcmVhdGVkIHhzaTp0eXBlPSJkY3Rlcm1zOlczQ0RURiI+MjAxMy0wMy0yNVQxOToyNDozOS44NjYxOTY5WjwvZGN0ZXJtczpjcmVhdGVkPjxkY3Rlcm1zOm1vZGlmaWVkIHhzaTp0eXBlPSJkY3Rlcm1zOlczQ0RURiI+MjAxMy0wMy0yNVQxOToyNDozOS44NjYxOTY5WjwvZGN0ZXJtczptb2RpZmllZD48L2NvcmVQcm9wZXJ0aWVzPlBLAwQKAAAAAACLdTlIAAAAAAAAAAAAAAAAAwAAAHhsL1BLAwQKAAAAAADFhXlCAAAAAAAAAAAAAAAACQAAAHhsL19yZWxzL1BLAwQKAAAAAAATe3lCJ0p8MrwCAAC8AgAAGgAAAHhsL19yZWxzL3dvcmtib29rLnhtbC5yZWxz77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48UmVsYXRpb25zaGlwcyB4bWxucz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL3BhY2thZ2UvMjAwNi9yZWxhdGlvbnNoaXBzIj48UmVsYXRpb25zaGlwIFR5cGU9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZpY2VEb2N1bWVudC8yMDA2L3JlbGF0aW9uc2hpcHMvc2hhcmVkU3RyaW5ncyIgVGFyZ2V0PSIveGwvc2hhcmVkU3RyaW5ncy54bWwiIElkPSJySWQzIiAvPjxSZWxhdGlvbnNoaXAgVHlwZT0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvcmVsYXRpb25zaGlwcy9zdHlsZXMiIFRhcmdldD0iL3hsL3N0eWxlcy54bWwiIElkPSJySWQ0IiAvPjxSZWxhdGlvbnNoaXAgVHlwZT0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvcmVsYXRpb25zaGlwcy93b3Jrc2hlZXQiIFRhcmdldD0iL3hsL3dvcmtzaGVldHMvc2hlZXQueG1sIiBJZD0icklkMiIgLz48UmVsYXRpb25zaGlwIFR5cGU9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZpY2VEb2N1bWVudC8yMDA2L3JlbGF0aW9uc2hpcHMvdGhlbWUiIFRhcmdldD0iL3hsL3RoZW1lL3RoZW1lLnhtbCIgSWQ9InJJZDYiIC8+PC9SZWxhdGlvbnNoaXBzPlBLAwQKAAAAAAATe3lCflKRBZAAAACQAAAAFAAAAHhsL3NoYXJlZFN0cmluZ3MueG1s77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48eDpzc3QgY291bnQ9IjAiIHVuaXF1ZUNvdW50PSIwIiB4bWxuczp4PSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvc3ByZWFkc2hlZXRtbC8yMDA2L21haW4iIC8+UEsDBAoAAAAAABN7eUIi2lsreggAAHoIAAANAAAAeGwvc3R5bGVzLnhtbO+7vzw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi04Ij8+PHg6c3R5bGVTaGVldCB4bWxuczp4PSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvc3ByZWFkc2hlZXRtbC8yMDA2L21haW4iPjx4Om51bUZtdHMgY291bnQ9IjEiPjx4Om51bUZtdCBudW1GbXRJZD0iMCIgZm9ybWF0Q29kZT0iIiAvPjwveDpudW1GbXRzPjx4OmZvbnRzIGNvdW50PSIxIj48eDpmb250Pjx4OnZlcnRBbGlnbiB2YWw9ImJhc2VsaW5lIiAvPjx4OnN6IHZhbD0iMTEiIC8+PHg6Y29sb3IgcmdiPSJGRjAwMDAwMCIgLz48eDpuYW1lIHZhbD0iQ2FsaWJyaSIgLz48eDpmYW1pbHkgdmFsPSIyIiAvPjwveDpmb250PjwveDpmb250cz48eDpmaWxscyBjb3VudD0iMiI+PHg6ZmlsbD48eDpwYXR0ZXJuRmlsbCBwYXR0ZXJuVHlwZT0ibm9uZSIgLz48L3g6ZmlsbD48eDpmaWxsPjx4OnBhdHRlcm5GaWxsIHBhdHRlcm5UeXBlPSJncmF5MTI1IiAvPjwveDpmaWxsPjwveDpmaWxscz48eDpib3JkZXJzIGNvdW50PSIxIj48eDpib3JkZXIgZGlhZ29uYWxVcD0iMCIgZGlhZ29uYWxEb3duPSIwIj48eDpsZWZ0IHN0eWxlPSJub25lIj48eDpjb2xvciByZ2I9IkZGMDAwMDAwIiAvPjwveDpsZWZ0Pjx4OnJpZ2h0IHN0eWxlPSJub25lIj48eDpjb2xvciByZ2I9IkZGMDAwMDAwIiAvPjwveDpyaWdodD48eDp0b3Agc3R5bGU9Im5vbmUiPjx4OmNvbG9yIHJnYj0iRkYwMDAwMDAiIC8+PC94OnRvcD48eDpib3R0b20gc3R5bGU9Im5vbmUiPjx4OmNvbG9yIHJnYj0iRkYwMDAwMDAiIC8+PC94OmJvdHRvbT48eDpkaWFnb25hbCBzdHlsZT0ibm9uZSI+PHg6Y29sb3IgcmdiPSJGRjAwMDAwMCIgLz48L3g6ZGlhZ29uYWw+PC94OmJvcmRlcj48L3g6Ym9yZGVycz48eDpjZWxsU3R5bGVYZnMgY291bnQ9IjIiPjx4OnhmIG51bUZtdElkPSIwIiBmb250SWQ9IjAiIGZpbGxJZD0iMCIgYm9yZGVySWQ9IjAiIGFwcGx5TnVtYmVyRm9ybWF0PSIwIiBhcHBseUZpbGw9IjEiIGFwcGx5Qm9yZGVyPSIwIiBhcHBseUFsaWdubWVudD0iMCIgYXBwbHlQcm90ZWN0aW9uPSIxIj48eDpwcm90ZWN0aW9uIGxvY2tlZD0iMSIgaGlkZGVuPSIwIiAvPjwveDp4Zj48eDp4ZiBudW1GbXRJZD0iMTQiIGZvbnRJZD0iMCIgZmlsbElkPSIwIiBib3JkZXJJZD0iMCIgYXBwbHlOdW1iZXJGb3JtYXQ9IjAiIGFwcGx5RmlsbD0iMSIgYXBwbHlCb3JkZXI9IjAiIGFwcGx5QWxpZ25tZW50PSIwIiBhcHBseVByb3RlY3Rpb249IjEiPjx4OnByb3RlY3Rpb24gbG9ja2VkPSIxIiBoaWRkZW49IjAiIC8+PC94OnhmPjwveDpjZWxsU3R5bGVYZnM+PHg6Y2VsbFhmcyBjb3VudD0iMiI+PHg6eGYgbnVtRm10SWQ9IjAiIGZvbnRJZD0iMCIgZmlsbElkPSIwIiBib3JkZXJJZD0iMCIgeGZJZD0iMCIgYXBwbHlOdW1iZXJGb3JtYXQ9IjAiIGFwcGx5RmlsbD0iMSIgYXBwbHlCb3JkZXI9IjAiIGFwcGx5QWxpZ25tZW50PSIwIiBhcHBseVByb3RlY3Rpb249IjEiPjx4OmFsaWdubWVudCBob3Jpem9udGFsPSJnZW5lcmFsIiB2ZXJ0aWNhbD0iYm90dG9tIiB0ZXh0Um90YXRpb249IjAiIHdyYXBUZXh0PSIwIiBpbmRlbnQ9IjAiIHJlbGF0aXZlSW5kZW50PSIwIiBqdXN0aWZ5TGFzdExpbmU9IjAiIHNocmlua1RvRml0PSIwIiByZWFkaW5nT3JkZXI9IjAiIC8+PHg6cHJvdGVjdGlvbiBsb2NrZWQ9IjEiIGhpZGRlbj0iMCIgLz48L3g6eGY+PHg6eGYgbnVtRm10SWQ9IjE0IiBmb250SWQ9IjAiIGZpbGxJZD0iMCIgYm9yZGVySWQ9IjAiIHhmSWQ9IjAiIGFwcGx5TnVtYmVyRm9ybWF0PSIwIiBhcHBseUZpbGw9IjEiIGFwcGx5Qm9yZGVyPSIwIiBhcHBseUFsaWdubWVudD0iMCIgYXBwbHlQcm90ZWN0aW9uPSIxIj48eDphbGlnbm1lbnQgaG9yaXpvbnRhbD0iZ2VuZXJhbCIgdmVydGljYWw9ImJvdHRvbSIgdGV4dFJvdGF0aW9uPSIwIiB3cmFwVGV4dD0iMCIgaW5kZW50PSIwIiByZWxhdGl2ZUluZGVudD0iMCIganVzdGlmeUxhc3RMaW5lPSIwIiBzaHJpbmtUb0ZpdD0iMCIgcmVhZGluZ09yZGVyPSIwIiAvPjx4OnByb3RlY3Rpb24gbG9ja2VkPSIxIiBoaWRkZW49IjAiIC8+PC94OnhmPjwveDpjZWxsWGZzPjx4OmNlbGxTdHlsZXMgY291bnQ9IjEiPjx4OmNlbGxTdHlsZSBuYW1lPSJOb3JtYWwiIHhmSWQ9IjAiIGJ1aWx0aW5JZD0iMCIgLz48L3g6Y2VsbFN0eWxlcz48L3g6c3R5bGVTaGVldD5QSwMECgAAAAAAxYV5QgAAAAAAAAAAAAAAAAkAAAB4bC90aGVtZS9QSwMECgAAAAAAE3t5QnWxkV67GwAAuxsAABIAAAB4bC90aGVtZS90aGVtZS54bWzvu788P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJ1dGYtOCI/PjxhOnRoZW1lIHhtbG5zOmE9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9kcmF3aW5nbWwvMjAwNi9tYWluIiBuYW1lPSJPZmZpY2UgVGhlbWUiPjxhOnRoZW1lRWxlbWVudHM+PGE6Y2xyU2NoZW1lIG5hbWU9Ik9mZmljZSI+PGE6ZGsxPjxhOnN5c0NsciB2YWw9IndpbmRvd1RleHQiIGxhc3RDbHI9IjAwMDAwMCIgLz48L2E6ZGsxPjxhOmx0MT48YTpzeXNDbHIgdmFsPSJ3aW5kb3ciIGxhc3RDbHI9IkZGRkZGRiIgLz48L2E6bHQxPjxhOmRrMj48YTpzcmdiQ2xyIHZhbD0iMUY0OTdEIiAvPjwvYTpkazI+PGE6bHQyPjxhOnNyZ2JDbHIgdmFsPSJFRUVDRTEiIC8+PC9hOmx0Mj48YTphY2NlbnQxPjxhOnNyZ2JDbHIgdmFsPSI0RjgxQkQiIC8+PC9hOmFjY2VudDE+PGE6YWNjZW50Mj48YTpzcmdiQ2xyIHZhbD0iQzA1MDREIiAvPjwvYTphY2NlbnQyPjxhOmFjY2VudDM+PGE6c3JnYkNsciB2YWw9IjlCQkI1OSIgLz48L2E6YWNjZW50Mz48YTphY2NlbnQ0PjxhOnNyZ2JDbHIgdmFsPSI4MDY0QTIiIC8+PC9hOmFjY2VudDQ+PGE6YWNjZW50NT48YTpzcmdiQ2xyIHZhbD0iNEJBQ0M2IiAvPjwvYTphY2NlbnQ1PjxhOmFjY2VudDY+PGE6c3JnYkNsciB2YWw9IkY3OTY0NiIgLz48L2E6YWNjZW50Nj48YTpobGluaz48YTpzcmdiQ2xyIHZhbD0iMDAwMEZGIiAvPjwvYTpobGluaz48YTpmb2xIbGluaz48YTpzcmdiQ2xyIHZhbD0iODAwMDgwIiAvPjwvYTpmb2xIbGluaz48L2E6Y2xyU2NoZW1lPjxhOmZvbnRTY2hlbWUgbmFtZT0iT2ZmaWNlIj48YTptYWpvckZvbnQ+PGE6bGF0aW4gdHlwZWZhY2U9IkNhbWJyaWEiIC8+PGE6ZWEgdHlwZWZhY2U9IiIgLz48YTpjcyB0eXBlZmFjZT0iIiAvPjxhOmZvbnQgc2NyaXB0PSJKcGFuIiB0eXBlZmFjZT0i77yt77yzIO+8sOOCtOOCt+ODg+OCryIgLz48YTpmb250IHNjcmlwdD0iSGFuZyIgdHlwZWZhY2U9IuunkeydgCDqs6DrlJUiIC8+PGE6Zm9udCBzY3JpcHQ9IkhhbnMiIHR5cGVmYWNlPSLlrovkvZMiIC8+PGE6Zm9udCBzY3JpcHQ9IkhhbnQiIHR5cGVmYWNlPSLmlrDntLDmmI7pq5QiIC8+PGE6Zm9udCBzY3JpcHQ9IkFyYWIiIHR5cGVmYWNlPSJUaW1lcyBOZXcgUm9tYW4iIC8+PGE6Zm9udCBzY3JpcHQ9IkhlYnIiIHR5cGVmYWNlPSJUaW1lcyBOZXcgUm9tYW4iIC8+PGE6Zm9udCBzY3JpcHQ9IlRoYWkiIHR5cGVmYWNlPSJUYWhvbWEiIC8+PGE6Zm9udCBzY3JpcHQ9IkV0aGkiIHR5cGVmYWNlPSJOeWFsYSIgLz48YTpmb250IHNjcmlwdD0iQmVuZyIgdHlwZWZhY2U9IlZyaW5kYSIgLz48YTpmb250IHNjcmlwdD0iR3VqciIgdHlwZWZhY2U9IlNocnV0aSIgLz48YTpmb250IHNjcmlwdD0iS2htciIgdHlwZWZhY2U9Ik1vb2xCb3JhbiIgLz48YTpmb250IHNjcmlwdD0iS25kYSIgdHlwZWZhY2U9IlR1bmdhIiAvPjxhOmZvbnQgc2NyaXB0PSJHdXJ1IiB0eXBlZmFjZT0iUmFhdmkiIC8+PGE6Zm9udCBzY3JpcHQ9IkNhbnMiIHR5cGVmYWNlPSJFdXBoZW1pYSIgLz48YTpmb250IHNjcmlwdD0iQ2hlciIgdHlwZWZhY2U9IlBsYW50YWdlbmV0IENoZXJva2VlIiAvPjxhOmZvbnQgc2NyaXB0PSJZaWlpIiB0eXBlZmFjZT0iTWljcm9zb2Z0IFlpIEJhaXRpIiAvPjxhOmZvbnQgc2NyaXB0PSJUaWJ0IiB0eXBlZmFjZT0iTWljcm9zb2Z0IEhpbWFsYXlhIiAvPjxhOmZvbnQgc2NyaXB0PSJUaGFhIiB0eXBlZmFjZT0iTVYgQm9saSIgLz48YTpmb250IHNjcmlwdD0iRGV2YSIgdHlwZWZhY2U9Ik1hbmdhbCIgLz48YTpmb250IHNjcmlwdD0iVGVsdSIgdHlwZWZhY2U9IkdhdXRhbWkiIC8+PGE6Zm9udCBzY3JpcHQ9IlRhbWwiIHR5cGVmYWNlPSJMYXRoYSIgLz48YTpmb250IHNjcmlwdD0iU3lyYyIgdHlwZWZhY2U9IkVzdHJhbmdlbG8gRWRlc3NhIiAvPjxhOmZvbnQgc2NyaXB0PSJPcnlhIiB0eXBlZmFjZT0iS2FsaW5nYSIgLz48YTpmb250IHNjcmlwdD0iTWx5bSIgdHlwZWZhY2U9IkthcnRpa2EiIC8+PGE6Zm9udCBzY3JpcHQ9Ikxhb28iIHR5cGVmYWNlPSJEb2tDaGFtcGEiIC8+PGE6Zm9udCBzY3JpcHQ9IlNpbmgiIHR5cGVmYWNlPSJJc2tvb2xhIFBvdGEiIC8+PGE6Zm9udCBzY3JpcHQ9Ik1vbmciIHR5cGVmYWNlPSJNb25nb2xpYW4gQmFpdGkiIC8+PGE6Zm9udCBzY3JpcHQ9IlZpZXQiIHR5cGVmYWNlPSJUaW1lcyBOZXcgUm9tYW4iIC8+PGE6Zm9udCBzY3JpcHQ9IlVpZ2giIHR5cGVmYWNlPSJNaWNyb3NvZnQgVWlnaHVyIiAvPjwvYTptYWpvckZvbnQ+PGE6bWlub3JGb250PjxhOmxhdGluIHR5cGVmYWNlPSJDYWxpYnJpIiAvPjxhOmVhIHR5cGVmYWNlPSIiIC8+PGE6Y3MgdHlwZWZhY2U9IiIgLz48YTpmb250IHNjcmlwdD0iSnBhbiIgdHlwZWZhY2U9Iu+8re+8syDvvLDjgrTjgrfjg4Pjgq8iIC8+PGE6Zm9udCBzY3JpcHQ9IkhhbmciIHR5cGVmYWNlPSLrp5HsnYAg6rOg65SVIiAvPjxhOmZvbnQgc2NyaXB0PSJIYW5zIiB0eXBlZmFjZT0i5a6L5L2TIiAvPjxhOmZvbnQgc2NyaXB0PSJIYW50IiB0eXBlZmFjZT0i5paw57Sw5piO6auUIiAvPjxhOmZvbnQgc2NyaXB0PSJBcmFiIiB0eXBlZmFjZT0iQXJpYWwiIC8+PGE6Zm9udCBzY3JpcHQ9IkhlYnIiIHR5cGVmYWNlPSJBcmlhbCIgLz48YTpmb250IHNjcmlwdD0iVGhhaSIgdHlwZWZhY2U9IlRhaG9tYSIgLz48YTpmb250IHNjcmlwdD0iRXRoaSIgdHlwZWZhY2U9Ik55YWxhIiAvPjxhOmZvbnQgc2NyaXB0PSJCZW5nIiB0eXBlZmFjZT0iVnJpbmRhIiAvPjxhOmZvbnQgc2NyaXB0PSJHdWpyIiB0eXBlZmFjZT0iU2hydXRpIiAvPjxhOmZvbnQgc2NyaXB0PSJLaG1yIiB0eXBlZmFjZT0iRGF1blBlbmgiIC8+PGE6Zm9udCBzY3JpcHQ9IktuZGEiIHR5cGVmYWNlPSJUdW5nYSIgLz48YTpmb250IHNjcmlwdD0iR3VydSIgdHlwZWZhY2U9IlJhYXZpIiAvPjxhOmZvbnQgc2NyaXB0PSJDYW5zIiB0eXBlZmFjZT0iRXVwaGVtaWEiIC8+PGE6Zm9udCBzY3JpcHQ9IkNoZXIiIHR5cGVmYWNlPSJQbGFudGFnZW5ldCBDaGVyb2tlZSIgLz48YTpmb250IHNjcmlwdD0iWWlpaSIgdHlwZWZhY2U9Ik1pY3Jvc29mdCBZaSBCYWl0aSIgLz48YTpmb250IHNjcmlwdD0iVGlidCIgdHlwZWZhY2U9Ik1pY3Jvc29mdCBIaW1hbGF5YSIgLz48YTpmb250IHNjcmlwdD0iVGhhYSIgdHlwZWZhY2U9Ik1WIEJvbGkiIC8+PGE6Zm9udCBzY3JpcHQ9IkRldmEiIHR5cGVmYWNlPSJNYW5nYWwiIC8+PGE6Zm9udCBzY3JpcHQ9IlRlbHUiIHR5cGVmYWNlPSJHYXV0YW1pIiAvPjxhOmZvbnQgc2NyaXB0PSJUYW1sIiB0eXBlZmFjZT0iTGF0aGEiIC8+PGE6Zm9udCBzY3JpcHQ9IlN5cmMiIHR5cGVmYWNlPSJFc3RyYW5nZWxvIEVkZXNzYSIgLz48YTpmb250IHNjcmlwdD0iT3J5YSIgdHlwZWZhY2U9IkthbGluZ2EiIC8+PGE6Zm9udCBzY3JpcHQ9Ik1seW0iIHR5cGVmYWNlPSJLYXJ0aWthIiAvPjxhOmZvbnQgc2NyaXB0PSJMYW9vIiB0eXBlZmFjZT0iRG9rQ2hhbXBhIiAvPjxhOmZvbnQgc2NyaXB0PSJTaW5oIiB0eXBlZmFjZT0iSXNrb29sYSBQb3RhIiAvPjxhOmZvbnQgc2NyaXB0PSJNb25nIiB0eXBlZmFjZT0iTW9uZ29saWFuIEJhaXRpIiAvPjxhOmZvbnQgc2NyaXB0PSJWaWV0IiB0eXBlZmFjZT0iQXJpYWwiIC8+PGE6Zm9udCBzY3JpcHQ9IlVpZ2giIHR5cGVmYWNlPSJNaWNyb3NvZnQgVWlnaHVyIiAvPjwvYTptaW5vckZvbnQ+PC9hOmZvbnRTY2hlbWU+PGE6Zm10U2NoZW1lIG5hbWU9Ik9mZmljZSI+PGE6ZmlsbFN0eWxlTHN0PjxhOnNvbGlkRmlsbD48YTpzY2hlbWVDbHIgdmFsPSJwaENsciIgLz48L2E6c29saWRGaWxsPjxhOmdyYWRGaWxsIHJvdFdpdGhTaGFwZT0iMSI+PGE6Z3NMc3Q+PGE6Z3MgcG9zPSIwIj48YTpzY2hlbWVDbHIgdmFsPSJwaENsciI+PGE6dGludCB2YWw9IjUwMDAwIiAvPjxhOnNhdE1vZCB2YWw9IjMwMDAwMCIgLz48L2E6c2NoZW1lQ2xyPjwvYTpncz48YTpncyBwb3M9IjM1MDAwIj48YTpzY2hlbWVDbHIgdmFsPSJwaENsciI+PGE6dGludCB2YWw9IjM3MDAwIiAvPjxhOnNhdE1vZCB2YWw9IjMwMDAwMCIgLz48L2E6c2NoZW1lQ2xyPjwvYTpncz48YTpncyBwb3M9IjEwMDAwMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnRpbnQgdmFsPSIxNTAwMCIgLz48YTpzYXRNb2QgdmFsPSIzNTAwMDAiIC8+PC9hOnNjaGVtZUNscj48L2E6Z3M+PC9hOmdzTHN0PjxhOmxpbiBhbmc9IjE2MjAwMDAwIiBzY2FsZWQ9IjEiIC8+PC9hOmdyYWRGaWxsPjxhOmdyYWRGaWxsIHJvdFdpdGhTaGFwZT0iMSI+PGE6Z3NMc3Q+PGE6Z3MgcG9zPSIwIj48YTpzY2hlbWVDbHIgdmFsPSJwaENsciI+PGE6c2hhZGUgdmFsPSI1MTAwMCIgLz48YTpzYXRNb2QgdmFsPSIxMzAwMDAiIC8+PC9hOnNjaGVtZUNscj48L2E6Z3M+PGE6Z3MgcG9zPSI4MDAwMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnNoYWRlIHZhbD0iOTMwMDAiIC8+PGE6c2F0TW9kIHZhbD0iMTMwMDAwIiAvPjwvYTpzY2hlbWVDbHI+PC9hOmdzPjxhOmdzIHBvcz0iMTAwMDAwIj48YTpzY2hlbWVDbHIgdmFsPSJwaENsciI+PGE6c2hhZGUgdmFsPSI5NDAwMCIgLz48YTpzYXRNb2QgdmFsPSIxMzUwMDAiIC8+PC9hOnNjaGVtZUNscj48L2E6Z3M+PC9hOmdzTHN0PjxhOmxpbiBhbmc9IjE2MjAwMDAwIiBzY2FsZWQ9IjAiIC8+PC9hOmdyYWRGaWxsPjwvYTpmaWxsU3R5bGVMc3Q+PGE6bG5TdHlsZUxzdD48YTpsbiB3PSI5NTI1IiBjYXA9ImZsYXQiIGNtcGQ9InNuZyIgYWxnbj0iY3RyIj48YTpzb2xpZEZpbGw+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnNoYWRlIHZhbD0iOTUwMDAiIC8+PGE6c2F0TW9kIHZhbD0iMTA1MDAwIiAvPjwvYTpzY2hlbWVDbHI+PC9hOnNvbGlkRmlsbD48YTpwcnN0RGFzaCB2YWw9InNvbGlkIiAvPjwvYTpsbj48YTpsbiB3PSIyNTQwMCIgY2FwPSJmbGF0IiBjbXBkPSJzbmciIGFsZ249ImN0ciI+PGE6c29saWRGaWxsPjxhOnNjaGVtZUNsciB2YWw9InBoQ2xyIiAvPjwvYTpzb2xpZEZpbGw+PGE6cHJzdERhc2ggdmFsPSJzb2xpZCIgLz48L2E6bG4+PGE6bG4gdz0iMzgxMDAiIGNhcD0iZmxhdCIgY21wZD0ic25nIiBhbGduPSJjdHIiPjxhOnNvbGlkRmlsbD48YTpzY2hlbWVDbHIgdmFsPSJwaENsciIgLz48L2E6c29saWRGaWxsPjxhOnByc3REYXNoIHZhbD0ic29saWQiIC8+PC9hOmxuPjwvYTpsblN0eWxlTHN0PjxhOmVmZmVjdFN0eWxlTHN0PjxhOmVmZmVjdFN0eWxlPjxhOmVmZmVjdExzdD48YTpvdXRlclNoZHcgYmx1clJhZD0iNDAwMDAiIGRpc3Q9IjIwMDAwIiBkaXI9IjU0MDAwMDAiIHJvdFdpdGhTaGFwZT0iMCI+PGE6c3JnYkNsciB2YWw9IjAwMDAwMCI+PGE6YWxwaGEgdmFsPSIzODAwMCIgLz48L2E6c3JnYkNscj48L2E6b3V0ZXJTaGR3PjwvYTplZmZlY3RMc3Q+PC9hOmVmZmVjdFN0eWxlPjxhOmVmZmVjdFN0eWxlPjxhOmVmZmVjdExzdD48YTpvdXRlclNoZHcgYmx1clJhZD0iNDAwMDAiIGRpc3Q9IjIzMDAwIiBkaXI9IjU0MDAwMDAiIHJvdFdpdGhTaGFwZT0iMCI+PGE6c3JnYkNsciB2YWw9IjAwMDAwMCI+PGE6YWxwaGEgdmFsPSIzNTAwMCIgLz48L2E6c3JnYkNscj48L2E6b3V0ZXJTaGR3PjwvYTplZmZlY3RMc3Q+PC9hOmVmZmVjdFN0eWxlPjxhOmVmZmVjdFN0eWxlPjxhOmVmZmVjdExzdD48YTpvdXRlclNoZHcgYmx1clJhZD0iNDAwMDAiIGRpc3Q9IjIzMDAwIiBkaXI9IjU0MDAwMDAiIHJvdFdpdGhTaGFwZT0iMCI+PGE6c3JnYkNsciB2YWw9IjAwMDAwMCI+PGE6YWxwaGEgdmFsPSIzNTAwMCIgLz48L2E6c3JnYkNscj48L2E6b3V0ZXJTaGR3PjwvYTplZmZlY3RMc3Q+PGE6c2NlbmUzZD48YTpjYW1lcmEgcHJzdD0ib3J0aG9ncmFwaGljRnJvbnQiPjxhOnJvdCBsYXQ9IjAiIGxvbj0iMCIgcmV2PSIwIiAvPjwvYTpjYW1lcmE+PGE6bGlnaHRSaWcgcmlnPSJ0aHJlZVB0IiBkaXI9InQiPjxhOnJvdCBsYXQ9IjAiIGxvbj0iMCIgcmV2PSIxMjAwMDAwIiAvPjwvYTpsaWdodFJpZz48L2E6c2NlbmUzZD48YTpzcDNkPjxhOmJldmVsVCB3PSI2MzUwMCIgaD0iMjU0MDAiIC8+PC9hOnNwM2Q+PC9hOmVmZmVjdFN0eWxlPjwvYTplZmZlY3RTdHlsZUxzdD48YTpiZ0ZpbGxTdHlsZUxzdD48YTpzb2xpZEZpbGw+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiIC8+PC9hOnNvbGlkRmlsbD48YTpncmFkRmlsbCByb3RXaXRoU2hhcGU9IjEiPjxhOmdzTHN0PjxhOmdzIHBvcz0iMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnRpbnQgdmFsPSI0MDAwMCIgLz48YTpzYXRNb2QgdmFsPSIzNTAwMDAiIC8+PC9hOnNjaGVtZUNscj48L2E6Z3M+PGE6Z3MgcG9zPSI0MDAwMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnRpbnQgdmFsPSI0NTAwMCIgLz48YTpzaGFkZSB2YWw9Ijk5MDAwIiAvPjxhOnNhdE1vZCB2YWw9IjM1MDAwMCIgLz48L2E6c2NoZW1lQ2xyPjwvYTpncz48YTpncyBwb3M9IjEwMDAwMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnNoYWRlIHZhbD0iMjAwMDAiIC8+PGE6c2F0TW9kIHZhbD0iMjU1MDAwIiAvPjwvYTpzY2hlbWVDbHI+PC9hOmdzPjwvYTpnc0xzdD48YTpwYXRoIHBhdGg9ImNpcmNsZSI+PGE6ZmlsbFRvUmVjdCBsPSI1MDAwMCIgdD0iLTgwMDAwIiByPSI1MDAwMCIgYj0iMTgwMDAwIiAvPjwvYTpwYXRoPjwvYTpncmFkRmlsbD48YTpncmFkRmlsbCByb3RXaXRoU2hhcGU9IjEiPjxhOmdzTHN0PjxhOmdzIHBvcz0iMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnRpbnQgdmFsPSI4MDAwMCIgLz48YTpzYXRNb2QgdmFsPSIzMDAwMDAiIC8+PC9hOnNjaGVtZUNscj48L2E6Z3M+PGE6Z3MgcG9zPSIxMDAwMDAiPjxhOnNjaGVtZUNsciB2YWw9InBoQ2xyIj48YTpzaGFkZSB2YWw9IjMwMDAwIiAvPjxhOnNhdE1vZCB2YWw9IjIwMDAwMCIgLz48L2E6c2NoZW1lQ2xyPjwvYTpncz48L2E6Z3NMc3Q+PGE6cGF0aCBwYXRoPSJjaXJjbGUiPjxhOmZpbGxUb1JlY3QgbD0iNTAwMDAiIHQ9IjUwMDAwIiByPSI1MDAwMCIgYj0iNTAwMDAiIC8+PC9hOnBhdGg+PC9hOmdyYWRGaWxsPjwvYTpiZ0ZpbGxTdHlsZUxzdD48L2E6Zm10U2NoZW1lPjwvYTp0aGVtZUVsZW1lbnRzPjxhOm9iamVjdERlZmF1bHRzIC8+PGE6ZXh0cmFDbHJTY2hlbWVMc3QgLz48L2E6dGhlbWU+UEsDBAoAAAAAABN7eUKJ3nBGuwEAALsBAAAPAAAAeGwvd29ya2Jvb2sueG1s77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48eDp3b3JrYm9vayB4bWxuczpyPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9yZWxhdGlvbnNoaXBzIiB4bWxuczp4PSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvc3ByZWFkc2hlZXRtbC8yMDA2L21haW4iPjx4Ondvcmtib29rUHIgY29kZU5hbWU9IlRoaXNXb3JrYm9vayIgLz48eDpib29rVmlld3M+PHg6d29ya2Jvb2tWaWV3IGZpcnN0U2hlZXQ9IjAiIGFjdGl2ZVRhYj0iMCIgLz48L3g6Ym9va1ZpZXdzPjx4OnNoZWV0cz48eDpzaGVldCBuYW1lPSJTaGVldCAxIiBzaGVldElkPSIyIiByOmlkPSJySWQyIiAvPjwveDpzaGVldHM+PHg6ZGVmaW5lZE5hbWVzIC8+PHg6Y2FsY1ByIGNhbGNJZD0iMTI1NzI1IiAvPjwveDp3b3JrYm9vaz5QSwMECgAAAAAAxYV5QgAAAAAAAAAAAAAAAA4AAAB4bC93b3Jrc2hlZXRzL1BLAQIUAAoAAAAAABN7eUK9Z10uNQQAADUEAAATAAAAAAAAAAAAAAAAAAAAAABbQ29udGVudF9UeXBlc10ueG1sUEsBAhQACgAAAAAAi3U5SAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAQAAAAZgQAAF9yZWxzL1BLAQIUAAoAAAAAABN7eUJ0mYADnAIAAJwCAAALAAAAAAAAAAAAAAAAAIoEAABfcmVscy8ucmVsc1BLAQIUAAoAAAAAAIt1OUgAAAAAAAAAAAAAAAAJAAAAAAAAAAAAEAAAAE8HAABkb2NQcm9wcy9QSwECFAAKAAAAAAATe3lC717fXj0DAAA9AwAAEAAAAAAAAAAAAAAAAAB2BwAAZG9jUHJvcHMvYXBwLnhtbFBLAQIUAAoAAAAAAIt1OUgAAAAAAAAAAAAAAAAIAAAAAAAAAAAAEAAAAOEKAABwYWNrYWdlL1BLAQIUAAoAAAAAAMWFeUIAAAAAAAAAAAAAAAARAAAAAAAAAAAAEAAAAAcLAABwYWNrYWdlL3NlcnZpY2VzL1BLAQIUAAoAAAAAAMWFeUIAAAAAAAAAAAAAAAAaAAAAAAAAAAAAEAAAADYLAABwYWNrYWdlL3NlcnZpY2VzL21ldGFkYXRhL1BLAQIUAAoAAAAAAMWFeUIAAAAAAAAAAAAAAAAqAAAAAAAAAAAAEAAAAG4LAABwYWNrYWdlL3NlcnZpY2VzL21ldGFkYXRhL2NvcmUtcHJvcGVydGllcy9QSwECFAAKAAAAAAATe3lCc4c2yNoBAADaAQAAUQAAAAAAAAAAAAAAAAC2CwAAcGFja2FnZS9zZXJ2aWNlcy9tZXRhZGF0YS9jb3JlLXByb3BlcnRpZXMvZWNmZGQzMTQzZjIxNDg5MDk1YTQ0YzcxMTE1YjcyM2IucHNtZGNwUEsBAhQACgAAAAAAi3U5SAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAQAAAA/w0AAHhsL1BLAQIUAAoAAAAAAMWFeUIAAAAAAAAAAAAAAAAJAAAAAAAAAAAAEAAAACAOAAB4bC9fcmVscy9QSwECFAAKAAAAAAATe3lCJ0p8MrwCAAC8AgAAGgAAAAAAAAAAAAAAAABHDgAAeGwvX3JlbHMvd29ya2Jvb2sueG1sLnJlbHNQSwECFAAKAAAAAAATe3lCflKRBZAAAACQAAAAFAAAAAAAAAAAAAAAAAA7EQAAeGwvc2hhcmVkU3RyaW5ncy54bWxQSwECFAAKAAAAAAATe3lCItpbK3oIAAB6CAAADQAAAAAAAAAAAAAAAAD9EQAAeGwvc3R5bGVzLnhtbFBLAQIUAAoAAAAAAMWFeUIAAAAAAAAAAAAAAAAJAAAAAAAAAAAAEAAAAKIaAAB4bC90aGVtZS9QSwECFAAKAAAAAAATe3lCdbGRXrsbAAC7GwAAEgAAAAAAAAAAAAAAAADJGgAAeGwvdGhlbWUvdGhlbWUueG1sUEsBAhQACgAAAAAAE3t5QonecEa7AQAAuwEAAA8AAAAAAAAAAAAAAAAAtDYAAHhsL3dvcmtib29rLnhtbFBLAQIUAAoAAAAAAMWFeUIAAAAAAAAAAAAAAAAOAAAAAAAAAAAAEAAAAJw4AAB4bC93b3Jrc2hlZXRzL1BLBQYAAAAAEwATANQEAADIOAAAAAA=";
+var templateXLSX = 'UEsDBAoAAAAAABN7eUK9Z10uNQQAADUEAAATAAAAW0NvbnRlbnRfVHlwZXNdLnhtbO+7vzw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi04Ij8+PFR5cGVzIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvcGFja2FnZS8yMDA2L2NvbnRlbnQtdHlwZXMiPjxEZWZhdWx0IEV4dGVuc2lvbj0ieG1sIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24vdm5kLm9wZW54bWxmb3JtYXRzLW9mZmljZWRvY3VtZW50LnNwcmVhZHNoZWV0bWwuc2hlZXQubWFpbit4bWwiIC8+PERlZmF1bHQgRXh0ZW5zaW9uPSJyZWxzIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24vdm5kLm9wZW54bWxmb3JtYXRzLXBhY2thZ2UucmVsYXRpb25zaGlwcyt4bWwiIC8+PERlZmF1bHQgRXh0ZW5zaW9uPSJwc21kY3AiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtcGFja2FnZS5jb3JlLXByb3BlcnRpZXMreG1sIiAvPjxPdmVycmlkZSBQYXJ0TmFtZT0iL2RvY1Byb3BzL2FwcC54bWwiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQuZXh0ZW5kZWQtcHJvcGVydGllcyt4bWwiIC8+PE92ZXJyaWRlIFBhcnROYW1lPSIveGwvc2hhcmVkU3RyaW5ncy54bWwiIENvbnRlbnRUeXBlPSJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQuc3ByZWFkc2hlZXRtbC5zaGFyZWRTdHJpbmdzK3htbCIgLz48T3ZlcnJpZGUgUGFydE5hbWU9Ii94bC9zdHlsZXMueG1sIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24vdm5kLm9wZW54bWxmb3JtYXRzLW9mZmljZWRvY3VtZW50LnNwcmVhZHNoZWV0bWwuc3R5bGVzK3htbCIgLz48T3ZlcnJpZGUgUGFydE5hbWU9Ii94bC93b3Jrc2hlZXRzL3NoZWV0LnhtbCIgQ29udGVudFR5cGU9ImFwcGxpY2F0aW9uL3ZuZC5vcGVueG1sZm9ybWF0cy1vZmZpY2Vkb2N1bWVudC5zcHJlYWRzaGVldG1sLndvcmtzaGVldCt4bWwiIC8+PE92ZXJyaWRlIFBhcnROYW1lPSIveGwvdGhlbWUvdGhlbWUueG1sIiBDb250ZW50VHlwZT0iYXBwbGljYXRpb24vdm5kLm9wZW54bWxmb3JtYXRzLW9mZmljZWRvY3VtZW50LnRoZW1lK3htbCIgLz48L1R5cGVzPlBLAwQKAAAAAACLdTlIAAAAAAAAAAAAAAAABgAAAF9yZWxzL1BLAwQKAAAAAAATe3lCdJmAA5wCAACcAgAACwAAAF9yZWxzLy5yZWxz77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48UmVsYXRpb25zaGlwcyB4bWxucz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL3BhY2thZ2UvMjAwNi9yZWxhdGlvbnNoaXBzIj48UmVsYXRpb25zaGlwIFR5cGU9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZpY2VEb2N1bWVudC8yMDA2L3JlbGF0aW9uc2hpcHMvb2ZmaWNlRG9jdW1lbnQiIFRhcmdldD0iL3hsL3dvcmtib29rLnhtbCIgSWQ9IlI0YWEyMmIzMWExYTc0MjkxIiAvPjxSZWxhdGlvbnNoaXAgVHlwZT0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvcmVsYXRpb25zaGlwcy9leHRlbmRlZC1wcm9wZXJ0aWVzIiBUYXJnZXQ9Ii9kb2NQcm9wcy9hcHAueG1sIiBJZD0icklkMSIgLz48UmVsYXRpb25zaGlwIFR5cGU9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9wYWNrYWdlLzIwMDYvcmVsYXRpb25zaGlwcy9tZXRhZGF0YS9jb3JlLXByb3BlcnRpZXMiIFRhcmdldD0iL3BhY2thZ2Uvc2VydmljZXMvbWV0YWRhdGEvY29yZS1wcm9wZXJ0aWVzL2VjZmRkMzE0M2YyMTQ4OTA5NWE0NGM3MTExNWI3MjNiLnBzbWRjcCIgSWQ9IlJlZjQ4N2MzZTBjNzQ0YTg3IiAvPjwvUmVsYXRpb25zaGlwcz5QSwMECgAAAAAAi3U5SAAAAAAAAAAAAAAAAAkAAABkb2NQcm9wcy9QSwMECgAAAAAAE3t5Qu9e3149AwAAPQMAABAAAABkb2NQcm9wcy9hcHAueG1s77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48YXA6UHJvcGVydGllcyB4bWxuczp2dD0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvZG9jUHJvcHNWVHlwZXMiIHhtbG5zOmFwPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9leHRlbmRlZC1wcm9wZXJ0aWVzIj48YXA6QXBwbGljYXRpb24+TWljcm9zb2Z0IEV4Y2VsPC9hcDpBcHBsaWNhdGlvbj48YXA6RG9jU2VjdXJpdHk+MDwvYXA6RG9jU2VjdXJpdHk+PGFwOlNjYWxlQ3JvcD5mYWxzZTwvYXA6U2NhbGVDcm9wPjxhcDpIZWFkaW5nUGFpcnM+PHZ0OnZlY3RvciBiYXNlVHlwZT0idmFyaWFudCIgc2l6ZT0iNCI+PHZ0OnZhcmlhbnQ+PHZ0Omxwc3RyPldvcmtzaGVldHM8L3Z0Omxwc3RyPjwvdnQ6dmFyaWFudD48dnQ6dmFyaWFudD48dnQ6aTQ+MTwvdnQ6aTQ+PC92dDp2YXJpYW50Pjx2dDp2YXJpYW50Pjx2dDpscHN0cj5OYW1lZCBSYW5nZXM8L3Z0Omxwc3RyPjwvdnQ6dmFyaWFudD48dnQ6dmFyaWFudD48dnQ6aTQ+MjwvdnQ6aTQ+PC92dDp2YXJpYW50PjwvdnQ6dmVjdG9yPjwvYXA6SGVhZGluZ1BhaXJzPjxhcDpUaXRsZXNPZlBhcnRzPjx2dDp2ZWN0b3IgYmFzZVR5cGU9Imxwc3RyIiBzaXplPSIzIj48dnQ6bHBzdHI+U2hlZXQgMTwvdnQ6bHBzdHI+PHZ0Omxwc3RyPlNoZWV0IDEhUHJpbnRfQXJlYTwvdnQ6bHBzdHI+PHZ0Omxwc3RyPlNoZWV0IDEhUHJpbnRfVGl0bGVzPC92dDpscHN0cj48L3Z0OnZlY3Rvcj48L2FwOlRpdGxlc09mUGFydHM+PC9hcDpQcm9wZXJ0aWVzPlBLAwQKAAAAAACLdTlIAAAAAAAAAAAAAAAACAAAAHBhY2thZ2UvUEsDBAoAAAAAAMWFeUIAAAAAAAAAAAAAAAARAAAAcGFja2FnZS9zZXJ2aWNlcy9QSwMECgAAAAAAxYV5QgAAAAAAAAAAAAAAABoAAABwYWNrYWdlL3NlcnZpY2VzL21ldGFkYXRhL1BLAwQKAAAAAADFhXlCAAAAAAAAAAAAAAAAKgAAAHBhY2thZ2Uvc2VydmljZXMvbWV0YWRhdGEvY29yZS1wcm9wZXJ0aWVzL1BLAwQKAAAAAAATe3lCc4c2yNoBAADaAQAAUQAAAHBhY2thZ2Uvc2VydmljZXMvbWV0YWRhdGEvY29yZS1wcm9wZXJ0aWVzL2VjZmRkMzE0M2YyMTQ4OTA5NWE0NGM3MTExNWI3MjNiLnBzbWRjcO+7vzw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi04Ij8+PGNvcmVQcm9wZXJ0aWVzIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6ZGN0ZXJtcz0iaHR0cDovL3B1cmwub3JnL2RjL3Rlcm1zLyIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9wYWNrYWdlLzIwMDYvbWV0YWRhdGEvY29yZS1wcm9wZXJ0aWVzIj48ZGN0ZXJtczpjcmVhdGVkIHhzaTp0eXBlPSJkY3Rlcm1zOlczQ0RURiI+MjAxMy0wMy0yNVQxOToyNDozOS44NjYxOTY5WjwvZGN0ZXJtczpjcmVhdGVkPjxkY3Rlcm1zOm1vZGlmaWVkIHhzaTp0eXBlPSJkY3Rlcm1zOlczQ0RURiI+MjAxMy0wMy0yNVQxOToyNDozOS44NjYxOTY5WjwvZGN0ZXJtczptb2RpZmllZD48L2NvcmVQcm9wZXJ0aWVzPlBLAwQKAAAAAACLdTlIAAAAAAAAAAAAAAAAAwAAAHhsL1BLAwQKAAAAAADFhXlCAAAAAAAAAAAAAAAACQAAAHhsL19yZWxzL1BLAwQKAAAAAAATe3lCJ0p8MrwCAAC8AgAAGgAAAHhsL19yZWxzL3dvcmtib29rLnhtbC5yZWxz77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48UmVsYXRpb25zaGlwcyB4bWxucz0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL3BhY2thZ2UvMjAwNi9yZWxhdGlvbnNoaXBzIj48UmVsYXRpb25zaGlwIFR5cGU9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZpY2VEb2N1bWVudC8yMDA2L3JlbGF0aW9uc2hpcHMvc2hhcmVkU3RyaW5ncyIgVGFyZ2V0PSIveGwvc2hhcmVkU3RyaW5ncy54bWwiIElkPSJySWQzIiAvPjxSZWxhdGlvbnNoaXAgVHlwZT0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvcmVsYXRpb25zaGlwcy9zdHlsZXMiIFRhcmdldD0iL3hsL3N0eWxlcy54bWwiIElkPSJySWQ0IiAvPjxSZWxhdGlvbnNoaXAgVHlwZT0iaHR0cDovL3NjaGVtYXMub3BlbnhtbGZvcm1hdHMub3JnL29mZmljZURvY3VtZW50LzIwMDYvcmVsYXRpb25zaGlwcy93b3Jrc2hlZXQiIFRhcmdldD0iL3hsL3dvcmtzaGVldHMvc2hlZXQueG1sIiBJZD0icklkMiIgLz48UmVsYXRpb25zaGlwIFR5cGU9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9vZmZpY2VEb2N1bWVudC8yMDA2L3JlbGF0aW9uc2hpcHMvdGhlbWUiIFRhcmdldD0iL3hsL3RoZW1lL3RoZW1lLnhtbCIgSWQ9InJJZDYiIC8+PC9SZWxhdGlvbnNoaXBzPlBLAwQKAAAAAAATe3lCflKRBZAAAACQAAAAFAAAAHhsL3NoYXJlZFN0cmluZ3MueG1s77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48eDpzc3QgY291bnQ9IjAiIHVuaXF1ZUNvdW50PSIwIiB4bWxuczp4PSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvc3ByZWFkc2hlZXRtbC8yMDA2L21haW4iIC8+UEsDBAoAAAAAABN7eUIi2lsreggAAHoIAAANAAAAeGwvc3R5bGVzLnhtbO+7vzw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi04Ij8+PHg6c3R5bGVTaGVldCB4bWxuczp4PSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvc3ByZWFkc2hlZXRtbC8yMDA2L21haW4iPjx4Om51bUZtdHMgY291bnQ9IjEiPjx4Om51bUZtdCBudW1GbXRJZD0iMCIgZm9ybWF0Q29kZT0iIiAvPjwveDpudW1GbXRzPjx4OmZvbnRzIGNvdW50PSIxIj48eDpmb250Pjx4OnZlcnRBbGlnbiB2YWw9ImJhc2VsaW5lIiAvPjx4OnN6IHZhbD0iMTEiIC8+PHg6Y29sb3IgcmdiPSJGRjAwMDAwMCIgLz48eDpuYW1lIHZhbD0iQ2FsaWJyaSIgLz48eDpmYW1pbHkgdmFsPSIyIiAvPjwveDpmb250PjwveDpmb250cz48eDpmaWxscyBjb3VudD0iMiI+PHg6ZmlsbD48eDpwYXR0ZXJuRmlsbCBwYXR0ZXJuVHlwZT0ibm9uZSIgLz48L3g6ZmlsbD48eDpmaWxsPjx4OnBhdHRlcm5GaWxsIHBhdHRlcm5UeXBlPSJncmF5MTI1IiAvPjwveDpmaWxsPjwveDpmaWxscz48eDpib3JkZXJzIGNvdW50PSIxIj48eDpib3JkZXIgZGlhZ29uYWxVcD0iMCIgZGlhZ29uYWxEb3duPSIwIj48eDpsZWZ0IHN0eWxlPSJub25lIj48eDpjb2xvciByZ2I9IkZGMDAwMDAwIiAvPjwveDpsZWZ0Pjx4OnJpZ2h0IHN0eWxlPSJub25lIj48eDpjb2xvciByZ2I9IkZGMDAwMDAwIiAvPjwveDpyaWdodD48eDp0b3Agc3R5bGU9Im5vbmUiPjx4OmNvbG9yIHJnYj0iRkYwMDAwMDAiIC8+PC94OnRvcD48eDpib3R0b20gc3R5bGU9Im5vbmUiPjx4OmNvbG9yIHJnYj0iRkYwMDAwMDAiIC8+PC94OmJvdHRvbT48eDpkaWFnb25hbCBzdHlsZT0ibm9uZSI+PHg6Y29sb3IgcmdiPSJGRjAwMDAwMCIgLz48L3g6ZGlhZ29uYWw+PC94OmJvcmRlcj48L3g6Ym9yZGVycz48eDpjZWxsU3R5bGVYZnMgY291bnQ9IjIiPjx4OnhmIG51bUZtdElkPSIwIiBmb250SWQ9IjAiIGZpbGxJZD0iMCIgYm9yZGVySWQ9IjAiIGFwcGx5TnVtYmVyRm9ybWF0PSIwIiBhcHBseUZpbGw9IjEiIGFwcGx5Qm9yZGVyPSIwIiBhcHBseUFsaWdubWVudD0iMCIgYXBwbHlQcm90ZWN0aW9uPSIxIj48eDpwcm90ZWN0aW9uIGxvY2tlZD0iMSIgaGlkZGVuPSIwIiAvPjwveDp4Zj48eDp4ZiBudW1GbXRJZD0iMTQiIGZvbnRJZD0iMCIgZmlsbElkPSIwIiBib3JkZXJJZD0iMCIgYXBwbHlOdW1iZXJGb3JtYXQ9IjAiIGFwcGx5RmlsbD0iMSIgYXBwbHlCb3JkZXI9IjAiIGFwcGx5QWxpZ25tZW50PSIwIiBhcHBseVByb3RlY3Rpb249IjEiPjx4OnByb3RlY3Rpb24gbG9ja2VkPSIxIiBoaWRkZW49IjAiIC8+PC94OnhmPjwveDpjZWxsU3R5bGVYZnM+PHg6Y2VsbFhmcyBjb3VudD0iMiI+PHg6eGYgbnVtRm10SWQ9IjAiIGZvbnRJZD0iMCIgZmlsbElkPSIwIiBib3JkZXJJZD0iMCIgeGZJZD0iMCIgYXBwbHlOdW1iZXJGb3JtYXQ9IjAiIGFwcGx5RmlsbD0iMSIgYXBwbHlCb3JkZXI9IjAiIGFwcGx5QWxpZ25tZW50PSIwIiBhcHBseVByb3RlY3Rpb249IjEiPjx4OmFsaWdubWVudCBob3Jpem9udGFsPSJnZW5lcmFsIiB2ZXJ0aWNhbD0iYm90dG9tIiB0ZXh0Um90YXRpb249IjAiIHdyYXBUZXh0PSIwIiBpbmRlbnQ9IjAiIHJlbGF0aXZlSW5kZW50PSIwIiBqdXN0aWZ5TGFzdExpbmU9IjAiIHNocmlua1RvRml0PSIwIiByZWFkaW5nT3JkZXI9IjAiIC8+PHg6cHJvdGVjdGlvbiBsb2NrZWQ9IjEiIGhpZGRlbj0iMCIgLz48L3g6eGY+PHg6eGYgbnVtRm10SWQ9IjE0IiBmb250SWQ9IjAiIGZpbGxJZD0iMCIgYm9yZGVySWQ9IjAiIHhmSWQ9IjAiIGFwcGx5TnVtYmVyRm9ybWF0PSIwIiBhcHBseUZpbGw9IjEiIGFwcGx5Qm9yZGVyPSIwIiBhcHBseUFsaWdubWVudD0iMCIgYXBwbHlQcm90ZWN0aW9uPSIxIj48eDphbGlnbm1lbnQgaG9yaXpvbnRhbD0iZ2VuZXJhbCIgdmVydGljYWw9ImJvdHRvbSIgdGV4dFJvdGF0aW9uPSIwIiB3cmFwVGV4dD0iMCIgaW5kZW50PSIwIiByZWxhdGl2ZUluZGVudD0iMCIganVzdGlmeUxhc3RMaW5lPSIwIiBzaHJpbmtUb0ZpdD0iMCIgcmVhZGluZ09yZGVyPSIwIiAvPjx4OnByb3RlY3Rpb24gbG9ja2VkPSIxIiBoaWRkZW49IjAiIC8+PC94OnhmPjwveDpjZWxsWGZzPjx4OmNlbGxTdHlsZXMgY291bnQ9IjEiPjx4OmNlbGxTdHlsZSBuYW1lPSJOb3JtYWwiIHhmSWQ9IjAiIGJ1aWx0aW5JZD0iMCIgLz48L3g6Y2VsbFN0eWxlcz48L3g6c3R5bGVTaGVldD5QSwMECgAAAAAAxYV5QgAAAAAAAAAAAAAAAAkAAAB4bC90aGVtZS9QSwMECgAAAAAAE3t5QnWxkV67GwAAuxsAABIAAAB4bC90aGVtZS90aGVtZS54bWzvu788P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJ1dGYtOCI/PjxhOnRoZW1lIHhtbG5zOmE9Imh0dHA6Ly9zY2hlbWFzLm9wZW54bWxmb3JtYXRzLm9yZy9kcmF3aW5nbWwvMjAwNi9tYWluIiBuYW1lPSJPZmZpY2UgVGhlbWUiPjxhOnRoZW1lRWxlbWVudHM+PGE6Y2xyU2NoZW1lIG5hbWU9Ik9mZmljZSI+PGE6ZGsxPjxhOnN5c0NsciB2YWw9IndpbmRvd1RleHQiIGxhc3RDbHI9IjAwMDAwMCIgLz48L2E6ZGsxPjxhOmx0MT48YTpzeXNDbHIgdmFsPSJ3aW5kb3ciIGxhc3RDbHI9IkZGRkZGRiIgLz48L2E6bHQxPjxhOmRrMj48YTpzcmdiQ2xyIHZhbD0iMUY0OTdEIiAvPjwvYTpkazI+PGE6bHQyPjxhOnNyZ2JDbHIgdmFsPSJFRUVDRTEiIC8+PC9hOmx0Mj48YTphY2NlbnQxPjxhOnNyZ2JDbHIgdmFsPSI0RjgxQkQiIC8+PC9hOmFjY2VudDE+PGE6YWNjZW50Mj48YTpzcmdiQ2xyIHZhbD0iQzA1MDREIiAvPjwvYTphY2NlbnQyPjxhOmFjY2VudDM+PGE6c3JnYkNsciB2YWw9IjlCQkI1OSIgLz48L2E6YWNjZW50Mz48YTphY2NlbnQ0PjxhOnNyZ2JDbHIgdmFsPSI4MDY0QTIiIC8+PC9hOmFjY2VudDQ+PGE6YWNjZW50NT48YTpzcmdiQ2xyIHZhbD0iNEJBQ0M2IiAvPjwvYTphY2NlbnQ1PjxhOmFjY2VudDY+PGE6c3JnYkNsciB2YWw9IkY3OTY0NiIgLz48L2E6YWNjZW50Nj48YTpobGluaz48YTpzcmdiQ2xyIHZhbD0iMDAwMEZGIiAvPjwvYTpobGluaz48YTpmb2xIbGluaz48YTpzcmdiQ2xyIHZhbD0iODAwMDgwIiAvPjwvYTpmb2xIbGluaz48L2E6Y2xyU2NoZW1lPjxhOmZvbnRTY2hlbWUgbmFtZT0iT2ZmaWNlIj48YTptYWpvckZvbnQ+PGE6bGF0aW4gdHlwZWZhY2U9IkNhbWJyaWEiIC8+PGE6ZWEgdHlwZWZhY2U9IiIgLz48YTpjcyB0eXBlZmFjZT0iIiAvPjxhOmZvbnQgc2NyaXB0PSJKcGFuIiB0eXBlZmFjZT0i77yt77yzIO+8sOOCtOOCt+ODg+OCryIgLz48YTpmb250IHNjcmlwdD0iSGFuZyIgdHlwZWZhY2U9IuunkeydgCDqs6DrlJUiIC8+PGE6Zm9udCBzY3JpcHQ9IkhhbnMiIHR5cGVmYWNlPSLlrovkvZMiIC8+PGE6Zm9udCBzY3JpcHQ9IkhhbnQiIHR5cGVmYWNlPSLmlrDntLDmmI7pq5QiIC8+PGE6Zm9udCBzY3JpcHQ9IkFyYWIiIHR5cGVmYWNlPSJUaW1lcyBOZXcgUm9tYW4iIC8+PGE6Zm9udCBzY3JpcHQ9IkhlYnIiIHR5cGVmYWNlPSJUaW1lcyBOZXcgUm9tYW4iIC8+PGE6Zm9udCBzY3JpcHQ9IlRoYWkiIHR5cGVmYWNlPSJUYWhvbWEiIC8+PGE6Zm9udCBzY3JpcHQ9IkV0aGkiIHR5cGVmYWNlPSJOeWFsYSIgLz48YTpmb250IHNjcmlwdD0iQmVuZyIgdHlwZWZhY2U9IlZyaW5kYSIgLz48YTpmb250IHNjcmlwdD0iR3VqciIgdHlwZWZhY2U9IlNocnV0aSIgLz48YTpmb250IHNjcmlwdD0iS2htciIgdHlwZWZhY2U9Ik1vb2xCb3JhbiIgLz48YTpmb250IHNjcmlwdD0iS25kYSIgdHlwZWZhY2U9IlR1bmdhIiAvPjxhOmZvbnQgc2NyaXB0PSJHdXJ1IiB0eXBlZmFjZT0iUmFhdmkiIC8+PGE6Zm9udCBzY3JpcHQ9IkNhbnMiIHR5cGVmYWNlPSJFdXBoZW1pYSIgLz48YTpmb250IHNjcmlwdD0iQ2hlciIgdHlwZWZhY2U9IlBsYW50YWdlbmV0IENoZXJva2VlIiAvPjxhOmZvbnQgc2NyaXB0PSJZaWlpIiB0eXBlZmFjZT0iTWljcm9zb2Z0IFlpIEJhaXRpIiAvPjxhOmZvbnQgc2NyaXB0PSJUaWJ0IiB0eXBlZmFjZT0iTWljcm9zb2Z0IEhpbWFsYXlhIiAvPjxhOmZvbnQgc2NyaXB0PSJUaGFhIiB0eXBlZmFjZT0iTVYgQm9saSIgLz48YTpmb250IHNjcmlwdD0iRGV2YSIgdHlwZWZhY2U9Ik1hbmdhbCIgLz48YTpmb250IHNjcmlwdD0iVGVsdSIgdHlwZWZhY2U9IkdhdXRhbWkiIC8+PGE6Zm9udCBzY3JpcHQ9IlRhbWwiIHR5cGVmYWNlPSJMYXRoYSIgLz48YTpmb250IHNjcmlwdD0iU3lyYyIgdHlwZWZhY2U9IkVzdHJhbmdlbG8gRWRlc3NhIiAvPjxhOmZvbnQgc2NyaXB0PSJPcnlhIiB0eXBlZmFjZT0iS2FsaW5nYSIgLz48YTpmb250IHNjcmlwdD0iTWx5bSIgdHlwZWZhY2U9IkthcnRpa2EiIC8+PGE6Zm9udCBzY3JpcHQ9Ikxhb28iIHR5cGVmYWNlPSJEb2tDaGFtcGEiIC8+PGE6Zm9udCBzY3JpcHQ9IlNpbmgiIHR5cGVmYWNlPSJJc2tvb2xhIFBvdGEiIC8+PGE6Zm9udCBzY3JpcHQ9Ik1vbmciIHR5cGVmYWNlPSJNb25nb2xpYW4gQmFpdGkiIC8+PGE6Zm9udCBzY3JpcHQ9IlZpZXQiIHR5cGVmYWNlPSJUaW1lcyBOZXcgUm9tYW4iIC8+PGE6Zm9udCBzY3JpcHQ9IlVpZ2giIHR5cGVmYWNlPSJNaWNyb3NvZnQgVWlnaHVyIiAvPjwvYTptYWpvckZvbnQ+PGE6bWlub3JGb250PjxhOmxhdGluIHR5cGVmYWNlPSJDYWxpYnJpIiAvPjxhOmVhIHR5cGVmYWNlPSIiIC8+PGE6Y3MgdHlwZWZhY2U9IiIgLz48YTpmb250IHNjcmlwdD0iSnBhbiIgdHlwZWZhY2U9Iu+8re+8syDvvLDjgrTjgrfjg4Pjgq8iIC8+PGE6Zm9udCBzY3JpcHQ9IkhhbmciIHR5cGVmYWNlPSLrp5HsnYAg6rOg65SVIiAvPjxhOmZvbnQgc2NyaXB0PSJIYW5zIiB0eXBlZmFjZT0i5a6L5L2TIiAvPjxhOmZvbnQgc2NyaXB0PSJIYW50IiB0eXBlZmFjZT0i5paw57Sw5piO6auUIiAvPjxhOmZvbnQgc2NyaXB0PSJBcmFiIiB0eXBlZmFjZT0iQXJpYWwiIC8+PGE6Zm9udCBzY3JpcHQ9IkhlYnIiIHR5cGVmYWNlPSJBcmlhbCIgLz48YTpmb250IHNjcmlwdD0iVGhhaSIgdHlwZWZhY2U9IlRhaG9tYSIgLz48YTpmb250IHNjcmlwdD0iRXRoaSIgdHlwZWZhY2U9Ik55YWxhIiAvPjxhOmZvbnQgc2NyaXB0PSJCZW5nIiB0eXBlZmFjZT0iVnJpbmRhIiAvPjxhOmZvbnQgc2NyaXB0PSJHdWpyIiB0eXBlZmFjZT0iU2hydXRpIiAvPjxhOmZvbnQgc2NyaXB0PSJLaG1yIiB0eXBlZmFjZT0iRGF1blBlbmgiIC8+PGE6Zm9udCBzY3JpcHQ9IktuZGEiIHR5cGVmYWNlPSJUdW5nYSIgLz48YTpmb250IHNjcmlwdD0iR3VydSIgdHlwZWZhY2U9IlJhYXZpIiAvPjxhOmZvbnQgc2NyaXB0PSJDYW5zIiB0eXBlZmFjZT0iRXVwaGVtaWEiIC8+PGE6Zm9udCBzY3JpcHQ9IkNoZXIiIHR5cGVmYWNlPSJQbGFudGFnZW5ldCBDaGVyb2tlZSIgLz48YTpmb250IHNjcmlwdD0iWWlpaSIgdHlwZWZhY2U9Ik1pY3Jvc29mdCBZaSBCYWl0aSIgLz48YTpmb250IHNjcmlwdD0iVGlidCIgdHlwZWZhY2U9Ik1pY3Jvc29mdCBIaW1hbGF5YSIgLz48YTpmb250IHNjcmlwdD0iVGhhYSIgdHlwZWZhY2U9Ik1WIEJvbGkiIC8+PGE6Zm9udCBzY3JpcHQ9IkRldmEiIHR5cGVmYWNlPSJNYW5nYWwiIC8+PGE6Zm9udCBzY3JpcHQ9IlRlbHUiIHR5cGVmYWNlPSJHYXV0YW1pIiAvPjxhOmZvbnQgc2NyaXB0PSJUYW1sIiB0eXBlZmFjZT0iTGF0aGEiIC8+PGE6Zm9udCBzY3JpcHQ9IlN5cmMiIHR5cGVmYWNlPSJFc3RyYW5nZWxvIEVkZXNzYSIgLz48YTpmb250IHNjcmlwdD0iT3J5YSIgdHlwZWZhY2U9IkthbGluZ2EiIC8+PGE6Zm9udCBzY3JpcHQ9Ik1seW0iIHR5cGVmYWNlPSJLYXJ0aWthIiAvPjxhOmZvbnQgc2NyaXB0PSJMYW9vIiB0eXBlZmFjZT0iRG9rQ2hhbXBhIiAvPjxhOmZvbnQgc2NyaXB0PSJTaW5oIiB0eXBlZmFjZT0iSXNrb29sYSBQb3RhIiAvPjxhOmZvbnQgc2NyaXB0PSJNb25nIiB0eXBlZmFjZT0iTW9uZ29saWFuIEJhaXRpIiAvPjxhOmZvbnQgc2NyaXB0PSJWaWV0IiB0eXBlZmFjZT0iQXJpYWwiIC8+PGE6Zm9udCBzY3JpcHQ9IlVpZ2giIHR5cGVmYWNlPSJNaWNyb3NvZnQgVWlnaHVyIiAvPjwvYTptaW5vckZvbnQ+PC9hOmZvbnRTY2hlbWU+PGE6Zm10U2NoZW1lIG5hbWU9Ik9mZmljZSI+PGE6ZmlsbFN0eWxlTHN0PjxhOnNvbGlkRmlsbD48YTpzY2hlbWVDbHIgdmFsPSJwaENsciIgLz48L2E6c29saWRGaWxsPjxhOmdyYWRGaWxsIHJvdFdpdGhTaGFwZT0iMSI+PGE6Z3NMc3Q+PGE6Z3MgcG9zPSIwIj48YTpzY2hlbWVDbHIgdmFsPSJwaENsciI+PGE6dGludCB2YWw9IjUwMDAwIiAvPjxhOnNhdE1vZCB2YWw9IjMwMDAwMCIgLz48L2E6c2NoZW1lQ2xyPjwvYTpncz48YTpncyBwb3M9IjM1MDAwIj48YTpzY2hlbWVDbHIgdmFsPSJwaENsciI+PGE6dGludCB2YWw9IjM3MDAwIiAvPjxhOnNhdE1vZCB2YWw9IjMwMDAwMCIgLz48L2E6c2NoZW1lQ2xyPjwvYTpncz48YTpncyBwb3M9IjEwMDAwMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnRpbnQgdmFsPSIxNTAwMCIgLz48YTpzYXRNb2QgdmFsPSIzNTAwMDAiIC8+PC9hOnNjaGVtZUNscj48L2E6Z3M+PC9hOmdzTHN0PjxhOmxpbiBhbmc9IjE2MjAwMDAwIiBzY2FsZWQ9IjEiIC8+PC9hOmdyYWRGaWxsPjxhOmdyYWRGaWxsIHJvdFdpdGhTaGFwZT0iMSI+PGE6Z3NMc3Q+PGE6Z3MgcG9zPSIwIj48YTpzY2hlbWVDbHIgdmFsPSJwaENsciI+PGE6c2hhZGUgdmFsPSI1MTAwMCIgLz48YTpzYXRNb2QgdmFsPSIxMzAwMDAiIC8+PC9hOnNjaGVtZUNscj48L2E6Z3M+PGE6Z3MgcG9zPSI4MDAwMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnNoYWRlIHZhbD0iOTMwMDAiIC8+PGE6c2F0TW9kIHZhbD0iMTMwMDAwIiAvPjwvYTpzY2hlbWVDbHI+PC9hOmdzPjxhOmdzIHBvcz0iMTAwMDAwIj48YTpzY2hlbWVDbHIgdmFsPSJwaENsciI+PGE6c2hhZGUgdmFsPSI5NDAwMCIgLz48YTpzYXRNb2QgdmFsPSIxMzUwMDAiIC8+PC9hOnNjaGVtZUNscj48L2E6Z3M+PC9hOmdzTHN0PjxhOmxpbiBhbmc9IjE2MjAwMDAwIiBzY2FsZWQ9IjAiIC8+PC9hOmdyYWRGaWxsPjwvYTpmaWxsU3R5bGVMc3Q+PGE6bG5TdHlsZUxzdD48YTpsbiB3PSI5NTI1IiBjYXA9ImZsYXQiIGNtcGQ9InNuZyIgYWxnbj0iY3RyIj48YTpzb2xpZEZpbGw+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnNoYWRlIHZhbD0iOTUwMDAiIC8+PGE6c2F0TW9kIHZhbD0iMTA1MDAwIiAvPjwvYTpzY2hlbWVDbHI+PC9hOnNvbGlkRmlsbD48YTpwcnN0RGFzaCB2YWw9InNvbGlkIiAvPjwvYTpsbj48YTpsbiB3PSIyNTQwMCIgY2FwPSJmbGF0IiBjbXBkPSJzbmciIGFsZ249ImN0ciI+PGE6c29saWRGaWxsPjxhOnNjaGVtZUNsciB2YWw9InBoQ2xyIiAvPjwvYTpzb2xpZEZpbGw+PGE6cHJzdERhc2ggdmFsPSJzb2xpZCIgLz48L2E6bG4+PGE6bG4gdz0iMzgxMDAiIGNhcD0iZmxhdCIgY21wZD0ic25nIiBhbGduPSJjdHIiPjxhOnNvbGlkRmlsbD48YTpzY2hlbWVDbHIgdmFsPSJwaENsciIgLz48L2E6c29saWRGaWxsPjxhOnByc3REYXNoIHZhbD0ic29saWQiIC8+PC9hOmxuPjwvYTpsblN0eWxlTHN0PjxhOmVmZmVjdFN0eWxlTHN0PjxhOmVmZmVjdFN0eWxlPjxhOmVmZmVjdExzdD48YTpvdXRlclNoZHcgYmx1clJhZD0iNDAwMDAiIGRpc3Q9IjIwMDAwIiBkaXI9IjU0MDAwMDAiIHJvdFdpdGhTaGFwZT0iMCI+PGE6c3JnYkNsciB2YWw9IjAwMDAwMCI+PGE6YWxwaGEgdmFsPSIzODAwMCIgLz48L2E6c3JnYkNscj48L2E6b3V0ZXJTaGR3PjwvYTplZmZlY3RMc3Q+PC9hOmVmZmVjdFN0eWxlPjxhOmVmZmVjdFN0eWxlPjxhOmVmZmVjdExzdD48YTpvdXRlclNoZHcgYmx1clJhZD0iNDAwMDAiIGRpc3Q9IjIzMDAwIiBkaXI9IjU0MDAwMDAiIHJvdFdpdGhTaGFwZT0iMCI+PGE6c3JnYkNsciB2YWw9IjAwMDAwMCI+PGE6YWxwaGEgdmFsPSIzNTAwMCIgLz48L2E6c3JnYkNscj48L2E6b3V0ZXJTaGR3PjwvYTplZmZlY3RMc3Q+PC9hOmVmZmVjdFN0eWxlPjxhOmVmZmVjdFN0eWxlPjxhOmVmZmVjdExzdD48YTpvdXRlclNoZHcgYmx1clJhZD0iNDAwMDAiIGRpc3Q9IjIzMDAwIiBkaXI9IjU0MDAwMDAiIHJvdFdpdGhTaGFwZT0iMCI+PGE6c3JnYkNsciB2YWw9IjAwMDAwMCI+PGE6YWxwaGEgdmFsPSIzNTAwMCIgLz48L2E6c3JnYkNscj48L2E6b3V0ZXJTaGR3PjwvYTplZmZlY3RMc3Q+PGE6c2NlbmUzZD48YTpjYW1lcmEgcHJzdD0ib3J0aG9ncmFwaGljRnJvbnQiPjxhOnJvdCBsYXQ9IjAiIGxvbj0iMCIgcmV2PSIwIiAvPjwvYTpjYW1lcmE+PGE6bGlnaHRSaWcgcmlnPSJ0aHJlZVB0IiBkaXI9InQiPjxhOnJvdCBsYXQ9IjAiIGxvbj0iMCIgcmV2PSIxMjAwMDAwIiAvPjwvYTpsaWdodFJpZz48L2E6c2NlbmUzZD48YTpzcDNkPjxhOmJldmVsVCB3PSI2MzUwMCIgaD0iMjU0MDAiIC8+PC9hOnNwM2Q+PC9hOmVmZmVjdFN0eWxlPjwvYTplZmZlY3RTdHlsZUxzdD48YTpiZ0ZpbGxTdHlsZUxzdD48YTpzb2xpZEZpbGw+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiIC8+PC9hOnNvbGlkRmlsbD48YTpncmFkRmlsbCByb3RXaXRoU2hhcGU9IjEiPjxhOmdzTHN0PjxhOmdzIHBvcz0iMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnRpbnQgdmFsPSI0MDAwMCIgLz48YTpzYXRNb2QgdmFsPSIzNTAwMDAiIC8+PC9hOnNjaGVtZUNscj48L2E6Z3M+PGE6Z3MgcG9zPSI0MDAwMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnRpbnQgdmFsPSI0NTAwMCIgLz48YTpzaGFkZSB2YWw9Ijk5MDAwIiAvPjxhOnNhdE1vZCB2YWw9IjM1MDAwMCIgLz48L2E6c2NoZW1lQ2xyPjwvYTpncz48YTpncyBwb3M9IjEwMDAwMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnNoYWRlIHZhbD0iMjAwMDAiIC8+PGE6c2F0TW9kIHZhbD0iMjU1MDAwIiAvPjwvYTpzY2hlbWVDbHI+PC9hOmdzPjwvYTpnc0xzdD48YTpwYXRoIHBhdGg9ImNpcmNsZSI+PGE6ZmlsbFRvUmVjdCBsPSI1MDAwMCIgdD0iLTgwMDAwIiByPSI1MDAwMCIgYj0iMTgwMDAwIiAvPjwvYTpwYXRoPjwvYTpncmFkRmlsbD48YTpncmFkRmlsbCByb3RXaXRoU2hhcGU9IjEiPjxhOmdzTHN0PjxhOmdzIHBvcz0iMCI+PGE6c2NoZW1lQ2xyIHZhbD0icGhDbHIiPjxhOnRpbnQgdmFsPSI4MDAwMCIgLz48YTpzYXRNb2QgdmFsPSIzMDAwMDAiIC8+PC9hOnNjaGVtZUNscj48L2E6Z3M+PGE6Z3MgcG9zPSIxMDAwMDAiPjxhOnNjaGVtZUNsciB2YWw9InBoQ2xyIj48YTpzaGFkZSB2YWw9IjMwMDAwIiAvPjxhOnNhdE1vZCB2YWw9IjIwMDAwMCIgLz48L2E6c2NoZW1lQ2xyPjwvYTpncz48L2E6Z3NMc3Q+PGE6cGF0aCBwYXRoPSJjaXJjbGUiPjxhOmZpbGxUb1JlY3QgbD0iNTAwMDAiIHQ9IjUwMDAwIiByPSI1MDAwMCIgYj0iNTAwMDAiIC8+PC9hOnBhdGg+PC9hOmdyYWRGaWxsPjwvYTpiZ0ZpbGxTdHlsZUxzdD48L2E6Zm10U2NoZW1lPjwvYTp0aGVtZUVsZW1lbnRzPjxhOm9iamVjdERlZmF1bHRzIC8+PGE6ZXh0cmFDbHJTY2hlbWVMc3QgLz48L2E6dGhlbWU+UEsDBAoAAAAAABN7eUKJ3nBGuwEAALsBAAAPAAAAeGwvd29ya2Jvb2sueG1s77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48eDp3b3JrYm9vayB4bWxuczpyPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9yZWxhdGlvbnNoaXBzIiB4bWxuczp4PSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvc3ByZWFkc2hlZXRtbC8yMDA2L21haW4iPjx4Ondvcmtib29rUHIgY29kZU5hbWU9IlRoaXNXb3JrYm9vayIgLz48eDpib29rVmlld3M+PHg6d29ya2Jvb2tWaWV3IGZpcnN0U2hlZXQ9IjAiIGFjdGl2ZVRhYj0iMCIgLz48L3g6Ym9va1ZpZXdzPjx4OnNoZWV0cz48eDpzaGVldCBuYW1lPSJTaGVldCAxIiBzaGVldElkPSIyIiByOmlkPSJySWQyIiAvPjwveDpzaGVldHM+PHg6ZGVmaW5lZE5hbWVzIC8+PHg6Y2FsY1ByIGNhbGNJZD0iMTI1NzI1IiAvPjwveDp3b3JrYm9vaz5QSwMECgAAAAAAxYV5QgAAAAAAAAAAAAAAAA4AAAB4bC93b3Jrc2hlZXRzL1BLAQIUAAoAAAAAABN7eUK9Z10uNQQAADUEAAATAAAAAAAAAAAAAAAAAAAAAABbQ29udGVudF9UeXBlc10ueG1sUEsBAhQACgAAAAAAi3U5SAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAQAAAAZgQAAF9yZWxzL1BLAQIUAAoAAAAAABN7eUJ0mYADnAIAAJwCAAALAAAAAAAAAAAAAAAAAIoEAABfcmVscy8ucmVsc1BLAQIUAAoAAAAAAIt1OUgAAAAAAAAAAAAAAAAJAAAAAAAAAAAAEAAAAE8HAABkb2NQcm9wcy9QSwECFAAKAAAAAAATe3lC717fXj0DAAA9AwAAEAAAAAAAAAAAAAAAAAB2BwAAZG9jUHJvcHMvYXBwLnhtbFBLAQIUAAoAAAAAAIt1OUgAAAAAAAAAAAAAAAAIAAAAAAAAAAAAEAAAAOEKAABwYWNrYWdlL1BLAQIUAAoAAAAAAMWFeUIAAAAAAAAAAAAAAAARAAAAAAAAAAAAEAAAAAcLAABwYWNrYWdlL3NlcnZpY2VzL1BLAQIUAAoAAAAAAMWFeUIAAAAAAAAAAAAAAAAaAAAAAAAAAAAAEAAAADYLAABwYWNrYWdlL3NlcnZpY2VzL21ldGFkYXRhL1BLAQIUAAoAAAAAAMWFeUIAAAAAAAAAAAAAAAAqAAAAAAAAAAAAEAAAAG4LAABwYWNrYWdlL3NlcnZpY2VzL21ldGFkYXRhL2NvcmUtcHJvcGVydGllcy9QSwECFAAKAAAAAAATe3lCc4c2yNoBAADaAQAAUQAAAAAAAAAAAAAAAAC2CwAAcGFja2FnZS9zZXJ2aWNlcy9tZXRhZGF0YS9jb3JlLXByb3BlcnRpZXMvZWNmZGQzMTQzZjIxNDg5MDk1YTQ0YzcxMTE1YjcyM2IucHNtZGNwUEsBAhQACgAAAAAAi3U5SAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAQAAAA/w0AAHhsL1BLAQIUAAoAAAAAAMWFeUIAAAAAAAAAAAAAAAAJAAAAAAAAAAAAEAAAACAOAAB4bC9fcmVscy9QSwECFAAKAAAAAAATe3lCJ0p8MrwCAAC8AgAAGgAAAAAAAAAAAAAAAABHDgAAeGwvX3JlbHMvd29ya2Jvb2sueG1sLnJlbHNQSwECFAAKAAAAAAATe3lCflKRBZAAAACQAAAAFAAAAAAAAAAAAAAAAAA7EQAAeGwvc2hhcmVkU3RyaW5ncy54bWxQSwECFAAKAAAAAAATe3lCItpbK3oIAAB6CAAADQAAAAAAAAAAAAAAAAD9EQAAeGwvc3R5bGVzLnhtbFBLAQIUAAoAAAAAAMWFeUIAAAAAAAAAAAAAAAAJAAAAAAAAAAAAEAAAAKIaAAB4bC90aGVtZS9QSwECFAAKAAAAAAATe3lCdbGRXrsbAAC7GwAAEgAAAAAAAAAAAAAAAADJGgAAeGwvdGhlbWUvdGhlbWUueG1sUEsBAhQACgAAAAAAE3t5QonecEa7AQAAuwEAAA8AAAAAAAAAAAAAAAAAtDYAAHhsL3dvcmtib29rLnhtbFBLAQIUAAoAAAAAAMWFeUIAAAAAAAAAAAAAAAAOAAAAAAAAAAAAEAAAAJw4AAB4bC93b3Jrc2hlZXRzL1BLBQYAAAAAEwATANQEAADIOAAAAAA='
var sheetsFront = ''
+ ''
- + '';
-var sheetsBack = '';
+ + ''
+var sheetsBack = ''
-var relFront = '';
+var relFront = ''
-var relBack = '';
+var relBack = ''
var contentTypeFront = ''
+ ''
+ ''
+ ''
+ ''
+ ''
- + '';
-var contentTypeBack = '';
-var sharedStringsFront = '';
-var sharedStringsBack = '';
-var shareStrings, convertedShareStrings;
+ + ''
+var contentTypeBack = ''
+var sharedStringsFront = ''
+var sharedStringsBack = ''
+var convertedShareStrings
-function generateMultiSheets(configs, xlsx) {
- var i = 1;
- configs.forEach(function(config) {
- config.name = config.name ? config.name : ('sheet'+i);
- i++;
- var sheet = new Sheet(config, xlsx, shareStrings, convertedShareStrings);
- sheet.generate();
+function generateMultiSheets (configs, xlsx, shareStrings) {
+ var i = 1
+ configs.forEach(function (config) {
+ config.name = config.name ? config.name : ('sheet' + i)
+ i++
+ var sheet = new Sheet(config, xlsx, shareStrings, convertedShareStrings)
+ sheet.generate()
convertedShareStrings = sheet.convertedShareStrings
- });
+ })
}
-function generateContentType(configs, xlsx) {
- var workbook = contentTypeFront;
- configs.forEach( function(config) {
- workbook += '';
- });
- workbook += contentTypeBack;
- xlsx.file('[Content_Types].xml', workbook);
+function generateContentType (configs, xlsx) {
+ var workbook = contentTypeFront
+ configs.forEach(function (config) {
+ workbook += ''
+ })
+ workbook += contentTypeBack
+ xlsx.file('[Content_Types].xml', workbook)
}
-function generateRel(configs,xlsx) {
- var workbook = relFront;
- var i = 1;
- configs.forEach( function(config) {
- workbook += '';
- i++;
- });
- workbook += relBack;
- xlsx.file('xl/_rels/workbook.xml.rels', workbook);
- xlsx.file('_rels/.rels', ''
- + ''
- + ''
- + '');
+function generateRel (configs, xlsx) {
+ var workbook = relFront
+ var i = 1
+ configs.forEach(function (config) {
+ workbook += ''
+ i++
+ })
+ workbook += relBack
+ xlsx.file('xl/_rels/workbook.xml.rels', workbook)
+ xlsx.file('_rels/.rels', ''
+ + ''
+ + ''
+ + '')
}
-function generateWorkbook(configs,xlsx) {
- var workbook = sheetsFront;
- var i = 1;
- configs.forEach( function(config) {
- workbook += '';
- i++;
- });
- workbook += sheetsBack;
- xlsx.file('xl/workbook.xml', workbook);
+function generateWorkbook (configs, xlsx) {
+ var workbook = sheetsFront
+ var i = 1
+ configs.forEach(function (config) {
+ workbook += ''
+ i++
+ })
+ workbook += sheetsBack
+ xlsx.file('xl/workbook.xml', workbook)
}
-function generateSharedStringsFile(xlsx){
- if (shareStrings.length > 0) {
- var sharedStringsFrontTmp = sharedStringsFront.replace(/\$count/g, shareStrings.length);
- xlsx.file("xl/sharedStrings.xml", (sharedStringsFrontTmp + convertedShareStrings + sharedStringsBack));
- }
- convertedShareStrings = "";
+function generateSharedStringsFile (xlsx, shareStrings) {
+ if (shareStrings.size > 0) {
+ var sharedStringsFrontTmp = sharedStringsFront.replace(/\$count/g, shareStrings.size)
+ xlsx.file('xl/sharedStrings.xml', (sharedStringsFrontTmp + convertedShareStrings + sharedStringsBack))
+ }
+ convertedShareStrings = ''
}
-exports.executeAsync = function(config, callBack) {
- return process.nextTick(function() {
- var r = exports.execute(config);
- callBack(r);
- });
-};
+exports.execute = function (config) {
+ var xlsx = new JSZip(templateXLSX, {
+ base64: true,
+ checkCRC32: false
+ })
+ var shareStrings = new Map()
+ convertedShareStrings = ''
-exports.execute = function(config) {
- var xlsx = new JSZip(templateXLSX, {
- base64: true,
- checkCRC32: false
- });
- shareStrings = new SortedMap();
- convertedShareStrings = "";
-
- var configs = [];
- if (config instanceof Array) {
- configs = config;
- }else{
- configs.push(config);
- }
- generateMultiSheets(configs, xlsx);
- generateWorkbook(configs, xlsx);
- generateRel(configs,xlsx) ;
- generateContentType(configs, xlsx);
- generateSharedStringsFile(xlsx);
- var results = xlsx.generate({
- base64: false,
- compression: "DEFLATE"
- });
- delete shareStrings;
- delete xlsx;
- return results;
+ var configs = []
+ if (config instanceof Array) {
+ configs = config
+ } else {
+ configs.push(config)
+ }
+ generateMultiSheets(configs, xlsx, shareStrings)
+ generateWorkbook(configs, xlsx)
+ generateRel(configs, xlsx)
+ generateContentType(configs, xlsx)
+ generateSharedStringsFile(xlsx, shareStrings)
+ return xlsx.generate({
+ base64: false,
+ compression: 'DEFLATE'
+ })
}
diff --git a/package.json b/package.json
index 6180b13..886e543 100644
--- a/package.json
+++ b/package.json
@@ -1,12 +1,12 @@
{
- "name": "excel-export",
- "version": "0.5.1",
- "description": "Simple data set export to Excel xlsx file",
+ "name": "js-excel",
+ "version": "1.0.0",
+ "description": "Data to excel in the browser and the server",
"main": "index.js",
"scripts": {
"test": "mocha test/main"
},
- "repository": "https://github.com/functionscope/Node-Excel-Export",
+ "repository": "https://github.com/furstenheim/js-excel",
"keywords": [
"Excel",
"xlsx"
@@ -14,11 +14,11 @@
"author": "Ber-Lin Lai ",
"license": "BSD",
"dependencies": {
- "collections": "^3.0.0",
- "node-zip": "1.x"
+ "jszip": "2.5.0"
},
"devDependencies": {
"mocha": "",
- "should": ""
+ "should": "",
+ "standard": "^8.6.0"
}
}
diff --git a/sheet.js b/sheet.js
index e63ffe7..fc84667 100644
--- a/sheet.js
+++ b/sheet.js
@@ -1,175 +1,165 @@
-var sheetFront = ''
- + ' '
- + ' ';
-var sheetBack =' '
- + ' ';
-
-var fs = require('fs');
+module.exports = Sheet
-function Sheet(config, xlsx, shareStrings, convertedShareStrings){
- this.config = config;
- this.xlsx = xlsx;
- this.shareStrings = shareStrings;
- this.convertedShareStrings = convertedShareStrings;
-}
-
-Sheet.prototype.generate = function(){
- var config = this.config, xlsx = this.xlsx;
- var cols = config.cols,
- data = config.rows,
- colsLength = cols.length,
- rows = "",
- row = "",
- colsWidth = "",
- styleIndex,
- self = this,
- k;
- config.fileName = 'xl/worksheets/' + (config.name || "sheet").replace(/[*?\]\[\/\/]/g, '') + '.xml';
- if (config.stylesXmlFile) {
- var path = config.stylesXmlFile;
- var styles = null;
- styles = fs.readFileSync(path, 'utf8');
- if (styles) {
- xlsx.file("xl/styles.xml", styles);
- }
- }
-
- //first row for column caption
- row = '';
- var colStyleIndex;
- for (k = 0; k < colsLength; k++) {
- colStyleIndex = cols[k].captionStyleIndex || 0;
- row += addStringCell(self, getColumnLetter(k + 1) + 1, cols[k].caption, colStyleIndex);
- if (cols[k].width) {
- colsWidth += '';
- }
- }
- row += '';
- rows += row;
+var sheetFront = ''
+ + ' '
+ + ' '
+var sheetBack = ' '
+ + ' '
- //fill in data
- var i, j, r, cellData, currRow, cellType, dataLength = data.length;
-
- for (i = 0; i < dataLength; i++) {
- r = data[i],
- currRow = i + 2;
- row = '';
- for (j = 0; j < colsLength; j++) {
- styleIndex = null;
- cellData = r[j];
- cellType = cols[j].type;
- if (typeof cols[j].beforeCellWrite === 'function') {
- var e = {
- rowNum: currRow,
- styleIndex: null,
- cellType: cellType
- };
- cellData = cols[j].beforeCellWrite(r, cellData, e);
- styleIndex = e.styleIndex || styleIndex;
- cellType = e.cellType;
- delete e;
- }
- switch (cellType) {
- case 'number':
- row += addNumberCell(getColumnLetter(j + 1) + currRow, cellData, styleIndex);
- break;
- case 'date':
- row += addDateCell(getColumnLetter(j + 1) + currRow, cellData, styleIndex);
- break;
- case 'bool':
- row += addBoolCell(getColumnLetter(j + 1) + currRow, cellData, styleIndex);
- break;
- default:
- row += addStringCell(self, getColumnLetter(j + 1) + currRow, cellData, styleIndex);
- }
- }
- row += '';
- rows += row;
- }
- if (colsWidth !== "") {
- sheetFront += '' + colsWidth + '';
- }
- xlsx.file(config.fileName, sheetFront + '' + rows + '' + sheetBack);
+function Sheet (config, xlsx, shareStrings, convertedShareStrings) {
+ this.config = config
+ this.xlsx = xlsx
+ this.shareStrings = shareStrings
+ this.convertedShareStrings = convertedShareStrings
}
-module.exports = Sheet;
+Sheet.prototype.generate = function () {
+ var config = this.config, xlsx = this.xlsx
+ var cols = config.cols,
+ data = config.rows,
+ colsLength = cols.length,
+ rows = '',
+ row = '',
+ colsWidth = '',
+ styleIndex,
+ self = this,
+ k
+ config.fileName = 'xl/worksheets/' + (config.name || 'sheet').replace(/[*?\]\[\/\/]/g, '') + '.xml'
+ if (config.stylesXml) {
+ var styles = config.stylesXml
+ xlsx.file('xl/styles.xml', styles)
+ }
-var startTag = function (obj, tagName, closed){
- var result = "<" + tagName, p;
- for (p in obj){
- result += " " + p + "=" + obj[p];
+ // first row for column caption
+ row = ''
+ var colStyleIndex
+ for (k = 0; k < colsLength; k++) {
+ colStyleIndex = cols[k].captionStyleIndex || 0
+ row += addStringCell(self, getColumnLetter(k + 1) + 1, cols[k].caption, colStyleIndex)
+ if (cols[k].width) {
+ colsWidth += ''
+ }
}
- if (!closed)
- result += ">";
- else
- result += "/>";
- return result;
-};
+ row += ''
+ rows += row
-var endTag = function(tagName){
- return "" + tagName + ">";
-};
+ // fill in data
+ var i, j, r, cellData, currRow, cellType, el, dataLength = data.length
-var addNumberCell = function(cellRef, value, styleIndex){
- styleIndex = styleIndex || 0;
- if (value===null)
- return "";
- else
- return ''+value+'';
-};
+ for (i = 0; i < dataLength; i++) {
+ r = data[i],
+ currRow = i + 2
+ row = ''
+ for (j = 0; j < colsLength; j++) {
+ styleIndex = null
+ cellData = r[j]
+ cellType = cols[j].type
+ if (typeof cols[j].beforeCellWrite === 'function') {
+ el = {
+ rowNum: currRow,
+ styleIndex: null,
+ cellType: cellType
+ }
+ cellData = cols[j].beforeCellWrite(r, cellData, el)
+ styleIndex = el.styleIndex || styleIndex
+ cellType = el.cellType
+ }
+ switch (cellType) {
+ case 'number':
+ row += addNumberCell(getColumnLetter(j + 1) + currRow, cellData, styleIndex)
+ break
+ case 'date':
+ row += addDateCell(getColumnLetter(j + 1) + currRow, cellData, styleIndex)
+ break
+ case 'bool':
+ row += addBoolCell(getColumnLetter(j + 1) + currRow, cellData, styleIndex)
+ break
+ default:
+ row += addStringCell(self, getColumnLetter(j + 1) + currRow, cellData, styleIndex)
+ }
+ }
+ row += ''
+ rows += row
+ }
+ if (colsWidth !== '') {
+ sheetFront += '' + colsWidth + ''
+ }
+ xlsx.file(config.fileName, sheetFront + '' + rows + '' + sheetBack)
+}
+var startTag = function (obj, tagName, closed) {
+ var result = '<' + tagName, p
+ for (p in obj) {
+ result += ' ' + p + '=' + obj[p]
+ }
+ if (!closed) { result += '>' } else { result += '/>' }
+ return result
+}
-var addDateCell = function(cellRef, value, styleIndex){
- styleIndex = styleIndex || 1;
- if (value===null)
- return "";
- else
- return ''+value+'';
-};
+var endTag = function (tagName) {
+ return '' + tagName + '>'
+}
-var addBoolCell = function(cellRef, value, styleIndex){
- styleIndex = styleIndex || 0;
- if (value===null)
- return "";
- if (value){
- value = 1;
- } else
- value = 0;
- return ''+value+'';
-};
+var addNumberCell = function (cellRef, value, styleIndex) {
+ styleIndex = styleIndex || 0
+ if (value === null) { return '' } else {
+ return '' + value + ''
+ }
+}
+var addDateCell = function (cellRef, value, styleIndex) {
+ styleIndex = styleIndex || 1
+ if (value === null) {
+ return ''
+ } else {
+ return '' + value + ''
+ }
+}
-var addStringCell = function(sheet, cellRef, value, styleIndex){
- styleIndex = styleIndex || 0;
- if (value===null)
- return "";
- if (typeof value ==='string'){
- value = value.replace(/&/g, "&").replace(/'/g, "'").replace(/>/g, ">").replace(/"+value+"";
- }
- return ''+i+'';
-};
+ return '' + value + ''
+}
+var addStringCell = function (sheet, cellRef, value, styleIndex) {
+ styleIndex = styleIndex || 0
+ if (value === null) { return '' }
+ if (typeof value === 'string') {
+ value = value.replace(/&/g, '&').replace(/'/g, ''').replace(/>/g, '>').replace(/' + value + ''
+ }
+ return '' + i + ''
+}
-var getColumnLetter = function(col){
- if (col <= 0)
- throw "col must be more than 0";
- var array = new Array();
- while (col > 0)
- {
- var remainder = col % 26;
- col /= 26;
- col = Math.floor(col);
- if(remainder ===0)
- {
- remainder = 26;
- col--;
- }
- array.push(64 + remainder);
+var getColumnLetter = function (col) {
+ if (col <= 0) { throw 'col must be more than 0' }
+ var array = []
+ while (col > 0) {
+ var remainder = col % 26
+ col /= 26
+ col = Math.floor(col)
+ if (remainder === 0) {
+ remainder = 26
+ col--
+ }
+ array.push(64 + remainder)
}
- return String.fromCharCode.apply(null, array.reverse());
-};
+ return String.fromCharCode.apply(null, array.reverse())
+}
diff --git a/test/date-utils.js b/test/date-utils.js
new file mode 100644
index 0000000..6bb3f17
--- /dev/null
+++ b/test/date-utils.js
@@ -0,0 +1,9 @@
+module.exports = {getJulian, oaDate}
+
+function getJulian (date) {
+ return Math.floor((date / 86400000) - (date.getTimezoneOffset() / 1440) + 2440587.5)
+}
+
+function oaDate (date) {
+ return (date - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000)
+}
\ No newline at end of file
diff --git a/test/main.js b/test/main.js
index 1d0d528..2c186e0 100644
--- a/test/main.js
+++ b/test/main.js
@@ -1,65 +1,66 @@
// test/main.js
-var should = require('should');
-var nodeExcel = require('../index');
+var should = require('should')
+var nodeExcel = require('../index')
+var dateUtils = require('./date-utils')
-describe('Simple Excel xlsx Export', function() {
- describe('Export', function() {
- it('returns xlsx', function() {
- var conf = {};
- conf.name = 'xxxxxx';
- conf.cols = [{
- caption: 'string',
- type: 'string'
- },
- {
- caption: 'date',
- type: 'date'
- },
- {
- caption: 'bool',
- type: 'bool'
- },
- {
- caption: 'number 2',
- type: 'number'
- }];
- conf.rows = [['pi', (new Date(Date.UTC(2013, 4, 1))).oaDate(), true, 3.14], ["e", (new Date(2012, 4, 1)).oaDate(), false, 2.7182], ["M&M<>'", (new Date(Date.UTC(2013, 6, 9))).oaDate(), false, 1.2], ["null", null, null, null]];
+describe('Simple Excel xlsx Export', function () {
+ describe('Export', function () {
+ it('returns xlsx', function () {
+ var conf = {}
+ conf.name = 'xxxxxx'
+ conf.cols = [{
+ caption: 'string',
+ type: 'string'
+ },
+ {
+ caption: 'date',
+ type: 'date'
+ },
+ {
+ caption: 'bool',
+ type: 'bool'
+ },
+ {
+ caption: 'number 2',
+ type: 'number'
+ }]
+ conf.rows = [['pi', dateUtils.oaDate(new Date(Date.UTC(2013, 4, 1))), true, 3.14], ['e', dateUtils.oaDate(new Date(2012, 4, 1)), false, 2.7182], ["M&M<>'", dateUtils.oaDate(new Date(Date.UTC(2013, 6, 9))), false, 1.2], ['null', null, null, null]]
- var result = nodeExcel.execute(conf);
- //console.log(result);
+ var result = nodeExcel.execute(conf)
+ // console.log(result);
- var fs = require('fs');
- fs.writeFileSync('single.xlsx', result, 'binary');
- });
- it('returns multisheet xlsx', function() {
- var confs = [];
- var conf = {};
- conf.cols = [{
- caption: 'string',
- type: 'string'
- },
- {
- caption: 'date',
- type: 'date'
- },
- {
- caption: 'bool',
- type: 'bool'
- },
- {
- caption: 'number 2',
- type: 'number'
- }];
- conf.rows = [['hahai', (new Date(Date.UTC(2013, 4, 1))).oaDate(), true, 3.14], ["e", (new Date(2012, 4, 1)).oaDate(), false, 2.7182], ["M&M<>'", (new Date(Date.UTC(2013, 6, 9))).oaDate(), false, 1.2], ["null", null, null, null]];
- for (var i = 0; i < 3; i++) {
- conf = JSON.parse(JSON.stringify(conf)); //clone
- conf.name = 'sheet'+i;
- confs.push(conf);
- }
- var result = nodeExcel.execute(confs),
- fs = require('fs');
- fs.writeFileSync('multi.xlsx', result, 'binary');
- })
- });
-});
+ var fs = require('fs')
+ fs.writeFileSync('single.xlsx', result, 'binary')
+ })
+ it('returns multisheet xlsx', function () {
+ var confs = []
+ var conf = {}
+ conf.cols = [{
+ caption: 'string',
+ type: 'string'
+ },
+ {
+ caption: 'date',
+ type: 'date'
+ },
+ {
+ caption: 'bool',
+ type: 'bool'
+ },
+ {
+ caption: 'number 2',
+ type: 'number'
+ }]
+ conf.rows = [['hahai', dateUtils.oaDate(new Date(Date.UTC(2013, 4, 1))), true, 3.14], ['e', dateUtils.oaDate(new Date(2012, 4, 1)), false, 2.7182], ["M&M<>'", dateUtils.oaDate(new Date(Date.UTC(2013, 6, 9))), false, 1.2], ['null', null, null, null]]
+ for (var i = 0; i < 3; i++) {
+ conf = JSON.parse(JSON.stringify(conf)) // clone
+ conf.name = 'sheet' + i
+ confs.push(conf)
+ }
+ var result = nodeExcel.execute(confs),
+ fs = require('fs')
+ fs.writeFileSync('multi.xlsx', result, 'binary')
+ })
+ })
+})