made with requirebin
Last active
October 1, 2017 17:17
-
-
Save erickzhao/a830925068890ad30533e13e51206194 to your computer and use it in GitHub Desktop.
requirebin sketch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let CSVExportService = require('json2csvexporter').default; | |
const exporter = CSVExportService.create(); | |
function download(htmlTable) { | |
exporter.downloadCSV(tableToJson(htmlTable)); | |
} | |
// Credits: http://johndyer.name/html-table-to-json/ | |
function tableToJson(table) { | |
let data = []; // first row needs to be headers | |
var headers = []; | |
for (var i=0; i<table.rows[0].cells.length; i++) { | |
headers[i] = table.rows[0].cells[i].innerHTML.toLowerCase().replace(/ /gi,''); | |
} | |
// go through cells | |
for (var i=1; i<table.rows.length; i++) { | |
var tableRow = table.rows[i]; var rowData = {}; | |
for (var j=0; j<tableRow.cells.length; j++) { | |
rowData[ headers[j] ] = tableRow.cells[j].innerHTML; | |
} | |
data.push(rowData); | |
} | |
return data; | |
} | |
const table = document.querySelector('#data-table'); | |
const button = document.querySelector('#dl-btn'); | |
button.addEventListener('click', () => download(document.querySelector('#data-table'))); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
setTimeout(function(){ | |
;require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
'use strict'; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | |
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | |
/** | |
* Provides an interface for maping JS datatypes to a delimiter-seperated value. | |
* Creates a list of lists called rows and maps it to a Blob via toBlob(). | |
*/ | |
var WriterService = function () { | |
/** | |
* Default constructors. Takes two optional params. | |
* @param {String} delimiter - Delimitercharacter(s) to be used in the CSV. | |
* @param {String} contentType - Type of file. | |
*/ | |
function WriterService() { | |
var delimiter = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ','; | |
var contentType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'text/csv'; | |
_classCallCheck(this, WriterService); | |
this.delimiter = delimiter; | |
this.contentType = contentType; | |
this.rows = [[]]; | |
} | |
/** | |
* Returns the current row | |
* @return {Array} - An array of values. | |
*/ | |
_createClass(WriterService, [{ | |
key: 'wrapWithQuotes', | |
/** | |
* Returns the input string | |
* @param {String} string - The input string. | |
* @return {String} - A safe strings wrapped in quotes. | |
*/ | |
value: function wrapWithQuotes(string) { | |
var safeString = string.replace(/"/g, '""'); | |
return '"' + safeString + '"'; | |
} | |
/** | |
* Pushes a new value into the current row. | |
* @param {Any} value - The value to push. | |
*/ | |
}, { | |
key: 'writeValue', | |
value: function writeValue(value) { | |
var stringValue = value === undefined ? '' : String(value); | |
var needsQuotes = stringValue.indexOf(this.delimiter) !== -1 || /"\r\n/.test(stringValue); | |
this.currentRow.push(needsQuotes ? this.wrapWithQuotes(stringValue) : stringValue); | |
} | |
/** | |
* Adds a en empty array to rows property. This maps to an empty line. | |
*/ | |
}, { | |
key: 'writeLine', | |
value: function writeLine() { | |
this.rows.push([]); | |
} | |
/** | |
* Flatten rows to a String. | |
* @return {String} - A string representation of the rows.. | |
*/ | |
}, { | |
key: 'toString', | |
value: function toString() { | |
var _this = this; | |
return this.rows.map(function (row) { | |
return row.join(_this.delimiter); | |
}).reduce(function (content, row) { | |
return content + '\r\n' + row; | |
}); | |
} | |
/** | |
* Transform the rows into a Blob. | |
* @return {Object} - A representation of the rows in the form of a Blob. The returned Object is an instance of Blob, but typeof Object. | |
*/ | |
}, { | |
key: 'toBlob', | |
value: function toBlob() { | |
return new Blob([this.toString()], { type: this.contentType }); | |
} | |
}, { | |
key: 'currentRow', | |
get: function get() { | |
return this.rows[this.rows.length - 1]; | |
} | |
}]); | |
return WriterService; | |
}(); | |
exports.default = WriterService; | |
},{}],"json2csvexporter":[function(require,module,exports){ | |
'use strict'; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | |
var _WriterService = require('./WriterService'); | |
var _WriterService2 = _interopRequireDefault(_WriterService); | |
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | |
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | |
/** | |
* Provides an ExportService that uses WriterService to mentain an in-memory representation of the CSV file. | |
* Uses downloadCSV to map the [data] via the Writer to a Blob and initiate download which triggers the download of the actual file in the browser. | |
* Provides static methods for Singleton-like usage. | |
*/ | |
var CSVExportService = function () { | |
/** | |
* Default constructor. Takes an optional options param. | |
* @param {Object} options - Provides the configuration options. | |
*/ | |
function CSVExportService(options) { | |
_classCallCheck(this, CSVExportService); | |
this.options = options || {}; | |
} | |
/** | |
* Shorthand for createCSV() with a pre-set writerType | |
*/ | |
_createClass(CSVExportService, [{ | |
key: 'createCSVBlob', | |
value: function createCSVBlob(data) { | |
return this.createCSV(data); | |
} | |
/** | |
* Shorthand for createCSV() with a pre-set writerType | |
*/ | |
}, { | |
key: 'dataToString', | |
value: function dataToString(data) { | |
return this.createCSV(data, 'string'); | |
} | |
/** | |
* Creates a Blob based on the provided data and configuration options. | |
* @param {Array} data - An array of JSON objects that will be mapped to the Blob. | |
* @param {String} writerType - ENUM for choosing the return type. Default to 'blo' | |
* @return {Object|String} - The Blob object (Is an instance of Blob, but typeof Object) or a String version of the CSV with newlines. | |
*/ | |
}, { | |
key: 'createCSV', | |
value: function createCSV(data) { | |
var writerType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'blob'; | |
var _ref = this.options || {}, | |
optionsColumns = _ref.columns, | |
optionsContentType = _ref.contentType, | |
optionsDelimeter = _ref.delimeter, | |
optionsDelimiter = _ref.delimiter, | |
optionsFormatters = _ref.formatters, | |
optionsHeaders = _ref.headers, | |
optionsIncludeHeaders = _ref.includeHeaders; | |
var contentType = optionsContentType || 'text/csv'; | |
var delimiter = optionsDelimeter || ','; | |
var formatters = optionsFormatters || {}; | |
var getFormater = function getFormater(header) { | |
return formatters[header] || function (v) { | |
return v; | |
}; | |
}; | |
var headerNames = optionsHeaders || {}; | |
var headers = optionsColumns || Object.getOwnPropertyNames(data[0]); | |
var includeHeaders = optionsIncludeHeaders; | |
var writer = new _WriterService2.default(delimiter, contentType); | |
if (includeHeaders === undefined || includeHeaders) { | |
headers.forEach(function (header) { | |
return writer.writeValue(headerNames[header] || header); | |
}); | |
writer.writeLine(); | |
} | |
data.forEach(function (row) { | |
headers.forEach(function (header) { | |
return writer.writeValue(getFormater(header)(row[header])); | |
}); | |
writer.writeLine(); | |
}); | |
return writerType === 'string' ? writer.toString() : writer.toBlob(); | |
} | |
/** | |
* Triggers the download of the file. | |
* @param {Object} blob - The blob to be downloaded. | |
* @param {String} filename - Name of the file. | |
*/ | |
}, { | |
key: 'download', | |
value: function download(blob, filename) { | |
if (navigator.msSaveBlob) { | |
navigator.msSaveBlob(blob, filename); | |
return; | |
} | |
var link = document.createElement('A'); | |
var url = URL.createObjectURL(blob); | |
link.href = url; | |
link.download = filename; | |
link.style.display = 'none'; | |
document.body.appendChild(link); | |
link.click(); | |
document.body.removeChild(link); | |
} | |
/** | |
* Creates and passes the blob and filename params to the download() method. In case of error, calls the onError callback (if provided) and prints a error mesage if devMode is enabled via options. | |
* @param {Array} data - An array of objects to map and store. | |
*/ | |
}, { | |
key: 'downloadCSV', | |
value: function downloadCSV(data) { | |
try { | |
var blob = this.createCSV(data, 'blob'); | |
var filename = this.options.filename || 'export-' + (new Date().getTime() / 1000 | 0) + '.csv'; | |
this.download(blob, filename); | |
} catch (err) { | |
if (this.options.devMode) { | |
console.error('Error downloading CSV. Send this log to the developers: \n', err); | |
} | |
if (this.options.onError) { | |
this.options.onError(err); | |
} | |
} | |
} | |
}, { | |
key: 'toString', | |
value: function toString(data) { | |
var writer = new _WriterService2.default(delimiter, contentType); | |
} | |
/** | |
* Shorthand for constructor. | |
* @param {Object} options | |
* @return {Object} - An instance of CSVExportService | |
*/ | |
}], [{ | |
key: 'create', | |
value: function create(options) { | |
return new CSVExportService(options); | |
} | |
/** | |
* Shorthand for initialization and download() call. | |
* @param {Array} data - An array of objects to map and store. | |
* @return {undefined} | |
*/ | |
}, { | |
key: 'download', | |
value: function download(data) { | |
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | |
return new CSVExportService(options).downloadCSV(data); | |
} | |
}]); | |
return CSVExportService; | |
}(); | |
exports.default = CSVExportService; | |
},{"./WriterService":1}]},{},[]) | |
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImxpYi9Xcml0ZXJTZXJ2aWNlLmpzIiwianNvbjJjc3ZleHBvcnRlciJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiJ3VzZSBzdHJpY3QnO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHtcbiAgdmFsdWU6IHRydWVcbn0pO1xuXG52YXIgX2NyZWF0ZUNsYXNzID0gZnVuY3Rpb24gKCkgeyBmdW5jdGlvbiBkZWZpbmVQcm9wZXJ0aWVzKHRhcmdldCwgcHJvcHMpIHsgZm9yICh2YXIgaSA9IDA7IGkgPCBwcm9wcy5sZW5ndGg7IGkrKykgeyB2YXIgZGVzY3JpcHRvciA9IHByb3BzW2ldOyBkZXNjcmlwdG9yLmVudW1lcmFibGUgPSBkZXNjcmlwdG9yLmVudW1lcmFibGUgfHwgZmFsc2U7IGRlc2NyaXB0b3IuY29uZmlndXJhYmxlID0gdHJ1ZTsgaWYgKFwidmFsdWVcIiBpbiBkZXNjcmlwdG9yKSBkZXNjcmlwdG9yLndyaXRhYmxlID0gdHJ1ZTsgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwgZGVzY3JpcHRvci5rZXksIGRlc2NyaXB0b3IpOyB9IH0gcmV0dXJuIGZ1bmN0aW9uIChDb25zdHJ1Y3RvciwgcHJvdG9Qcm9wcywgc3RhdGljUHJvcHMpIHsgaWYgKHByb3RvUHJvcHMpIGRlZmluZVByb3BlcnRpZXMoQ29uc3RydWN0b3IucHJvdG90eXBlLCBwcm90b1Byb3BzKTsgaWYgKHN0YXRpY1Byb3BzKSBkZWZpbmVQcm9wZXJ0aWVzKENvbnN0cnVjdG9yLCBzdGF0aWNQcm9wcyk7IHJldHVybiBDb25zdHJ1Y3RvcjsgfTsgfSgpO1xuXG5mdW5jdGlvbiBfY2xhc3NDYWxsQ2hlY2soaW5zdGFuY2UsIENvbnN0cnVjdG9yKSB7IGlmICghKGluc3RhbmNlIGluc3RhbmNlb2YgQ29uc3RydWN0b3IpKSB7IHRocm93IG5ldyBUeXBlRXJyb3IoXCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb25cIik7IH0gfVxuXG4vKipcbiAqIFByb3ZpZGVzIGFuIGludGVyZmFjZSBmb3IgbWFwaW5nIEpTIGRhdGF0eXBlcyB0byBhIGRlbGltaXRlci1zZXBlcmF0ZWQgdmFsdWUuXG4gKiBDcmVhdGVzIGEgbGlzdCBvZiBsaXN0cyBjYWxsZWQgcm93cyBhbmQgbWFwcyBpdCB0byBhIEJsb2IgdmlhIHRvQmxvYigpLlxuICovXG52YXIgV3JpdGVyU2VydmljZSA9IGZ1bmN0aW9uICgpIHtcbiAgLyoqXG4gICAqIERlZmF1bHQgY29uc3RydWN0b3JzLiBUYWtlcyB0d28gb3B0aW9uYWwgcGFyYW1zLlxuICAgKiBAcGFyYW0gIHtTdHJpbmd9IGRlbGltaXRlciAtIERlbGltaXRlcmNoYXJhY3RlcihzKSB0byBiZSB1c2VkIGluIHRoZSBDU1YuXG4gICAqIEBwYXJhbSAge1N0cmluZ30gY29udGVudFR5cGUgLSBUeXBlIG9mIGZpbGUuXG4gICAqL1xuICBmdW5jdGlvbiBXcml0ZXJTZXJ2aWNlKCkge1xuICAgIHZhciBkZWxpbWl0ZXIgPSBhcmd1bWVudHMubGVuZ3RoID4gMCAmJiBhcmd1bWVudHNbMF0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1swXSA6ICcsJztcbiAgICB2YXIgY29udGVudFR5cGUgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6ICd0ZXh0L2Nzdic7XG5cbiAgICBfY2xhc3NDYWxsQ2hlY2sodGhpcywgV3JpdGVyU2VydmljZSk7XG5cbiAgICB0aGlzLmRlbGltaXRlciA9IGRlbGltaXRlcjtcbiAgICB0aGlzLmNvbnRlbnRUeXBlID0gY29udGVudFR5cGU7XG4gICAgdGhpcy5yb3dzID0gW1tdXTtcbiAgfVxuICAvKipcbiAgICogUmV0dXJucyB0aGUgY3VycmVudCByb3dcbiAgICogQHJldHVybiB7QXJyYXl9IC0gQW4gYXJyYXkgb2YgdmFsdWVzLlxuICAgKi9cblxuXG4gIF9jcmVhdGVDbGFzcyhXcml0ZXJTZXJ2aWNlLCBbe1xuICAgIGtleTogJ3dyYXBXaXRoUXVvdGVzJyxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGlucHV0IHN0cmluZ1xuICAgICAqIEBwYXJhbSAge1N0cmluZ30gc3RyaW5nIC0gVGhlIGlucHV0IHN0cmluZy5cbiAgICAgKiBAcmV0dXJuIHtTdHJpbmd9IC0gQSBzYWZlIHN0cmluZ3Mgd3JhcHBlZCBpbiBxdW90ZXMuXG4gICAgICovXG4gICAgdmFsdWU6IGZ1bmN0aW9uIHdyYXBXaXRoUXVvdGVzKHN0cmluZykge1xuICAgICAgdmFyIHNhZmVTdHJpbmcgPSBzdHJpbmcucmVwbGFjZSgvXCIvZywgJ1wiXCInKTtcbiAgICAgIHJldHVybiAnXCInICsgc2FmZVN0cmluZyArICdcIic7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFB1c2hlcyBhIG5ldyB2YWx1ZSBpbnRvIHRoZSBjdXJyZW50IHJvdy5cbiAgICAgKiBAcGFyYW0gIHtBbnl9IHZhbHVlIC0gVGhlIHZhbHVlIHRvIHB1c2guXG4gICAgICovXG5cbiAgfSwge1xuICAgIGtleTogJ3dyaXRlVmFsdWUnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiB3cml0ZVZhbHVlKHZhbHVlKSB7XG4gICAgICB2YXIgc3RyaW5nVmFsdWUgPSB2YWx1ZSA9PT0gdW5kZWZpbmVkID8gJycgOiBTdHJpbmcodmFsdWUpO1xuICAgICAgdmFyIG5lZWRzUXVvdGVzID0gc3RyaW5nVmFsdWUuaW5kZXhPZih0aGlzLmRlbGltaXRlcikgIT09IC0xIHx8IC9cIlxcclxcbi8udGVzdChzdHJpbmdWYWx1ZSk7XG4gICAgICB0aGlzLmN1cnJlbnRSb3cucHVzaChuZWVkc1F1b3RlcyA/IHRoaXMud3JhcFdpdGhRdW90ZXMoc3RyaW5nVmFsdWUpIDogc3RyaW5nVmFsdWUpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBBZGRzIGEgZW4gZW1wdHkgYXJyYXkgdG8gcm93cyBwcm9wZXJ0eS4gVGhpcyBtYXBzIHRvIGFuIGVtcHR5IGxpbmUuXG4gICAgICovXG5cbiAgfSwge1xuICAgIGtleTogJ3dyaXRlTGluZScsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIHdyaXRlTGluZSgpIHtcbiAgICAgIHRoaXMucm93cy5wdXNoKFtdKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogRmxhdHRlbiByb3dzIHRvIGEgU3RyaW5nLlxuICAgICAqIEByZXR1cm4ge1N0cmluZ30gLSBBIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgcm93cy4uXG4gICAgICovXG5cbiAgfSwge1xuICAgIGtleTogJ3RvU3RyaW5nJyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gdG9TdHJpbmcoKSB7XG4gICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICByZXR1cm4gdGhpcy5yb3dzLm1hcChmdW5jdGlvbiAocm93KSB7XG4gICAgICAgIHJldHVybiByb3cuam9pbihfdGhpcy5kZWxpbWl0ZXIpO1xuICAgICAgfSkucmVkdWNlKGZ1bmN0aW9uIChjb250ZW50LCByb3cpIHtcbiAgICAgICAgcmV0dXJuIGNvbnRlbnQgKyAnXFxyXFxuJyArIHJvdztcbiAgICAgIH0pO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBUcmFuc2Zvcm0gdGhlIHJvd3MgaW50byBhIEJsb2IuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSAtIEEgcmVwcmVzZW50YXRpb24gb2YgdGhlIHJvd3MgaW4gdGhlIGZvcm0gb2YgYSBCbG9iLiBUaGUgcmV0dXJuZWQgT2JqZWN0IGlzIGFuIGluc3RhbmNlIG9mIEJsb2IsIGJ1dCB0eXBlb2YgT2JqZWN0LlxuICAgICAqL1xuXG4gIH0sIHtcbiAgICBrZXk6ICd0b0Jsb2InLFxuICAgIHZhbHVlOiBmdW5jdGlvbiB0b0Jsb2IoKSB7XG4gICAgICByZXR1cm4gbmV3IEJsb2IoW3RoaXMudG9TdHJpbmcoKV0sIHsgdHlwZTogdGhpcy5jb250ZW50VHlwZSB9KTtcbiAgICB9XG4gIH0sIHtcbiAgICBrZXk6ICdjdXJyZW50Um93JyxcbiAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgIHJldHVybiB0aGlzLnJvd3NbdGhpcy5yb3dzLmxlbmd0aCAtIDFdO1xuICAgIH1cbiAgfV0pO1xuXG4gIHJldHVybiBXcml0ZXJTZXJ2aWNlO1xufSgpO1xuXG5leHBvcnRzLmRlZmF1bHQgPSBXcml0ZXJTZXJ2aWNlOyIsIid1c2Ugc3RyaWN0JztcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7XG4gIHZhbHVlOiB0cnVlXG59KTtcblxudmFyIF9jcmVhdGVDbGFzcyA9IGZ1bmN0aW9uICgpIHsgZnVuY3Rpb24gZGVmaW5lUHJvcGVydGllcyh0YXJnZXQsIHByb3BzKSB7IGZvciAodmFyIGkgPSAwOyBpIDwgcHJvcHMubGVuZ3RoOyBpKyspIHsgdmFyIGRlc2NyaXB0b3IgPSBwcm9wc1tpXTsgZGVzY3JpcHRvci5lbnVtZXJhYmxlID0gZGVzY3JpcHRvci5lbnVtZXJhYmxlIHx8IGZhbHNlOyBkZXNjcmlwdG9yLmNvbmZpZ3VyYWJsZSA9IHRydWU7IGlmIChcInZhbHVlXCIgaW4gZGVzY3JpcHRvcikgZGVzY3JpcHRvci53cml0YWJsZSA9IHRydWU7IE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIGRlc2NyaXB0b3Iua2V5LCBkZXNjcmlwdG9yKTsgfSB9IHJldHVybiBmdW5jdGlvbiAoQ29uc3RydWN0b3IsIHByb3RvUHJvcHMsIHN0YXRpY1Byb3BzKSB7IGlmIChwcm90b1Byb3BzKSBkZWZpbmVQcm9wZXJ0aWVzKENvbnN0cnVjdG9yLnByb3RvdHlwZSwgcHJvdG9Qcm9wcyk7IGlmIChzdGF0aWNQcm9wcykgZGVmaW5lUHJvcGVydGllcyhDb25zdHJ1Y3Rvciwgc3RhdGljUHJvcHMpOyByZXR1cm4gQ29uc3RydWN0b3I7IH07IH0oKTtcblxudmFyIF9Xcml0ZXJTZXJ2aWNlID0gcmVxdWlyZSgnLi9Xcml0ZXJTZXJ2aWNlJyk7XG5cbnZhciBfV3JpdGVyU2VydmljZTIgPSBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KF9Xcml0ZXJTZXJ2aWNlKTtcblxuZnVuY3Rpb24gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChvYmopIHsgcmV0dXJuIG9iaiAmJiBvYmouX19lc01vZHVsZSA/IG9iaiA6IHsgZGVmYXVsdDogb2JqIH07IH1cblxuZnVuY3Rpb24gX2NsYXNzQ2FsbENoZWNrKGluc3RhbmNlLCBDb25zdHJ1Y3RvcikgeyBpZiAoIShpbnN0YW5jZSBpbnN0YW5jZW9mIENvbnN0cnVjdG9yKSkgeyB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uXCIpOyB9IH1cblxuLyoqXG4gKiBQcm92aWRlcyBhbiBFeHBvcnRTZXJ2aWNlIHRoYXQgdXNlcyBXcml0ZXJTZXJ2aWNlIHRvIG1lbnRhaW4gYW4gaW4tbWVtb3J5IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBDU1YgZmlsZS5cbiAqIFVzZXMgZG93bmxvYWRDU1YgdG8gbWFwIHRoZSBbZGF0YV0gdmlhIHRoZSBXcml0ZXIgdG8gYSBCbG9iIGFuZCBpbml0aWF0ZSBkb3dubG9hZCB3aGljaCB0cmlnZ2VycyB0aGUgZG93bmxvYWQgb2YgdGhlIGFjdHVhbCBmaWxlIGluIHRoZSBicm93c2VyLlxuICogUHJvdmlkZXMgc3RhdGljIG1ldGhvZHMgZm9yIFNpbmdsZXRvbi1saWtlIHVzYWdlLlxuICovXG52YXIgQ1NWRXhwb3J0U2VydmljZSA9IGZ1bmN0aW9uICgpIHtcbiAgLyoqXG4gICAqIERlZmF1bHQgY29uc3RydWN0b3IuIFRha2VzIGFuIG9wdGlvbmFsIG9wdGlvbnMgcGFyYW0uXG4gICAqIEBwYXJhbSAge09iamVjdH0gb3B0aW9ucyAtIFByb3ZpZGVzIHRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAqL1xuICBmdW5jdGlvbiBDU1ZFeHBvcnRTZXJ2aWNlKG9wdGlvbnMpIHtcbiAgICBfY2xhc3NDYWxsQ2hlY2sodGhpcywgQ1NWRXhwb3J0U2VydmljZSk7XG5cbiAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICB9XG5cbiAgLyoqXG4gICAqIFNob3J0aGFuZCBmb3IgY3JlYXRlQ1NWKCkgd2l0aCBhIHByZS1zZXQgd3JpdGVyVHlwZVxuICAqL1xuXG5cbiAgX2NyZWF0ZUNsYXNzKENTVkV4cG9ydFNlcnZpY2UsIFt7XG4gICAga2V5OiAnY3JlYXRlQ1NWQmxvYicsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIGNyZWF0ZUNTVkJsb2IoZGF0YSkge1xuICAgICAgcmV0dXJuIHRoaXMuY3JlYXRlQ1NWKGRhdGEpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAgKiBTaG9ydGhhbmQgZm9yIGNyZWF0ZUNTVigpIHdpdGggYSBwcmUtc2V0IHdyaXRlclR5cGVcbiAgICAqL1xuXG4gIH0sIHtcbiAgICBrZXk6ICdkYXRhVG9TdHJpbmcnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiBkYXRhVG9TdHJpbmcoZGF0YSkge1xuICAgICAgcmV0dXJuIHRoaXMuY3JlYXRlQ1NWKGRhdGEsICdzdHJpbmcnKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgQmxvYiBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgZGF0YSBhbmQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqIEBwYXJhbSAge0FycmF5fSBkYXRhIC0gQW4gYXJyYXkgb2YgSlNPTiBvYmplY3RzIHRoYXQgd2lsbCBiZSBtYXBwZWQgdG8gdGhlIEJsb2IuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSB3cml0ZXJUeXBlIC0gRU5VTSBmb3IgY2hvb3NpbmcgdGhlIHJldHVybiB0eXBlLiBEZWZhdWx0IHRvICdibG8nXG4gICAgICogQHJldHVybiB7T2JqZWN0fFN0cmluZ30gLSBUaGUgQmxvYiBvYmplY3QgKElzIGFuIGluc3RhbmNlIG9mIEJsb2IsIGJ1dCB0eXBlb2YgT2JqZWN0KSBvciBhIFN0cmluZyB2ZXJzaW9uIG9mIHRoZSBDU1Ygd2l0aCBuZXdsaW5lcy5cbiAgICAgKi9cblxuICB9LCB7XG4gICAga2V5OiAnY3JlYXRlQ1NWJyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gY3JlYXRlQ1NWKGRhdGEpIHtcbiAgICAgIHZhciB3cml0ZXJUeXBlID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiAnYmxvYic7XG5cbiAgICAgIHZhciBfcmVmID0gdGhpcy5vcHRpb25zIHx8IHt9LFxuICAgICAgICAgIG9wdGlvbnNDb2x1bW5zID0gX3JlZi5jb2x1bW5zLFxuICAgICAgICAgIG9wdGlvbnNDb250ZW50VHlwZSA9IF9yZWYuY29udGVudFR5cGUsXG4gICAgICAgICAgb3B0aW9uc0RlbGltZXRlciA9IF9yZWYuZGVsaW1ldGVyLFxuICAgICAgICAgIG9wdGlvbnNEZWxpbWl0ZXIgPSBfcmVmLmRlbGltaXRlcixcbiAgICAgICAgICBvcHRpb25zRm9ybWF0dGVycyA9IF9yZWYuZm9ybWF0dGVycyxcbiAgICAgICAgICBvcHRpb25zSGVhZGVycyA9IF9yZWYuaGVhZGVycyxcbiAgICAgICAgICBvcHRpb25zSW5jbHVkZUhlYWRlcnMgPSBfcmVmLmluY2x1ZGVIZWFkZXJzO1xuXG4gICAgICB2YXIgY29udGVudFR5cGUgPSBvcHRpb25zQ29udGVudFR5cGUgfHwgJ3RleHQvY3N2JztcbiAgICAgIHZhciBkZWxpbWl0ZXIgPSBvcHRpb25zRGVsaW1ldGVyIHx8ICcsJztcbiAgICAgIHZhciBmb3JtYXR0ZXJzID0gb3B0aW9uc0Zvcm1hdHRlcnMgfHwge307XG4gICAgICB2YXIgZ2V0Rm9ybWF0ZXIgPSBmdW5jdGlvbiBnZXRGb3JtYXRlcihoZWFkZXIpIHtcbiAgICAgICAgcmV0dXJuIGZvcm1hdHRlcnNbaGVhZGVyXSB8fCBmdW5jdGlvbiAodikge1xuICAgICAgICAgIHJldHVybiB2O1xuICAgICAgICB9O1xuICAgICAgfTtcbiAgICAgIHZhciBoZWFkZXJOYW1lcyA9IG9wdGlvbnNIZWFkZXJzIHx8IHt9O1xuICAgICAgdmFyIGhlYWRlcnMgPSBvcHRpb25zQ29sdW1ucyB8fCBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhkYXRhWzBdKTtcbiAgICAgIHZhciBpbmNsdWRlSGVhZGVycyA9IG9wdGlvbnNJbmNsdWRlSGVhZGVycztcbiAgICAgIHZhciB3cml0ZXIgPSBuZXcgX1dyaXRlclNlcnZpY2UyLmRlZmF1bHQoZGVsaW1pdGVyLCBjb250ZW50VHlwZSk7XG5cbiAgICAgIGlmIChpbmNsdWRlSGVhZGVycyA9PT0gdW5kZWZpbmVkIHx8IGluY2x1ZGVIZWFkZXJzKSB7XG4gICAgICAgIGhlYWRlcnMuZm9yRWFjaChmdW5jdGlvbiAoaGVhZGVyKSB7XG4gICAgICAgICAgcmV0dXJuIHdyaXRlci53cml0ZVZhbHVlKGhlYWRlck5hbWVzW2hlYWRlcl0gfHwgaGVhZGVyKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHdyaXRlci53cml0ZUxpbmUoKTtcbiAgICAgIH1cbiAgICAgIGRhdGEuZm9yRWFjaChmdW5jdGlvbiAocm93KSB7XG4gICAgICAgIGhlYWRlcnMuZm9yRWFjaChmdW5jdGlvbiAoaGVhZGVyKSB7XG4gICAgICAgICAgcmV0dXJuIHdyaXRlci53cml0ZVZhbHVlKGdldEZvcm1hdGVyKGhlYWRlcikocm93W2hlYWRlcl0pKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHdyaXRlci53cml0ZUxpbmUoKTtcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHdyaXRlclR5cGUgPT09ICdzdHJpbmcnID8gd3JpdGVyLnRvU3RyaW5nKCkgOiB3cml0ZXIudG9CbG9iKCk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFRyaWdnZXJzIHRoZSBkb3dubG9hZCBvZiB0aGUgZmlsZS5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9IGJsb2IgLSBUaGUgYmxvYiB0byBiZSBkb3dubG9hZGVkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gZmlsZW5hbWUgLSBOYW1lIG9mIHRoZSBmaWxlLlxuICAgICAqL1xuXG4gIH0sIHtcbiAgICBrZXk6ICdkb3dubG9hZCcsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIGRvd25sb2FkKGJsb2IsIGZpbGVuYW1lKSB7XG4gICAgICBpZiAobmF2aWdhdG9yLm1zU2F2ZUJsb2IpIHtcbiAgICAgICAgbmF2aWdhdG9yLm1zU2F2ZUJsb2IoYmxvYiwgZmlsZW5hbWUpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB2YXIgbGluayA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ0EnKTtcbiAgICAgIHZhciB1cmwgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKGJsb2IpO1xuICAgICAgbGluay5ocmVmID0gdXJsO1xuICAgICAgbGluay5kb3dubG9hZCA9IGZpbGVuYW1lO1xuICAgICAgbGluay5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChsaW5rKTtcbiAgICAgIGxpbmsuY2xpY2soKTtcbiAgICAgIGRvY3VtZW50LmJvZHkucmVtb3ZlQ2hpbGQobGluayk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW5kIHBhc3NlcyB0aGUgYmxvYiBhbmQgZmlsZW5hbWUgcGFyYW1zIHRvIHRoZSBkb3dubG9hZCgpIG1ldGhvZC4gSW4gY2FzZSBvZiBlcnJvciwgY2FsbHMgdGhlIG9uRXJyb3IgY2FsbGJhY2sgKGlmIHByb3ZpZGVkKSBhbmQgcHJpbnRzIGEgZXJyb3IgbWVzYWdlIGlmIGRldk1vZGUgaXMgZW5hYmxlZCB2aWEgb3B0aW9ucy5cbiAgICAgKiBAcGFyYW0gIHtBcnJheX0gZGF0YSAtIEFuIGFycmF5IG9mIG9iamVjdHMgdG8gbWFwIGFuZCBzdG9yZS5cbiAgICAgKi9cblxuICB9LCB7XG4gICAga2V5OiAnZG93bmxvYWRDU1YnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiBkb3dubG9hZENTVihkYXRhKSB7XG4gICAgICB0cnkge1xuICAgICAgICB2YXIgYmxvYiA9IHRoaXMuY3JlYXRlQ1NWKGRhdGEsICdibG9iJyk7XG4gICAgICAgIHZhciBmaWxlbmFtZSA9IHRoaXMub3B0aW9ucy5maWxlbmFtZSB8fCAnZXhwb3J0LScgKyAobmV3IERhdGUoKS5nZXRUaW1lKCkgLyAxMDAwIHwgMCkgKyAnLmNzdic7XG4gICAgICAgIHRoaXMuZG93bmxvYWQoYmxvYiwgZmlsZW5hbWUpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuZGV2TW9kZSkge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGRvd25sb2FkaW5nIENTVi4gU2VuZCB0aGlzIGxvZyB0byB0aGUgZGV2ZWxvcGVyczogXFxuJywgZXJyKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLm9uRXJyb3IpIHtcbiAgICAgICAgICB0aGlzLm9wdGlvbnMub25FcnJvcihlcnIpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9LCB7XG4gICAga2V5OiAndG9TdHJpbmcnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiB0b1N0cmluZyhkYXRhKSB7XG4gICAgICB2YXIgd3JpdGVyID0gbmV3IF9Xcml0ZXJTZXJ2aWNlMi5kZWZhdWx0KGRlbGltaXRlciwgY29udGVudFR5cGUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNob3J0aGFuZCBmb3IgY29uc3RydWN0b3IuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zXG4gICAgICogQHJldHVybiB7T2JqZWN0fSAtIEFuIGluc3RhbmNlIG9mIENTVkV4cG9ydFNlcnZpY2VcbiAgICAgKi9cblxuICB9XSwgW3tcbiAgICBrZXk6ICdjcmVhdGUnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiBjcmVhdGUob3B0aW9ucykge1xuICAgICAgcmV0dXJuIG5ldyBDU1ZFeHBvcnRTZXJ2aWNlKG9wdGlvbnMpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBTaG9ydGhhbmQgZm9yIGluaXRpYWxpemF0aW9uIGFuZCBkb3dubG9hZCgpIGNhbGwuXG4gICAgICogQHBhcmFtICB7QXJyYXl9IGRhdGEgLSBBbiBhcnJheSBvZiBvYmplY3RzIHRvIG1hcCBhbmQgc3RvcmUuXG4gICAgICogQHJldHVybiB7dW5kZWZpbmVkfVxuICAgICAqL1xuXG4gIH0sIHtcbiAgICBrZXk6ICdkb3dubG9hZCcsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIGRvd25sb2FkKGRhdGEpIHtcbiAgICAgIHZhciBvcHRpb25zID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiB7fTtcblxuICAgICAgcmV0dXJuIG5ldyBDU1ZFeHBvcnRTZXJ2aWNlKG9wdGlvbnMpLmRvd25sb2FkQ1NWKGRhdGEpO1xuICAgIH1cbiAgfV0pO1xuXG4gIHJldHVybiBDU1ZFeHBvcnRTZXJ2aWNlO1xufSgpO1xuXG5leHBvcnRzLmRlZmF1bHQgPSBDU1ZFeHBvcnRTZXJ2aWNlOyJdfQ== | |
let CSVExportService = require('json2csvexporter').default; | |
const exporter = CSVExportService.create(); | |
function download(htmlTable) { | |
exporter.downloadCSV(tableToJson(htmlTable)); | |
} | |
// Credits: http://johndyer.name/html-table-to-json/ | |
function tableToJson(table) { | |
let data = []; // first row needs to be headers | |
var headers = []; | |
for (var i=0; i<table.rows[0].cells.length; i++) { | |
headers[i] = table.rows[0].cells[i].innerHTML.toLowerCase().replace(/ /gi,''); | |
} | |
// go through cells | |
for (var i=1; i<table.rows.length; i++) { | |
var tableRow = table.rows[i]; var rowData = {}; | |
for (var j=0; j<tableRow.cells.length; j++) { | |
rowData[ headers[j] ] = tableRow.cells[j].innerHTML; | |
} | |
data.push(rowData); | |
} | |
return data; | |
} | |
const table = document.querySelector('#data-table'); | |
const button = document.querySelector('#dl-btn'); | |
button.addEventListener('click', () => download(document.querySelector('#data-table'))); | |
;}, 0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "json2csvexporter-demo", | |
"version": "1.0.0", | |
"dependencies": { | |
"json2csvexporter": "0.2.4" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- contents of this file will be placed inside the <body> --> | |
<table id="data-table" class="table"> | |
<tr> | |
<th>Make</th> | |
<th>Model</th> | |
<th>Year</th> | |
</tr> | |
<tr> | |
<td>Toyota</td> | |
<td>Corolla</td> | |
<td>2014</td> | |
</tr> | |
<tr> | |
<td>Ford</td> | |
<td>Mustang</td> | |
<td>1970</td> | |
</tr> | |
<tr> | |
<td>Honda</td> | |
<td>Civic</td> | |
<td>2007</td> | |
</tr> | |
</table> | |
<button type="button" class="btn btn-default" id='dl-btn'>Download CSV</button> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- contents of this file will be placed inside the <head> --> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous"> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment