Comparing version
{ | ||
"optOut": false, | ||
"lastUpdateCheck": 1648063932373 | ||
"lastUpdateCheck": 1676937741898 | ||
} |
@@ -1,322 +0,317 @@ | ||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Precedent = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ | ||
/** | ||
* @license MIT | ||
* @author <steven@velozo.com> | ||
*/ | ||
(function (f) { | ||
if (typeof exports === "object" && typeof module !== "undefined") { | ||
module.exports = f(); | ||
} else if (typeof define === "function" && define.amd) { | ||
define([], f); | ||
} else { | ||
var g; | ||
if (typeof window !== "undefined") { | ||
g = window; | ||
} else if (typeof global !== "undefined") { | ||
g = global; | ||
} else if (typeof self !== "undefined") { | ||
g = self; | ||
} else { | ||
g = this; | ||
} | ||
g.Precedent = f(); | ||
} | ||
})(function () { | ||
var define, module, exports; | ||
return function () { | ||
function r(e, n, t) { | ||
function o(i, f) { | ||
if (!n[i]) { | ||
if (!e[i]) { | ||
var c = "function" == typeof require && require; | ||
if (!f && c) return c(i, !0); | ||
if (u) return u(i, !0); | ||
var a = new Error("Cannot find module '" + i + "'"); | ||
throw a.code = "MODULE_NOT_FOUND", a; | ||
} | ||
var p = n[i] = { | ||
exports: {} | ||
}; | ||
e[i][0].call(p.exports, function (r) { | ||
var n = e[i][1][r]; | ||
return o(n || r); | ||
}, p, p.exports, r, e, n, t); | ||
} | ||
return n[i].exports; | ||
} | ||
for (var u = "function" == typeof require && require, i = 0; i < t.length; i++) o(t[i]); | ||
return o; | ||
} | ||
return r; | ||
}()({ | ||
1: [function (require, module, exports) { | ||
/** | ||
* Simple browser shim loader - assign the npm module to a window global automatically | ||
* | ||
* @license MIT | ||
* @author <steven@velozo.com> | ||
*/ | ||
var libNPMModuleWrapper = require('./Precedent.js'); | ||
if (typeof window == 'object' && !window.hasOwnProperty('Precedent')) { | ||
window.Precedent = libNPMModuleWrapper; | ||
} | ||
module.exports = libNPMModuleWrapper; | ||
}, { | ||
"./Precedent.js": 2 | ||
}], | ||
2: [function (require, module, exports) { | ||
/** | ||
* Precedent Meta-Templating | ||
* | ||
* @license MIT | ||
* | ||
* @author Steven Velozo <steven@velozo.com> | ||
* | ||
* @description Process text streams, parsing out meta-template expressions. | ||
*/ | ||
var libWordTree = require(`./WordTree.js`); | ||
var libStringParser = require(`./StringParser.js`); | ||
class Precedent { | ||
/** | ||
* Precedent Constructor | ||
*/ | ||
constructor() { | ||
this.WordTree = new libWordTree(); | ||
this.StringParser = new libStringParser(); | ||
this.ParseTree = this.WordTree.ParseTree; | ||
} | ||
/** | ||
* Precedent browser shim loader | ||
*/ | ||
/** | ||
* Add a Pattern to the Parse Tree | ||
* @method addPattern | ||
* @param {Object} pTree - A node on the parse tree to push the characters into | ||
* @param {string} pPattern - The string to add to the tree | ||
* @param {number} pIndex - callback function | ||
* @return {bool} True if adding the pattern was successful | ||
*/ | ||
addPattern(pPatternStart, pPatternEnd, pParser) { | ||
return this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser); | ||
} | ||
// Load the precedent module into the browser global automatically. | ||
var libPrecedent = require('./Precedent.js'); | ||
/** | ||
* Parse a string with the existing parse tree | ||
* @method parseString | ||
* @param {string} pString - The string to parse | ||
* @return {string} The result from the parser | ||
*/ | ||
parseString(pString) { | ||
return this.StringParser.parseString(pString, this.ParseTree); | ||
} | ||
} | ||
module.exports = Precedent; | ||
}, { | ||
"./StringParser.js": 3, | ||
"./WordTree.js": 4 | ||
}], | ||
3: [function (require, module, exports) { | ||
/** | ||
* String Parser | ||
* | ||
* @license MIT | ||
* | ||
* @author Steven Velozo <steven@velozo.com> | ||
* | ||
* @description Parse a string, properly processing each matched token in the word tree. | ||
*/ | ||
if ((typeof(window) == 'object') && (!window.hasOwnProperty('Precedent'))) | ||
{ | ||
window.Precedent = libPrecedent; | ||
} | ||
class StringParser { | ||
/** | ||
* StringParser Constructor | ||
*/ | ||
constructor() {} | ||
module.exports = libPrecedent; | ||
},{"./Precedent.js":2}],2:[function(require,module,exports){ | ||
/** | ||
* Precedent Meta-Templating | ||
* | ||
* @license MIT | ||
* | ||
* @author Steven Velozo <steven@velozo.com> | ||
* | ||
* @description Process text streams, parsing out meta-template expressions. | ||
*/ | ||
var libWordTree = require(`./WordTree.js`); | ||
var libStringParser = require(`./StringParser.js`); | ||
/** | ||
* Create a fresh parsing state object to work with. | ||
* @method newParserState | ||
* @param {Object} pParseTree - A node on the parse tree to begin parsing from (usually root) | ||
* @return {Object} A new parser state object for running a character parser on | ||
* @private | ||
*/ | ||
newParserState(pParseTree) { | ||
return { | ||
ParseTree: pParseTree, | ||
Output: '', | ||
OutputBuffer: '', | ||
Pattern: false, | ||
PatternMatch: false, | ||
PatternMatchOutputBuffer: '' | ||
}; | ||
} | ||
class Precedent | ||
{ | ||
/** | ||
* Precedent Constructor | ||
*/ | ||
constructor() | ||
{ | ||
this.WordTree = new libWordTree(); | ||
this.StringParser = new libStringParser(); | ||
/** | ||
* Assign a node of the parser tree to be the next potential match. | ||
* If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match). | ||
* @method assignNode | ||
* @param {Object} pNode - A node on the parse tree to assign | ||
* @param {Object} pParserState - The state object for the current parsing task | ||
* @private | ||
*/ | ||
assignNode(pNode, pParserState) { | ||
pParserState.PatternMatch = pNode; | ||
this.ParseTree = this.WordTree.ParseTree; | ||
} | ||
/** | ||
* Add a Pattern to the Parse Tree | ||
* @method addPattern | ||
* @param {Object} pTree - A node on the parse tree to push the characters into | ||
* @param {string} pPattern - The string to add to the tree | ||
* @param {number} pIndex - callback function | ||
* @return {bool} True if adding the pattern was successful | ||
*/ | ||
addPattern(pPatternStart, pPatternEnd, pParser) | ||
{ | ||
return this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser); | ||
} | ||
/** | ||
* Parse a string with the existing parse tree | ||
* @method parseString | ||
* @param {string} pString - The string to parse | ||
* @return {string} The result from the parser | ||
*/ | ||
parseString(pString) | ||
{ | ||
return this.StringParser.parseString(pString, this.ParseTree); | ||
} | ||
} | ||
// If the pattern has a END we can assume it has a parse function... | ||
if (pParserState.PatternMatch.hasOwnProperty('PatternEnd')) { | ||
// ... this is the legitimate start of a pattern. | ||
pParserState.Pattern = pParserState.PatternMatch; | ||
} | ||
} | ||
module.exports = Precedent; | ||
/** | ||
* Append a character to the output buffer in the parser state. | ||
* This output buffer is used when a potential match is being explored, or a match is being explored. | ||
* @method appendOutputBuffer | ||
* @param {string} pCharacter - The character to append | ||
* @param {Object} pParserState - The state object for the current parsing task | ||
* @private | ||
*/ | ||
appendOutputBuffer(pCharacter, pParserState) { | ||
pParserState.OutputBuffer += pCharacter; | ||
} | ||
},{"./StringParser.js":3,"./WordTree.js":4}],3:[function(require,module,exports){ | ||
/** | ||
* String Parser | ||
* | ||
* @license MIT | ||
* | ||
* @author Steven Velozo <steven@velozo.com> | ||
* | ||
* @description Parse a string, properly processing each matched token in the word tree. | ||
*/ | ||
/** | ||
* Flush the output buffer to the output and clear it. | ||
* @method flushOutputBuffer | ||
* @param {Object} pParserState - The state object for the current parsing task | ||
* @private | ||
*/ | ||
flushOutputBuffer(pParserState) { | ||
pParserState.Output += pParserState.OutputBuffer; | ||
pParserState.OutputBuffer = ''; | ||
} | ||
class StringParser | ||
{ | ||
/** | ||
* StringParser Constructor | ||
*/ | ||
constructor() | ||
{ | ||
} | ||
/** | ||
* Create a fresh parsing state object to work with. | ||
* @method newParserState | ||
* @param {Object} pParseTree - A node on the parse tree to begin parsing from (usually root) | ||
* @return {Object} A new parser state object for running a character parser on | ||
* @private | ||
*/ | ||
newParserState (pParseTree) | ||
{ | ||
return ( | ||
{ | ||
ParseTree: pParseTree, | ||
/** | ||
* Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns. | ||
* @method checkPatternEnd | ||
* @param {Object} pParserState - The state object for the current parsing task | ||
* @private | ||
*/ | ||
checkPatternEnd(pParserState) { | ||
if (pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length + pParserState.Pattern.PatternStart.length && pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd) { | ||
// ... this is the end of a pattern, cut off the end tag and parse it. | ||
// Trim the start and end tags off the output buffer now | ||
pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length + pParserState.Pattern.PatternEnd.length))); | ||
// Flush the output buffer. | ||
this.flushOutputBuffer(pParserState); | ||
// End pattern mode | ||
pParserState.Pattern = false; | ||
pParserState.PatternMatch = false; | ||
} | ||
} | ||
Output: '', | ||
OutputBuffer: '', | ||
/** | ||
* Parse a character in the buffer. | ||
* @method parseCharacter | ||
* @param {string} pCharacter - The character to append | ||
* @param {Object} pParserState - The state object for the current parsing task | ||
* @private | ||
*/ | ||
parseCharacter(pCharacter, pParserState) { | ||
// (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern.... | ||
if (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter)) { | ||
// ... assign the node as the matched node. | ||
this.assignNode(pParserState.ParseTree[pCharacter], pParserState); | ||
this.appendOutputBuffer(pCharacter, pParserState); | ||
} | ||
// (2) If we are in a pattern match (actively seeing if this is part of a new pattern token) | ||
else if (pParserState.PatternMatch) { | ||
// If the pattern has a subpattern with this key | ||
if (pParserState.PatternMatch.hasOwnProperty(pCharacter)) { | ||
// Continue matching patterns. | ||
this.assignNode(pParserState.PatternMatch[pCharacter], pParserState); | ||
} | ||
this.appendOutputBuffer(pCharacter, pParserState); | ||
if (pParserState.Pattern) { | ||
// ... Check if this is the end of the pattern (if we are matching a valid pattern)... | ||
this.checkPatternEnd(pParserState); | ||
} | ||
} | ||
// (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode).... | ||
else { | ||
pParserState.Output += pCharacter; | ||
} | ||
} | ||
Pattern: false, | ||
/** | ||
* Parse a string for matches, and process any template segments that occur. | ||
* @method parseString | ||
* @param {string} pString - The string to parse. | ||
* @param {Object} pParseTree - The parse tree to begin parsing from (usually root) | ||
*/ | ||
parseString(pString, pParseTree) { | ||
let tmpParserState = this.newParserState(pParseTree); | ||
for (var i = 0; i < pString.length; i++) { | ||
// TODO: This is not fast. | ||
this.parseCharacter(pString[i], tmpParserState); | ||
} | ||
this.flushOutputBuffer(tmpParserState); | ||
return tmpParserState.Output; | ||
} | ||
} | ||
module.exports = StringParser; | ||
}, {}], | ||
4: [function (require, module, exports) { | ||
/** | ||
* Word Tree | ||
* | ||
* @license MIT | ||
* | ||
* @author Steven Velozo <steven@velozo.com> | ||
* | ||
* @description Create a tree (directed graph) of Javascript objects, one character per object. | ||
*/ | ||
PatternMatch: false, | ||
PatternMatchOutputBuffer: '' | ||
}); | ||
} | ||
/** | ||
* Assign a node of the parser tree to be the next potential match. | ||
* If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match). | ||
* @method assignNode | ||
* @param {Object} pNode - A node on the parse tree to assign | ||
* @param {Object} pParserState - The state object for the current parsing task | ||
* @private | ||
*/ | ||
assignNode (pNode, pParserState) | ||
{ | ||
pParserState.PatternMatch = pNode; | ||
class WordTree { | ||
/** | ||
* WordTree Constructor | ||
*/ | ||
constructor() { | ||
this.ParseTree = {}; | ||
} | ||
// If the pattern has a END we can assume it has a parse function... | ||
if (pParserState.PatternMatch.hasOwnProperty('PatternEnd')) | ||
{ | ||
// ... this is the legitimate start of a pattern. | ||
pParserState.Pattern = pParserState.PatternMatch; | ||
} | ||
} | ||
/** | ||
* Append a character to the output buffer in the parser state. | ||
* This output buffer is used when a potential match is being explored, or a match is being explored. | ||
* @method appendOutputBuffer | ||
* @param {string} pCharacter - The character to append | ||
* @param {Object} pParserState - The state object for the current parsing task | ||
* @private | ||
*/ | ||
appendOutputBuffer (pCharacter, pParserState) | ||
{ | ||
pParserState.OutputBuffer += pCharacter; | ||
} | ||
/** | ||
* Flush the output buffer to the output and clear it. | ||
* @method flushOutputBuffer | ||
* @param {Object} pParserState - The state object for the current parsing task | ||
* @private | ||
*/ | ||
flushOutputBuffer (pParserState) | ||
{ | ||
pParserState.Output += pParserState.OutputBuffer; | ||
pParserState.OutputBuffer = ''; | ||
} | ||
/** | ||
* Add a child character to a Parse Tree node | ||
* @method addChild | ||
* @param {Object} pTree - A parse tree to push the characters into | ||
* @param {string} pPattern - The string to add to the tree | ||
* @param {number} pIndex - callback function | ||
* @returns {Object} The resulting leaf node that was added (or found) | ||
* @private | ||
*/ | ||
addChild(pTree, pPattern, pIndex) { | ||
if (pIndex > pPattern.length) return pTree; | ||
if (!pTree.hasOwnProperty(pPattern[pIndex])) pTree[pPattern[pIndex]] = {}; | ||
return pTree[pPattern[pIndex]]; | ||
} | ||
/** | ||
* Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns. | ||
* @method checkPatternEnd | ||
* @param {Object} pParserState - The state object for the current parsing task | ||
* @private | ||
*/ | ||
checkPatternEnd (pParserState) | ||
{ | ||
if ((pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length+pParserState.Pattern.PatternStart.length) && | ||
(pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd)) | ||
{ | ||
// ... this is the end of a pattern, cut off the end tag and parse it. | ||
// Trim the start and end tags off the output buffer now | ||
pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length+pParserState.Pattern.PatternEnd.length))); | ||
// Flush the output buffer. | ||
this.flushOutputBuffer(pParserState); | ||
// End pattern mode | ||
pParserState.Pattern = false; | ||
pParserState.PatternMatch = false; | ||
} | ||
} | ||
/** | ||
* Parse a character in the buffer. | ||
* @method parseCharacter | ||
* @param {string} pCharacter - The character to append | ||
* @param {Object} pParserState - The state object for the current parsing task | ||
* @private | ||
*/ | ||
parseCharacter (pCharacter, pParserState) | ||
{ | ||
// (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern.... | ||
if (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter)) | ||
{ | ||
// ... assign the node as the matched node. | ||
this.assignNode(pParserState.ParseTree[pCharacter], pParserState); | ||
this.appendOutputBuffer(pCharacter, pParserState); | ||
} | ||
// (2) If we are in a pattern match (actively seeing if this is part of a new pattern token) | ||
else if (pParserState.PatternMatch) | ||
{ | ||
// If the pattern has a subpattern with this key | ||
if (pParserState.PatternMatch.hasOwnProperty(pCharacter)) | ||
{ | ||
// Continue matching patterns. | ||
this.assignNode(pParserState.PatternMatch[pCharacter], pParserState); | ||
} | ||
this.appendOutputBuffer(pCharacter, pParserState); | ||
if (pParserState.Pattern) | ||
{ | ||
// ... Check if this is the end of the pattern (if we are matching a valid pattern)... | ||
this.checkPatternEnd(pParserState); | ||
} | ||
} | ||
// (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode).... | ||
else | ||
{ | ||
pParserState.Output += pCharacter; | ||
} | ||
} | ||
/** | ||
* Parse a string for matches, and process any template segments that occur. | ||
* @method parseString | ||
* @param {string} pString - The string to parse. | ||
* @param {Object} pParseTree - The parse tree to begin parsing from (usually root) | ||
*/ | ||
parseString (pString, pParseTree) | ||
{ | ||
let tmpParserState = this.newParserState(pParseTree); | ||
/** Add a Pattern to the Parse Tree | ||
* @method addPattern | ||
* @param {Object} pTree - A node on the parse tree to push the characters into | ||
* @param {string} pPattern - The string to add to the tree | ||
* @param {number} pIndex - callback function | ||
* @return {bool} True if adding the pattern was successful | ||
*/ | ||
addPattern(pPatternStart, pPatternEnd, pParser) { | ||
if (pPatternStart.length < 1) return false; | ||
let tmpLeaf = this.ParseTree; | ||
for (var i = 0; i < pString.length; i++) | ||
{ | ||
// TODO: This is not fast. | ||
this.parseCharacter(pString[i], tmpParserState); | ||
} | ||
this.flushOutputBuffer(tmpParserState); | ||
return tmpParserState.Output; | ||
} | ||
} | ||
module.exports = StringParser; | ||
},{}],4:[function(require,module,exports){ | ||
/** | ||
* Word Tree | ||
* | ||
* @license MIT | ||
* | ||
* @author Steven Velozo <steven@velozo.com> | ||
* | ||
* @description Create a tree (directed graph) of Javascript objects, one character per object. | ||
*/ | ||
class WordTree | ||
{ | ||
/** | ||
* WordTree Constructor | ||
*/ | ||
constructor() | ||
{ | ||
this.ParseTree = {}; | ||
} | ||
/** | ||
* Add a child character to a Parse Tree node | ||
* @method addChild | ||
* @param {Object} pTree - A parse tree to push the characters into | ||
* @param {string} pPattern - The string to add to the tree | ||
* @param {number} pIndex - callback function | ||
* @returns {Object} The resulting leaf node that was added (or found) | ||
* @private | ||
*/ | ||
addChild (pTree, pPattern, pIndex) | ||
{ | ||
if (pIndex > pPattern.length) | ||
return pTree; | ||
if (!pTree.hasOwnProperty(pPattern[pIndex])) | ||
pTree[pPattern[pIndex]] = {}; | ||
return pTree[pPattern[pIndex]]; | ||
} | ||
/** Add a Pattern to the Parse Tree | ||
* @method addPattern | ||
* @param {Object} pTree - A node on the parse tree to push the characters into | ||
* @param {string} pPattern - The string to add to the tree | ||
* @param {number} pIndex - callback function | ||
* @return {bool} True if adding the pattern was successful | ||
*/ | ||
addPattern (pPatternStart, pPatternEnd, pParser) | ||
{ | ||
if (pPatternStart.length < 1) | ||
return false; | ||
let tmpLeaf = this.ParseTree; | ||
// Add the tree of leaves iteratively | ||
for (var i = 0; i < pPatternStart.length; i++) | ||
tmpLeaf = this.addChild(tmpLeaf, pPatternStart, i); | ||
tmpLeaf.PatternStart = pPatternStart; | ||
tmpLeaf.PatternEnd = ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length > 0)) ? pPatternEnd : pPatternStart; | ||
tmpLeaf.Parse = (typeof(pParser) === 'function') ? pParser : | ||
(typeof(pParser) === 'string') ? () => { return pParser; } : | ||
(pData) => { return pData; }; | ||
return true; | ||
} | ||
} | ||
module.exports = WordTree; | ||
},{}]},{},[1])(1) | ||
}); | ||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzb3VyY2UvUHJlY2VkZW50LUJyb3dzZXItU2hpbS5qcyIsInNvdXJjZS9QcmVjZWRlbnQuanMiLCJzb3VyY2UvU3RyaW5nUGFyc2VyLmpzIiwic291cmNlL1dvcmRUcmVlLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uKCl7ZnVuY3Rpb24gcihlLG4sdCl7ZnVuY3Rpb24gbyhpLGYpe2lmKCFuW2ldKXtpZighZVtpXSl7dmFyIGM9XCJmdW5jdGlvblwiPT10eXBlb2YgcmVxdWlyZSYmcmVxdWlyZTtpZighZiYmYylyZXR1cm4gYyhpLCEwKTtpZih1KXJldHVybiB1KGksITApO3ZhciBhPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIraStcIidcIik7dGhyb3cgYS5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGF9dmFyIHA9bltpXT17ZXhwb3J0czp7fX07ZVtpXVswXS5jYWxsKHAuZXhwb3J0cyxmdW5jdGlvbihyKXt2YXIgbj1lW2ldWzFdW3JdO3JldHVybiBvKG58fHIpfSxwLHAuZXhwb3J0cyxyLGUsbix0KX1yZXR1cm4gbltpXS5leHBvcnRzfWZvcih2YXIgdT1cImZ1bmN0aW9uXCI9PXR5cGVvZiByZXF1aXJlJiZyZXF1aXJlLGk9MDtpPHQubGVuZ3RoO2krKylvKHRbaV0pO3JldHVybiBvfXJldHVybiByfSkoKSIsIi8qKlxuKiBAbGljZW5zZSBNSVRcbiogQGF1dGhvciA8c3RldmVuQHZlbG96by5jb20+XG4qL1xuXG4vKipcbiogUHJlY2VkZW50IGJyb3dzZXIgc2hpbSBsb2FkZXJcbiovXG5cbi8vIExvYWQgdGhlIHByZWNlZGVudCBtb2R1bGUgaW50byB0aGUgYnJvd3NlciBnbG9iYWwgYXV0b21hdGljYWxseS5cbnZhciBsaWJQcmVjZWRlbnQgPSByZXF1aXJlKCcuL1ByZWNlZGVudC5qcycpO1xuXG5pZiAoKHR5cGVvZih3aW5kb3cpID09ICdvYmplY3QnKSAmJiAoIXdpbmRvdy5oYXNPd25Qcm9wZXJ0eSgnUHJlY2VkZW50JykpKVxue1xuXHR3aW5kb3cuUHJlY2VkZW50ID0gbGliUHJlY2VkZW50O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGxpYlByZWNlZGVudDsiLCIvKipcbiogUHJlY2VkZW50IE1ldGEtVGVtcGxhdGluZ1xuKlxuKiBAbGljZW5zZSAgICAgTUlUXG4qXG4qIEBhdXRob3IgICAgICBTdGV2ZW4gVmVsb3pvIDxzdGV2ZW5AdmVsb3pvLmNvbT5cbipcbiogQGRlc2NyaXB0aW9uIFByb2Nlc3MgdGV4dCBzdHJlYW1zLCBwYXJzaW5nIG91dCBtZXRhLXRlbXBsYXRlIGV4cHJlc3Npb25zLlxuKi9cbnZhciBsaWJXb3JkVHJlZSA9IHJlcXVpcmUoYC4vV29yZFRyZWUuanNgKTtcbnZhciBsaWJTdHJpbmdQYXJzZXIgPSByZXF1aXJlKGAuL1N0cmluZ1BhcnNlci5qc2ApO1xuXG5jbGFzcyBQcmVjZWRlbnRcbntcblx0LyoqXG5cdCAqIFByZWNlZGVudCBDb25zdHJ1Y3RvclxuXHQgKi9cblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cdFx0dGhpcy5Xb3JkVHJlZSA9IG5ldyBsaWJXb3JkVHJlZSgpO1xuXHRcdFxuXHRcdHRoaXMuU3RyaW5nUGFyc2VyID0gbmV3IGxpYlN0cmluZ1BhcnNlcigpO1xuXG5cdFx0dGhpcy5QYXJzZVRyZWUgPSB0aGlzLldvcmRUcmVlLlBhcnNlVHJlZTtcblx0fVxuXHRcblx0LyoqXG5cdCAqIEFkZCBhIFBhdHRlcm4gdG8gdGhlIFBhcnNlIFRyZWVcblx0ICogQG1ldGhvZCBhZGRQYXR0ZXJuXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBwVHJlZSAtIEEgbm9kZSBvbiB0aGUgcGFyc2UgdHJlZSB0byBwdXNoIHRoZSBjaGFyYWN0ZXJzIGludG9cblx0ICogQHBhcmFtIHtzdHJpbmd9IHBQYXR0ZXJuIC0gVGhlIHN0cmluZyB0byBhZGQgdG8gdGhlIHRyZWVcblx0ICogQHBhcmFtIHtudW1iZXJ9IHBJbmRleCAtIGNhbGxiYWNrIGZ1bmN0aW9uXG5cdCAqIEByZXR1cm4ge2Jvb2x9IFRydWUgaWYgYWRkaW5nIHRoZSBwYXR0ZXJuIHdhcyBzdWNjZXNzZnVsXG5cdCAqL1xuXHRhZGRQYXR0ZXJuKHBQYXR0ZXJuU3RhcnQsIHBQYXR0ZXJuRW5kLCBwUGFyc2VyKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuV29yZFRyZWUuYWRkUGF0dGVybihwUGF0dGVyblN0YXJ0LCBwUGF0dGVybkVuZCwgcFBhcnNlcik7XG5cdH1cblx0XG5cdC8qKlxuXHQgKiBQYXJzZSBhIHN0cmluZyB3aXRoIHRoZSBleGlzdGluZyBwYXJzZSB0cmVlXG5cdCAqIEBtZXRob2QgcGFyc2VTdHJpbmdcblx0ICogQHBhcmFtIHtzdHJpbmd9IHBTdHJpbmcgLSBUaGUgc3RyaW5nIHRvIHBhcnNlXG5cdCAqIEByZXR1cm4ge3N0cmluZ30gVGhlIHJlc3VsdCBmcm9tIHRoZSBwYXJzZXJcblx0ICovXG5cdHBhcnNlU3RyaW5nKHBTdHJpbmcpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5TdHJpbmdQYXJzZXIucGFyc2VTdHJpbmcocFN0cmluZywgdGhpcy5QYXJzZVRyZWUpO1xuXHR9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gUHJlY2VkZW50O1xuIiwiLyoqXG4qIFN0cmluZyBQYXJzZXJcbipcbiogQGxpY2Vuc2UgICAgIE1JVFxuKlxuKiBAYXV0aG9yICAgICAgU3RldmVuIFZlbG96byA8c3RldmVuQHZlbG96by5jb20+XG4qXG4qIEBkZXNjcmlwdGlvbiBQYXJzZSBhIHN0cmluZywgcHJvcGVybHkgcHJvY2Vzc2luZyBlYWNoIG1hdGNoZWQgdG9rZW4gaW4gdGhlIHdvcmQgdHJlZS5cbiovXG5cbmNsYXNzIFN0cmluZ1BhcnNlclxue1xuXHQvKipcblx0ICogU3RyaW5nUGFyc2VyIENvbnN0cnVjdG9yXG5cdCAqL1xuXHRjb25zdHJ1Y3RvcigpXG5cdHtcblx0fVxuXHRcblx0LyoqXG5cdCAqIENyZWF0ZSBhIGZyZXNoIHBhcnNpbmcgc3RhdGUgb2JqZWN0IHRvIHdvcmsgd2l0aC5cblx0ICogQG1ldGhvZCBuZXdQYXJzZXJTdGF0ZVxuXHQgKiBAcGFyYW0ge09iamVjdH0gcFBhcnNlVHJlZSAtIEEgbm9kZSBvbiB0aGUgcGFyc2UgdHJlZSB0byBiZWdpbiBwYXJzaW5nIGZyb20gKHVzdWFsbHkgcm9vdClcblx0ICogQHJldHVybiB7T2JqZWN0fSBBIG5ldyBwYXJzZXIgc3RhdGUgb2JqZWN0IGZvciBydW5uaW5nIGEgY2hhcmFjdGVyIHBhcnNlciBvblxuXHQgKiBAcHJpdmF0ZVxuXHQgKi9cblx0bmV3UGFyc2VyU3RhdGUgKHBQYXJzZVRyZWUpXG5cdHtcblx0XHRyZXR1cm4gKFxuXHRcdHtcblx0XHQgICAgUGFyc2VUcmVlOiBwUGFyc2VUcmVlLFxuXG5cdFx0XHRPdXRwdXQ6ICcnLFxuXHRcdFx0T3V0cHV0QnVmZmVyOiAnJyxcblxuXHRcdFx0UGF0dGVybjogZmFsc2UsXG5cblx0XHRcdFBhdHRlcm5NYXRjaDogZmFsc2UsXG5cdFx0XHRQYXR0ZXJuTWF0Y2hPdXRwdXRCdWZmZXI6ICcnXG5cdFx0fSk7XG5cdH1cblx0XHRcblx0LyoqXG5cdCAqIEFzc2lnbiBhIG5vZGUgb2YgdGhlIHBhcnNlciB0cmVlIHRvIGJlIHRoZSBuZXh0IHBvdGVudGlhbCBtYXRjaC5cblx0ICogSWYgdGhlIG5vZGUgaGFzIGEgUGF0dGVybkVuZCBwcm9wZXJ0eSwgaXQgaXMgYSB2YWxpZCBtYXRjaCBhbmQgc3VwZXJjZWRlcyB0aGUgbGFzdCB2YWxpZCBtYXRjaCAob3IgYmVjb21lcyB0aGUgaW5pdGlhbCBtYXRjaCkuXG5cdCAqIEBtZXRob2QgYXNzaWduTm9kZVxuXHQgKiBAcGFyYW0ge09iamVjdH0gcE5vZGUgLSBBIG5vZGUgb24gdGhlIHBhcnNlIHRyZWUgdG8gYXNzaWduXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBwUGFyc2VyU3RhdGUgLSBUaGUgc3RhdGUgb2JqZWN0IGZvciB0aGUgY3VycmVudCBwYXJzaW5nIHRhc2tcblx0ICogQHByaXZhdGVcblx0ICovXG5cdGFzc2lnbk5vZGUgKHBOb2RlLCBwUGFyc2VyU3RhdGUpXG5cdHtcblx0XHRwUGFyc2VyU3RhdGUuUGF0dGVybk1hdGNoID0gcE5vZGU7XG5cblx0XHQvLyBJZiB0aGUgcGF0dGVybiBoYXMgYSBFTkQgd2UgY2FuIGFzc3VtZSBpdCBoYXMgYSBwYXJzZSBmdW5jdGlvbi4uLlxuXHRcdGlmIChwUGFyc2VyU3RhdGUuUGF0dGVybk1hdGNoLmhhc093blByb3BlcnR5KCdQYXR0ZXJuRW5kJykpXG5cdFx0e1xuXHRcdFx0Ly8gLi4uIHRoaXMgaXMgdGhlIGxlZ2l0aW1hdGUgc3RhcnQgb2YgYSBwYXR0ZXJuLlxuXHRcdFx0cFBhcnNlclN0YXRlLlBhdHRlcm4gPSBwUGFyc2VyU3RhdGUuUGF0dGVybk1hdGNoO1xuXHRcdH1cblx0fVxuXHRcblx0LyoqXG5cdCAqIEFwcGVuZCBhIGNoYXJhY3RlciB0byB0aGUgb3V0cHV0IGJ1ZmZlciBpbiB0aGUgcGFyc2VyIHN0YXRlLlxuXHQgKiBUaGlzIG91dHB1dCBidWZmZXIgaXMgdXNlZCB3aGVuIGEgcG90ZW50aWFsIG1hdGNoIGlzIGJlaW5nIGV4cGxvcmVkLCBvciBhIG1hdGNoIGlzIGJlaW5nIGV4cGxvcmVkLlxuXHQgKiBAbWV0aG9kIGFwcGVuZE91dHB1dEJ1ZmZlclxuXHQgKiBAcGFyYW0ge3N0cmluZ30gcENoYXJhY3RlciAtIFRoZSBjaGFyYWN0ZXIgdG8gYXBwZW5kXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBwUGFyc2VyU3RhdGUgLSBUaGUgc3RhdGUgb2JqZWN0IGZvciB0aGUgY3VycmVudCBwYXJzaW5nIHRhc2tcblx0ICogQHByaXZhdGVcblx0ICovXG5cdGFwcGVuZE91dHB1dEJ1ZmZlciAocENoYXJhY3RlciwgcFBhcnNlclN0YXRlKVxuXHR7XG5cdFx0cFBhcnNlclN0YXRlLk91dHB1dEJ1ZmZlciArPSBwQ2hhcmFjdGVyO1xuXHR9XG5cdFxuXHQvKipcblx0ICogRmx1c2ggdGhlIG91dHB1dCBidWZmZXIgdG8gdGhlIG91dHB1dCBhbmQgY2xlYXIgaXQuXG5cdCAqIEBtZXRob2QgZmx1c2hPdXRwdXRCdWZmZXJcblx0ICogQHBhcmFtIHtPYmplY3R9IHBQYXJzZXJTdGF0ZSAtIFRoZSBzdGF0ZSBvYmplY3QgZm9yIHRoZSBjdXJyZW50IHBhcnNpbmcgdGFza1xuXHQgKiBAcHJpdmF0ZVxuXHQgKi9cblx0Zmx1c2hPdXRwdXRCdWZmZXIgKHBQYXJzZXJTdGF0ZSlcblx0e1xuXHRcdHBQYXJzZXJTdGF0ZS5PdXRwdXQgKz0gcFBhcnNlclN0YXRlLk91dHB1dEJ1ZmZlcjtcblx0XHRwUGFyc2VyU3RhdGUuT3V0cHV0QnVmZmVyID0gJyc7XG5cdH1cblxuXHRcblx0LyoqXG5cdCAqIENoZWNrIGlmIHRoZSBwYXR0ZXJuIGhhcyBlbmRlZC4gIElmIGl0IGhhcywgcHJvcGVybHkgZmx1c2ggdGhlIGJ1ZmZlciBhbmQgc3RhcnQgbG9va2luZyBmb3IgbmV3IHBhdHRlcm5zLlxuXHQgKiBAbWV0aG9kIGNoZWNrUGF0dGVybkVuZFxuXHQgKiBAcGFyYW0ge09iamVjdH0gcFBhcnNlclN0YXRlIC0gVGhlIHN0YXRlIG9iamVjdCBmb3IgdGhlIGN1cnJlbnQgcGFyc2luZyB0YXNrXG5cdCAqIEBwcml2YXRlXG5cdCAqL1xuXHRjaGVja1BhdHRlcm5FbmQgKHBQYXJzZXJTdGF0ZSlcblx0e1xuXHRcdGlmICgocFBhcnNlclN0YXRlLk91dHB1dEJ1ZmZlci5sZW5ndGggPj0gcFBhcnNlclN0YXRlLlBhdHRlcm4uUGF0dGVybkVuZC5sZW5ndGgrcFBhcnNlclN0YXRlLlBhdHRlcm4uUGF0dGVyblN0YXJ0Lmxlbmd0aCkgJiYgXG5cdFx0XHQocFBhcnNlclN0YXRlLk91dHB1dEJ1ZmZlci5zdWJzdHIoLXBQYXJzZXJTdGF0ZS5QYXR0ZXJuLlBhdHRlcm5FbmQubGVuZ3RoKSA9PT0gcFBhcnNlclN0YXRlLlBhdHRlcm4uUGF0dGVybkVuZCkpXG5cdFx0e1xuXHRcdFx0Ly8gLi4uIHRoaXMgaXMgdGhlIGVuZCBvZiBhIHBhdHRlcm4sIGN1dCBvZmYgdGhlIGVuZCB0YWcgYW5kIHBhcnNlIGl0LlxuXHRcdFx0Ly8gVHJpbSB0aGUgc3RhcnQgYW5kIGVuZCB0YWdzIG9mZiB0aGUgb3V0cHV0IGJ1ZmZlciBub3dcblx0XHRcdHBQYXJzZXJTdGF0ZS5PdXRwdXRCdWZmZXIgPSBwUGFyc2VyU3RhdGUuUGF0dGVybi5QYXJzZShwUGFyc2VyU3RhdGUuT3V0cHV0QnVmZmVyLnN1YnN0cihwUGFyc2VyU3RhdGUuUGF0dGVybi5QYXR0ZXJuU3RhcnQubGVuZ3RoLCBwUGFyc2VyU3RhdGUuT3V0cHV0QnVmZmVyLmxlbmd0aCAtIChwUGFyc2VyU3RhdGUuUGF0dGVybi5QYXR0ZXJuU3RhcnQubGVuZ3RoK3BQYXJzZXJTdGF0ZS5QYXR0ZXJuLlBhdHRlcm5FbmQubGVuZ3RoKSkpO1xuXHRcdFx0Ly8gRmx1c2ggdGhlIG91dHB1dCBidWZmZXIuXG5cdFx0XHR0aGlzLmZsdXNoT3V0cHV0QnVmZmVyKHBQYXJzZXJTdGF0ZSk7XG5cdFx0XHQvLyBFbmQgcGF0dGVybiBtb2RlXG5cdFx0XHRwUGFyc2VyU3RhdGUuUGF0dGVybiA9IGZhbHNlO1xuXHRcdFx0cFBhcnNlclN0YXRlLlBhdHRlcm5NYXRjaCA9IGZhbHNlO1xuXHRcdH1cblx0fVxuXHRcblx0LyoqXG5cdCAqIFBhcnNlIGEgY2hhcmFjdGVyIGluIHRoZSBidWZmZXIuXG5cdCAqIEBtZXRob2QgcGFyc2VDaGFyYWN0ZXJcblx0ICogQHBhcmFtIHtzdHJpbmd9IHBDaGFyYWN0ZXIgLSBUaGUgY2hhcmFjdGVyIHRvIGFwcGVuZFxuXHQgKiBAcGFyYW0ge09iamVjdH0gcFBhcnNlclN0YXRlIC0gVGhlIHN0YXRlIG9iamVjdCBmb3IgdGhlIGN1cnJlbnQgcGFyc2luZyB0YXNrXG5cdCAqIEBwcml2YXRlXG5cdCAqL1xuXHRwYXJzZUNoYXJhY3RlciAocENoYXJhY3RlciwgcFBhcnNlclN0YXRlKVxuXHR7XG5cdFx0Ly8gKDEpIElmIHdlIGFyZW4ndCBpbiBhIHBhdHRlcm4gbWF0Y2gsIGFuZCB3ZSBhcmVuJ3QgcG90ZW50aWFsbHkgbWF0Y2hpbmcsIGFuZCB0aGlzIG1heSBiZSB0aGUgc3RhcnQgb2YgYSBuZXcgcGF0dGVybi4uLi5cblx0XHRpZiAoIXBQYXJzZXJTdGF0ZS5QYXR0ZXJuTWF0Y2ggJiYgcFBhcnNlclN0YXRlLlBhcnNlVHJlZS5oYXNPd25Qcm9wZXJ0eShwQ2hhcmFjdGVyKSlcblx0XHR7XG5cdFx0XHQvLyAuLi4gYXNzaWduIHRoZSBub2RlIGFzIHRoZSBtYXRjaGVkIG5vZGUuXG5cdFx0XHR0aGlzLmFzc2lnbk5vZGUocFBhcnNlclN0YXRlLlBhcnNlVHJlZVtwQ2hhcmFjdGVyXSwgcFBhcnNlclN0YXRlKTtcblx0XHRcdHRoaXMuYXBwZW5kT3V0cHV0QnVmZmVyKHBDaGFyYWN0ZXIsIHBQYXJzZXJTdGF0ZSk7XG5cdFx0fVxuXHRcdC8vICgyKSBJZiB3ZSBhcmUgaW4gYSBwYXR0ZXJuIG1hdGNoIChhY3RpdmVseSBzZWVpbmcgaWYgdGhpcyBpcyBwYXJ0IG9mIGEgbmV3IHBhdHRlcm4gdG9rZW4pXG5cdFx0ZWxzZSBpZiAocFBhcnNlclN0YXRlLlBhdHRlcm5NYXRjaClcblx0XHR7XG5cdFx0XHQvLyBJZiB0aGUgcGF0dGVybiBoYXMgYSBzdWJwYXR0ZXJuIHdpdGggdGhpcyBrZXlcblx0XHRcdGlmIChwUGFyc2VyU3RhdGUuUGF0dGVybk1hdGNoLmhhc093blByb3BlcnR5KHBDaGFyYWN0ZXIpKVxuXHRcdFx0e1xuXHRcdFx0XHQvLyBDb250aW51ZSBtYXRjaGluZyBwYXR0ZXJucy5cblx0XHRcdFx0dGhpcy5hc3NpZ25Ob2RlKHBQYXJzZXJTdGF0ZS5QYXR0ZXJuTWF0Y2hbcENoYXJhY3Rlcl0sIHBQYXJzZXJTdGF0ZSk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLmFwcGVuZE91dHB1dEJ1ZmZlcihwQ2hhcmFjdGVyLCBwUGFyc2VyU3RhdGUpO1xuXHRcdFx0aWYgKHBQYXJzZXJTdGF0ZS5QYXR0ZXJuKVxuXHRcdFx0e1xuXHRcdFx0XHQvLyAuLi4gQ2hlY2sgaWYgdGhpcyBpcyB0aGUgZW5kIG9mIHRoZSBwYXR0ZXJuIChpZiB3ZSBhcmUgbWF0Y2hpbmcgYSB2YWxpZCBwYXR0ZXJuKS4uLlxuXHRcdFx0XHR0aGlzLmNoZWNrUGF0dGVybkVuZChwUGFyc2VyU3RhdGUpO1xuXHRcdFx0fVxuXHRcdH1cblx0XHQvLyAoMykgSWYgd2UgYXJlbid0IGluIGEgcGF0dGVybiBtYXRjaCBvciBwYXR0ZXJuLCBhbmQgdGhpcyBpc24ndCB0aGUgc3RhcnQgb2YgYSBuZXcgcGF0dGVybiAoUkFXIG1vZGUpLi4uLlxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHRwUGFyc2VyU3RhdGUuT3V0cHV0ICs9IHBDaGFyYWN0ZXI7XG5cdFx0fVxuXHR9XG5cdFxuXHQvKipcblx0ICogUGFyc2UgYSBzdHJpbmcgZm9yIG1hdGNoZXMsIGFuZCBwcm9jZXNzIGFueSB0ZW1wbGF0ZSBzZWdtZW50cyB0aGF0IG9jY3VyLlxuXHQgKiBAbWV0aG9kIHBhcnNlU3RyaW5nXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBwU3RyaW5nIC0gVGhlIHN0cmluZyB0byBwYXJzZS5cblx0ICogQHBhcmFtIHtPYmplY3R9IHBQYXJzZVRyZWUgLSBUaGUgcGFyc2UgdHJlZSB0byBiZWdpbiBwYXJzaW5nIGZyb20gKHVzdWFsbHkgcm9vdClcblx0ICovXG5cdHBhcnNlU3RyaW5nIChwU3RyaW5nLCBwUGFyc2VUcmVlKVxuXHR7XG5cdFx0bGV0IHRtcFBhcnNlclN0YXRlID0gdGhpcy5uZXdQYXJzZXJTdGF0ZShwUGFyc2VUcmVlKTtcblxuXHRcdGZvciAodmFyIGkgPSAwOyBpIDwgcFN0cmluZy5sZW5ndGg7IGkrKylcblx0XHR7XG5cdFx0XHQvLyBUT0RPOiBUaGlzIGlzIG5vdCBmYXN0LlxuXHRcdFx0dGhpcy5wYXJzZUNoYXJhY3RlcihwU3RyaW5nW2ldLCB0bXBQYXJzZXJTdGF0ZSk7XG5cdFx0fVxuXHRcdFxuXHRcdHRoaXMuZmx1c2hPdXRwdXRCdWZmZXIodG1wUGFyc2VyU3RhdGUpO1xuXHRcdFxuXHRcdHJldHVybiB0bXBQYXJzZXJTdGF0ZS5PdXRwdXQ7XG5cdH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBTdHJpbmdQYXJzZXI7XG4iLCIvKipcbiogV29yZCBUcmVlXG4qXG4qIEBsaWNlbnNlICAgICBNSVRcbipcbiogQGF1dGhvciAgICAgIFN0ZXZlbiBWZWxvem8gPHN0ZXZlbkB2ZWxvem8uY29tPlxuKlxuKiBAZGVzY3JpcHRpb24gQ3JlYXRlIGEgdHJlZSAoZGlyZWN0ZWQgZ3JhcGgpIG9mIEphdmFzY3JpcHQgb2JqZWN0cywgb25lIGNoYXJhY3RlciBwZXIgb2JqZWN0LlxuKi9cblxuY2xhc3MgV29yZFRyZWVcbntcblx0LyoqXG5cdCAqIFdvcmRUcmVlIENvbnN0cnVjdG9yXG5cdCAqL1xuXHRjb25zdHJ1Y3RvcigpXG5cdHtcblx0XHR0aGlzLlBhcnNlVHJlZSA9IHt9O1xuXHR9XG5cdFxuXHQvKiogXG5cdCAqIEFkZCBhIGNoaWxkIGNoYXJhY3RlciB0byBhIFBhcnNlIFRyZWUgbm9kZVxuXHQgKiBAbWV0aG9kIGFkZENoaWxkXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBwVHJlZSAtIEEgcGFyc2UgdHJlZSB0byBwdXNoIHRoZSBjaGFyYWN0ZXJzIGludG9cblx0ICogQHBhcmFtIHtzdHJpbmd9IHBQYXR0ZXJuIC0gVGhlIHN0cmluZyB0byBhZGQgdG8gdGhlIHRyZWVcblx0ICogQHBhcmFtIHtudW1iZXJ9IHBJbmRleCAtIGNhbGxiYWNrIGZ1bmN0aW9uXG5cdCAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSByZXN1bHRpbmcgbGVhZiBub2RlIHRoYXQgd2FzIGFkZGVkIChvciBmb3VuZClcblx0ICogQHByaXZhdGVcblx0ICovXG5cdGFkZENoaWxkIChwVHJlZSwgcFBhdHRlcm4sIHBJbmRleClcblx0e1xuXHRcdGlmIChwSW5kZXggPiBwUGF0dGVybi5sZW5ndGgpXG5cdFx0XHRyZXR1cm4gcFRyZWU7XG5cdFx0XG5cdFx0aWYgKCFwVHJlZS5oYXNPd25Qcm9wZXJ0eShwUGF0dGVybltwSW5kZXhdKSlcblx0XHRcdHBUcmVlW3BQYXR0ZXJuW3BJbmRleF1dID0ge307XG5cdFx0XG5cdFx0cmV0dXJuIHBUcmVlW3BQYXR0ZXJuW3BJbmRleF1dO1xuXHR9XG5cdFxuXHQvKiogQWRkIGEgUGF0dGVybiB0byB0aGUgUGFyc2UgVHJlZVxuXHQgKiBAbWV0aG9kIGFkZFBhdHRlcm5cblx0ICogQHBhcmFtIHtPYmplY3R9IHBUcmVlIC0gQSBub2RlIG9uIHRoZSBwYXJzZSB0cmVlIHRvIHB1c2ggdGhlIGNoYXJhY3RlcnMgaW50b1xuXHQgKiBAcGFyYW0ge3N0cmluZ30gcFBhdHRlcm4gLSBUaGUgc3RyaW5nIHRvIGFkZCB0byB0aGUgdHJlZVxuXHQgKiBAcGFyYW0ge251bWJlcn0gcEluZGV4IC0gY2FsbGJhY2sgZnVuY3Rpb25cblx0ICogQHJldHVybiB7Ym9vbH0gVHJ1ZSBpZiBhZGRpbmcgdGhlIHBhdHRlcm4gd2FzIHN1Y2Nlc3NmdWxcblx0ICovXG5cdGFkZFBhdHRlcm4gKHBQYXR0ZXJuU3RhcnQsIHBQYXR0ZXJuRW5kLCBwUGFyc2VyKVxuXHR7XG5cdFx0aWYgKHBQYXR0ZXJuU3RhcnQubGVuZ3RoIDwgMSlcblx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdGxldCB0bXBMZWFmID0gdGhpcy5QYXJzZVRyZWU7XG5cblx0XHQvLyBBZGQgdGhlIHRyZWUgb2YgbGVhdmVzIGl0ZXJhdGl2ZWx5XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBwUGF0dGVyblN0YXJ0Lmxlbmd0aDsgaSsrKVxuXHRcdFx0dG1wTGVhZiA9IHRoaXMuYWRkQ2hpbGQodG1wTGVhZiwgcFBhdHRlcm5TdGFydCwgaSk7XG5cblx0XHR0bXBMZWFmLlBhdHRlcm5TdGFydCA9IHBQYXR0ZXJuU3RhcnQ7XG5cdFx0dG1wTGVhZi5QYXR0ZXJuRW5kID0gKCh0eXBlb2YocFBhdHRlcm5FbmQpID09PSAnc3RyaW5nJykgJiYgKHBQYXR0ZXJuRW5kLmxlbmd0aCA+IDApKSA/IHBQYXR0ZXJuRW5kIDogcFBhdHRlcm5TdGFydDtcblx0XHR0bXBMZWFmLlBhcnNlID0gKHR5cGVvZihwUGFyc2VyKSA9PT0gJ2Z1bmN0aW9uJykgPyBwUGFyc2VyIDogXG5cdFx0XHRcdFx0XHQodHlwZW9mKHBQYXJzZXIpID09PSAnc3RyaW5nJykgPyAoKSA9PiB7IHJldHVybiBwUGFyc2VyOyB9IDpcblx0XHRcdFx0XHRcdChwRGF0YSkgPT4geyByZXR1cm4gcERhdGE7IH07XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFdvcmRUcmVlO1xuIl19 | ||
// Add the tree of leaves iteratively | ||
for (var i = 0; i < pPatternStart.length; i++) tmpLeaf = this.addChild(tmpLeaf, pPatternStart, i); | ||
tmpLeaf.PatternStart = pPatternStart; | ||
tmpLeaf.PatternEnd = typeof pPatternEnd === 'string' && pPatternEnd.length > 0 ? pPatternEnd : pPatternStart; | ||
tmpLeaf.Parse = typeof pParser === 'function' ? pParser : typeof pParser === 'string' ? () => { | ||
return pParser; | ||
} : pData => { | ||
return pData; | ||
}; | ||
return true; | ||
} | ||
} | ||
module.exports = WordTree; | ||
}, {}] | ||
}, {}, [1])(1); | ||
}); |
!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).Precedent=t()}}((function(){return function t(e,r,n){function a(s,f){if(!r[s]){if(!e[s]){var o="function"==typeof require&&require;if(!f&&o)return o(s,!0);if(u)return u(s,!0);var i=new Error("Cannot find module '"+s+"'");throw i.code="MODULE_NOT_FOUND",i}var P=r[s]={exports:{}};e[s][0].call(P.exports,(function(t){return a(e[s][1][t]||t)}),P,P.exports,t,e,r,n)}return r[s].exports}for(var u="function"==typeof require&&require,s=0;s<n.length;s++)a(n[s]);return a}({1:[function(t,e,r){ | ||
/** | ||
* @license MIT | ||
* @author <steven@velozo.com> | ||
*/ | ||
* Simple browser shim loader - assign the npm module to a window global automatically | ||
* | ||
* @license MIT | ||
* @author <steven@velozo.com> | ||
*/ | ||
var n=t("./Precedent.js");"object"!=typeof window||window.hasOwnProperty("Precedent")||(window.Precedent=n),e.exports=n},{"./Precedent.js":2}],2:[function(t,e,r){ | ||
/** | ||
* Precedent Meta-Templating | ||
* | ||
* @license MIT | ||
* | ||
* @author Steven Velozo <steven@velozo.com> | ||
* | ||
* @description Process text streams, parsing out meta-template expressions. | ||
*/ | ||
* Precedent Meta-Templating | ||
* | ||
* @license MIT | ||
* | ||
* @author Steven Velozo <steven@velozo.com> | ||
* | ||
* @description Process text streams, parsing out meta-template expressions. | ||
*/ | ||
var n=t("./WordTree.js"),a=t("./StringParser.js");e.exports=class{constructor(){this.WordTree=new n,this.StringParser=new a,this.ParseTree=this.WordTree.ParseTree}addPattern(t,e,r){return this.WordTree.addPattern(t,e,r)}parseString(t){return this.StringParser.parseString(t,this.ParseTree)}}},{"./StringParser.js":3,"./WordTree.js":4}],3:[function(t,e,r){e.exports= | ||
/** | ||
* String Parser | ||
* | ||
* @license MIT | ||
* | ||
* @author Steven Velozo <steven@velozo.com> | ||
* | ||
* @description Parse a string, properly processing each matched token in the word tree. | ||
*/ | ||
* String Parser | ||
* | ||
* @license MIT | ||
* | ||
* @author Steven Velozo <steven@velozo.com> | ||
* | ||
* @description Parse a string, properly processing each matched token in the word tree. | ||
*/ | ||
class{constructor(){}newParserState(t){return{ParseTree:t,Output:"",OutputBuffer:"",Pattern:!1,PatternMatch:!1,PatternMatchOutputBuffer:""}}assignNode(t,e){e.PatternMatch=t,e.PatternMatch.hasOwnProperty("PatternEnd")&&(e.Pattern=e.PatternMatch)}appendOutputBuffer(t,e){e.OutputBuffer+=t}flushOutputBuffer(t){t.Output+=t.OutputBuffer,t.OutputBuffer=""}checkPatternEnd(t){t.OutputBuffer.length>=t.Pattern.PatternEnd.length+t.Pattern.PatternStart.length&&t.OutputBuffer.substr(-t.Pattern.PatternEnd.length)===t.Pattern.PatternEnd&&(t.OutputBuffer=t.Pattern.Parse(t.OutputBuffer.substr(t.Pattern.PatternStart.length,t.OutputBuffer.length-(t.Pattern.PatternStart.length+t.Pattern.PatternEnd.length))),this.flushOutputBuffer(t),t.Pattern=!1,t.PatternMatch=!1)}parseCharacter(t,e){!e.PatternMatch&&e.ParseTree.hasOwnProperty(t)?(this.assignNode(e.ParseTree[t],e),this.appendOutputBuffer(t,e)):e.PatternMatch?(e.PatternMatch.hasOwnProperty(t)&&this.assignNode(e.PatternMatch[t],e),this.appendOutputBuffer(t,e),e.Pattern&&this.checkPatternEnd(e)):e.Output+=t}parseString(t,e){let r=this.newParserState(e);for(var n=0;n<t.length;n++)this.parseCharacter(t[n],r);return this.flushOutputBuffer(r),r.Output}}},{}],4:[function(t,e,r){e.exports= | ||
/** | ||
* Word Tree | ||
* | ||
* @license MIT | ||
* | ||
* @author Steven Velozo <steven@velozo.com> | ||
* | ||
* @description Create a tree (directed graph) of Javascript objects, one character per object. | ||
*/ | ||
* Word Tree | ||
* | ||
* @license MIT | ||
* | ||
* @author Steven Velozo <steven@velozo.com> | ||
* | ||
* @description Create a tree (directed graph) of Javascript objects, one character per object. | ||
*/ | ||
class{constructor(){this.ParseTree={}}addChild(t,e,r){return r>e.length?t:(t.hasOwnProperty(e[r])||(t[e[r]]={}),t[e[r]])}addPattern(t,e,r){if(t.length<1)return!1;let n=this.ParseTree;for(var a=0;a<t.length;a++)n=this.addChild(n,t,a);return n.PatternStart=t,n.PatternEnd="string"==typeof e&&e.length>0?e:t,n.Parse="function"==typeof r?r:"string"==typeof r?()=>r:t=>t,!0}}},{}]},{},[1])(1)})); | ||
//# sourceMappingURL=precedent.min.js.map |
'use strict'; | ||
// We aren't abstracting this yet but here's the ... "Config" | ||
const _CONFIG = ( | ||
{ | ||
// The input source file that should be passed to browserify: | ||
// (if you need to auto-instantiate an object, for instance) | ||
EntrypointInputSourceFile: `${__dirname}/source/Precedent-Browser-Shim.js`, | ||
// The name of the packaged object to be passed to browserify: | ||
// (browserify sets this to global scope and window.SOMEOBJECTNAMEHERE where SOMEOBJECTNAMEHERE is the string below) | ||
LibraryObjectName: `Precedent`, | ||
// The folder to write the library files and maps out to: | ||
LibraryOutputFolder: `${__dirname}/dist/`, | ||
// The name of the unminified version of the packaged library, for easy debugging: | ||
LibraryUniminifiedFileName: `precedent.js`, | ||
// The name of the minified version of the packaged library, for production release: | ||
LibraryMinifiedFileName: `precedent.min.js` | ||
}); | ||
// ---> Boilerplate Browser Uglification and Packaging <--- \\ | ||
const libBrowserify = require('browserify'); | ||
@@ -9,10 +32,8 @@ const libGulp = require('gulp'); | ||
const libTerser = require('gulp-terser'); | ||
const libBuble = require('gulp-buble'); | ||
const libSourcemaps = require('gulp-sourcemaps'); | ||
const libGulpUtil = require('gulp-util'); | ||
const libBabel = require('gulp-babel'); | ||
const libTerser = require('gulp-terser'); | ||
// Build the module for the browser | ||
// This gulp task is taken from the gulp recipe repository: | ||
// https://github.com/gulpjs/gulp/blob/master/docs/recipes/browserify-uglify-sourcemap.md | ||
libGulp.task('minified', | ||
@@ -23,4 +44,4 @@ () => { | ||
{ | ||
entries: './source/Precedent-Browser-Shim.js', | ||
standalone: 'Precedent', | ||
entries: _CONFIG.EntrypointInputSourceFile, | ||
standalone: _CONFIG.LibraryObjectName, | ||
debug: true | ||
@@ -30,15 +51,14 @@ }); | ||
return tmpBrowserify.bundle() | ||
.pipe(libVinylSourceStream('precedent.min.js')) | ||
.pipe(libVinylSourceStream(_CONFIG.LibraryMinifiedFileName)) | ||
.pipe(libVinylBuffer()) | ||
.pipe(libSourcemaps.init({loadMaps: true})) | ||
// Add transformation tasks to the pipeline here. | ||
.pipe(libBabel()) | ||
.pipe(libTerser()) | ||
.on('error', libGulpUtil.log) | ||
.pipe(libSourcemaps.write('./')) | ||
.pipe(libGulp.dest('./dist/')); | ||
.pipe(libGulp.dest(_CONFIG.LibraryOutputFolder)); | ||
}); | ||
// Build the module for the browser | ||
// This gulp task is taken from the gulp recipe repository: | ||
// https://github.com/gulpjs/gulp/blob/master/docs/recipes/browserify-uglify-sourcemap.md | ||
libGulp.task('debug', | ||
@@ -49,4 +69,4 @@ () => { | ||
{ | ||
entries: './source/Precedent-Browser-Shim.js', | ||
standalone: 'Precedent', | ||
entries: _CONFIG.EntrypointInputSourceFile, | ||
standalone: _CONFIG.LibraryObjectName, | ||
debug: true | ||
@@ -56,6 +76,7 @@ }); | ||
return tmpBrowserify.bundle() | ||
.pipe(libVinylSourceStream('precedent.js')) | ||
.pipe(libVinylSourceStream(_CONFIG.LibraryUniminifiedFileName)) | ||
.pipe(libVinylBuffer()) | ||
.pipe(libBabel()) | ||
.on('error', libGulpUtil.log) | ||
.pipe(libGulp.dest('./dist/')); | ||
.pipe(libGulp.dest(_CONFIG.LibraryOutputFolder)); | ||
}); | ||
@@ -67,2 +88,2 @@ | ||
libGulp.series('debug', 'minified') | ||
); | ||
); |
{ | ||
"name": "precedent", | ||
"version": "1.0.7", | ||
"version": "1.0.8", | ||
"description": "Precedent Meta-Templating", | ||
@@ -11,4 +11,7 @@ "main": "source/Precedent.js", | ||
"start": "node source/Precedent.js", | ||
"coverage": "./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- -u tdd -R spec", | ||
"test": "./node_modules/mocha/bin/_mocha -u tdd -R spec" | ||
"coverage": "./node_modules/.bin/nyc --reporter=lcov --reporter=text-lcov ./node_modules/mocha/bin/_mocha -- -u tdd -R spec", | ||
"test": "./node_modules/.bin/mocha -u tdd -R spec", | ||
"docker-dev-build-image": "docker build ./ -f Dockerfile_LUXURYCode -t retold/precedent:local", | ||
"docker-dev-run": "docker run -it -d --name precedent-dev -p 127.0.0.1:12340:8080 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/precedent\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" retold/precedent:local", | ||
"build": "./node_modules/.bin/gulp build" | ||
}, | ||
@@ -27,18 +30,29 @@ "repository": { | ||
}, | ||
"mocha": { | ||
"diff": true, | ||
"extension": [ | ||
"js" | ||
], | ||
"package": "./package.json", | ||
"reporter": "spec", | ||
"slow": "75", | ||
"timeout": "5000", | ||
"ui": "tdd", | ||
"watch-files": [ | ||
"source/**/*.js", | ||
"test/**/*.js" | ||
], | ||
"watch-ignore": [ | ||
"lib/vendor" | ||
] | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.17.9", | ||
"@babel/preset-env": "^7.16.11", | ||
"@testing-library/dom": "^8.13.0", | ||
"async": "^3.2.3", | ||
"browserify": "^17.0.0", | ||
"chai": "4.3.6", | ||
"chai": "4.3.7", | ||
"gulp": "^4.0.2", | ||
"gulp-babel": "^8.0.0", | ||
"gulp-buble": "^0.9.0", | ||
"gulp-sourcemaps": "^3.0.0", | ||
"gulp-terser": "^2.1.0", | ||
"gulp-util": "^3.0.8", | ||
"jsdom": "^19.0.0", | ||
"mocha": "9.2.2", | ||
"npm-check-updates": "^12.5.9", | ||
"mocha": "10.2.0", | ||
"nyc": "^15.1.0", | ||
@@ -45,0 +59,0 @@ "vinyl-buffer": "^1.0.1", |
/** | ||
* Simple browser shim loader - assign the npm module to a window global automatically | ||
* | ||
* @license MIT | ||
* @author <steven@velozo.com> | ||
*/ | ||
var libNPMModuleWrapper = require('./Precedent.js'); | ||
/** | ||
* Precedent browser shim loader | ||
*/ | ||
// Load the precedent module into the browser global automatically. | ||
var libPrecedent = require('./Precedent.js'); | ||
if ((typeof(window) == 'object') && (!window.hasOwnProperty('Precedent'))) | ||
{ | ||
window.Precedent = libPrecedent; | ||
window.Precedent = libNPMModuleWrapper; | ||
} | ||
module.exports = libPrecedent; | ||
module.exports = libNPMModuleWrapper; |
@@ -31,3 +31,3 @@ /** | ||
{ | ||
ParseTree: pParseTree, | ||
ParseTree: pParseTree, | ||
@@ -34,0 +34,0 @@ Output: '', |
@@ -26,3 +26,3 @@ /** | ||
* @param {string} pPattern - The string to add to the tree | ||
* @param {number} pIndex - callback function | ||
* @param {number} pIndex - The index of the character in the pattern | ||
* @returns {Object} The resulting leaf node that was added (or found) | ||
@@ -33,5 +33,2 @@ * @private | ||
{ | ||
if (pIndex > pPattern.length) | ||
return pTree; | ||
if (!pTree.hasOwnProperty(pPattern[pIndex])) | ||
@@ -45,5 +42,5 @@ pTree[pPattern[pIndex]] = {}; | ||
* @method addPattern | ||
* @param {Object} pTree - A node on the parse tree to push the characters into | ||
* @param {string} pPattern - The string to add to the tree | ||
* @param {number} pIndex - callback function | ||
* @param {Object} pPatternStart - The starting string for the pattern (e.g. "${") | ||
* @param {string} pPatternEnd - The ending string for the pattern (e.g. "}") | ||
* @param {number} pParser - The function to parse if this is the matched pattern, once the Pattern End is met. If this is a string, a simple replacement occurs. | ||
* @return {bool} True if adding the pattern was successful | ||
@@ -56,2 +53,5 @@ */ | ||
if ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length < 1)) | ||
return false; | ||
let tmpLeaf = this.ParseTree; | ||
@@ -58,0 +58,0 @@ |
@@ -125,2 +125,24 @@ /** | ||
( | ||
'Bad pattern start parameter...', | ||
(fDone) => | ||
{ | ||
var testPrecedent = loadPrecedentModule(); | ||
configPrecedent(testPrecedent); | ||
Expect(testPrecedent.addPattern('', '>', 'SHORTEST_MATCH')).to.equal(false); | ||
fDone(); | ||
} | ||
); | ||
test | ||
( | ||
'Bad pattern end parameter...', | ||
(fDone) => | ||
{ | ||
var testPrecedent = loadPrecedentModule(); | ||
configPrecedent(testPrecedent); | ||
Expect(testPrecedent.addPattern('<', '', 'SHORTEST_MATCH')).to.equal(false); | ||
fDone(); | ||
} | ||
); | ||
test | ||
( | ||
'Identifier fallback...', | ||
@@ -161,2 +183,86 @@ (fDone) => | ||
); | ||
test | ||
( | ||
'Config magic example...', | ||
(fDone) => | ||
{ | ||
// Use case is take a string with the following template expressions and translate them into the value from the environment variable if a default isn't passed in: | ||
// 'Expressions like ${VariableWithDefault|DefaultValue} have a Default value after the pipe; others like ${VariableWithoutDefault} expressions do not have a Default value after the pipe. but should be processed properly.', | ||
// 'Expressions like DefaultValue have a Default value after the pipe; others like VariableWithoutDefault expressions do not have a Default value after the pipe. but should be processed properly.', | ||
// The usual case is just expressions in the string, but composability is fine. | ||
var testPrecedent = new libPrecedent(); | ||
testPrecedent.addPattern('${', '}', | ||
(pTemplateValue)=> | ||
{ | ||
let tmpTemplateValue = pTemplateValue.trim(); | ||
let tmpSeparatorIndex = tmpTemplateValue.indexOf('|'); | ||
// If there is no pipe, the default value will end up being whatever the variable name is. | ||
let tmpDefaultValue = tmpTemplateValue.substring(tmpSeparatorIndex+1); | ||
let tmpEnvironmentVariableName = (tmpSeparatorIndex > -1) ? tmpTemplateValue.substring(0, tmpSeparatorIndex) : tmpTemplateValue; | ||
if (process.env.hasOwnProperty(tmpEnvironmentVariableName)) | ||
{ | ||
return process.env[tmpEnvironmentVariableName]; | ||
} | ||
else | ||
{ | ||
return tmpDefaultValue; | ||
} | ||
}); | ||
var tmpTestStrings = [ | ||
'Expressions like ${VariableWithDefault|DefaultValue} have a Default value after the pipe; others like ${VariableWithoutDefault} expressions do not have a Default value after the pipe. but should be processed properly.', | ||
'Expressions like DefaultValue have a Default value after the pipe; others like VariableWithoutDefault expressions do not have a Default value after the pipe. but should be processed properly.', | ||
'${PATH}', | ||
process.env.PATH, | ||
'AAA ${PATH}', | ||
'AAA '+process.env.PATH, | ||
' ${PATH} AAA ${PATH}', | ||
' '+process.env.PATH+' AAA '+process.env.PATH, | ||
'AAA ${PATH} BBB', | ||
'AAA '+process.env.PATH+' BBB', | ||
'AAA ${PATH} } BBB', | ||
'AAA '+process.env.PATH+' } BBB', | ||
'AAA ${ ${PATH} BBB', | ||
// Two start parameters isn't okay --- | ||
// ...it passes the pattern processor the following (without quotes): | ||
// " ${PATH" | ||
// Which is not going to match an environment variable. With the second | ||
'AAA ${PATH BBB', | ||
'${PATH|Malarky Default Value} ZZZ', | ||
process.env.PATH+' ZZZ', | ||
'${THISISNOTANENVIRONMENTVARIABLE|Real Default Value} ZZZed', | ||
'Real Default Value ZZZed', | ||
'${ THISISNOTANENVIRONMENTVARIABLETRIMMED|Real Trimmed Default Value } ZZZed', | ||
'Real Trimmed Default Value ZZZed', | ||
'${PATH} BBB', | ||
process.env.PATH+' BBB' | ||
]; | ||
var tmpResult = ''; | ||
// Test every pair in TestStrings | ||
for (var i = 0; i < tmpTestStrings.length; i+=2) | ||
{ | ||
tmpResult = testPrecedent.parseString(tmpTestStrings[i]); | ||
Expect(tmpResult).to.equal(tmpTestStrings[i+1]); | ||
} | ||
fDone(); | ||
} | ||
); | ||
} | ||
@@ -163,0 +269,0 @@ ); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
11
-38.89%73223
-59.45%24
-55.56%1046
-69.05%19
111.11%