UNPKG

@tricoteuses/arbre-de-la-loi

Version:

Generate ASTs from the French bills & laws; manipulate & export them to Markdown, etc.

827 lines (642 loc) 72.5 kB
"use strict"; require("core-js/modules/es.array.slice.js"); require("core-js/modules/es.object.to-string.js"); require("core-js/modules/es.function.name.js"); require("core-js/modules/es.array.from.js"); require("core-js/modules/es.symbol.js"); require("core-js/modules/es.symbol.description.js"); require("core-js/modules/es.symbol.iterator.js"); require("core-js/modules/es.array.is-array.js"); require("core-js/modules/es.object.define-property.js"); Object.defineProperty(exports, "__esModule", { value: true }); exports.documentsFromAssembleeHast = documentsFromAssembleeHast; require("regenerator-runtime/runtime.js"); require("core-js/modules/es.array.includes.js"); require("core-js/modules/es.string.includes.js"); require("core-js/modules/es.string.match.js"); require("core-js/modules/es.regexp.exec.js"); require("core-js/modules/es.string.iterator.js"); require("core-js/modules/es.array.iterator.js"); require("core-js/modules/web.dom-collections.iterator.js"); require("core-js/modules/es.string.replace.js"); require("core-js/modules/es.array.concat.js"); var _hastUtilToString = _interopRequireDefault(require("hast-util-to-string")); var _documents = require("./documents"); var _hast = require("./hast"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } var _marked = /*#__PURE__*/regeneratorRuntime.mark(iterMinimalBlockElements), _marked2 = /*#__PURE__*/regeneratorRuntime.mark(iterMinimalLinesSimplified); function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function documentsFromAssembleeHast(node) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var document = { type: _documents.UnstructuredType.Unknown }; var documents = [document]; var breadcrumb = { node: document }; convertHtmlPage(node, documents, breadcrumb, options); return documents; } function convertBody(node, documents, breadcrumb) { var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; console.assert(node.tagName === "body", "convertBody: Unexpected node tag: ".concat(node.tagName)); var _iterator = _createForOfIteratorHelper(node.children), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var child = _step.value; switch (child.type) { case _hast.HastType.Comment: warnUnexpectedNode(child, node); break; case _hast.HastType.Element: switch (child.tagName) { case "br": break; case "div": breadcrumb = convertBodyDiv(child, documents, breadcrumb, options); break; default: warnUnexpectedElement(child, node); } break; case _hast.HastType.Text: warnWhenNonEmptyText(child, node); break; default: (0, _hast.assertNeverHastNode)(child); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return breadcrumb; } function convertBodyDiv(node, documents, breadcrumb) { var _options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; console.assert(node.tagName === "div", "convertBodyDiv: Unexpected node tag: ".concat(node.tagName)); var document = documents[documents.length - 1]; var _iterator2 = _createForOfIteratorHelper(iterMinimalBlockElements(node)), _step2; try { iterLines: for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var element = _step2.value; // If one of the lines (simplified) contained in the element // starts with "PROJET DE LOI", etc, assume that the whole element // is a heading/preamble of the document and put it in the lines // of the document. var _iterator3 = _createForOfIteratorHelper(iterMinimalLinesSimplified(element)), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var lineSimplified = _step3.value; if (!lineSimplified) { continue; } var _iterator7 = _createForOfIteratorHelper([// "Exposé des motifs" without content: // * http://www.assemblee-nationale.fr/15/textes/0702.asp // "Exposé des motifs" with content: // * http://www.assemblee-nationale.fr/15/textes/1326.asp // * http://www.assemblee-nationale.fr/15/textes/1610.asp [/^EXPOSE_(GENERAL_)DES_MOTIFS$/, _documents.DocumentType.BillStatementOfReasons], // "Projet de loi" ou "Proposition de loi": // * http://www.assemblee-nationale.fr/15/textes/0232.asp // * http://www.assemblee-nationale.fr/15/textes/0626.asp // * http://www.assemblee-nationale.fr/15/textes/0676.asp [/^(PROJET|PROPOSITION)_DE_LOI(_|$)/, _documents.DocumentType.Bill], [/^TEXTE_(DE_LA_PROPOSITION|DU_PROJET)_DE_LOI(_|$)/, _documents.DocumentType.Bill]]), _step7; try { for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) { var _step7$value = _slicedToArray(_step7.value, 2), _regExp3 = _step7$value[0], documentType = _step7$value[1]; if (lineSimplified.match(_regExp3) !== null) { if (documentType === _documents.DocumentType.BillStatementOfReasons && breadcrumb.node.type === _documents.DivisionType.Article) { // The title "Exposé des motifs" occurs in a article. // => There is not a single document for the statement of reasons, // but a different one for each article. // So, it should be handled not as a BillStatementOfReasons, but // as a DivisionStatementOfReasons. continue; } if (breadcrumb.node === document && document.type === _documents.DocumentNodeType.Unknown) { // Type of current document is unknown and we are still in preamble (aka in lines). // Change document type. ; document.type = documentType; if (document.lines === undefined) { document.lines = []; } document.lines.push(element); if (document.children === undefined) { document.children = []; } } else { // Create a new document. document = { type: documentType, lines: [element], children: [] }; documents.push(document); breadcrumb = { node: document }; } continue iterLines; } } } catch (err) { _iterator7.e(err); } finally { _iterator7.f(); } } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } var text = (0, _hastUtilToString["default"])(element); var textSimplified = simplifyText(text); if (textSimplified && [_documents.DocumentType.Bill, _documents.UnstructuredType.Unknown].includes(document.type)) { var _iterator4 = _createForOfIteratorHelper([[/^ARTICLES?_/, _documents.DivisionType.Article], [/^CHAPITRE_/, _documents.DivisionType.Chapter], [/^LIVRE_/, _documents.DivisionType.Book], [/^PARTIE_/, _documents.DivisionType.Part], [/^(PREMIERE|SECONDE|DEUXIEME|TROISIEME|QUATRIEME)_PARTIE(_|$)/, _documents.DivisionType.Part], [/^SECTION_/, _documents.DivisionType.Section], [/^SOUSSECTION_/, _documents.DivisionType.Subsection], [/^SOUSTITRE_/, _documents.DivisionType.Subtitle], [/^TITRE_/, _documents.DivisionType.Title], [/^TOME_/, _documents.DivisionType.Tome]]), _step4; try { for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { var _step4$value = _slicedToArray(_step4.value, 2), _regExp2 = _step4$value[0], divisionType = _step4$value[1]; if (textSimplified.match(_regExp2) !== null) { if (document.type !== _documents.DocumentType.Bill) { // Current document was not a bill => Create a new bill. document = { type: _documents.DocumentType.Bill, children: [] }; documents.push(document); breadcrumb = { node: document }; } // Document is a bill. // Create a new division. var _division = { type: divisionType, headlines: [element], children: [] }; // Try to retrieve a division of the same type in breadcrumb and // append new division next to it. for (var ancestorBreadcrumb = breadcrumb; ancestorBreadcrumb !== undefined; ancestorBreadcrumb = ancestorBreadcrumb.parent) { if (ancestorBreadcrumb.node.type === _division.type) { ancestorBreadcrumb.parent.node.children.push(_division); breadcrumb = { node: _division, parent: ancestorBreadcrumb.parent }; continue iterLines; } } // The type of the division doesn't exit in the breadcrumb. // When the new division must be above the current node, climb the // breadcrumb hierarchy. for (var _ancestorBreadcrumb = breadcrumb; _ancestorBreadcrumb !== undefined; _ancestorBreadcrumb = (_ancestorBreadcrumb2 = _ancestorBreadcrumb) === null || _ancestorBreadcrumb2 === void 0 ? void 0 : _ancestorBreadcrumb2.parent) { var _ancestorBreadcrumb2; if (![_documents.DivisionType.Article, _documents.UnstructuredType.DivisionStatementOfReasons].includes(_ancestorBreadcrumb.node.type)) { breadcrumb = _ancestorBreadcrumb; break; } // An article can not contain a sub-division (except for // a division-related statement of reason). // Neither can the statement of reasons of a division. continue; } // Create a new level in breadcrumb for the new division. if (breadcrumb.node.children === undefined) { breadcrumb.node.children = []; } breadcrumb.node.children.push(_division); breadcrumb = { node: _division, parent: breadcrumb }; continue iterLines; } } } catch (err) { _iterator4.e(err); } finally { _iterator4.f(); } if (textSimplified && document.type === _documents.DocumentType.Bill) { var _division$children, _division$lines; var _iterator5 = _createForOfIteratorHelper([[/^ETAT_/, _documents.UnstructuredType.Annex], [/^(RAPPORT_)?ANNEXE(_|$)/, _documents.UnstructuredType.Annex]]), _step5; try { for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { var _step5$value = _slicedToArray(_step5.value, 2), regExp = _step5$value[0], unstructuredType = _step5$value[1]; if (textSimplified.match(regExp) !== null) { // Add a new "état" or "rapport" to the current bill (as a direct child of bill). var unstructured = { type: unstructuredType, headlines: [element] }; var documentBreadcrumb = breadcrumb; while (documentBreadcrumb.parent !== undefined) { documentBreadcrumb = documentBreadcrumb.parent; } documentBreadcrumb.node.children.push(unstructured); breadcrumb = { node: unstructured, parent: documentBreadcrumb }; continue iterLines; } } } catch (err) { _iterator5.e(err); } finally { _iterator5.f(); } var _iterator6 = _createForOfIteratorHelper([[/^EXPOSE_DES_MOTIFS(_|$)/, _documents.UnstructuredType.DivisionStatementOfReasons]]), _step6; try { for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) { var _step6$value = _slicedToArray(_step6.value, 2), _regExp = _step6$value[0], _unstructuredType = _step6$value[1]; if (textSimplified.match(_regExp) !== null) { // Add a new "exposé des motifs" as a child of the current node. var _unstructured = { type: _unstructuredType, headlines: [element] }; breadcrumb.node.children.push(_unstructured); breadcrumb = { node: _unstructured, parent: breadcrumb }; continue iterLines; } } } catch (err) { _iterator6.e(err); } finally { _iterator6.f(); } var division = breadcrumb.node; console.assert(!((_division$children = division.children) !== null && _division$children !== void 0 && _division$children.length), "The current division of breadcrumb should never have children: ".concat(JSON.stringify(division, null, 2))); if (_documents.divisionTypes.has(division.type) && division.type !== _documents.DocumentNodeType.Article && division.headlines !== undefined && division.headlines.length === 1 && !((_division$lines = division.lines) !== null && _division$lines !== void 0 && _division$lines.length)) { // The current division has no subtitle (and can have one) // => Add element as subtitle. if (!text.match(/^[ \t\n\f\r\xa0]*$/)) { // Second title of division division.headlines.push(element); continue iterLines; } } // Otherwise, assume that element is a line or an alinea. if (division.lines === undefined) { division.lines = []; } // TODO: Remove (optional) "pastille" (aka alinea number) from alinea. division.lines.push(element); continue iterLines; } } // The Document is not a bill. var _node = breadcrumb.node; if (_node.lines === undefined) { _node.lines = []; } _node.lines.push(element); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } return breadcrumb; } // function convertBodyDivP( // node: HastElement, // documents: Array<Document | Unknown>, // breadcrumb: Breadcrumb, // options: Options = {}, // ): Breadcrumb { // console.assert( // node.tagName === "p", // `convertBodyDivP: Unexpected node tag: ${node.tagName}`, // ) // // for (const child of node.children) { // // switch (child.type) { // // case HastType.Comment: // // warnUnexpectedNode(child, node) // // break // // case HastType.Element: // // switch (child.tagName) { // // // case "br": // // // break // // // case "div": // // // breadcrumb = convertDiv(child, bill, options) // // // break // // default: // // warnUnexpectedElement(child, node) // // } // // break // // case HastType.Text: // // warnWhenNonEmptyText(child, node) // // break // // default: // // assertNeverHastNode(child) // // } // // } // return breadcrumb // } function convertHtml(node, documents, breadcrumb) { var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; console.assert(node.tagName === "html", "convertHtml: Unexpected node tag: ".concat(node.tagName)); var _iterator8 = _createForOfIteratorHelper(node.children), _step8; try { for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) { var child = _step8.value; switch (child.type) { case _hast.HastType.Comment: warnUnexpectedNode(child, node); break; case _hast.HastType.Element: switch (child.tagName) { case "head": break; case "body": breadcrumb = convertBody(child, documents, breadcrumb, options); break; default: warnUnexpectedElement(child, node); } break; case _hast.HastType.Text: warnWhenNonEmptyText(child, node); break; default: (0, _hast.assertNeverHastNode)(child); } } } catch (err) { _iterator8.e(err); } finally { _iterator8.f(); } return breadcrumb; } function convertHtmlPage(node, documents, breadcrumb) { var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; var _iterator9 = _createForOfIteratorHelper(node.children), _step9; try { for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) { var child = _step9.value; switch (child.type) { case _hast.HastType.Comment: warnUnexpectedNode(child, node); break; case _hast.HastType.Doctype: break; case _hast.HastType.Element: if (child.tagName === "html") { breadcrumb = convertHtml(child, documents, breadcrumb, options); } else { warnUnexpectedElement(child, node); } break; case _hast.HastType.Text: warnWhenNonEmptyText(child, node); break; default: (0, _hast.assertNeverHastNode)(child); } } } catch (err) { _iterator9.e(err); } finally { _iterator9.f(); } return breadcrumb; } function iterMinimalBlockElements(node) { var blockElementsEncountered, _iterator10, _step10, child; return regeneratorRuntime.wrap(function iterMinimalBlockElements$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: blockElementsEncountered = false; _iterator10 = _createForOfIteratorHelper(node.children); _context.prev = 2; _iterator10.s(); case 4: if ((_step10 = _iterator10.n()).done) { _context.next = 39; break; } child = _step10.value; _context.t0 = child.type; _context.next = _context.t0 === _hast.HastType.Comment ? 9 : _context.t0 === _hast.HastType.Element ? 10 : _context.t0 === _hast.HastType.Text ? 27 : 36; break; case 9: return _context.abrupt("break", 37); case 10: _context.t1 = child.tagName; _context.next = _context.t1 === "br" ? 13 : _context.t1 === "hr" ? 13 : _context.t1 === "table" ? 13 : _context.t1 === "div" ? 17 : _context.t1 === "p" ? 17 : 20; break; case 13: blockElementsEncountered = true; _context.next = 16; return child; case 16: return _context.abrupt("break", 26); case 17: blockElementsEncountered = true; return _context.delegateYield(iterMinimalBlockElements(child), "t2", 19); case 19: return _context.abrupt("break", 26); case 20: if (blockElementsEncountered) { _context.next = 24; break; } _context.next = 23; return node; case 23: return _context.abrupt("return"); case 24: _context.next = 26; return child; case 26: return _context.abrupt("break", 37); case 27: if (!(child.value.match(/^[ \t\n\f\r\xa0]*$/) === null)) { _context.next = 35; break; } if (blockElementsEncountered) { _context.next = 32; break; } _context.next = 31; return node; case 31: return _context.abrupt("return"); case 32: _context.next = 34; return { type: _hast.HastType.Element, tagName: "span", children: [child] }; case 34: return _context.abrupt("break", 37); case 35: return _context.abrupt("break", 37); case 36: (0, _hast.assertNeverHastNode)(child); case 37: _context.next = 4; break; case 39: _context.next = 44; break; case 41: _context.prev = 41; _context.t3 = _context["catch"](2); _iterator10.e(_context.t3); case 44: _context.prev = 44; _iterator10.f(); return _context.finish(44); case 47: case "end": return _context.stop(); } } }, _marked, null, [[2, 41, 44, 47]]); } function iterMinimalLinesSimplified(node) { var _iterator11, _step11, child; return regeneratorRuntime.wrap(function iterMinimalLinesSimplified$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: _iterator11 = _createForOfIteratorHelper(node.children); _context2.prev = 1; _iterator11.s(); case 3: if ((_step11 = _iterator11.n()).done) { _context2.next = 26; break; } child = _step11.value; _context2.t0 = child.type; _context2.next = _context2.t0 === _hast.HastType.Comment ? 8 : _context2.t0 === _hast.HastType.Element ? 9 : _context2.t0 === _hast.HastType.Text ? 18 : 23; break; case 8: return _context2.abrupt("break", 24); case 9: _context2.t1 = child.tagName; _context2.next = _context2.t1 === "div" ? 12 : _context2.t1 === "p" ? 12 : _context2.t1 === "table" ? 12 : _context2.t1 === "tbody" ? 12 : _context2.t1 === "tr" ? 12 : 14; break; case 12: return _context2.delegateYield(iterMinimalLinesSimplified(child), "t2", 13); case 13: return _context2.abrupt("break", 17); case 14: _context2.next = 16; return simplifyText((0, _hastUtilToString["default"])(node)); case 16: return _context2.abrupt("return"); case 17: return _context2.abrupt("break", 24); case 18: if (!(child.value.match(/^[ \t\n\f\r\xa0]*$/) === null)) { _context2.next = 22; break; } _context2.next = 21; return simplifyText((0, _hastUtilToString["default"])(node)); case 21: return _context2.abrupt("return"); case 22: return _context2.abrupt("break", 24); case 23: (0, _hast.assertNeverHastNode)(child); case 24: _context2.next = 3; break; case 26: _context2.next = 31; break; case 28: _context2.prev = 28; _context2.t3 = _context2["catch"](1); _iterator11.e(_context2.t3); case 31: _context2.prev = 31; _iterator11.f(); return _context2.finish(31); case 34: case "end": return _context2.stop(); } } }, _marked2, null, [[1, 28, 31, 34]]); } function simplifyText(text) { return text.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/\(nouveau\)/, "").replace(/\(Pour coordination\)/, "").replace(/\(Supprimés?\)/, "").replace(/[_\t\n\f\r\xa0]/g, " ").replace(/[\-,.…]/g, "").replace(/ {2,}/g, " ").replace(/^\s+/, "") // Trim begin of line. .replace(/\s+$/, "") // Trim end of line. .replace(/ /g, "_").toUpperCase(); } function warnUnexpectedElement(node, parent) { switch (parent.type) { case _hast.HastType.Element: console.warn("Unexpected element of tag \"".concat(node.tagName, "\" in node of tag: ").concat(parent.tagName)); break; case _hast.HastType.Root: console.warn("Unexpected element of tag \"".concat(node.tagName, "\" in node of type: ").concat(parent.type)); break; default: (0, _hast.assertNeverHastNode)(parent); } // console.warn(JSON.stringify(parent, null, 2)) } function warnUnexpectedNode(node, parent) { switch (parent.type) { case _hast.HastType.Element: console.warn("Unexpected node of type \"".concat(node.type, "\" in node of tag: ").concat(parent.tagName)); break; case _hast.HastType.Root: console.warn("Unexpected node of type \"".concat(node.type, "\" in node of type: ").concat(parent.type)); break; default: (0, _hast.assertNeverHastNode)(parent); } // console.warn(JSON.stringify(parent, null, 2)) } function warnWhenNonEmptyText(node, parent) { // See <https://html.spec.whatwg.org/#space-character>. if (!node.value.match(/^[ \t\n\f\r\xa0]*$/)) { switch (parent.type) { case _hast.HastType.Element: console.warn("Unexpected non empty text \"".concat(node.value, "\" in node of tag: ").concat(parent.tagName)); break; case _hast.HastType.Root: console.warn("Unexpected non empty text \"".concat(node.value, "\" in node of type: ").concat(parent.type)); break; default: (0, _hast.assertNeverHastNode)(parent); } } } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9hc3NlbWJsZWVfaHRtbF9wYXJzZXIudHMiXSwibmFtZXMiOlsiaXRlck1pbmltYWxCbG9ja0VsZW1lbnRzIiwiaXRlck1pbmltYWxMaW5lc1NpbXBsaWZpZWQiLCJkb2N1bWVudHNGcm9tQXNzZW1ibGVlSGFzdCIsIm5vZGUiLCJvcHRpb25zIiwiZG9jdW1lbnQiLCJ0eXBlIiwiVW5zdHJ1Y3R1cmVkVHlwZSIsIlVua25vd24iLCJkb2N1bWVudHMiLCJicmVhZGNydW1iIiwiY29udmVydEh0bWxQYWdlIiwiY29udmVydEJvZHkiLCJjb25zb2xlIiwiYXNzZXJ0IiwidGFnTmFtZSIsImNoaWxkcmVuIiwiY2hpbGQiLCJIYXN0VHlwZSIsIkNvbW1lbnQiLCJ3YXJuVW5leHBlY3RlZE5vZGUiLCJFbGVtZW50IiwiY29udmVydEJvZHlEaXYiLCJ3YXJuVW5leHBlY3RlZEVsZW1lbnQiLCJUZXh0Iiwid2FybldoZW5Ob25FbXB0eVRleHQiLCJfb3B0aW9ucyIsImxlbmd0aCIsIml0ZXJMaW5lcyIsImVsZW1lbnQiLCJsaW5lU2ltcGxpZmllZCIsIkRvY3VtZW50VHlwZSIsIkJpbGxTdGF0ZW1lbnRPZlJlYXNvbnMiLCJCaWxsIiwicmVnRXhwIiwiZG9jdW1lbnRUeXBlIiwibWF0Y2giLCJEaXZpc2lvblR5cGUiLCJBcnRpY2xlIiwiRG9jdW1lbnROb2RlVHlwZSIsImxpbmVzIiwidW5kZWZpbmVkIiwicHVzaCIsInRleHQiLCJ0ZXh0U2ltcGxpZmllZCIsInNpbXBsaWZ5VGV4dCIsImluY2x1ZGVzIiwiQ2hhcHRlciIsIkJvb2siLCJQYXJ0IiwiU2VjdGlvbiIsIlN1YnNlY3Rpb24iLCJTdWJ0aXRsZSIsIlRpdGxlIiwiVG9tZSIsImRpdmlzaW9uVHlwZSIsImRpdmlzaW9uIiwiaGVhZGxpbmVzIiwiYW5jZXN0b3JCcmVhZGNydW1iIiwicGFyZW50IiwiRGl2aXNpb25TdGF0ZW1lbnRPZlJlYXNvbnMiLCJBbm5leCIsInVuc3RydWN0dXJlZFR5cGUiLCJ1bnN0cnVjdHVyZWQiLCJkb2N1bWVudEJyZWFkY3J1bWIiLCJKU09OIiwic3RyaW5naWZ5IiwiZGl2aXNpb25UeXBlcyIsImhhcyIsImNvbnZlcnRIdG1sIiwiRG9jdHlwZSIsImJsb2NrRWxlbWVudHNFbmNvdW50ZXJlZCIsInZhbHVlIiwibm9ybWFsaXplIiwicmVwbGFjZSIsInRvVXBwZXJDYXNlIiwid2FybiIsIlJvb3QiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOztBQUVBOztBQVdBOzs7O21EQXliVUEsd0I7b0RBMERBQywwQjs7Ozs7Ozs7Ozs7Ozs7OztBQWhlSCxTQUFTQywwQkFBVCxDQUNMQyxJQURLLEVBR3NCO0FBQUEsTUFEM0JDLE9BQzJCLHVFQURSLEVBQ1E7QUFDM0IsTUFBTUMsUUFBaUIsR0FBRztBQUN4QkMsSUFBQUEsSUFBSSxFQUFFQyw0QkFBaUJDO0FBREMsR0FBMUI7QUFHQSxNQUFNQyxTQUFvQyxHQUFHLENBQUNKLFFBQUQsQ0FBN0M7QUFDQSxNQUFNSyxVQUFzQixHQUFHO0FBQUVQLElBQUFBLElBQUksRUFBRUU7QUFBUixHQUEvQjtBQUVBTSxFQUFBQSxlQUFlLENBQUNSLElBQUQsRUFBT00sU0FBUCxFQUFrQkMsVUFBbEIsRUFBOEJOLE9BQTlCLENBQWY7QUFDQSxTQUFPSyxTQUFQO0FBQ0Q7O0FBRUQsU0FBU0csV0FBVCxDQUNFVCxJQURGLEVBRUVNLFNBRkYsRUFHRUMsVUFIRixFQUtjO0FBQUEsTUFEWk4sT0FDWSx1RUFETyxFQUNQO0FBQ1pTLEVBQUFBLE9BQU8sQ0FBQ0MsTUFBUixDQUNFWCxJQUFJLENBQUNZLE9BQUwsS0FBaUIsTUFEbkIsOENBRXVDWixJQUFJLENBQUNZLE9BRjVDOztBQURZLDZDQUtRWixJQUFJLENBQUNhLFFBTGI7QUFBQTs7QUFBQTtBQUtaLHdEQUFtQztBQUFBLFVBQXhCQyxLQUF3Qjs7QUFDakMsY0FBUUEsS0FBSyxDQUFDWCxJQUFkO0FBQ0UsYUFBS1ksZUFB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QUFNLENBQUM1QyxPQUR0RTtBQUdBOztBQUVGLFdBQUtHLGVBQVMyRCxJQUFkO0FBQ0VoRSxRQUFBQSxPQUFPLENBQUMrRCxJQUFSLHVDQUNnQ3pFLElBQUksQ0FBQ3FFLEtBRHJDLGlDQUNnRWIsTUFBTSxDQUFDckQsSUFEdkU7QUFHQTs7QUFFRjtBQUNFLHVDQUFvQnFELE1BQXBCO0FBZEo7QUFnQkQ7QUFDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBoYXN0VG90U3RyaW5nIGZyb20gXCJoYXN0LXV0aWwtdG8tc3RyaW5nXCJcblxuaW1wb3J0IHtcbiAgRGl2aXNpb24sXG4gIERpdmlzaW9uVHlwZSxcbiAgZGl2aXNpb25UeXBlcyxcbiAgRG9jdW1lbnQsXG4gIERvY3VtZW50Tm9kZVR5cGUsXG4gIERvY3VtZW50VHlwZSxcbiAgVW5rbm93bixcbiAgVW5zdHJ1Y3R1cmVkLFxuICBVbnN0cnVjdHVyZWRUeXBlLFxufSBmcm9tIFwiLi9kb2N1bWVudHNcIlxuaW1wb3J0IHtcbiAgYXNzZXJ0TmV2ZXJIYXN0Tm9kZSxcbiAgSGFzdEVsZW1lbnQsXG4gIEhhc3ROb2RlLFxuICBIYXN0Um9vdCxcbiAgSGFzdFRleHQsXG4gIEhhc3RUeXBlLFxufSBmcm9tIFwiLi9oYXN0XCJcblxuaW50ZXJmYWNlIEJyZWFkY3J1bWIge1xuICBub2RlOiBEaXZpc2lvbiB8IERvY3VtZW50IHwgVW5zdHJ1Y3R1cmVkXG4gIHBhcmVudD86IEJyZWFkY3J1bWJcbn1cblxuaW50ZXJmYWNlIE9wdGlvbnMge1xuICBzaWxlbnQ/OiBib29sZWFuXG4gIHZlcmJvc2U/OiBib29sZWFuXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkb2N1bWVudHNGcm9tQXNzZW1ibGVlSGFzdChcbiAgbm9kZTogSGFzdFJvb3QsXG4gIG9wdGlvbnM6IE9wdGlvbnMgPSB7fSxcbik6IEFycmF5PERvY3VtZW50IHwgVW5rbm93bj4ge1xuICBjb25zdCBkb2N1bWVudDogVW5rbm93biA9IHtcbiAgICB0eXBlOiBVbnN0cnVjdHVyZWRUeXBlLlVua25vd24sXG4gIH1cbiAgY29uc3QgZG9jdW1lbnRzOiBBcnJheTxEb2N1bWVudCB8IFVua25vd24+ID0gW2RvY3VtZW50XVxuICBjb25zdCBicmVhZGNydW1iOiBCcmVhZGNydW1iID0geyBub2RlOiBkb2N1bWVudCB9XG5cbiAgY29udmVydEh0bWxQYWdlKG5vZGUsIGRvY3VtZW50cywgYnJlYWRjcnVtYiwgb3B0aW9ucylcbiAgcmV0dXJuIGRvY3VtZW50c1xufVxuXG5mdW5jdGlvbiBjb252ZXJ0Qm9keShcbiAgbm9kZTogSGFzdEVsZW1lbnQsXG4gIGRvY3VtZW50czogQXJyYXk8RG9jdW1lbnQgfCBVbmtub3duPixcbiAgYnJlYWRjcnVtYjogQnJlYWRjcnVtYixcbiAgb3B0aW9uczogT3B0aW9ucyA9IHt9LFxuKTogQnJlYWRjcnVtYiB7XG4gIGNvbnNvbGUuYXNzZXJ0KFxuICAgIG5vZGUudGFnTmFtZSA9PT0gXCJib2R5XCIsXG4gICAgYGNvbnZlcnRCb2R5OiBVbmV4cGVjdGVkIG5vZGUgdGFnOiAke25vZGUudGFnTmFtZX1gLFxuICApXG4gIGZvciAoY29uc3QgY2hpbGQgb2Ygbm9kZS5jaGlsZHJlbikge1xuICAgIHN3aXRjaCAoY2hpbGQudHlwZSkge1xuICAgICAgY2FzZSBIYXN0VHlwZS5Db21tZW50OlxuICAgICAgICB3YXJuVW5leHBlY3RlZE5vZGUoY2hpbGQsIG5vZGUpXG4gICAgICAgIGJyZWFrXG5cbiAgICAgIGNhc2UgSGFzdFR5cGUuRWxlbWVudDpcbiAgICAgICAgc3dpdGNoIChjaGlsZC50YWdOYW1lKSB7XG4gICAgICAgICAgY2FzZSBcImJyXCI6XG4gICAgICAgICAgICBicmVha1xuXG4gICAgICAgICAgY2FzZSBcImRpdlwiOlxuICAgICAgICAgICAgYnJlYWRjcnVtYiA9IGNvbnZlcnRCb2R5RGl2KGNoaWxkLCBkb2N1bWVudHMsIGJyZWFkY3J1bWIsIG9wdGlvbnMpXG4gICAgICAgICAgICBicmVha1xuXG4gICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHdhcm5VbmV4cGVjdGVkRWxlbWVudChjaGlsZCwgbm9kZSlcbiAgICAgICAgfVxuICAgICAgICBicmVha1xuXG4gICAgICBjYXNlIEhhc3RUeXBlLlRleHQ6XG4gICAgICAgIHdhcm5XaGVuTm9uRW1wdHlUZXh0KGNoaWxkLCBub2RlKVxuICAgICAgICBicmVha1xuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBhc3NlcnROZXZlckhhc3ROb2RlKGNoaWxkKVxuICAgIH1cbiAgfVxuICByZXR1cm4gYnJlYWRjcnVtYlxufVxuXG5mdW5jdGlvbiBjb252ZXJ0Qm9keURpdihcbiAgbm9kZTogSGFzdEVsZW1lbnQsXG4gIGRvY3VtZW50czogQXJyYXk8RG9jdW1lbnQgfCBVbmtub3duPixcbiAgYnJlYWRjcnVtYjogQnJlYWRjcnVtYixcbiAgX29wdGlvbnM6IE9wdGlvbnMgPSB7fSxcbik6IEJyZWFkY3J1bWIge1xuICBjb25zb2xlLmFzc2VydChcbiAgICBub2RlLnRhZ05hbWUgPT09IFwiZGl2XCIsXG4gICAgYGNvbnZlcnRCb2R5RGl2OiBVbmV4cGVjdGVkIG5vZGUgdGFnOiAke25vZGUudGFnTmFtZX1gLFxuICApXG4gIGxldCBkb2N1bWVudCA9IGRvY3VtZW50c1tkb2N1bWVudHMubGVuZ3RoIC0gMV1cbiAgaXRlckxpbmVzOiBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgaXRlck1pbmltYWxCbG9ja0VsZW1lbnRzKG5vZGUpKSB7XG4gICAgLy8gSWYgb25lIG9mIHRoZSBsaW5lcyAoc2ltcGxpZmllZCkgY29udGFpbmVkIGluIHRoZSBlbGVtZW50XG4gICAgLy8gc3RhcnRzIHdpdGggXCJQUk9KRVQgREUgTE9JXCIsIGV0YywgYXNzdW1lIHRoYXQgdGhlIHdob2xlIGVsZW1lbnRcbiAgICAvLyBpcyBhIGhlYWRpbmcvcHJlYW1ibGUgb2YgdGhlIGRvY3VtZW50IGFuZCBwdXQgaXQgaW4gdGhlIGxpbmVzXG4gICAgLy8gb2YgdGhlIGR